aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMichael Hudson-Doyle <michael.hudson@canonical.com>2015-10-16 15:54:10 +1300
committerMichael Hudson-Doyle <michael.hudson@canonical.com>2015-11-13 00:25:21 +0000
commit2ac993107fcae841ca6e81ad75e88d8b5973a115 (patch)
tree09f3211e39ae055fb4b7e1a281e99b4cdc6ff0a9 /src
parent9a476028c0f109723026ff7880f14e306429128c (diff)
downloadgo-2ac993107fcae841ca6e81ad75e88d8b5973a115.tar.xz
cmd/internal/obj, cmd/link: access global data via GOT when dynlinking on ppc64le
Change-Id: I79c60241df6c785f35371e70c777a7bd6e93571c Reviewed-on: https://go-review.googlesource.com/15968 Reviewed-by: Russ Cox <rsc@golang.org>
Diffstat (limited to 'src')
-rw-r--r--src/cmd/internal/obj/link.go5
-rw-r--r--src/cmd/internal/obj/ppc64/a.out.go1
-rw-r--r--src/cmd/internal/obj/ppc64/anames9.go1
-rw-r--r--src/cmd/internal/obj/ppc64/asm9.go18
-rw-r--r--src/cmd/internal/obj/ppc64/obj9.go127
-rw-r--r--src/cmd/link/internal/ppc64/asm.go7
6 files changed, 159 insertions, 0 deletions
diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go
index a7e0c2f863..ee0b4e9fa4 100644
--- a/src/cmd/internal/obj/link.go
+++ b/src/cmd/internal/obj/link.go
@@ -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.
diff --git a/src/cmd/internal/obj/ppc64/a.out.go b/src/cmd/internal/obj/ppc64/a.out.go
index d28e1e895e..4f6cdcde06 100644
--- a/src/cmd/internal/obj/ppc64/a.out.go
+++ b/src/cmd/internal/obj/ppc64/a.out.go
@@ -221,6 +221,7 @@ const (
C_ANY
C_GOK
C_ADDR
+ C_GOTADDR
C_TLS_LE
C_TLS_IE
C_TEXTSIZE
diff --git a/src/cmd/internal/obj/ppc64/anames9.go b/src/cmd/internal/obj/ppc64/anames9.go
index 1b5d564dfe..d7140b1c8a 100644
--- a/src/cmd/internal/obj/ppc64/anames9.go
+++ b/src/cmd/internal/obj/ppc64/anames9.go
@@ -35,6 +35,7 @@ var cnames9 = []string{
"ANY",
"GOK",
"ADDR",
+ "GOTADDR",
"TLS_LE",
"TLS_IE",
"TEXTSIZE",
diff --git a/src/cmd/internal/obj/ppc64/asm9.go b/src/cmd/internal/obj/ppc64/asm9.go
index 25b9aef830..25deeada42 100644
--- a/src/cmd/internal/obj/ppc64/asm9.go
+++ b/src/cmd/internal/obj/ppc64/asm9.go
@@ -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
diff --git a/src/cmd/internal/obj/ppc64/obj9.go b/src/cmd/internal/obj/ppc64/obj9.go
index 389d6ac88d..a876b99a76 100644
--- a/src/cmd/internal/obj/ppc64/obj9.go
+++ b/src/cmd/internal/obj/ppc64/obj9.go
@@ -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) {
diff --git a/src/cmd/link/internal/ppc64/asm.go b/src/cmd/link/internal/ppc64/asm.go
index 706160d0fb..c16cd3cf7a 100644
--- a/src/cmd/link/internal/ppc64/asm.go
+++ b/src/cmd/link/internal/ppc64/asm.go
@@ -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