1
0
mirror of https://github.com/golang/go synced 2024-11-18 04:14:49 -07:00

[dev.link] cmd/link: begin converting gentext to loader APIs

Begin the job of converting the linker's "gentext" phase over to use
loader APIs. This patch includes most architectures except for s390x
and PPC (these will be added in subsequent patches, since they require
a couple of loader changes first).

Change-Id: Ic7f55c207dcdbbba657330ef007a72ff7c837416
Reviewed-on: https://go-review.googlesource.com/c/go/+/227017
Reviewed-by: Jeremy Faller <jeremy@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
This commit is contained in:
Than McIntosh 2020-04-01 13:42:20 -04:00
parent 6435590182
commit 8e457c865d
19 changed files with 125 additions and 171 deletions

View File

@ -45,59 +45,29 @@ func PADDR(x uint32) uint32 {
return x &^ 0x80000000
}
func Addcall(ctxt *ld.Link, s *sym.Symbol, t *sym.Symbol) int64 {
s.Attr |= sym.AttrReachable
i := s.Size
s.Size += 4
s.Grow(s.Size)
r := s.AddRel()
r.Sym = t
r.Off = int32(i)
r.Type = objabi.R_CALL
r.Siz = 4
return i + int64(r.Siz)
}
func gentext2(ctxt *ld.Link, ldr *loader.Loader) {
initfunc, addmoduledata := ld.PrepareAddmoduledata(ctxt)
if initfunc == nil {
return
}
func gentext(ctxt *ld.Link) {
if !ctxt.DynlinkingGo() {
return
}
addmoduledata := ctxt.Syms.Lookup("runtime.addmoduledata", 0)
if addmoduledata.Type == sym.STEXT && ctxt.BuildMode != ld.BuildModePlugin {
// we're linking a module containing the runtime -> no need for
// an init function
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 ...uint8) {
for _, op1 := range op {
initfunc.AddUint8(op1)
}
}
// 0000000000000000 <local.dso_init>:
// 0: 48 8d 3d 00 00 00 00 lea 0x0(%rip),%rdi # 7 <local.dso_init+0x7>
// 3: R_X86_64_PC32 runtime.firstmoduledata-0x4
o(0x48, 0x8d, 0x3d)
initfunc.AddPCRelPlus(ctxt.Arch, ctxt.Moduledata, 0)
initfunc.AddPCRelPlus(ctxt.Arch, ctxt.Moduledata2, 0)
// 7: e8 00 00 00 00 callq c <local.dso_init+0xc>
// 8: R_X86_64_PLT32 runtime.addmoduledata-0x4
o(0xe8)
Addcall(ctxt, initfunc, addmoduledata)
initfunc.AddSymRef(ctxt.Arch, addmoduledata, 0, objabi.R_CALL, 4)
// c: c3 retq
o(0xc3)
if ctxt.BuildMode == ld.BuildModePlugin {
ctxt.Textp = append(ctxt.Textp, addmoduledata)
}
ctxt.Textp = append(ctxt.Textp, initfunc)
initarray_entry := ctxt.Syms.Lookup("go.link.addmoduledatainit", 0)
initarray_entry.Attr |= sym.AttrReachable
initarray_entry.Attr |= sym.AttrLocal
initarray_entry.Type = sym.SINITARR
initarray_entry.AddAddr(ctxt.Arch, initfunc)
}
// makeWritable makes a readonly symbol writable if we do opcode rewriting.

View File

@ -54,7 +54,7 @@ func Init() (*sys.Arch, ld.Arch) {
Asmb2: asmb2,
Elfreloc1: elfreloc1,
Elfsetupplt: elfsetupplt,
Gentext: gentext,
Gentext2: gentext2,
Machoreloc1: machoreloc1,
PEreloc1: pereloc1,
TLSIEtoLE: tlsIEtoLE,

View File

@ -63,21 +63,12 @@ import (
// c: 00000004 .word 0x00000004
// c: R_ARM_GOT_PREL local.moduledata
func gentext(ctxt *ld.Link) {
if !ctxt.DynlinkingGo() {
func gentext2(ctxt *ld.Link, ldr *loader.Loader) {
initfunc, addmoduledata := ld.PrepareAddmoduledata(ctxt)
if initfunc == nil {
return
}
addmoduledata := ctxt.Syms.Lookup("runtime.addmoduledata", 0)
if addmoduledata.Type == sym.STEXT && ctxt.BuildMode != ld.BuildModePlugin {
// we're linking a module containing the runtime -> no need for
// an init function
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)
}
@ -85,30 +76,25 @@ func gentext(ctxt *ld.Link) {
o(0xe08f0000)
o(0xeafffffe)
rel := initfunc.AddRel()
rel.Off = 8
rel.Siz = 4
rel.Sym = ctxt.Syms.Lookup("runtime.addmoduledata", 0)
rel.Type = objabi.R_CALLARM
rel.Add = 0xeafffffe // vomit
rel := loader.Reloc{
Off: 8,
Size: 4,
Type: objabi.R_CALLARM,
Sym: addmoduledata,
Add: 0xeafffffe, // vomit
}
initfunc.AddReloc(rel)
o(0x00000000)
rel = initfunc.AddRel()
rel.Off = 12
rel.Siz = 4
rel.Sym = ctxt.Moduledata
rel.Type = objabi.R_PCREL
rel.Add = 4
if ctxt.BuildMode == ld.BuildModePlugin {
ctxt.Textp = append(ctxt.Textp, addmoduledata)
rel2 := loader.Reloc{
Off: 12,
Size: 4,
Type: objabi.R_PCREL,
Sym: ctxt.Moduledata2,
Add: 4,
}
ctxt.Textp = append(ctxt.Textp, initfunc)
initarray_entry := ctxt.Syms.Lookup("go.link.addmoduledatainit", 0)
initarray_entry.Attr |= sym.AttrReachable
initarray_entry.Attr |= sym.AttrLocal
initarray_entry.Type = sym.SINITARR
initarray_entry.AddAddr(ctxt.Arch, initfunc)
initfunc.AddReloc(rel2)
}
// Preserve highest 8 bits of a, and do addition to lower 24-bit

View File

@ -55,7 +55,7 @@ func Init() (*sys.Arch, ld.Arch) {
Asmb2: asmb2,
Elfreloc1: elfreloc1,
Elfsetupplt: elfsetupplt,
Gentext: gentext,
Gentext2: gentext2,
Machoreloc1: machoreloc1,
PEreloc1: pereloc1,

View File

@ -42,21 +42,12 @@ import (
"sync"
)
func gentext(ctxt *ld.Link) {
if !ctxt.DynlinkingGo() {
func gentext2(ctxt *ld.Link, ldr *loader.Loader) {
initfunc, addmoduledata := ld.PrepareAddmoduledata(ctxt)
if initfunc == nil {
return
}
addmoduledata := ctxt.Syms.Lookup("runtime.addmoduledata", 0)
if addmoduledata.Type == sym.STEXT && ctxt.BuildMode != ld.BuildModePlugin {
// we're linking a module containing the runtime -> no need for
// an init function
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)
}
@ -67,30 +58,24 @@ func gentext(ctxt *ld.Link) {
// 4: R_AARCH64_ADD_ABS_LO12_NC local.moduledata
o(0x90000000)
o(0x91000000)
rel := initfunc.AddRel()
rel.Off = 0
rel.Siz = 8
rel.Sym = ctxt.Moduledata
rel.Type = objabi.R_ADDRARM64
rel := loader.Reloc{
Off: 0,
Size: 8,
Type: objabi.R_ADDRARM64,
Sym: ctxt.Moduledata2,
}
initfunc.AddReloc(rel)
// 8: 14000000 b 0 <runtime.addmoduledata>
// 8: R_AARCH64_CALL26 runtime.addmoduledata
o(0x14000000)
rel = initfunc.AddRel()
rel.Off = 8
rel.Siz = 4
rel.Sym = ctxt.Syms.Lookup("runtime.addmoduledata", 0)
rel.Type = objabi.R_CALLARM64 // Really should be R_AARCH64_JUMP26 but doesn't seem to make any difference
if ctxt.BuildMode == ld.BuildModePlugin {
ctxt.Textp = append(ctxt.Textp, addmoduledata)
rel2 := loader.Reloc{
Off: 8,
Size: 4,
Type: objabi.R_CALLARM64, // Really should be R_AARCH64_JUMP26 but doesn't seem to make any difference
Sym: addmoduledata,
}
ctxt.Textp = append(ctxt.Textp, initfunc)
initarray_entry := ctxt.Syms.Lookup("go.link.addmoduledatainit", 0)
initarray_entry.Attr |= sym.AttrReachable
initarray_entry.Attr |= sym.AttrLocal
initarray_entry.Type = sym.SINITARR
initarray_entry.AddAddr(ctxt.Arch, initfunc)
initfunc.AddReloc(rel2)
}
func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool {

View File

@ -54,7 +54,7 @@ func Init() (*sys.Arch, ld.Arch) {
Asmb2: asmb2,
Elfreloc1: elfreloc1,
Elfsetupplt: elfsetupplt,
Gentext: gentext,
Gentext2: gentext2,
Machoreloc1: machoreloc1,
Androiddynld: "/system/bin/linker64",

View File

@ -32,6 +32,7 @@
package ld
import (
"cmd/link/internal/loader"
"cmd/link/internal/sym"
"io/ioutil"
"log"
@ -215,3 +216,46 @@ func atolwhex(s string) int64 {
n, _ := strconv.ParseInt(s, 0, 64)
return n
}
// PrepareAddmoduledata returns a symbol builder that target-specific
// code can use to build up the linker-generated go.link.addmoduledata
// function, along with the sym for runtime.addmoduledata itself. If
// this function is not needed (for example in cases where we're
// linking a module that contains the runtime) the returned builder
// will be nil.
func PrepareAddmoduledata(ctxt *Link) (*loader.SymbolBuilder, loader.Sym) {
if !ctxt.DynlinkingGo() {
return nil, 0
}
amd := ctxt.loader.LookupOrCreateSym("runtime.addmoduledata", 0)
if ctxt.loader.SymType(amd) == sym.STEXT && ctxt.BuildMode != BuildModePlugin {
// we're linking a module containing the runtime -> no need for
// an init function
return nil, 0
}
ctxt.loader.SetAttrReachable(amd, true)
// Create a new init func text symbol. Caller will populate this
// sym with arch-specific content.
ifs := ctxt.loader.LookupOrCreateSym("go.link.addmoduledata", 0)
initfunc := ctxt.loader.MakeSymbolUpdater(ifs)
ctxt.loader.SetAttrReachable(ifs, true)
ctxt.loader.SetAttrLocal(ifs, true)
initfunc.SetType(sym.STEXT)
// Add the init func and/or addmoduledata to Textp2.
if ctxt.BuildMode == BuildModePlugin {
ctxt.Textp2 = append(ctxt.Textp2, amd)
}
ctxt.Textp2 = append(ctxt.Textp2, initfunc.Sym())
// Create an init array entry
amdi := ctxt.loader.LookupOrCreateSym("go.link.addmoduledatainit", 0)
initarray_entry := ctxt.loader.MakeSymbolUpdater(amdi)
ctxt.loader.SetAttrReachable(amdi, true)
ctxt.loader.SetAttrLocal(amdi, true)
initarray_entry.SetType(sym.SINITARR)
initarray_entry.AddAddr(ctxt.Arch, ifs)
return initfunc, amd
}

View File

@ -263,6 +263,7 @@ type Arch struct {
Elfreloc1 func(*Link, *sym.Reloc, int64) bool
Elfsetupplt func(ctxt *Link, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym)
Gentext func(*Link)
Gentext2 func(*Link, *loader.Loader)
Machoreloc1 func(*sys.Arch, *OutBuf, *sym.Symbol, *sym.Reloc, int64) bool
PEreloc1 func(*sys.Arch, *OutBuf, *sym.Symbol, *sym.Reloc, int64) bool
Xcoffreloc1 func(*sys.Arch, *OutBuf, *sym.Symbol, *sym.Reloc, int64) bool

View File

@ -285,12 +285,19 @@ 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("loadlibfull")
ctxt.loadlibfull() // XXX do it here for now
bench.Start("Gentext")
thearch.Gentext(ctxt) // trampolines, call stubs, etc.
if thearch.Gentext2 == nil {
bench.Start("Gentext")
thearch.Gentext(ctxt) // trampolines, call stubs, etc.
}
bench.Start("textaddress")
ctxt.textaddress()
bench.Start("pclntab")

View File

@ -42,7 +42,7 @@ import (
"sync"
)
func gentext(ctxt *ld.Link) {
func gentext2(ctxt *ld.Link, ldr *loader.Loader) {
return
}

View File

@ -57,7 +57,7 @@ func Init() (*sys.Arch, ld.Arch) {
Asmb2: asmb2,
Elfreloc1: elfreloc1,
Elfsetupplt: elfsetupplt,
Gentext: gentext,
Gentext2: gentext2,
Machoreloc1: machoreloc1,
Linuxdynld: "/lib/ld.so.1",

View File

@ -42,7 +42,7 @@ import (
"sync"
)
func gentext(ctxt *ld.Link) {}
func gentext2(ctxt *ld.Link, ldr *loader.Loader) {}
func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool {
log.Fatalf("adddynrel not implemented")

View File

@ -56,7 +56,7 @@ func Init() (*sys.Arch, ld.Arch) {
Asmb2: asmb2,
Elfreloc1: elfreloc1,
Elfsetupplt: elfsetupplt,
Gentext: gentext,
Gentext2: gentext2,
Machoreloc1: machoreloc1,
Linuxdynld: "/lib64/ld64.so.1",

View File

@ -16,7 +16,7 @@ import (
"sync"
)
func gentext(ctxt *ld.Link) {
func gentext2(ctxt *ld.Link, ldr *loader.Loader) {
}
func adddynrela(target *ld.Target, syms *ld.ArchSyms, rel *sym.Symbol, s *sym.Symbol, r *sym.Reloc) {

View File

@ -28,7 +28,7 @@ func Init() (*sys.Arch, ld.Arch) {
Asmb2: asmb2,
Elfreloc1: elfreloc1,
Elfsetupplt: elfsetupplt,
Gentext: gentext,
Gentext2: gentext2,
Machoreloc1: machoreloc1,
Linuxdynld: "/lib/ld.so.1",

View File

@ -8,6 +8,7 @@ import (
"bytes"
"cmd/internal/objabi"
"cmd/link/internal/ld"
"cmd/link/internal/loader"
"cmd/link/internal/sym"
"io"
"regexp"
@ -38,7 +39,7 @@ const (
// funcValueOffset is the offset between the PC_F value of a function and the index of the function in WebAssembly
const funcValueOffset = 0x1000 // TODO(neelance): make function addresses play nice with heap addresses
func gentext(ctxt *ld.Link) {
func gentext2(ctxt *ld.Link, ldr *loader.Loader) {
}
type wasmFunc struct {

View File

@ -19,7 +19,7 @@ func Init() (*sys.Arch, ld.Arch) {
AssignAddress: assignAddress,
Asmb: asmb,
Asmb2: asmb2,
Gentext: gentext,
Gentext2: gentext2,
}
return sys.ArchWasm, theArch

View File

@ -41,20 +41,7 @@ import (
"sync"
)
// Append 4 bytes to s and create a R_CALL relocation targeting t to fill them in.
func addcall(ctxt *ld.Link, s *sym.Symbol, t *sym.Symbol) {
s.Attr |= sym.AttrReachable
i := s.Size
s.Size += 4
s.Grow(s.Size)
r := s.AddRel()
r.Sym = t
r.Off = int32(i)
r.Type = objabi.R_CALL
r.Siz = 4
}
func gentext(ctxt *ld.Link) {
func gentext2(ctxt *ld.Link, ldr *loader.Loader) {
if ctxt.DynlinkingGo() {
// We need get_pc_thunk.
} else {
@ -71,7 +58,7 @@ func gentext(ctxt *ld.Link) {
}
// Generate little thunks that load the PC of the next instruction into a register.
thunks := make([]*sym.Symbol, 0, 7+len(ctxt.Textp))
thunks := make([]loader.Sym, 0, 7+len(ctxt.Textp2))
for _, r := range [...]struct {
name string
num uint8
@ -85,10 +72,9 @@ func gentext(ctxt *ld.Link) {
{"si", 6},
{"di", 7},
} {
thunkfunc := ctxt.Syms.Lookup("__x86.get_pc_thunk."+r.name, 0)
thunkfunc.Type = sym.STEXT
thunkfunc.Attr |= sym.AttrLocal
thunkfunc.Attr |= sym.AttrReachable //TODO: remove?
thunkfunc := ldr.CreateSymForUpdate("__x86.get_pc_thunk."+r.name, 0)
thunkfunc.SetType(sym.STEXT)
ldr.SetAttrLocal(thunkfunc.Sym(), true)
o := func(op ...uint8) {
for _, op1 := range op {
thunkfunc.AddUint8(op1)
@ -100,23 +86,15 @@ func gentext(ctxt *ld.Link) {
// c3 ret
o(0xc3)
thunks = append(thunks, thunkfunc)
thunks = append(thunks, thunkfunc.Sym())
}
ctxt.Textp = append(thunks, ctxt.Textp...) // keep Textp in dependency order
ctxt.Textp2 = append(thunks, ctxt.Textp2...) // keep Textp2 in dependency order
addmoduledata := ctxt.Syms.Lookup("runtime.addmoduledata", 0)
if addmoduledata.Type == sym.STEXT && ctxt.BuildMode != ld.BuildModePlugin {
// we're linking a module containing the runtime -> no need for
// an init function
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 ...uint8) {
for _, op1 := range op {
initfunc.AddUint8(op1)
@ -135,38 +113,20 @@ func gentext(ctxt *ld.Link) {
o(0x53)
o(0xe8)
addcall(ctxt, initfunc, ctxt.Syms.Lookup("__x86.get_pc_thunk.cx", 0))
initfunc.AddSymRef(ctxt.Arch, ldr.Lookup("__x86.get_pc_thunk.cx", 0), 0, objabi.R_CALL, 4)
o(0x8d, 0x81)
initfunc.AddPCRelPlus(ctxt.Arch, ctxt.Moduledata, 6)
initfunc.AddPCRelPlus(ctxt.Arch, ctxt.Moduledata2, 6)
o(0x8d, 0x99)
i := initfunc.Size
initfunc.Size += 4
initfunc.Grow(initfunc.Size)
r := initfunc.AddRel()
r.Sym = ctxt.Syms.Lookup("_GLOBAL_OFFSET_TABLE_", 0)
r.Off = int32(i)
r.Type = objabi.R_PCREL
r.Add = 12
r.Siz = 4
gotsym := ldr.LookupOrCreateSym("_GLOBAL_OFFSET_TABLE_", 0)
initfunc.AddSymRef(ctxt.Arch, gotsym, 12, objabi.R_PCREL, 4)
o(0xe8)
addcall(ctxt, initfunc, addmoduledata)
initfunc.AddSymRef(ctxt.Arch, addmoduledata, 0, objabi.R_CALL, 4)
o(0x5b)
o(0xc3)
if ctxt.BuildMode == ld.BuildModePlugin {
ctxt.Textp = append(ctxt.Textp, addmoduledata)
}
ctxt.Textp = append(ctxt.Textp, initfunc)
initarray_entry := ctxt.Syms.Lookup("go.link.addmoduledatainit", 0)
initarray_entry.Attr |= sym.AttrReachable
initarray_entry.Attr |= sym.AttrLocal
initarray_entry.Type = sym.SINITARR
initarray_entry.AddAddr(ctxt.Arch, initfunc)
}
func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool {

View File

@ -54,7 +54,7 @@ func Init() (*sys.Arch, ld.Arch) {
Asmb2: asmb2,
Elfreloc1: elfreloc1,
Elfsetupplt: elfsetupplt,
Gentext: gentext,
Gentext2: gentext2,
Machoreloc1: machoreloc1,
PEreloc1: pereloc1,