]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/internal/obj, cmd/link: access global data via a GOT in -dynlink mode on arm64
authorMichael Hudson-Doyle <michael.hudson@canonical.com>
Thu, 27 Aug 2015 09:09:46 +0000 (21:09 +1200)
committerMichael Hudson-Doyle <michael.hudson@canonical.com>
Sun, 15 Nov 2015 23:40:22 +0000 (23:40 +0000)
Change-Id: I6ca9406207e40c7c2c661075ccfe57b6600235cf
Reviewed-on: https://go-review.googlesource.com/13997
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/cmd/internal/obj/arm64/a.out.go
src/cmd/internal/obj/arm64/anames7.go
src/cmd/internal/obj/arm64/asm7.go
src/cmd/internal/obj/arm64/obj7.go
src/cmd/internal/obj/link.go
src/cmd/link/internal/arm64/asm.go
src/cmd/link/internal/ld/elf.go

index 06c4ea552d36aeff2de9ea97c3c6d726d3b70f65..d3e1e5ecbbac06fa03a2ad8847858579febeb1d8 100644 (file)
@@ -322,6 +322,9 @@ const (
 
        C_ADDR // TODO(aram): explain difference from C_VCONADDR
 
+       // The GOT slot for a symbol in -dynlink mode.
+       C_GOTADDR
+
        // TLS "var" in local exec mode: will become a constant offset from
        // thread local base that is ultimately chosen by the program linker.
        C_TLS_LE
index f9df74ff89807189901dbb1a0699d7d294cac594..2d17d171628bfb06efa95eee324ac0fda791f15d 100644 (file)
@@ -55,6 +55,7 @@ var cnames7 = []string{
        "UOREG64K",
        "LOREG",
        "ADDR",
+       "GOTADDR",
        "TLS_LE",
        "TLS_IE",
        "ROFF",
index 243ff898179e24129082db7afa697a4e334e8a01..38fe3ee92d7f2f6a19f2570c040ce18d96868d45 100644 (file)
@@ -270,6 +270,7 @@ var optab = []Optab{
        {AMOVH, C_ADDR, C_NONE, C_REG, 65, 12, 0, 0, 0},
        {AMOVW, C_ADDR, C_NONE, C_REG, 65, 12, 0, 0, 0},
        {AMOVD, C_ADDR, C_NONE, C_REG, 65, 12, 0, 0, 0},
+       {AMOVD, C_GOTADDR, C_NONE, C_REG, 71, 8, 0, 0, 0},
        {AMOVD, C_TLS_LE, C_NONE, C_REG, 69, 4, 0, 0, 0},
        {AMOVD, C_TLS_IE, C_NONE, C_REG, 70, 8, 0, 0, 0},
        {AMUL, C_REG, C_REG, C_REG, 15, 4, 0, 0, 0},
@@ -981,6 +982,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
                        return autoclass(ctxt.Instoffset)
@@ -2789,6 +2793,16 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
                        ctxt.Diag("invalid offset on MOVW $tlsvar")
                }
 
+       case 71: /* movd sym@GOT, reg -> adrp REGTMP, #0; ldr reg, [REGTMP, #0] + relocs */
+               o1 = ADR(1, 0, REGTMP)
+               o2 = olsr12u(ctxt, int32(opldr12(ctxt, AMOVD)), 0, REGTMP, int(p.To.Reg))
+               rel := obj.Addrel(ctxt.Cursym)
+               rel.Off = int32(ctxt.Pc)
+               rel.Siz = 8
+               rel.Sym = p.From.Sym
+               rel.Add = 0
+               rel.Type = obj.R_ARM64_GOTPCREL
+
        // This is supposed to be something that stops execution.
        // It's not supposed to be reached, ever, but if it is, we'd
        // like to be able to tell how we got there.  Assemble as
index f6f8c7129540b3650130828b1c171d2de367644f..39330c6c12d9f1b9a9861ab256f5a71a2097e85e 100644 (file)
@@ -250,6 +250,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
                }
@@ -262,6 +263,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
                }
@@ -287,6 +289,121 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
 
                break
        }
+
+       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, REGTMP
+               //     ADD $offset, REGTMP
+               //     CALL REGTMP
+               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 = REGTMP
+               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 = REGTMP
+               p2 := obj.Appendp(ctxt, p1)
+               p2.As = obj.ACALL
+               p2.To.Type = obj.TYPE_REG
+               p2.To.Reg = REGTMP
+       }
+
+       // 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; MOVD 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 follow(ctxt *obj.Link, s *obj.LSym) {
index d6c4be13cc04b195fb2b3bd984d51e6702cfd6c6..511e4098d07b68a45521beba58de139957c311a1 100644 (file)
@@ -410,6 +410,8 @@ const (
        // the referenced symbol into the immediate field of the first instruction and the
        // low 16 bits into that of the second instruction.
        R_ADDRPOWER
+       // R_ADDRARM64 relocates an adrp, add pair to compute the address of the
+       // referenced symbol.
        R_ADDRARM64
        // R_ADDRMIPS (only used on mips64) resolves to a 32-bit external address,
        // by loading the address into a register with two instructions (lui, ori).
@@ -467,6 +469,10 @@ const (
        // referenced (thread local) symbol from the GOT.
        R_ARM64_TLS_IE
 
+       // R_ARM64_GOTPCREL relocates an adrp, ld64 pair to compute the address of the GOT
+       // slot of the referenced symbol.
+       R_ARM64_GOTPCREL
+
        // PPC64.
 
        // R_POWER_TLS_LE is used to implement the "local exec" model for tls
index 2b1f4d52c5c30beac1f6f93ce733a5c5a799172b..844a363d7a37ee310b7238dd52ca9ec86c14fbef 100644 (file)
@@ -133,6 +133,12 @@ func elfreloc1(r *ld.Reloc, sectoff int64) int {
                ld.Thearch.Vput(uint64(sectoff + 4))
                ld.Thearch.Vput(ld.R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC | uint64(elfsym)<<32)
 
+       case obj.R_ARM64_GOTPCREL:
+               ld.Thearch.Vput(ld.R_AARCH64_ADR_GOT_PAGE | uint64(elfsym)<<32)
+               ld.Thearch.Vput(uint64(r.Xadd))
+               ld.Thearch.Vput(uint64(sectoff + 4))
+               ld.Thearch.Vput(ld.R_AARCH64_LD64_GOT_LO12_NC | uint64(elfsym)<<32)
+
        case obj.R_CALLARM64:
                if r.Siz != 4 {
                        return -1
@@ -235,7 +241,8 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
                default:
                        return -1
 
-               case obj.R_ADDRARM64:
+               case obj.R_ADDRARM64,
+                       obj.R_ARM64_GOTPCREL:
                        r.Done = 0
 
                        // set up addend for eventual relocation via outer symbol.
@@ -246,7 +253,7 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
                                rs = rs.Outer
                        }
 
-                       if rs.Type != obj.SHOSTOBJ && rs.Sect == nil {
+                       if rs.Type != obj.SHOSTOBJ && rs.Type != obj.SDYNIMPORT && rs.Sect == nil {
                                ld.Diag("missing section for %s", rs.Name)
                        }
                        r.Xsym = rs
index a2ce0ab9e24c67c9d4697052fe7a2763a799b738..a34cf3cac865e72c16cabc2d5ef021ca3f2ab5ac 100644 (file)
@@ -372,6 +372,12 @@ const (
        R_AARCH64_CALL26                      = 283
        R_AARCH64_ADR_PREL_PG_HI21            = 275
        R_AARCH64_ADD_ABS_LO12_NC             = 277
+       R_AARCH64_LDST8_ABS_LO12_NC           = 278
+       R_AARCH64_LDST16_ABS_LO12_NC          = 284
+       R_AARCH64_LDST32_ABS_LO12_NC          = 285
+       R_AARCH64_LDST64_ABS_LO12_NC          = 286
+       R_AARCH64_ADR_GOT_PAGE                = 311
+       R_AARCH64_LD64_GOT_LO12_NC            = 312
        R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21   = 541
        R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC = 542
        R_AARCH64_TLSLE_MOVW_TPREL_G0         = 547