]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/internal/obj/x86, cmd/link: enable access to global data via GOT when -dynlink...
authorMichael Hudson-Doyle <michael.hudson@canonical.com>
Tue, 17 Nov 2015 23:30:23 +0000 (12:30 +1300)
committerMichael Hudson-Doyle <michael.hudson@canonical.com>
Wed, 18 Nov 2015 21:27:45 +0000 (21:27 +0000)
Change-Id: I97504a11291ee60e656efb7704e37387e864d74f
Reviewed-on: https://go-review.googlesource.com/16385
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/cmd/internal/obj/x86/asm6.go
src/cmd/internal/obj/x86/obj6.go
src/cmd/link/internal/x86/asm.go

index 219d29c44a67ec9dd97d09d636ce2584b130a9f3..04ef3b343f14fb4cd2d85dec47a4acf4fc8c1c3a 100644 (file)
@@ -4575,6 +4575,11 @@ func asmins(ctxt *obj.Link, p *obj.Prog) {
                                r.Add += int64(r.Off) - p.Pc + int64(r.Siz)
                        }
                }
+               if r.Type == obj.R_GOTPCREL && p.Mode == 32 {
+                       // On 386, R_GOTPCREL makes the same assumptions as R_PCREL.
+                       r.Add += int64(r.Off) - p.Pc + int64(r.Siz)
+               }
+
        }
 
        if p.Mode == 64 && ctxt.Headtype == obj.Hnacl && p.As != ACMPL && p.As != ACMPQ && p.To.Type == obj.TYPE_REG {
index c6e93a6902b0bd7a68fe039c1b2b087c914d56a3..ef22e55cd8892783ba234947a32c968d04bed068 100644 (file)
@@ -319,12 +319,25 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
 
 // Rewrite p, if necessary, to access global data via the global offset table.
 func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
+       var add, lea, mov, reg int16
+       if p.Mode == 64 {
+               add = AADDQ
+               lea = ALEAQ
+               mov = AMOVQ
+               reg = REG_R15
+       } else {
+               add = AADDL
+               lea = ALEAL
+               mov = AMOVL
+               reg = REG_CX
+       }
+
        if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
                //     ADUFFxxx $offset
                // becomes
-               //     MOVQ runtime.duffxxx@GOT, R15
-               //     ADDQ $offset, R15
-               //     CALL R15
+               //     $MOV runtime.duffxxx@GOT, $reg
+               //     $ADD $offset, $reg
+               //     CALL $reg
                var sym *obj.LSym
                if p.As == obj.ADUFFZERO {
                        sym = obj.Linklookup(ctxt, "runtime.duffzero", 0)
@@ -332,60 +345,78 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
                        sym = obj.Linklookup(ctxt, "runtime.duffcopy", 0)
                }
                offset := p.To.Offset
-               p.As = AMOVQ
+               p.As = mov
                p.From.Type = obj.TYPE_MEM
                p.From.Name = obj.NAME_GOTREF
                p.From.Sym = sym
                p.To.Type = obj.TYPE_REG
-               p.To.Reg = REG_R15
+               p.To.Reg = reg
                p.To.Offset = 0
                p.To.Sym = nil
                p1 := obj.Appendp(ctxt, p)
-               p1.As = AADDQ
+               p1.As = add
                p1.From.Type = obj.TYPE_CONST
                p1.From.Offset = offset
                p1.To.Type = obj.TYPE_REG
-               p1.To.Reg = REG_R15
+               p1.To.Reg = reg
                p2 := obj.Appendp(ctxt, p1)
                p2.As = obj.ACALL
                p2.To.Type = obj.TYPE_REG
-               p2.To.Reg = REG_R15
+               p2.To.Reg = reg
        }
 
        // We only care about global data: NAME_EXTERN means a global
        // symbol in the Go sense, and p.Sym.Local is true for a few
        // internally defined symbols.
-       if p.As == ALEAQ && p.From.Type == obj.TYPE_MEM && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
-               // LEAQ sym, Rx becomes MOVQ $sym, Rx which will be rewritten below
-               p.As = AMOVQ
+       if p.As == lea && p.From.Type == obj.TYPE_MEM && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
+               // $LEA sym, Rx becomes $MOV $sym, Rx which will be rewritten below
+               p.As = mov
                p.From.Type = obj.TYPE_ADDR
        }
        if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
-               // MOVQ $sym, Rx becomes MOVQ sym@GOT, Rx
-               // MOVQ $sym+<off>, Rx becomes MOVQ sym@GOT, Rx; ADDQ <off>, Rx
-               if p.As != AMOVQ {
-                       ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p)
-               }
-               if p.To.Type != obj.TYPE_REG {
-                       ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -dynlink", p)
+               // $MOV $sym, Rx becomes $MOV sym@GOT, Rx
+               // $MOV $sym+<off>, Rx becomes $MOV sym@GOT, Rx; $ADD <off>, Rx
+               // On 386 only, more complicated things like PUSHL $sym become $MOV sym@GOT, CX; PUSHL CX
+               cmplxdest := false
+               pAs := p.As
+               var dest obj.Addr
+               if p.To.Type != obj.TYPE_REG || pAs != mov {
+                       if p.Mode == 64 {
+                               ctxt.Diag("do not know how to handle LEA-type insn to non-register in %v with -dynlink", p)
+                       }
+                       cmplxdest = true
+                       dest = p.To
+                       p.As = mov
+                       p.To.Type = obj.TYPE_REG
+                       p.To.Reg = REG_CX
+                       p.To.Sym = nil
+                       p.To.Name = obj.NAME_NONE
                }
                p.From.Type = obj.TYPE_MEM
                p.From.Name = obj.NAME_GOTREF
+               q := p
                if p.From.Offset != 0 {
-                       q := obj.Appendp(ctxt, p)
-                       q.As = AADDQ
+                       q = obj.Appendp(ctxt, p)
+                       q.As = add
                        q.From.Type = obj.TYPE_CONST
                        q.From.Offset = p.From.Offset
                        q.To = p.To
                        p.From.Offset = 0
                }
+               if cmplxdest {
+                       q = obj.Appendp(ctxt, q)
+                       q.As = pAs
+                       q.To = dest
+                       q.From.Type = obj.TYPE_REG
+                       q.From.Reg = REG_CX
+               }
        }
        if p.From3 != nil && p.From3.Name == obj.NAME_EXTERN {
                ctxt.Diag("don't know how to handle %v with -dynlink", p)
        }
        var source *obj.Addr
-       // MOVx sym, Ry becomes MOVW sym@GOT, R15; MOVx (R15), Ry
-       // MOVx Ry, sym becomes MOVW sym@GOT, R15; MOVx Ry, (R15)
+       // MOVx sym, Ry becomes $MOV sym@GOT, R15; MOVx (R15), Ry
+       // MOVx Ry, sym becomes $MOV sym@GOT, R15; MOVx Ry, (R15)
        // An addition may be inserted between the two MOVs if there is an offset.
        if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
                if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local {
@@ -397,7 +428,41 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
        } else {
                return
        }
-       if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
+       if p.As == obj.ACALL {
+               // When dynlinking on 386, almost any call might end up being a call
+               // to a PLT, so make sure the GOT pointer is loaded into BX.
+               // RegTo2 is set on the replacement call insn to stop it being
+               // processed when it is in turn passed to progedit.
+               if p.Mode == 64 || (p.To.Sym != nil && p.To.Sym.Local) || p.RegTo2 != 0 {
+                       return
+               }
+               p1 := obj.Appendp(ctxt, p)
+               p2 := obj.Appendp(ctxt, p1)
+
+               p1.As = ALEAL
+               p1.From.Type = obj.TYPE_MEM
+               p1.From.Name = obj.NAME_STATIC
+               p1.From.Sym = obj.Linklookup(ctxt, "_GLOBAL_OFFSET_TABLE_", 0)
+               p1.To.Type = obj.TYPE_REG
+               p1.To.Reg = REG_BX
+
+               p2.As = p.As
+               p2.Scond = p.Scond
+               p2.From = p.From
+               p2.From3 = p.From3
+               p2.Reg = p.Reg
+               p2.To = p.To
+               // p.To.Type was set to TYPE_BRANCH above, but that makes checkaddr
+               // in ../pass.go complain, so set it back to TYPE_MEM here, until p2
+               // itself gets passed to progedit.
+               p2.To.Type = obj.TYPE_MEM
+               p2.RegTo2 = 1
+
+               obj.Nopout(p)
+               return
+
+       }
+       if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ARET || p.As == obj.AJMP {
                return
        }
        if source.Type != obj.TYPE_MEM {
@@ -406,22 +471,22 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
        p1 := obj.Appendp(ctxt, p)
        p2 := obj.Appendp(ctxt, p1)
 
-       p1.As = AMOVQ
+       p1.As = mov
        p1.From.Type = obj.TYPE_MEM
        p1.From.Sym = source.Sym
        p1.From.Name = obj.NAME_GOTREF
        p1.To.Type = obj.TYPE_REG
-       p1.To.Reg = REG_R15
+       p1.To.Reg = reg
 
        p2.As = p.As
        p2.From = p.From
        p2.To = p.To
        if p.From.Name == obj.NAME_EXTERN {
-               p2.From.Reg = REG_R15
+               p2.From.Reg = reg
                p2.From.Name = obj.NAME_NONE
                p2.From.Sym = nil
        } else if p.To.Name == obj.NAME_EXTERN {
-               p2.To.Reg = REG_R15
+               p2.To.Reg = reg
                p2.To.Name = obj.NAME_NONE
                p2.To.Sym = nil
        } else {
index 603aaa4ff1a58bf87e304c710c7c485106479626..5d214267fbe664d8d4f344a2f165937b532fdfc3 100644 (file)
@@ -267,8 +267,29 @@ func elfreloc1(r *ld.Reloc, sectoff int64) int {
                        return -1
                }
 
-       case obj.R_CALL,
-               obj.R_PCREL:
+       case obj.R_GOTPCREL:
+               if r.Siz == 4 {
+                       ld.Thearch.Lput(ld.R_386_GOTPC)
+                       if r.Xsym.Name != "_GLOBAL_OFFSET_TABLE_" {
+                               ld.Thearch.Lput(uint32(sectoff))
+                               ld.Thearch.Lput(ld.R_386_GOT32 | uint32(elfsym)<<8)
+                       }
+               } else {
+                       return -1
+               }
+
+       case obj.R_CALL:
+               if r.Siz == 4 {
+                       if r.Xsym.Type == obj.SDYNIMPORT {
+                               ld.Thearch.Lput(ld.R_386_PLT32 | uint32(elfsym)<<8)
+                       } else {
+                               ld.Thearch.Lput(ld.R_386_PC32 | uint32(elfsym)<<8)
+                       }
+               } else {
+                       return -1
+               }
+
+       case obj.R_PCREL:
                if r.Siz == 4 {
                        ld.Thearch.Lput(ld.R_386_PC32 | uint32(elfsym)<<8)
                } else {