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 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
+func gentext2(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 ...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.
Asmb2: asmb2,
Elfreloc1: elfreloc1,
Elfsetupplt: elfsetupplt,
- Gentext: gentext,
+ Gentext2: gentext2,
Machoreloc1: machoreloc1,
PEreloc1: pereloc1,
TLSIEtoLE: tlsIEtoLE,
// 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)
}
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)
- }
- 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)
+
+ rel2 := loader.Reloc{
+ Off: 12,
+ Size: 4,
+ Type: objabi.R_PCREL,
+ Sym: ctxt.Moduledata2,
+ Add: 4,
+ }
+ initfunc.AddReloc(rel2)
}
// Preserve highest 8 bits of a, and do addition to lower 24-bit
Asmb2: asmb2,
Elfreloc1: elfreloc1,
Elfsetupplt: elfsetupplt,
- Gentext: gentext,
+ Gentext2: gentext2,
Machoreloc1: machoreloc1,
PEreloc1: pereloc1,
"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)
}
// 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 {
Asmb2: asmb2,
Elfreloc1: elfreloc1,
Elfsetupplt: elfsetupplt,
- Gentext: gentext,
+ Gentext2: gentext2,
Machoreloc1: machoreloc1,
Androiddynld: "/system/bin/linker64",
package ld
import (
+ "cmd/link/internal/loader"
"cmd/link/internal/sym"
"io/ioutil"
"log"
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
+}
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
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")
"sync"
)
-func gentext(ctxt *ld.Link) {
+func gentext2(ctxt *ld.Link, ldr *loader.Loader) {
return
}
Asmb2: asmb2,
Elfreloc1: elfreloc1,
Elfsetupplt: elfsetupplt,
- Gentext: gentext,
+ Gentext2: gentext2,
Machoreloc1: machoreloc1,
Linuxdynld: "/lib/ld.so.1",
"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")
Asmb2: asmb2,
Elfreloc1: elfreloc1,
Elfsetupplt: elfsetupplt,
- Gentext: gentext,
+ Gentext2: gentext2,
Machoreloc1: machoreloc1,
Linuxdynld: "/lib64/ld64.so.1",
"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) {
Asmb2: asmb2,
Elfreloc1: elfreloc1,
Elfsetupplt: elfsetupplt,
- Gentext: gentext,
+ Gentext2: gentext2,
Machoreloc1: machoreloc1,
Linuxdynld: "/lib/ld.so.1",
"bytes"
"cmd/internal/objabi"
"cmd/link/internal/ld"
+ "cmd/link/internal/loader"
"cmd/link/internal/sym"
"io"
"regexp"
// 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 {
AssignAddress: assignAddress,
Asmb: asmb,
Asmb2: asmb2,
- Gentext: gentext,
+ Gentext2: gentext2,
}
return sys.ArchWasm, theArch
"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 {
}
// 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
{"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)
// 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)
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 {
Asmb2: asmb2,
Elfreloc1: elfreloc1,
Elfsetupplt: elfsetupplt,
- Gentext: gentext,
+ Gentext2: gentext2,
Machoreloc1: machoreloc1,
PEreloc1: pereloc1,