]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/internal/obj/arm: access global data via GOT on arm when -dynlink
authorMichael Hudson-Doyle <michael.hudson@canonical.com>
Sun, 5 Jul 2015 09:49:11 +0000 (21:49 +1200)
committerMichael Hudson-Doyle <michael.hudson@canonical.com>
Tue, 10 Nov 2015 19:57:05 +0000 (19:57 +0000)
Change-Id: I88034611f56cc06bb47b0c431075cc78ca8dbb09
Reviewed-on: https://go-review.googlesource.com/14188
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/cmd/internal/obj/arm/asm5.go
src/cmd/internal/obj/arm/obj5.go

index 3bf4a31729577a20081f4aadb789c97c8bb778ba..87ebc842ef2c047518e16cd03cb7d8f3a9704057 100644 (file)
@@ -981,6 +981,7 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
                return C_NONE
 
        case obj.TYPE_REG:
+               ctxt.Instoffset = 0
                if REG_R0 <= a.Reg && a.Reg <= REG_R15 {
                        return C_REG
                }
@@ -1010,6 +1011,7 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
        case obj.TYPE_MEM:
                switch a.Name {
                case obj.NAME_EXTERN,
+                       obj.NAME_GOTREF,
                        obj.NAME_STATIC:
                        if a.Sym == nil || a.Sym.Name == "" {
                                fmt.Printf("null sym external\n")
@@ -1130,6 +1132,7 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
                        return C_LCON
 
                case obj.NAME_EXTERN,
+                       obj.NAME_GOTREF,
                        obj.NAME_STATIC:
                        s := a.Sym
                        if s == nil {
@@ -1589,7 +1592,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
                aclass(ctxt, &p.To)
 
                if ctxt.Instoffset != 0 {
-                       ctxt.Diag("%v: doesn't support BL offset(REG) where offset != 0", p)
+                       ctxt.Diag("%v: doesn't support BL offset(REG) with non-zero offset %d", p, ctxt.Instoffset)
                }
                o1 = oprrr(ctxt, ABL, int(p.Scond))
                o1 |= (uint32(p.To.Reg) & 15) << 0
@@ -1644,7 +1647,11 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
                        rel.Add = p.To.Offset
 
                        if ctxt.Flag_shared != 0 {
-                               rel.Type = obj.R_PCREL
+                               if p.To.Name == obj.NAME_GOTREF {
+                                       rel.Type = obj.R_GOTPCREL
+                               } else {
+                                       rel.Type = obj.R_PCREL
+                               }
                                rel.Add += ctxt.Pc - p.Rel.Pc - 8
                        } else {
                                rel.Type = obj.R_ADDR
index 00ab13ccc3f3a759d3b76af56ac1292bc3eea2e4..ae045049eefe32ebe0e80c968ac741f735576d4c 100644 (file)
@@ -129,6 +129,123 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
                        p.From.Offset = 0
                }
        }
+
+       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
+               //     MOVW runtime.duffxxx@GOT, R9
+               //     ADD $offset, R9
+               //     CALL (R9)
+               var sym *obj.LSym
+               if p.As == obj.ADUFFZERO {
+                       sym = obj.Linklookup(ctxt, "runtime.duffzero", 0)
+               } else {
+                       sym = obj.Linklookup(ctxt, "runtime.duffcopy", 0)
+               }
+               offset := p.To.Offset
+               p.As = AMOVW
+               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_R9
+               p.To.Name = obj.NAME_NONE
+               p.To.Offset = 0
+               p.To.Sym = nil
+               p1 := obj.Appendp(ctxt, p)
+               p1.As = AADD
+               p1.From.Type = obj.TYPE_CONST
+               p1.From.Offset = offset
+               p1.To.Type = obj.TYPE_REG
+               p1.To.Reg = REG_R9
+               p2 := obj.Appendp(ctxt, p1)
+               p2.As = obj.ACALL
+               p2.To.Type = obj.TYPE_MEM
+               p2.To.Reg = REG_R9
+               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.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
+               // MOVW $sym, Rx becomes MOVW sym@GOT, Rx
+               // MOVW $sym+<off>, Rx becomes MOVW sym@GOT, Rx; ADD <off>, Rx
+               if p.As != AMOVW {
+                       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 = AADD
+                       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
+       // MOVx sym, Ry becomes MOVW sym@GOT, R9; MOVx (R9), Ry
+       // MOVx Ry, sym becomes MOVW sym@GOT, R9; MOVx Ry, (R9)
+       // 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)
+               }
+               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.Sym.Type == obj.STLSBSS {
+               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 = AMOVW
+       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_R9
+
+       p2.As = p.As
+       p2.From = p.From
+       p2.To = p.To
+       if p.From.Name == obj.NAME_EXTERN {
+               p2.From.Reg = REG_R9
+               p2.From.Name = obj.NAME_NONE
+               p2.From.Sym = nil
+       } else if p.To.Name == obj.NAME_EXTERN {
+               p2.To.Reg = REG_R9
+               p2.To.Name = obj.NAME_NONE
+               p2.To.Sym = nil
+       } else {
+               return
+       }
+       obj.Nopout(p)
 }
 
 // Prog.mark