]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/internal/obj, cmd/link: access global data via GOT when dynlinking on ppc64le
authorMichael Hudson-Doyle <michael.hudson@canonical.com>
Fri, 16 Oct 2015 02:54:10 +0000 (15:54 +1300)
committerMichael Hudson-Doyle <michael.hudson@canonical.com>
Fri, 13 Nov 2015 00:25:21 +0000 (00:25 +0000)
Change-Id: I79c60241df6c785f35371e70c777a7bd6e93571c
Reviewed-on: https://go-review.googlesource.com/15968
Reviewed-by: Russ Cox <rsc@golang.org>
src/cmd/internal/obj/link.go
src/cmd/internal/obj/ppc64/a.out.go
src/cmd/internal/obj/ppc64/anames9.go
src/cmd/internal/obj/ppc64/asm9.go
src/cmd/internal/obj/ppc64/obj9.go
src/cmd/link/internal/ppc64/asm.go

index a7e0c2f863abb34e8e5b89e4d27b652d400511ac..ee0b4e9fa4242394105e889bc43328ce8d7210e2 100644 (file)
@@ -500,6 +500,11 @@ const (
        // bits of the address are not 0.
        R_ADDRPOWER_DS
 
+       // R_ADDRPOWER_PCREL relocates a D-form, DS-form instruction sequence like
+       // R_ADDRPOWER_DS but inserts the offset of the GOT slot for the referenced symbol
+       // from the TOC rather than the symbol's address.
+       R_ADDRPOWER_GOT
+
        // R_ADDRPOWER_PCREL relocates two D-form instructions like R_ADDRPOWER, but
        // inserts the displacement from the place being relocated to the address of the
        // the relocated symbol instead of just its address.
index d28e1e895e5a4ac7d5c0d689a34860fb2aa0344a..4f6cdcde06b8b0169383e1252400390409d31252 100644 (file)
@@ -221,6 +221,7 @@ const (
        C_ANY
        C_GOK
        C_ADDR
+       C_GOTADDR
        C_TLS_LE
        C_TLS_IE
        C_TEXTSIZE
index 1b5d564dfecf9fa31d007632ebef7e1e1c84ca91..d7140b1c8a0be7d3e24269ee6e2eac76deb8b8fd 100644 (file)
@@ -35,6 +35,7 @@ var cnames9 = []string{
        "ANY",
        "GOK",
        "ADDR",
+       "GOTADDR",
        "TLS_LE",
        "TLS_IE",
        "TEXTSIZE",
index 25b9aef83000c5e375ebda5372bed8e05b9799b3..25deeada42c374d008408cf338f93802b42d0267 100644 (file)
@@ -248,6 +248,8 @@ var optab = []Optab{
        {AMOVD, C_TLS_LE, C_NONE, C_NONE, C_REG, 79, 4, 0},
        {AMOVD, C_TLS_IE, C_NONE, C_NONE, C_REG, 80, 8, 0},
 
+       {AMOVD, C_GOTADDR, C_NONE, C_NONE, C_REG, 81, 8, 0},
+
        /* load constant */
        {AMOVD, C_SECON, C_NONE, C_NONE, C_REG, 3, 4, REGSB},
        {AMOVD, C_SACON, C_NONE, C_NONE, C_REG, 3, 4, REGSP},
@@ -598,6 +600,9 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
                        }
                        return C_LEXT
 
+               case obj.NAME_GOTREF:
+                       return C_GOTADDR
+
                case obj.NAME_AUTO:
                        ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset
                        if ctxt.Instoffset >= -BIG && ctxt.Instoffset < BIG {
@@ -2503,6 +2508,19 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
                rel.Sym = p.From.Sym
                rel.Type = obj.R_POWER_TLS_IE
 
+       case 81:
+               v := vregoff(ctxt, &p.To)
+               if v != 0 {
+                       ctxt.Diag("invalid offset against GOT slot %v", p)
+               }
+
+               o1 = AOP_IRR(OP_ADDIS, uint32(p.To.Reg), REG_R2, 0)
+               o2 = AOP_IRR(uint32(opload(ctxt, AMOVD)), uint32(p.To.Reg), uint32(p.To.Reg), 0)
+               rel := obj.Addrel(ctxt.Cursym)
+               rel.Off = int32(ctxt.Pc)
+               rel.Siz = 8
+               rel.Sym = p.From.Sym
+               rel.Type = obj.R_ADDRPOWER_GOT
        }
 
        out[0] = o1
index 389d6ac88d5079ce925c924ef0616f98d1c3a36f..a876b99a76990c7e1fd577a1cb5553e48531dc42 100644 (file)
@@ -63,6 +63,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
                        s.Size = 4
                        p.From.Type = obj.TYPE_MEM
                        p.From.Sym = s
+                       p.From.Sym.Local = true
                        p.From.Name = obj.NAME_EXTERN
                        p.From.Offset = 0
                }
@@ -75,6 +76,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
                        s.Size = 8
                        p.From.Type = obj.TYPE_MEM
                        p.From.Sym = s
+                       p.From.Sym.Local = true
                        p.From.Name = obj.NAME_EXTERN
                        p.From.Offset = 0
                }
@@ -87,6 +89,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
                        s.Size = 8
                        p.From.Type = obj.TYPE_MEM
                        p.From.Sym = s
+                       p.From.Sym.Local = true
                        p.From.Name = obj.NAME_EXTERN
                        p.From.Offset = 0
                }
@@ -112,6 +115,130 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
                        p.As = AADD
                }
        }
+       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
+               //     MOVD runtime.duffxxx@GOT, R12
+               //     ADD $offset, R12
+               //     MOVD R12, CTR
+               //     BL (CTR)
+               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 = AMOVD
+               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_R12
+               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_R12
+               p2 := obj.Appendp(ctxt, p1)
+               p2.As = AMOVD
+               p2.From.Type = obj.TYPE_REG
+               p2.From.Reg = REG_R12
+               p2.To.Type = obj.TYPE_REG
+               p2.To.Reg = REG_CTR
+               p3 := obj.Appendp(ctxt, p2)
+               p3.As = obj.ACALL
+               p3.From.Type = obj.TYPE_REG
+               p3.From.Reg = REG_R12
+               p3.To.Type = obj.TYPE_REG
+               p3.To.Reg = REG_CTR
+       }
+
+       // 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 {
+               // MOVD $sym, Rx becomes MOVD sym@GOT, Rx
+               // MOVD $sym+<off>, Rx becomes MOVD sym@GOT, Rx; ADD <off>, Rx
+               if p.As != AMOVD {
+                       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 MOVD sym@GOT, REGTMP; MOVx (REGTMP), Ry
+       // MOVx Ry, sym becomes MOVD sym@GOT, REGTMP; MOVx Ry, (REGTMP)
+       // 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 = AMOVD
+       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 = REGTMP
+
+       p2.As = p.As
+       p2.From = p.From
+       p2.To = p.To
+       if p.From.Name == obj.NAME_EXTERN {
+               p2.From.Reg = REGTMP
+               p2.From.Name = obj.NAME_NONE
+               p2.From.Sym = nil
+       } else if p.To.Name == obj.NAME_EXTERN {
+               p2.To.Reg = REGTMP
+               p2.To.Name = obj.NAME_NONE
+               p2.To.Sym = nil
+       } else {
+               return
+       }
+       obj.Nopout(p)
 }
 
 func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
index 706160d0fb0340322164878aa94b037e4f9e104e..c16cd3cf7af6d52dba9011f7d0edd85f1b3ccc2c 100644 (file)
@@ -334,6 +334,12 @@ func elfreloc1(r *ld.Reloc, sectoff int64) int {
                ld.Thearch.Vput(uint64(sectoff + 4))
                ld.Thearch.Vput(ld.R_PPC64_ADDR16_LO_DS | uint64(elfsym)<<32)
 
+       case obj.R_ADDRPOWER_GOT:
+               ld.Thearch.Vput(ld.R_PPC64_GOT16_HA | uint64(elfsym)<<32)
+               ld.Thearch.Vput(uint64(r.Xadd))
+               ld.Thearch.Vput(uint64(sectoff + 4))
+               ld.Thearch.Vput(ld.R_PPC64_GOT16_LO_DS | uint64(elfsym)<<32)
+
        case obj.R_ADDRPOWER_PCREL:
                ld.Thearch.Vput(ld.R_PPC64_REL16_HA | uint64(elfsym)<<32)
                ld.Thearch.Vput(uint64(r.Xadd))
@@ -464,6 +470,7 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
                        obj.R_ADDRPOWER_DS,
                        obj.R_ADDRPOWER_TOCREL,
                        obj.R_ADDRPOWER_TOCREL_DS,
+                       obj.R_ADDRPOWER_GOT,
                        obj.R_ADDRPOWER_PCREL:
                        r.Done = 0