]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/internal/obj, runtime: fixes for defer in 386 shared libraries
authorMichael Hudson-Doyle <michael.hudson@canonical.com>
Wed, 1 Jun 2016 23:07:55 +0000 (11:07 +1200)
committerMichael Hudson-Doyle <michael.hudson@canonical.com>
Fri, 3 Jun 2016 02:50:27 +0000 (02:50 +0000)
Any defer in a shared object crashed when GOARCH=386. This turns out to be two
bugs:

 1) Calls to morestack were not processed to be PIC safe (must have been
    possible to trigger this another way too)
 2) jmpdefer needs to rewind the return address of the deferred function past
    the instructions that load the GOT pointer into BX, not just past the call

Bug 2) requires re-introducing the a way for .s files to know when they are
being compiled for dynamic linking but I've tried to do that in as minimal
a way as possible.

Fixes #15916

Change-Id: Ia0d09b69ec272a176934176b8eaef5f3bfcacf04
Reviewed-on: https://go-review.googlesource.com/23623
Run-TryBot: Michael Hudson-Doyle <michael.hudson@canonical.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
misc/cgo/testshared/src/depBase/dep.go
src/cmd/go/build.go
src/cmd/internal/obj/x86/obj6.go
src/runtime/asm_386.s

index 3ceba34a2ba4f061e4d571deee094a7043848934..c3ae96fe98278072f4c0356e617c91d8c12e5314 100644 (file)
@@ -17,5 +17,6 @@ func (d *Dep) Method() int {
 }
 
 func F() int {
+       defer func() {}()
        return V
 }
index 5327fb9e4a57de6137eba8f669b4bd5b25a7172d..a6cd6e4f497315e286d932730e497caeb4f83002 100644 (file)
@@ -2328,7 +2328,15 @@ func (gcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
        // Add -I pkg/GOOS_GOARCH so #include "textflag.h" works in .s files.
        inc := filepath.Join(goroot, "pkg", "include")
        sfile = mkAbs(p.Dir, sfile)
-       args := []interface{}{buildToolExec, tool("asm"), "-o", ofile, "-trimpath", b.work, "-I", obj, "-I", inc, "-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch, buildAsmflags, sfile}
+       args := []interface{}{buildToolExec, tool("asm"), "-o", ofile, "-trimpath", b.work, "-I", obj, "-I", inc, "-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch, buildAsmflags}
+       if p.ImportPath == "runtime" && goarch == "386" {
+               for _, arg := range buildAsmflags {
+                       if arg == "-dynlink" {
+                               args = append(args, "-D=GOBUILDMODE_shared=1")
+                       }
+               }
+       }
+       args = append(args, sfile)
        if err := b.run(p.Dir, p.ImportPath, nil, args...); err != nil {
                return err
        }
index 5dad0bbb982616d921cd15d254d7544f2e298eb4..75638a0183be9cf7da14a84aae9240d29245e911 100644 (file)
@@ -1092,6 +1092,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, textarg int32) *ob
        call.Mode = ctxt.Cursym.Text.Mode
        call.As = obj.ACALL
        call.To.Type = obj.TYPE_BRANCH
+       call.To.Name = obj.NAME_EXTERN
        morestack := "runtime.morestack"
        switch {
        case ctxt.Cursym.Cfunc:
@@ -1100,8 +1101,17 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, textarg int32) *ob
                morestack = "runtime.morestack_noctxt"
        }
        call.To.Sym = obj.Linklookup(ctxt, morestack, 0)
+       // When compiling 386 code for dynamic linking, the call needs to be adjusted
+       // to follow PIC rules. This in turn can insert more instructions, so we need
+       // to keep track of the start of the call (where the jump will be to) and the
+       // end (which following instructions are appended to).
+       callend := call
+       progedit(ctxt, callend)
+       for ; callend.Link != nil; callend = callend.Link {
+               progedit(ctxt, callend.Link)
+       }
 
-       jmp := obj.Appendp(ctxt, call)
+       jmp := obj.Appendp(ctxt, callend)
        jmp.As = obj.AJMP
        jmp.To.Type = obj.TYPE_BRANCH
        jmp.Pcond = ctxt.Cursym.Text.Link
index 530fbb0e27fca52cabbe5096871d4e905475abaa..c18e588345f19a271bc395d68e2bd6e99fe5b910 100644 (file)
@@ -539,13 +539,20 @@ TEXT ·publicationBarrier(SB),NOSPLIT,$0-0
 // void jmpdefer(fn, sp);
 // called from deferreturn.
 // 1. pop the caller
-// 2. sub 5 bytes from the callers return
+// 2. sub 5 bytes (the length of CALL & a 32 bit displacement) from the callers
+//    return (when building for shared libraries, subtract 16 bytes -- 5 bytes
+//    for CALL & displacement to call __x86.get_pc_thunk.cx, 6 bytes for the
+//    LEAL to load the offset into BX, and finally 5 for the call & displacement)
 // 3. jmp to the argument
 TEXT runtime·jmpdefer(SB), NOSPLIT, $0-8
        MOVL    fv+0(FP), DX    // fn
        MOVL    argp+4(FP), BX  // caller sp
        LEAL    -4(BX), SP      // caller sp after CALL
+#ifdef GOBUILDMODE_shared
+       SUBL    $16, (SP)       // return to CALL again
+#else
        SUBL    $5, (SP)        // return to CALL again
+#endif
        MOVL    0(DX), BX
        JMP     BX      // but first run the deferred function