Commit 2ac99310 authored by Michael Hudson-Doyle's avatar Michael Hudson-Doyle

cmd/internal/obj, cmd/link: access global data via GOT when dynlinking on ppc64le

Change-Id: I79c60241df6c785f35371e70c777a7bd6e93571c
Reviewed-on: https://go-review.googlesource.com/15968Reviewed-by: default avatarRuss Cox <rsc@golang.org>
parent 9a476028
...@@ -500,6 +500,11 @@ const ( ...@@ -500,6 +500,11 @@ const (
// bits of the address are not 0. // bits of the address are not 0.
R_ADDRPOWER_DS 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 // 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 // inserts the displacement from the place being relocated to the address of the
// the relocated symbol instead of just its address. // the relocated symbol instead of just its address.
......
...@@ -221,6 +221,7 @@ const ( ...@@ -221,6 +221,7 @@ const (
C_ANY C_ANY
C_GOK C_GOK
C_ADDR C_ADDR
C_GOTADDR
C_TLS_LE C_TLS_LE
C_TLS_IE C_TLS_IE
C_TEXTSIZE C_TEXTSIZE
......
...@@ -35,6 +35,7 @@ var cnames9 = []string{ ...@@ -35,6 +35,7 @@ var cnames9 = []string{
"ANY", "ANY",
"GOK", "GOK",
"ADDR", "ADDR",
"GOTADDR",
"TLS_LE", "TLS_LE",
"TLS_IE", "TLS_IE",
"TEXTSIZE", "TEXTSIZE",
......
...@@ -248,6 +248,8 @@ var optab = []Optab{ ...@@ -248,6 +248,8 @@ var optab = []Optab{
{AMOVD, C_TLS_LE, C_NONE, C_NONE, C_REG, 79, 4, 0}, {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_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 */ /* load constant */
{AMOVD, C_SECON, C_NONE, C_NONE, C_REG, 3, 4, REGSB}, {AMOVD, C_SECON, C_NONE, C_NONE, C_REG, 3, 4, REGSB},
{AMOVD, C_SACON, C_NONE, C_NONE, C_REG, 3, 4, REGSP}, {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 { ...@@ -598,6 +600,9 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
} }
return C_LEXT return C_LEXT
case obj.NAME_GOTREF:
return C_GOTADDR
case obj.NAME_AUTO: case obj.NAME_AUTO:
ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset
if ctxt.Instoffset >= -BIG && ctxt.Instoffset < BIG { if ctxt.Instoffset >= -BIG && ctxt.Instoffset < BIG {
...@@ -2503,6 +2508,19 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) { ...@@ -2503,6 +2508,19 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
rel.Sym = p.From.Sym rel.Sym = p.From.Sym
rel.Type = obj.R_POWER_TLS_IE 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 out[0] = o1
......
...@@ -63,6 +63,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) { ...@@ -63,6 +63,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
s.Size = 4 s.Size = 4
p.From.Type = obj.TYPE_MEM p.From.Type = obj.TYPE_MEM
p.From.Sym = s p.From.Sym = s
p.From.Sym.Local = true
p.From.Name = obj.NAME_EXTERN p.From.Name = obj.NAME_EXTERN
p.From.Offset = 0 p.From.Offset = 0
} }
...@@ -75,6 +76,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) { ...@@ -75,6 +76,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
s.Size = 8 s.Size = 8
p.From.Type = obj.TYPE_MEM p.From.Type = obj.TYPE_MEM
p.From.Sym = s p.From.Sym = s
p.From.Sym.Local = true
p.From.Name = obj.NAME_EXTERN p.From.Name = obj.NAME_EXTERN
p.From.Offset = 0 p.From.Offset = 0
} }
...@@ -87,6 +89,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) { ...@@ -87,6 +89,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
s.Size = 8 s.Size = 8
p.From.Type = obj.TYPE_MEM p.From.Type = obj.TYPE_MEM
p.From.Sym = s p.From.Sym = s
p.From.Sym.Local = true
p.From.Name = obj.NAME_EXTERN p.From.Name = obj.NAME_EXTERN
p.From.Offset = 0 p.From.Offset = 0
} }
...@@ -112,6 +115,130 @@ func progedit(ctxt *obj.Link, p *obj.Prog) { ...@@ -112,6 +115,130 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
p.As = AADD 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) { func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
......
...@@ -334,6 +334,12 @@ func elfreloc1(r *ld.Reloc, sectoff int64) int { ...@@ -334,6 +334,12 @@ func elfreloc1(r *ld.Reloc, sectoff int64) int {
ld.Thearch.Vput(uint64(sectoff + 4)) ld.Thearch.Vput(uint64(sectoff + 4))
ld.Thearch.Vput(ld.R_PPC64_ADDR16_LO_DS | uint64(elfsym)<<32) 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: case obj.R_ADDRPOWER_PCREL:
ld.Thearch.Vput(ld.R_PPC64_REL16_HA | uint64(elfsym)<<32) ld.Thearch.Vput(ld.R_PPC64_REL16_HA | uint64(elfsym)<<32)
ld.Thearch.Vput(uint64(r.Xadd)) ld.Thearch.Vput(uint64(r.Xadd))
...@@ -464,6 +470,7 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int { ...@@ -464,6 +470,7 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
obj.R_ADDRPOWER_DS, obj.R_ADDRPOWER_DS,
obj.R_ADDRPOWER_TOCREL, obj.R_ADDRPOWER_TOCREL,
obj.R_ADDRPOWER_TOCREL_DS, obj.R_ADDRPOWER_TOCREL_DS,
obj.R_ADDRPOWER_GOT,
obj.R_ADDRPOWER_PCREL: obj.R_ADDRPOWER_PCREL:
r.Done = 0 r.Done = 0
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment