[dev.link] cmd/link: convert gentext for ppc64

Convert the ppc64 architecture's version of gentext to use the new
loader APIs.

Change-Id: Ib4af2608f4b246cb6dde07ceaa4a1f7ced45a700
Reviewed-on: https://go-review.googlesource.com/c/go/+/227021
Run-TryBot: Than McIntosh <thanm@google.com>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
Than McIntosh 2020-04-02 08:27:09 -04:00
parent 60baf83a82
commit 95ea64ba96
3 changed files with 119 additions and 127 deletions

View File

@ -285,19 +285,12 @@ func Main(arch *sys.Arch, theArch Arch) {
setupdynexp(ctxt)
ctxt.setArchSyms(BeforeLoadlibFull)
ctxt.addexport()
if thearch.Gentext2 != nil {
bench.Start("Gentext")
thearch.Gentext2(ctxt, ctxt.loader) // trampolines, call stubs, etc.
}
bench.Start("Gentext")
thearch.Gentext2(ctxt, ctxt.loader) // trampolines, call stubs, etc.
bench.Start("loadlibfull")
ctxt.loadlibfull() // XXX do it here for now
if thearch.Gentext2 == nil {
bench.Start("Gentext")
thearch.Gentext(ctxt) // trampolines, call stubs, etc.
}
bench.Start("textaddress")
ctxt.textaddress()
bench.Start("pclntab")

View File

@ -44,7 +44,7 @@ import (
"sync"
)
func genplt(ctxt *ld.Link) {
func genplt2(ctxt *ld.Link, ldr *loader.Loader) {
// The ppc64 ABI PLT has similar concepts to other
// architectures, but is laid out quite differently. When we
// see an R_PPC64_REL24 relocation to a dynamic symbol
@ -93,68 +93,73 @@ func genplt(ctxt *ld.Link) {
//
// This assumes "case 1" from the ABI, where the caller needs
// us to save and restore the TOC pointer.
var stubs []*sym.Symbol
for _, s := range ctxt.Textp {
for i := range s.R {
r := &s.R[i]
if r.Type != objabi.ElfRelocOffset+objabi.RelocType(elf.R_PPC64_REL24) || r.Sym.Type != sym.SDYNIMPORT {
var stubs []loader.Sym
for _, s := range ctxt.Textp2 {
relocs := ldr.Relocs(s)
for i := 0; i < relocs.Count(); i++ {
r := relocs.At2(i)
if r.Type() != objabi.ElfRelocOffset+objabi.RelocType(elf.R_PPC64_REL24) || ldr.SymType(r.Sym()) != sym.SDYNIMPORT {
continue
}
// Reserve PLT entry and generate symbol
// resolver
addpltsym(ctxt, r.Sym)
addpltsym2(ctxt, ldr, r.Sym())
// Generate call stub
n := fmt.Sprintf("%s.%s", s.Name, r.Sym.Name)
stub := ctxt.Syms.Lookup(n, 0)
if s.Attr.Reachable() {
stub.Attr |= sym.AttrReachable
}
if stub.Size == 0 {
// Need outer to resolve .TOC.
stub.Outer = s
stubs = append(stubs, stub)
gencallstub(ctxt, 1, stub, r.Sym)
// Generate call stub. Important to note that we're looking
// up the stub using the same version as the parent symbol (s),
// needed so that symtoc() will select the right .TOC. symbol
// when processing the stub. In older versions of the linker
// this was done by setting stub.Outer to the parent, but
// if the stub has the right version initially this is not needed.
n := fmt.Sprintf("%s.%s", ldr.SymName(s), ldr.SymName(r.Sym()))
stub := ldr.CreateSymForUpdate(n, ldr.SymVersion(s))
if stub.Size() == 0 {
stubs = append(stubs, stub.Sym())
gencallstub2(ctxt, ldr, 1, stub, r.Sym())
}
// Update the relocation to use the call stub
r.Sym = stub
r.SetSym(stub.Sym())
// make sure the data is writeable
if ldr.AttrReadOnly(s) {
panic("can't write to read-only sym data")
}
// Restore TOC after bl. The compiler put a
// nop here for us to overwrite.
sp := ldr.Data(s)
const o1 = 0xe8410018 // ld r2,24(r1)
ctxt.Arch.ByteOrder.PutUint32(s.P[r.Off+4:], o1)
ctxt.Arch.ByteOrder.PutUint32(sp[r.Off()+4:], o1)
}
}
// Put call stubs at the beginning (instead of the end).
// So when resolving the relocations to calls to the stubs,
// the addresses are known and trampolines can be inserted
// when necessary.
ctxt.Textp = append(stubs, ctxt.Textp...)
ctxt.Textp2 = append(stubs, ctxt.Textp2...)
}
func genaddmoduledata(ctxt *ld.Link) {
addmoduledata := ctxt.Syms.ROLookup("runtime.addmoduledata", sym.SymVerABI0)
if addmoduledata.Type == sym.STEXT && ctxt.BuildMode != ld.BuildModePlugin {
func genaddmoduledata2(ctxt *ld.Link, ldr *loader.Loader) {
initfunc, addmoduledata := ld.PrepareAddmoduledata(ctxt)
if initfunc == nil {
return
}
addmoduledata.Attr |= sym.AttrReachable
initfunc := ctxt.Syms.Lookup("go.link.addmoduledata", 0)
initfunc.Type = sym.STEXT
initfunc.Attr |= sym.AttrLocal
initfunc.Attr |= sym.AttrReachable
o := func(op uint32) {
initfunc.AddUint32(ctxt.Arch, op)
}
// addis r2, r12, .TOC.-func@ha
rel := initfunc.AddRel()
rel.Off = int32(initfunc.Size)
rel.Siz = 8
rel.Sym = ctxt.Syms.Lookup(".TOC.", 0)
rel.Sym.Attr |= sym.AttrReachable
rel.Type = objabi.R_ADDRPOWER_PCREL
toc := ctxt.DotTOC2[0]
rel1 := loader.Reloc{
Off: 0,
Size: 8,
Type: objabi.R_ADDRPOWER_PCREL,
Sym: toc,
}
initfunc.AddReloc(rel1)
o(0x3c4c0000)
// addi r2, r2, .TOC.-func@l
o(0x38420000)
@ -163,28 +168,32 @@ func genaddmoduledata(ctxt *ld.Link) {
// stdu r31, -32(r1)
o(0xf801ffe1)
// addis r3, r2, local.moduledata@got@ha
rel = initfunc.AddRel()
rel.Off = int32(initfunc.Size)
rel.Siz = 8
if s := ctxt.Syms.ROLookup("local.moduledata", 0); s != nil {
rel.Sym = s
} else if s := ctxt.Syms.ROLookup("local.pluginmoduledata", 0); s != nil {
rel.Sym = s
var tgt loader.Sym
if s := ldr.Lookup("local.moduledata", 0); s != 0 {
tgt = s
} else if s := ldr.Lookup("local.pluginmoduledata", 0); s != 0 {
tgt = s
} else {
rel.Sym = ctxt.Syms.Lookup("runtime.firstmoduledata", 0)
tgt = ldr.LookupOrCreateSym("runtime.firstmoduledata", 0)
}
rel.Sym.Attr |= sym.AttrReachable
rel.Sym.Attr |= sym.AttrLocal
rel.Type = objabi.R_ADDRPOWER_GOT
rel2 := loader.Reloc{
Off: int32(initfunc.Size()),
Size: 8,
Type: objabi.R_ADDRPOWER_GOT,
Sym: tgt,
}
initfunc.AddReloc(rel2)
o(0x3c620000)
// ld r3, local.moduledata@got@l(r3)
o(0xe8630000)
// bl runtime.addmoduledata
rel = initfunc.AddRel()
rel.Off = int32(initfunc.Size)
rel.Siz = 4
rel.Sym = addmoduledata
rel.Type = objabi.R_CALLPOWER
rel3 := loader.Reloc{
Off: int32(initfunc.Size()),
Size: 4,
Type: objabi.R_CALLPOWER,
Sym: addmoduledata,
}
initfunc.AddReloc(rel3)
o(0x48000001)
// nop
o(0x60000000)
@ -196,67 +205,61 @@ func genaddmoduledata(ctxt *ld.Link) {
o(0x38210020)
// blr
o(0x4e800020)
if ctxt.BuildMode == ld.BuildModePlugin {
ctxt.Textp = append(ctxt.Textp, addmoduledata)
}
initarray_entry := ctxt.Syms.Lookup("go.link.addmoduledatainit", 0)
ctxt.Textp = append(ctxt.Textp, initfunc)
initarray_entry.Attr |= sym.AttrReachable
initarray_entry.Attr |= sym.AttrLocal
initarray_entry.Type = sym.SINITARR
initarray_entry.AddAddr(ctxt.Arch, initfunc)
}
func gentext(ctxt *ld.Link) {
func gentext2(ctxt *ld.Link, ldr *loader.Loader) {
if ctxt.DynlinkingGo() {
genaddmoduledata(ctxt)
genaddmoduledata2(ctxt, ldr)
}
if ctxt.LinkMode == ld.LinkInternal {
genplt(ctxt)
genplt2(ctxt, ldr)
}
}
// Construct a call stub in stub that calls symbol targ via its PLT
// entry.
func gencallstub(ctxt *ld.Link, abicase int, stub *sym.Symbol, targ *sym.Symbol) {
func gencallstub2(ctxt *ld.Link, ldr *loader.Loader, abicase int, stub *loader.SymbolBuilder, targ loader.Sym) {
if abicase != 1 {
// If we see R_PPC64_TOCSAVE or R_PPC64_REL24_NOTOC
// relocations, we'll need to implement cases 2 and 3.
log.Fatalf("gencallstub only implements case 1 calls")
}
plt := ctxt.Syms.Lookup(".plt", 0)
plt := ctxt.PLT2
stub.Type = sym.STEXT
stub.SetType(sym.STEXT)
// Save TOC pointer in TOC save slot
stub.AddUint32(ctxt.Arch, 0xf8410018) // std r2,24(r1)
// Load the function pointer from the PLT.
r := stub.AddRel()
r.Off = int32(stub.Size)
r.Sym = plt
r.Add = int64(targ.Plt())
r.Siz = 2
if ctxt.Arch.ByteOrder == binary.BigEndian {
r.Off += int32(r.Siz)
rel := loader.Reloc{
Off: int32(stub.Size()),
Size: 2,
Add: int64(ldr.SymPlt(targ)),
Type: objabi.R_POWER_TOC,
Sym: plt,
}
r.Type = objabi.R_POWER_TOC
r.Variant = sym.RV_POWER_HA
if ctxt.Arch.ByteOrder == binary.BigEndian {
rel.Off += int32(rel.Size)
}
ri1 := stub.AddReloc(rel)
ldr.SetRelocVariant(stub.Sym(), int(ri1), sym.RV_POWER_HA)
stub.AddUint32(ctxt.Arch, 0x3d820000) // addis r12,r2,targ@plt@toc@ha
r = stub.AddRel()
r.Off = int32(stub.Size)
r.Sym = plt
r.Add = int64(targ.Plt())
r.Siz = 2
if ctxt.Arch.ByteOrder == binary.BigEndian {
r.Off += int32(r.Siz)
rel2 := loader.Reloc{
Off: int32(stub.Size()),
Size: 2,
Add: int64(ldr.SymPlt(targ)),
Type: objabi.R_POWER_TOC,
Sym: plt,
}
r.Type = objabi.R_POWER_TOC
r.Variant = sym.RV_POWER_LO
if ctxt.Arch.ByteOrder == binary.BigEndian {
rel2.Off += int32(rel.Size)
}
ri2 := stub.AddReloc(rel2)
ldr.SetRelocVariant(stub.Sym(), int(ri2), sym.RV_POWER_LO)
stub.AddUint32(ctxt.Arch, 0xe98c0000) // ld r12,targ@plt@toc@l(r12)
// Jump to the loaded pointer
@ -956,31 +959,32 @@ overflow:
return t
}
func addpltsym(ctxt *ld.Link, s *sym.Symbol) {
if s.Plt() >= 0 {
func addpltsym2(ctxt *ld.Link, ldr *loader.Loader, s loader.Sym) {
if ldr.SymPlt(s) >= 0 {
return
}
ld.Adddynsym(&ctxt.Target, &ctxt.ArchSyms, s)
ld.Adddynsym2(ldr, &ctxt.ErrorReporter, &ctxt.Target, &ctxt.ArchSyms, s)
if ctxt.IsELF {
plt := ctxt.Syms.Lookup(".plt", 0)
rela := ctxt.Syms.Lookup(".rela.plt", 0)
if plt.Size == 0 {
plt := ldr.MakeSymbolUpdater(ctxt.PLT2)
rela := ldr.MakeSymbolUpdater(ctxt.RelaPLT2)
if plt.Size() == 0 {
panic("plt is not set up")
}
// Create the glink resolver if necessary
glink := ensureglinkresolver(ctxt)
glink := ensureglinkresolver2(ctxt, ldr)
// Write symbol resolver stub (just a branch to the
// glink resolver stub)
r := glink.AddRel()
r.Sym = glink
r.Off = int32(glink.Size)
r.Siz = 4
r.Type = objabi.R_CALLPOWER
rel := loader.Reloc{
Off: int32(glink.Size()),
Size: 4,
Type: objabi.R_CALLPOWER,
Sym: glink.Sym(),
}
glink.AddReloc(rel)
glink.AddUint32(ctxt.Arch, 0x48000000) // b .glink
// In the ppc64 ABI, the dynamic linker is responsible
@ -989,22 +993,23 @@ func addpltsym(ctxt *ld.Link, s *sym.Symbol) {
// JMP_SLOT dynamic relocation for it.
//
// TODO(austin): ABI v1 is different
s.SetPlt(int32(plt.Size))
ldr.SetPlt(s, int32(plt.Size()))
plt.Size += 8
plt.Grow(plt.Size() + 8)
rela.AddAddrPlus(ctxt.Arch, plt, int64(s.Plt()))
rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_PPC64_JMP_SLOT)))
rela.AddAddrPlus(ctxt.Arch, plt.Sym(), int64(ldr.SymPlt(s)))
rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(uint32(ldr.SymDynid(s)), uint32(elf.R_PPC64_JMP_SLOT)))
rela.AddUint64(ctxt.Arch, 0)
} else {
ld.Errorf(s, "addpltsym: unsupported binary format")
ctxt.Errorf(s, "addpltsym: unsupported binary format")
}
}
// Generate the glink resolver stub if necessary and return the .glink section
func ensureglinkresolver(ctxt *ld.Link) *sym.Symbol {
glink := ctxt.Syms.Lookup(".glink", 0)
if glink.Size != 0 {
func ensureglinkresolver2(ctxt *ld.Link, ldr *loader.Loader) *loader.SymbolBuilder {
gs := ldr.LookupOrCreateSym(".glink", 0)
glink := ldr.MakeSymbolUpdater(gs)
if glink.Size() != 0 {
return glink
}
@ -1030,12 +1035,7 @@ func ensureglinkresolver(ctxt *ld.Link) *sym.Symbol {
glink.AddUint32(ctxt.Arch, 0x7800f082) // srdi r0,r0,2
// r11 = address of the first byte of the PLT
r := glink.AddRel()
r.Off = int32(glink.Size)
r.Sym = ctxt.Syms.Lookup(".plt", 0)
r.Siz = 8
r.Type = objabi.R_ADDRPOWER
glink.AddSymRef(ctxt.Arch, ctxt.PLT2, 0, objabi.R_ADDRPOWER, 8)
glink.AddUint32(ctxt.Arch, 0x3d600000) // addis r11,0,.plt@ha
glink.AddUint32(ctxt.Arch, 0x396b0000) // addi r11,r11,.plt@l
@ -1054,9 +1054,8 @@ func ensureglinkresolver(ctxt *ld.Link) *sym.Symbol {
// Add DT_PPC64_GLINK .dynamic entry, which points to 32 bytes
// before the first symbol resolver stub.
s := ctxt.Syms.Lookup(".dynamic", 0)
ld.Elfwritedynentsymplus(ctxt.Arch, s, ld.DT_PPC64_GLINK, glink, glink.Size-32)
du := ldr.MakeSymbolUpdater(ctxt.Dynamic2)
ld.Elfwritedynentsymplus2(ctxt, du, ld.DT_PPC64_GLINK, glink.Sym(), glink.Size()-32)
return glink
}

View File

@ -57,7 +57,7 @@ func Init() (*sys.Arch, ld.Arch) {
Asmb2: asmb2,
Elfreloc1: elfreloc1,
Elfsetupplt: elfsetupplt,
Gentext: gentext,
Gentext2: gentext2,
Trampoline: trampoline,
Machoreloc1: machoreloc1,
Xcoffreloc1: xcoffreloc1,