]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/internal/obj/x86: factor rewriting to use GOT into separate function
authorMichael Hudson-Doyle <michael.hudson@canonical.com>
Wed, 11 Nov 2015 02:57:42 +0000 (15:57 +1300)
committerMichael Hudson-Doyle <michael.hudson@canonical.com>
Wed, 18 Nov 2015 21:25:55 +0000 (21:25 +0000)
I was prodded into doing this in review comments for the ARM version, and it's
going to make shared libs for 386 easier.

Change-Id: Id12de801b1425b8c6b5736fe91b418fc123a4e40
Reviewed-on: https://go-review.googlesource.com/17012
Reviewed-by: David Crawshaw <crawshaw@golang.org>
src/cmd/internal/obj/x86/asm6.go
src/cmd/internal/obj/x86/obj6.go
src/cmd/internal/obj/x86/obj6_test.go

index 416ed71231d4f2197415de2a4ce7d2db33f8b353..95b79e169578d4122b44f87167ccb456ceafbfb6 100644 (file)
@@ -2090,8 +2090,11 @@ func oclass(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int {
 
        case obj.TYPE_ADDR:
                switch a.Name {
+               case obj.NAME_GOTREF:
+                       ctxt.Diag("unexpected TYPE_ADDR with NAME_GOTREF")
+                       return Yxxx
+
                case obj.NAME_EXTERN,
-                       obj.NAME_GOTREF,
                        obj.NAME_STATIC:
                        if a.Sym != nil && isextern(a.Sym) || p.Mode == 32 {
                                return Yi32
index 49fa22aef06c1addd2bcc76930915b46406aaf48..f19fc7789800468df5f589f51b861559b15b100f 100644 (file)
@@ -308,7 +308,19 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
                }
        }
 
-       if ctxt.Flag_dynlink && (p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO) {
+       if ctxt.Flag_dynlink {
+               rewriteToUseGot(ctxt, p)
+       }
+}
+
+// Rewrite p, if necessary, to access global data via the global offset table.
+func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
+       if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
+               //     ADUFFxxx $offset
+               // becomes
+               //     MOVQ runtime.duffxxx@GOT, R15
+               //     ADDQ $offset, R15
+               //     CALL R15
                var sym *obj.LSym
                if p.As == obj.ADUFFZERO {
                        sym = obj.Linklookup(ctxt, "runtime.duffzero", 0)
@@ -336,80 +348,82 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
                p2.To.Reg = REG_R15
        }
 
-       if ctxt.Flag_dynlink {
-               if p.As == ALEAQ && p.From.Type == obj.TYPE_MEM && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
-                       p.As = AMOVQ
-                       p.From.Type = obj.TYPE_ADDR
-               }
-               if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
-                       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)
-                       }
-                       p.From.Type = obj.TYPE_MEM
-                       p.From.Name = obj.NAME_GOTREF
-                       if p.From.Offset != 0 {
-                               q := obj.Appendp(ctxt, p)
-                               q.As = AADDQ
-                               q.From.Type = obj.TYPE_CONST
-                               q.From.Offset = p.From.Offset
-                               q.To = p.To
-                               p.From.Offset = 0
-                       }
-               }
-               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
-               if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
-                       if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local {
-                               ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
-                       }
-                       source = &p.From
-               } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local {
-                       source = &p.To
-               } else {
-                       return
+       // 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
+               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.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
-                       return
+               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)
                }
-               if source.Type != obj.TYPE_MEM {
-                       ctxt.Diag("don't know how to handle %v with -dynlink", p)
+               p.From.Type = obj.TYPE_MEM
+               p.From.Name = obj.NAME_GOTREF
+               if p.From.Offset != 0 {
+                       q := obj.Appendp(ctxt, p)
+                       q.As = AADDQ
+                       q.From.Type = obj.TYPE_CONST
+                       q.From.Offset = p.From.Offset
+                       q.To = p.To
+                       p.From.Offset = 0
                }
-               p1 := obj.Appendp(ctxt, p)
-               p2 := obj.Appendp(ctxt, p1)
-
-               p1.As = AMOVQ
-               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
-
-               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.Name = obj.NAME_NONE
-                       p2.From.Sym = nil
-               } else if p.To.Name == obj.NAME_EXTERN {
-                       p2.To.Reg = REG_R15
-                       p2.To.Name = obj.NAME_NONE
-                       p2.To.Sym = nil
-               } else {
-                       return
+       }
+       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)
+       // 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 {
+                       ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
                }
-               l := p.Link
-               l2 := p2.Link
-               *p = *p1
-               *p1 = *p2
-               p.Link = l
-               p1.Link = l2
+               source = &p.From
+       } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local {
+               source = &p.To
+       } else {
+               return
+       }
+       if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
+               return
+       }
+       if source.Type != obj.TYPE_MEM {
+               ctxt.Diag("don't know how to handle %v with -dynlink", p)
+       }
+       p1 := obj.Appendp(ctxt, p)
+       p2 := obj.Appendp(ctxt, p1)
+
+       p1.As = AMOVQ
+       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
+
+       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.Name = obj.NAME_NONE
+               p2.From.Sym = nil
+       } else if p.To.Name == obj.NAME_EXTERN {
+               p2.To.Reg = REG_R15
+               p2.To.Name = obj.NAME_NONE
+               p2.To.Sym = nil
+       } else {
+               return
        }
+       obj.Nopout(p)
 }
 
 func nacladdr(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
index 63021075367c3e5461e1505e673cf4c1e4235f4a..4387db696d0cbe522e82256188f1927c8b5da355 100644 (file)
@@ -24,13 +24,13 @@ LEAQ name+10(SB), AX -> MOVQ name@GOT(SB), AX; ADDQ $10, AX
 MOVQ $name(SB), AX -> MOVQ name@GOT(SB), AX
 MOVQ $name+10(SB), AX -> MOVQ name@GOT(SB), AX; ADDQ $10, AX
 
-MOVQ name(SB), AX -> MOVQ name@GOT(SB), R15; MOVQ (R15), AX
-MOVQ name+10(SB), AX -> MOVQ name@GOT(SB), R15; MOVQ 10(R15), AX
+MOVQ name(SB), AX -> NOP; MOVQ name@GOT(SB), R15; MOVQ (R15), AX
+MOVQ name+10(SB), AX -> NOP; MOVQ name@GOT(SB), R15; MOVQ 10(R15), AX
 
-CMPQ name(SB), $0 -> MOVQ name@GOT(SB), R15; CMPQ (R15), $0
+CMPQ name(SB), $0 -> NOP; MOVQ name@GOT(SB), R15; CMPQ (R15), $0
 
-MOVQ $1, name(SB) -> MOVQ name@GOT(SB), R15; MOVQ $1, (R15)
-MOVQ $1, name+10(SB) -> MOVQ name@GOT(SB), R15; MOVQ $1, 10(R15)
+MOVQ $1, name(SB) -> NOP; MOVQ name@GOT(SB), R15; MOVQ $1, (R15)
+MOVQ $1, name+10(SB) -> NOP; MOVQ name@GOT(SB), R15; MOVQ $1, 10(R15)
 `
 
 type ParsedTestData struct {