mirror of
https://github.com/golang/go
synced 2024-11-18 17:54:57 -07:00
[dev.link] cmd/link: begin converting dodata() to loader APIs
This patch begins the work of converting the linker's dodata phase to work with loader APIs. Passes all.bash on linux/amd64, but hasn't been tested on anything else (more arch-specific code needs to be written). Use of the new dodata() phase is currently gated by a temporary command line flag ("-newdodata"), and there is code in the linker's main routine to insure that we only use the new version for the right GOOS/GOARCH (currently restricted to ELF + AMD64). Change-Id: Ied3966677d2a450bc3e0990e0f519b3fceaab806 Reviewed-on: https://go-review.googlesource.com/c/go/+/229706 Run-TryBot: Than McIntosh <thanm@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com>
This commit is contained in:
parent
3d1007d28e
commit
941de9760b
@ -78,48 +78,53 @@ func makeWritable(s *sym.Symbol) {
|
||||
}
|
||||
}
|
||||
|
||||
func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool {
|
||||
targ := r.Sym
|
||||
func adddynrel2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r *loader.Reloc2, rIdx int) bool {
|
||||
targ := r.Sym()
|
||||
var targType sym.SymKind
|
||||
if targ != 0 {
|
||||
targType = ldr.SymType(targ)
|
||||
}
|
||||
|
||||
switch r.Type {
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
switch r.Type() {
|
||||
default:
|
||||
if r.Type >= objabi.ElfRelocOffset {
|
||||
ld.Errorf(s, "unexpected relocation type %d (%s)", r.Type, sym.RelocName(target.Arch, r.Type))
|
||||
if r.Type() >= objabi.ElfRelocOffset {
|
||||
ldr.Errorf(s, "unexpected relocation type %d (%s)", r.Type(), sym.RelocName(target.Arch, r.Type()))
|
||||
return false
|
||||
}
|
||||
|
||||
// Handle relocations found in ELF object files.
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_PC32):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected R_X86_64_PC32 relocation for dynamic symbol %s", targ.Name)
|
||||
if targType == sym.SDYNIMPORT {
|
||||
ldr.Errorf(s, "unexpected R_X86_64_PC32 relocation for dynamic symbol %s", ldr.SymName(targ))
|
||||
}
|
||||
// TODO(mwhudson): the test of VisibilityHidden here probably doesn't make
|
||||
// sense and should be removed when someone has thought about it properly.
|
||||
if (targ.Type == 0 || targ.Type == sym.SXREF) && !targ.Attr.VisibilityHidden() {
|
||||
ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
|
||||
if (targType == 0 || targType == sym.SXREF) && !ldr.AttrVisibilityHidden(targ) {
|
||||
ldr.Errorf(s, "unknown symbol %s in pcrel", ldr.SymName(targ))
|
||||
}
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Add += 4
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
su.SetRelocAdd(rIdx, r.Add()+4)
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_PC64):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected R_X86_64_PC64 relocation for dynamic symbol %s", targ.Name)
|
||||
if targType == sym.SDYNIMPORT {
|
||||
ldr.Errorf(s, "unexpected R_X86_64_PC64 relocation for dynamic symbol %s", ldr.SymName(targ))
|
||||
}
|
||||
if targ.Type == 0 || targ.Type == sym.SXREF {
|
||||
ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
|
||||
if targType == 0 || targType == sym.SXREF {
|
||||
ldr.Errorf(s, "unknown symbol %s in pcrel", ldr.SymName(targ))
|
||||
}
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Add += 8
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
su.SetRelocAdd(rIdx, r.Add()+8)
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_PLT32):
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Add += 4
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
addpltsym(target, syms, targ)
|
||||
r.Sym = syms.PLT
|
||||
r.Add += int64(targ.Plt())
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
su.SetRelocAdd(rIdx, r.Add()+4)
|
||||
if targType == sym.SDYNIMPORT {
|
||||
addpltsym2(target, ldr, syms, targ)
|
||||
su.SetRelocSym(rIdx, syms.PLT2)
|
||||
su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ)))
|
||||
}
|
||||
|
||||
return true
|
||||
@ -127,34 +132,35 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_GOTPCREL),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_GOTPCRELX),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_REX_GOTPCRELX):
|
||||
if targ.Type != sym.SDYNIMPORT {
|
||||
if targType != sym.SDYNIMPORT {
|
||||
// have symbol
|
||||
if r.Off >= 2 && s.P[r.Off-2] == 0x8b {
|
||||
makeWritable(s)
|
||||
sData := ldr.Data(s)
|
||||
if r.Off() >= 2 && sData[r.Off()-2] == 0x8b {
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.MakeWritable()
|
||||
// turn MOVQ of GOT entry into LEAQ of symbol itself
|
||||
s.P[r.Off-2] = 0x8d
|
||||
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Add += 4
|
||||
writeableData := su.Data()
|
||||
writeableData[r.Off()-2] = 0x8d
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
su.SetRelocAdd(rIdx, r.Add()+4)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// fall back to using GOT and hope for the best (CMOV*)
|
||||
// TODO: just needs relocation, no need to put in .dynsym
|
||||
addgotsym(target, syms, targ)
|
||||
addgotsym2(target, ldr, syms, targ)
|
||||
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Sym = syms.GOT
|
||||
r.Add += 4
|
||||
r.Add += int64(targ.Got())
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
su.SetRelocSym(rIdx, syms.GOT2)
|
||||
su.SetRelocAdd(rIdx, r.Add()+4+int64(ldr.SymGot(targ)))
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_64):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected R_X86_64_64 relocation for dynamic symbol %s", targ.Name)
|
||||
if targType == sym.SDYNIMPORT {
|
||||
ldr.Errorf(s, "unexpected R_X86_64_64 relocation for dynamic symbol %s", ldr.SymName(targ))
|
||||
}
|
||||
r.Type = objabi.R_ADDR
|
||||
su.SetRelocType(rIdx, objabi.R_ADDR)
|
||||
if target.IsPIE() && target.IsInternal() {
|
||||
// For internal linking PIE, this R_ADDR relocation cannot
|
||||
// be resolved statically. We need to generate a dynamic
|
||||
@ -168,19 +174,19 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
|
||||
objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED*2 + 0,
|
||||
objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_BRANCH*2 + 0:
|
||||
// TODO: What is the difference between all these?
|
||||
r.Type = objabi.R_ADDR
|
||||
su.SetRelocType(rIdx, objabi.R_ADDR)
|
||||
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected reloc for dynamic symbol %s", targ.Name)
|
||||
if targType == sym.SDYNIMPORT {
|
||||
ldr.Errorf(s, "unexpected reloc for dynamic symbol %s", ldr.SymName(targ))
|
||||
}
|
||||
return true
|
||||
|
||||
case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_BRANCH*2 + 1:
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
addpltsym(target, syms, targ)
|
||||
r.Sym = syms.PLT
|
||||
r.Add = int64(targ.Plt())
|
||||
r.Type = objabi.R_PCREL
|
||||
if targType == sym.SDYNIMPORT {
|
||||
addpltsym2(target, ldr, syms, targ)
|
||||
su.SetRelocSym(rIdx, syms.PLT2)
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
|
||||
return true
|
||||
}
|
||||
fallthrough
|
||||
@ -190,44 +196,51 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
|
||||
objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED_1*2 + 1,
|
||||
objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED_2*2 + 1,
|
||||
objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED_4*2 + 1:
|
||||
r.Type = objabi.R_PCREL
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected pc-relative reloc for dynamic symbol %s", targ.Name)
|
||||
if targType == sym.SDYNIMPORT {
|
||||
ldr.Errorf(s, "unexpected pc-relative reloc for dynamic symbol %s", ldr.SymName(targ))
|
||||
}
|
||||
return true
|
||||
|
||||
case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_GOT_LOAD*2 + 1:
|
||||
if targ.Type != sym.SDYNIMPORT {
|
||||
if targType != sym.SDYNIMPORT {
|
||||
// have symbol
|
||||
// turn MOVQ of GOT entry into LEAQ of symbol itself
|
||||
if r.Off < 2 || s.P[r.Off-2] != 0x8b {
|
||||
ld.Errorf(s, "unexpected GOT_LOAD reloc for non-dynamic symbol %s", targ.Name)
|
||||
sdata := ldr.Data(s)
|
||||
if r.Off() < 2 || sdata[r.Off()-2] != 0x8b {
|
||||
ldr.Errorf(s, "unexpected GOT_LOAD reloc for non-dynamic symbol %s", ldr.SymName(targ))
|
||||
return false
|
||||
}
|
||||
|
||||
makeWritable(s)
|
||||
s.P[r.Off-2] = 0x8d
|
||||
r.Type = objabi.R_PCREL
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.MakeWritable()
|
||||
sdata = su.Data()
|
||||
sdata[r.Off()-2] = 0x8d
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
return true
|
||||
}
|
||||
fallthrough
|
||||
|
||||
case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_GOT*2 + 1:
|
||||
if targ.Type != sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
|
||||
if targType != sym.SDYNIMPORT {
|
||||
ldr.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", ldr.SymName(targ))
|
||||
}
|
||||
addgotsym(target, syms, targ)
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Sym = syms.GOT
|
||||
r.Add += int64(targ.Got())
|
||||
addgotsym2(target, ldr, syms, targ)
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
su.SetRelocSym(rIdx, syms.GOT2)
|
||||
su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
|
||||
return true
|
||||
}
|
||||
|
||||
switch r.Type {
|
||||
// Reread the reloc to incorporate any changes in type above.
|
||||
relocs := ldr.Relocs(s)
|
||||
*r = relocs.At2(rIdx)
|
||||
|
||||
switch r.Type() {
|
||||
case objabi.R_CALL,
|
||||
objabi.R_PCREL:
|
||||
if targ.Type != sym.SDYNIMPORT {
|
||||
if targType != sym.SDYNIMPORT {
|
||||
// nothing to do, the relocation will be laid out in reloc
|
||||
return true
|
||||
}
|
||||
@ -237,26 +250,26 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
|
||||
}
|
||||
// Internal linking, for both ELF and Mach-O.
|
||||
// Build a PLT entry and change the relocation target to that entry.
|
||||
addpltsym(target, syms, targ)
|
||||
r.Sym = syms.PLT
|
||||
r.Add = int64(targ.Plt())
|
||||
addpltsym2(target, ldr, syms, targ)
|
||||
su.SetRelocSym(rIdx, syms.PLT2)
|
||||
su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
|
||||
return true
|
||||
|
||||
case objabi.R_ADDR:
|
||||
if s.Type == sym.STEXT && target.IsElf() {
|
||||
if ldr.SymType(s) == sym.STEXT && target.IsElf() {
|
||||
if target.IsSolaris() {
|
||||
addpltsym(target, syms, targ)
|
||||
r.Sym = syms.PLT
|
||||
r.Add += int64(targ.Plt())
|
||||
addpltsym2(target, ldr, syms, targ)
|
||||
su.SetRelocSym(rIdx, syms.PLT2)
|
||||
su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ)))
|
||||
return true
|
||||
}
|
||||
// The code is asking for the address of an external
|
||||
// function. We provide it with the address of the
|
||||
// correspondent GOT symbol.
|
||||
addgotsym(target, syms, targ)
|
||||
addgotsym2(target, ldr, syms, targ)
|
||||
|
||||
r.Sym = syms.GOT
|
||||
r.Add += int64(targ.Got())
|
||||
su.SetRelocSym(rIdx, syms.GOT2)
|
||||
su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
|
||||
return true
|
||||
}
|
||||
|
||||
@ -293,7 +306,7 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
|
||||
// symbol offset as determined by reloc(), not the
|
||||
// final dynamically linked address as a dynamic
|
||||
// relocation would provide.
|
||||
switch s.Name {
|
||||
switch ldr.SymName(s) {
|
||||
case ".dynsym", ".rela", ".rela.plt", ".got.plt", ".dynamic":
|
||||
return false
|
||||
}
|
||||
@ -304,7 +317,7 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
|
||||
// linking, in which case the relocation will be
|
||||
// prepared in the 'reloc' phase and passed to the
|
||||
// external linker in the 'asmb' phase.
|
||||
if s.Type != sym.SDATA && s.Type != sym.SRODATA {
|
||||
if ldr.SymType(s) != sym.SDATA && ldr.SymType(s) != sym.SRODATA {
|
||||
break
|
||||
}
|
||||
}
|
||||
@ -327,14 +340,14 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
|
||||
// AddAddrPlus is used for r_offset and r_addend to
|
||||
// generate new R_ADDR relocations that will update
|
||||
// these fields in the 'reloc' phase.
|
||||
rela := syms.Rela
|
||||
rela.AddAddrPlus(target.Arch, s, int64(r.Off))
|
||||
if r.Siz == 8 {
|
||||
rela := ldr.MakeSymbolUpdater(syms.Rela2)
|
||||
rela.AddAddrPlus(target.Arch, s, int64(r.Off()))
|
||||
if r.Siz() == 8 {
|
||||
rela.AddUint64(target.Arch, ld.ELF64_R_INFO(0, uint32(elf.R_X86_64_RELATIVE)))
|
||||
} else {
|
||||
ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name)
|
||||
ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
|
||||
}
|
||||
rela.AddAddrPlus(target.Arch, targ, int64(r.Add))
|
||||
rela.AddAddrPlus(target.Arch, targ, int64(r.Add()))
|
||||
// Not mark r done here. So we still apply it statically,
|
||||
// so in the file content we'll also have the right offset
|
||||
// to the relocation target. So it can be examined statically
|
||||
@ -342,7 +355,7 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
|
||||
return true
|
||||
}
|
||||
|
||||
if target.IsDarwin() && s.Size == int64(target.Arch.PtrSize) && r.Off == 0 {
|
||||
if target.IsDarwin() && ldr.SymSize(s) == int64(target.Arch.PtrSize) && r.Off() == 0 {
|
||||
// Mach-O relocations are a royal pain to lay out.
|
||||
// They use a compact stateful bytecode representation
|
||||
// that is too much bother to deal with.
|
||||
@ -353,18 +366,17 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
|
||||
// just in case the C code assigns to the variable,
|
||||
// and of course it only works for single pointers,
|
||||
// but we only need to support cgo and that's all it needs.
|
||||
ld.Adddynsym(target, syms, targ)
|
||||
ld.Adddynsym2(ldr, target, syms, targ)
|
||||
|
||||
got := syms.GOT
|
||||
s.Type = got.Type
|
||||
s.Attr |= sym.AttrSubSymbol
|
||||
s.Outer = got
|
||||
s.Sub = got.Sub
|
||||
got.Sub = s
|
||||
s.Value = got.Size
|
||||
got := ldr.MakeSymbolUpdater(syms.GOT2)
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetType(got.Type())
|
||||
got.PrependSub(s)
|
||||
su.SetValue(got.Size())
|
||||
got.AddUint64(target.Arch, 0)
|
||||
syms.LinkEditGOT.AddUint32(target.Arch, uint32(targ.Dynid))
|
||||
r.Type = objabi.ElfRelocOffset // ignore during relocsym
|
||||
leg := ldr.MakeSymbolUpdater(syms.LinkEditGOT2)
|
||||
leg.AddUint32(target.Arch, uint32(ldr.SymDynid(targ)))
|
||||
su.SetRelocType(rIdx, objabi.ElfRelocOffset) // ignore during relocsym
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -569,18 +581,18 @@ func elfsetupplt(ctxt *ld.Link, plt, got *loader.SymbolBuilder, dynamic loader.S
|
||||
}
|
||||
}
|
||||
|
||||
func addpltsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
|
||||
if s.Plt() >= 0 {
|
||||
func addpltsym2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
|
||||
if ldr.SymPlt(s) >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
ld.Adddynsym(target, syms, s)
|
||||
ld.Adddynsym2(ldr, target, syms, s)
|
||||
|
||||
if target.IsElf() {
|
||||
plt := syms.PLT
|
||||
got := syms.GOTPLT
|
||||
rela := syms.RelaPLT
|
||||
if plt.Size == 0 {
|
||||
plt := ldr.MakeSymbolUpdater(syms.PLT2)
|
||||
got := ldr.MakeSymbolUpdater(syms.GOTPLT2)
|
||||
rela := ldr.MakeSymbolUpdater(syms.RelaPLT2)
|
||||
if plt.Size() == 0 {
|
||||
panic("plt is not set up")
|
||||
}
|
||||
|
||||
@ -588,28 +600,29 @@ func addpltsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
|
||||
plt.AddUint8(0xff)
|
||||
|
||||
plt.AddUint8(0x25)
|
||||
plt.AddPCRelPlus(target.Arch, got, got.Size)
|
||||
plt.AddPCRelPlus(target.Arch, got.Sym(), got.Size())
|
||||
|
||||
// add to got: pointer to current pos in plt
|
||||
got.AddAddrPlus(target.Arch, plt, plt.Size)
|
||||
got.AddAddrPlus(target.Arch, plt.Sym(), plt.Size())
|
||||
|
||||
// pushq $x
|
||||
plt.AddUint8(0x68)
|
||||
|
||||
plt.AddUint32(target.Arch, uint32((got.Size-24-8)/8))
|
||||
plt.AddUint32(target.Arch, uint32((got.Size()-24-8)/8))
|
||||
|
||||
// jmpq .plt
|
||||
plt.AddUint8(0xe9)
|
||||
|
||||
plt.AddUint32(target.Arch, uint32(-(plt.Size + 4)))
|
||||
plt.AddUint32(target.Arch, uint32(-(plt.Size() + 4)))
|
||||
|
||||
// rela
|
||||
rela.AddAddrPlus(target.Arch, got, got.Size-8)
|
||||
rela.AddAddrPlus(target.Arch, got.Sym(), got.Size()-8)
|
||||
|
||||
rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_X86_64_JMP_SLOT)))
|
||||
sDynid := ldr.SymDynid(s)
|
||||
rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(sDynid), uint32(elf.R_X86_64_JMP_SLOT)))
|
||||
rela.AddUint64(target.Arch, 0)
|
||||
|
||||
s.SetPlt(int32(plt.Size - 16))
|
||||
ldr.SetPlt(s, int32(plt.Size()-16))
|
||||
} else if target.IsDarwin() {
|
||||
// To do lazy symbol lookup right, we're supposed
|
||||
// to tell the dynamic loader which library each
|
||||
@ -621,41 +634,44 @@ func addpltsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
|
||||
// https://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html
|
||||
// has details about what we're avoiding.
|
||||
|
||||
addgotsym(target, syms, s)
|
||||
plt := syms.PLT
|
||||
addgotsym2(target, ldr, syms, s)
|
||||
plt := ldr.MakeSymbolUpdater(syms.PLT2)
|
||||
|
||||
syms.LinkEditPLT.AddUint32(target.Arch, uint32(s.Dynid))
|
||||
sDynid := ldr.SymDynid(s)
|
||||
lep := ldr.MakeSymbolUpdater(syms.LinkEditPLT2)
|
||||
lep.AddUint32(target.Arch, uint32(sDynid))
|
||||
|
||||
// jmpq *got+size(IP)
|
||||
s.SetPlt(int32(plt.Size))
|
||||
ldr.SetPlt(s, int32(plt.Size()))
|
||||
|
||||
plt.AddUint8(0xff)
|
||||
plt.AddUint8(0x25)
|
||||
plt.AddPCRelPlus(target.Arch, syms.GOT, int64(s.Got()))
|
||||
plt.AddPCRelPlus(target.Arch, syms.GOT2, int64(ldr.SymGot(s)))
|
||||
} else {
|
||||
ld.Errorf(s, "addpltsym: unsupported binary format")
|
||||
ldr.Errorf(s, "addpltsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func addgotsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
|
||||
if s.Got() >= 0 {
|
||||
func addgotsym2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
|
||||
if ldr.SymGot(s) >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
ld.Adddynsym(target, syms, s)
|
||||
got := syms.GOT
|
||||
s.SetGot(int32(got.Size))
|
||||
ld.Adddynsym2(ldr, target, syms, s)
|
||||
got := ldr.MakeSymbolUpdater(syms.GOT2)
|
||||
ldr.SetGot(s, int32(got.Size()))
|
||||
got.AddUint64(target.Arch, 0)
|
||||
|
||||
if target.IsElf() {
|
||||
rela := syms.Rela
|
||||
rela.AddAddrPlus(target.Arch, got, int64(s.Got()))
|
||||
rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_X86_64_GLOB_DAT)))
|
||||
rela := ldr.MakeSymbolUpdater(syms.Rela2)
|
||||
rela.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
|
||||
rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(ldr.SymDynid(s)), uint32(elf.R_X86_64_GLOB_DAT)))
|
||||
rela.AddUint64(target.Arch, 0)
|
||||
} else if target.IsDarwin() {
|
||||
syms.LinkEditGOT.AddUint32(target.Arch, uint32(s.Dynid))
|
||||
leg := ldr.MakeSymbolUpdater(syms.LinkEditGOT2)
|
||||
leg.AddUint32(target.Arch, uint32(ldr.SymDynid(s)))
|
||||
} else {
|
||||
ld.Errorf(s, "addgotsym: unsupported binary format")
|
||||
ldr.Errorf(s, "addgotsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
|
402
src/cmd/link/internal/amd64/asm2.go
Normal file
402
src/cmd/link/internal/amd64/asm2.go
Normal file
@ -0,0 +1,402 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package amd64
|
||||
|
||||
import (
|
||||
"cmd/internal/objabi"
|
||||
"cmd/link/internal/ld"
|
||||
"cmd/link/internal/loader"
|
||||
"cmd/link/internal/sym"
|
||||
"debug/elf"
|
||||
)
|
||||
|
||||
// Temporary dumping around for sym.Symbol version of helper
|
||||
// functions in asm.go, still being used for some oses.
|
||||
// FIXME: get rid of this file when dodata() is completely
|
||||
// converted.
|
||||
|
||||
func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool {
|
||||
targ := r.Sym
|
||||
|
||||
switch r.Type {
|
||||
default:
|
||||
if r.Type >= objabi.ElfRelocOffset {
|
||||
ld.Errorf(s, "unexpected relocation type %d (%s)", r.Type, sym.RelocName(target.Arch, r.Type))
|
||||
return false
|
||||
}
|
||||
|
||||
// Handle relocations found in ELF object files.
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_PC32):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected R_X86_64_PC32 relocation for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
// TODO(mwhudson): the test of VisibilityHidden here probably doesn't make
|
||||
// sense and should be removed when someone has thought about it properly.
|
||||
if (targ.Type == 0 || targ.Type == sym.SXREF) && !targ.Attr.VisibilityHidden() {
|
||||
ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
|
||||
}
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Add += 4
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_PC64):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected R_X86_64_PC64 relocation for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
if targ.Type == 0 || targ.Type == sym.SXREF {
|
||||
ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
|
||||
}
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Add += 8
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_PLT32):
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Add += 4
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
addpltsym(target, syms, targ)
|
||||
r.Sym = syms.PLT
|
||||
r.Add += int64(targ.Plt())
|
||||
}
|
||||
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_GOTPCREL),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_GOTPCRELX),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_REX_GOTPCRELX):
|
||||
if targ.Type != sym.SDYNIMPORT {
|
||||
// have symbol
|
||||
if r.Off >= 2 && s.P[r.Off-2] == 0x8b {
|
||||
makeWritable(s)
|
||||
// turn MOVQ of GOT entry into LEAQ of symbol itself
|
||||
s.P[r.Off-2] = 0x8d
|
||||
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Add += 4
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// fall back to using GOT and hope for the best (CMOV*)
|
||||
// TODO: just needs relocation, no need to put in .dynsym
|
||||
addgotsym(target, syms, targ)
|
||||
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Sym = syms.GOT
|
||||
r.Add += 4
|
||||
r.Add += int64(targ.Got())
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_64):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected R_X86_64_64 relocation for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
r.Type = objabi.R_ADDR
|
||||
if target.IsPIE() && target.IsInternal() {
|
||||
// For internal linking PIE, this R_ADDR relocation cannot
|
||||
// be resolved statically. We need to generate a dynamic
|
||||
// relocation. Let the code below handle it.
|
||||
break
|
||||
}
|
||||
return true
|
||||
|
||||
// Handle relocations found in Mach-O object files.
|
||||
case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_UNSIGNED*2 + 0,
|
||||
objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED*2 + 0,
|
||||
objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_BRANCH*2 + 0:
|
||||
// TODO: What is the difference between all these?
|
||||
r.Type = objabi.R_ADDR
|
||||
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected reloc for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
return true
|
||||
|
||||
case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_BRANCH*2 + 1:
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
addpltsym(target, syms, targ)
|
||||
r.Sym = syms.PLT
|
||||
r.Add = int64(targ.Plt())
|
||||
r.Type = objabi.R_PCREL
|
||||
return true
|
||||
}
|
||||
fallthrough
|
||||
|
||||
case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_UNSIGNED*2 + 1,
|
||||
objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED*2 + 1,
|
||||
objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED_1*2 + 1,
|
||||
objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED_2*2 + 1,
|
||||
objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED_4*2 + 1:
|
||||
r.Type = objabi.R_PCREL
|
||||
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected pc-relative reloc for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
return true
|
||||
|
||||
case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_GOT_LOAD*2 + 1:
|
||||
if targ.Type != sym.SDYNIMPORT {
|
||||
// have symbol
|
||||
// turn MOVQ of GOT entry into LEAQ of symbol itself
|
||||
if r.Off < 2 || s.P[r.Off-2] != 0x8b {
|
||||
ld.Errorf(s, "unexpected GOT_LOAD reloc for non-dynamic symbol %s", targ.Name)
|
||||
return false
|
||||
}
|
||||
|
||||
makeWritable(s)
|
||||
s.P[r.Off-2] = 0x8d
|
||||
r.Type = objabi.R_PCREL
|
||||
return true
|
||||
}
|
||||
fallthrough
|
||||
|
||||
case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_GOT*2 + 1:
|
||||
if targ.Type != sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
|
||||
}
|
||||
addgotsym(target, syms, targ)
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Sym = syms.GOT
|
||||
r.Add += int64(targ.Got())
|
||||
return true
|
||||
}
|
||||
|
||||
switch r.Type {
|
||||
case objabi.R_CALL,
|
||||
objabi.R_PCREL:
|
||||
if targ.Type != sym.SDYNIMPORT {
|
||||
// nothing to do, the relocation will be laid out in reloc
|
||||
return true
|
||||
}
|
||||
if target.IsExternal() {
|
||||
// External linker will do this relocation.
|
||||
return true
|
||||
}
|
||||
// Internal linking, for both ELF and Mach-O.
|
||||
// Build a PLT entry and change the relocation target to that entry.
|
||||
addpltsym(target, syms, targ)
|
||||
r.Sym = syms.PLT
|
||||
r.Add = int64(targ.Plt())
|
||||
return true
|
||||
|
||||
case objabi.R_ADDR:
|
||||
if s.Type == sym.STEXT && target.IsElf() {
|
||||
if target.IsSolaris() {
|
||||
addpltsym(target, syms, targ)
|
||||
r.Sym = syms.PLT
|
||||
r.Add += int64(targ.Plt())
|
||||
return true
|
||||
}
|
||||
// The code is asking for the address of an external
|
||||
// function. We provide it with the address of the
|
||||
// correspondent GOT symbol.
|
||||
addgotsym(target, syms, targ)
|
||||
|
||||
r.Sym = syms.GOT
|
||||
r.Add += int64(targ.Got())
|
||||
return true
|
||||
}
|
||||
|
||||
// Process dynamic relocations for the data sections.
|
||||
if target.IsPIE() && target.IsInternal() {
|
||||
// When internally linking, generate dynamic relocations
|
||||
// for all typical R_ADDR relocations. The exception
|
||||
// are those R_ADDR that are created as part of generating
|
||||
// the dynamic relocations and must be resolved statically.
|
||||
//
|
||||
// There are three phases relevant to understanding this:
|
||||
//
|
||||
// dodata() // we are here
|
||||
// address() // symbol address assignment
|
||||
// reloc() // resolution of static R_ADDR relocs
|
||||
//
|
||||
// At this point symbol addresses have not been
|
||||
// assigned yet (as the final size of the .rela section
|
||||
// will affect the addresses), and so we cannot write
|
||||
// the Elf64_Rela.r_offset now. Instead we delay it
|
||||
// until after the 'address' phase of the linker is
|
||||
// complete. We do this via Addaddrplus, which creates
|
||||
// a new R_ADDR relocation which will be resolved in
|
||||
// the 'reloc' phase.
|
||||
//
|
||||
// These synthetic static R_ADDR relocs must be skipped
|
||||
// now, or else we will be caught in an infinite loop
|
||||
// of generating synthetic relocs for our synthetic
|
||||
// relocs.
|
||||
//
|
||||
// Furthermore, the rela sections contain dynamic
|
||||
// relocations with R_ADDR relocations on
|
||||
// Elf64_Rela.r_offset. This field should contain the
|
||||
// symbol offset as determined by reloc(), not the
|
||||
// final dynamically linked address as a dynamic
|
||||
// relocation would provide.
|
||||
switch s.Name {
|
||||
case ".dynsym", ".rela", ".rela.plt", ".got.plt", ".dynamic":
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
// Either internally linking a static executable,
|
||||
// in which case we can resolve these relocations
|
||||
// statically in the 'reloc' phase, or externally
|
||||
// linking, in which case the relocation will be
|
||||
// prepared in the 'reloc' phase and passed to the
|
||||
// external linker in the 'asmb' phase.
|
||||
if s.Type != sym.SDATA && s.Type != sym.SRODATA {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if target.IsElf() {
|
||||
// Generate R_X86_64_RELATIVE relocations for best
|
||||
// efficiency in the dynamic linker.
|
||||
//
|
||||
// As noted above, symbol addresses have not been
|
||||
// assigned yet, so we can't generate the final reloc
|
||||
// entry yet. We ultimately want:
|
||||
//
|
||||
// r_offset = s + r.Off
|
||||
// r_info = R_X86_64_RELATIVE
|
||||
// r_addend = targ + r.Add
|
||||
//
|
||||
// The dynamic linker will set *offset = base address +
|
||||
// addend.
|
||||
//
|
||||
// AddAddrPlus is used for r_offset and r_addend to
|
||||
// generate new R_ADDR relocations that will update
|
||||
// these fields in the 'reloc' phase.
|
||||
rela := syms.Rela
|
||||
rela.AddAddrPlus(target.Arch, s, int64(r.Off))
|
||||
if r.Siz == 8 {
|
||||
rela.AddUint64(target.Arch, ld.ELF64_R_INFO(0, uint32(elf.R_X86_64_RELATIVE)))
|
||||
} else {
|
||||
ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
rela.AddAddrPlus(target.Arch, targ, int64(r.Add))
|
||||
// Not mark r done here. So we still apply it statically,
|
||||
// so in the file content we'll also have the right offset
|
||||
// to the relocation target. So it can be examined statically
|
||||
// (e.g. go version).
|
||||
return true
|
||||
}
|
||||
|
||||
if target.IsDarwin() && s.Size == int64(target.Arch.PtrSize) && r.Off == 0 {
|
||||
// Mach-O relocations are a royal pain to lay out.
|
||||
// They use a compact stateful bytecode representation
|
||||
// that is too much bother to deal with.
|
||||
// Instead, interpret the C declaration
|
||||
// void *_Cvar_stderr = &stderr;
|
||||
// as making _Cvar_stderr the name of a GOT entry
|
||||
// for stderr. This is separate from the usual GOT entry,
|
||||
// just in case the C code assigns to the variable,
|
||||
// and of course it only works for single pointers,
|
||||
// but we only need to support cgo and that's all it needs.
|
||||
ld.Adddynsym(target, syms, targ)
|
||||
|
||||
got := syms.GOT
|
||||
s.Type = got.Type
|
||||
s.Attr |= sym.AttrSubSymbol
|
||||
s.Outer = got
|
||||
s.Sub = got.Sub
|
||||
got.Sub = s
|
||||
s.Value = got.Size
|
||||
got.AddUint64(target.Arch, 0)
|
||||
syms.LinkEditGOT.AddUint32(target.Arch, uint32(targ.Dynid))
|
||||
r.Type = objabi.ElfRelocOffset // ignore during relocsym
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func addpltsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
|
||||
if s.Plt() >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
ld.Adddynsym(target, syms, s)
|
||||
|
||||
if target.IsElf() {
|
||||
plt := syms.PLT
|
||||
got := syms.GOTPLT
|
||||
rela := syms.RelaPLT
|
||||
if plt.Size == 0 {
|
||||
panic("plt is not set up")
|
||||
}
|
||||
|
||||
// jmpq *got+size(IP)
|
||||
plt.AddUint8(0xff)
|
||||
|
||||
plt.AddUint8(0x25)
|
||||
plt.AddPCRelPlus(target.Arch, got, got.Size)
|
||||
|
||||
// add to got: pointer to current pos in plt
|
||||
got.AddAddrPlus(target.Arch, plt, plt.Size)
|
||||
|
||||
// pushq $x
|
||||
plt.AddUint8(0x68)
|
||||
|
||||
plt.AddUint32(target.Arch, uint32((got.Size-24-8)/8))
|
||||
|
||||
// jmpq .plt
|
||||
plt.AddUint8(0xe9)
|
||||
|
||||
plt.AddUint32(target.Arch, uint32(-(plt.Size + 4)))
|
||||
|
||||
// rela
|
||||
rela.AddAddrPlus(target.Arch, got, got.Size-8)
|
||||
|
||||
rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_X86_64_JMP_SLOT)))
|
||||
rela.AddUint64(target.Arch, 0)
|
||||
|
||||
s.SetPlt(int32(plt.Size - 16))
|
||||
} else if target.IsDarwin() {
|
||||
// To do lazy symbol lookup right, we're supposed
|
||||
// to tell the dynamic loader which library each
|
||||
// symbol comes from and format the link info
|
||||
// section just so. I'm too lazy (ha!) to do that
|
||||
// so for now we'll just use non-lazy pointers,
|
||||
// which don't need to be told which library to use.
|
||||
//
|
||||
// https://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html
|
||||
// has details about what we're avoiding.
|
||||
|
||||
addgotsym(target, syms, s)
|
||||
plt := syms.PLT
|
||||
|
||||
syms.LinkEditPLT.AddUint32(target.Arch, uint32(s.Dynid))
|
||||
|
||||
// jmpq *got+size(IP)
|
||||
s.SetPlt(int32(plt.Size))
|
||||
|
||||
plt.AddUint8(0xff)
|
||||
plt.AddUint8(0x25)
|
||||
plt.AddPCRelPlus(target.Arch, syms.GOT, int64(s.Got()))
|
||||
} else {
|
||||
ld.Errorf(s, "addpltsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func addgotsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
|
||||
if s.Got() >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
ld.Adddynsym(target, syms, s)
|
||||
got := syms.GOT
|
||||
s.SetGot(int32(got.Size))
|
||||
got.AddUint64(target.Arch, 0)
|
||||
|
||||
if target.IsElf() {
|
||||
rela := syms.Rela
|
||||
rela.AddAddrPlus(target.Arch, got, int64(s.Got()))
|
||||
rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_X86_64_GLOB_DAT)))
|
||||
rela.AddUint64(target.Arch, 0)
|
||||
} else if target.IsDarwin() {
|
||||
syms.LinkEditGOT.AddUint32(target.Arch, uint32(s.Dynid))
|
||||
} else {
|
||||
ld.Errorf(s, "addgotsym: unsupported binary format")
|
||||
}
|
||||
}
|
@ -47,6 +47,7 @@ func Init() (*sys.Arch, ld.Arch) {
|
||||
Dwarfreglr: dwarfRegLR,
|
||||
|
||||
Adddynrel: adddynrel,
|
||||
Adddynrel2: adddynrel2,
|
||||
Archinit: archinit,
|
||||
Archreloc: archreloc,
|
||||
Archrelocvariant: archrelocvariant,
|
||||
|
File diff suppressed because it is too large
Load Diff
938
src/cmd/link/internal/ld/data2.go
Normal file
938
src/cmd/link/internal/ld/data2.go
Normal file
@ -0,0 +1,938 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ld
|
||||
|
||||
import (
|
||||
"cmd/internal/gcprog"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/link/internal/loader"
|
||||
"cmd/link/internal/sym"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Temporary dumping around for sym.Symbol version of helper
|
||||
// functions in dodata(), still being used for some archs/oses.
|
||||
// FIXME: get rid of this file when dodata() is completely
|
||||
// converted.
|
||||
|
||||
func (ctxt *Link) dodata() {
|
||||
// Give zeros sized symbols space if necessary.
|
||||
fixZeroSizedSymbols(ctxt)
|
||||
|
||||
// Collect data symbols by type into data.
|
||||
state := dodataState{ctxt: ctxt}
|
||||
for _, s := range ctxt.Syms.Allsym {
|
||||
if !s.Attr.Reachable() || s.Attr.Special() || s.Attr.SubSymbol() {
|
||||
continue
|
||||
}
|
||||
if s.Type <= sym.STEXT || s.Type >= sym.SXREF {
|
||||
continue
|
||||
}
|
||||
state.data[s.Type] = append(state.data[s.Type], s)
|
||||
}
|
||||
|
||||
// Now that we have the data symbols, but before we start
|
||||
// to assign addresses, record all the necessary
|
||||
// dynamic relocations. These will grow the relocation
|
||||
// symbol, which is itself data.
|
||||
//
|
||||
// On darwin, we need the symbol table numbers for dynreloc.
|
||||
if ctxt.HeadType == objabi.Hdarwin {
|
||||
machosymorder(ctxt)
|
||||
}
|
||||
state.dynreloc(ctxt)
|
||||
|
||||
// Move any RO data with relocations to a separate section.
|
||||
state.makeRelroForSharedLib(ctxt)
|
||||
|
||||
// Temporary for debugging.
|
||||
symToIdx := make(map[*sym.Symbol]loader.Sym)
|
||||
for s := loader.Sym(1); s < loader.Sym(ctxt.loader.NSym()); s++ {
|
||||
sp := ctxt.loader.Syms[s]
|
||||
if sp != nil {
|
||||
symToIdx[sp] = s
|
||||
}
|
||||
}
|
||||
|
||||
// Sort symbols.
|
||||
var wg sync.WaitGroup
|
||||
for symn := range state.data {
|
||||
symn := sym.SymKind(symn)
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
state.data[symn], state.dataMaxAlign[symn] = dodataSect(ctxt, symn, state.data[symn], symToIdx)
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
if ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal {
|
||||
// These symbols must have the same alignment as their section.
|
||||
// Otherwize, ld might change the layout of Go sections.
|
||||
ctxt.Syms.ROLookup("runtime.data", 0).Align = state.dataMaxAlign[sym.SDATA]
|
||||
ctxt.Syms.ROLookup("runtime.bss", 0).Align = state.dataMaxAlign[sym.SBSS]
|
||||
}
|
||||
|
||||
// Create *sym.Section objects and assign symbols to sections for
|
||||
// data/rodata (and related) symbols.
|
||||
state.allocateDataSections(ctxt)
|
||||
|
||||
// Create *sym.Section objects and assign symbols to sections for
|
||||
// DWARF symbols.
|
||||
state.allocateDwarfSections(ctxt)
|
||||
|
||||
/* number the sections */
|
||||
n := int16(1)
|
||||
|
||||
for _, sect := range Segtext.Sections {
|
||||
sect.Extnum = n
|
||||
n++
|
||||
}
|
||||
for _, sect := range Segrodata.Sections {
|
||||
sect.Extnum = n
|
||||
n++
|
||||
}
|
||||
for _, sect := range Segrelrodata.Sections {
|
||||
sect.Extnum = n
|
||||
n++
|
||||
}
|
||||
for _, sect := range Segdata.Sections {
|
||||
sect.Extnum = n
|
||||
n++
|
||||
}
|
||||
for _, sect := range Segdwarf.Sections {
|
||||
sect.Extnum = n
|
||||
n++
|
||||
}
|
||||
}
|
||||
|
||||
// makeRelroForSharedLib creates a section of readonly data if necessary.
|
||||
func (state *dodataState) makeRelroForSharedLib(target *Link) {
|
||||
if !target.UseRelro() {
|
||||
return
|
||||
}
|
||||
|
||||
// "read only" data with relocations needs to go in its own section
|
||||
// when building a shared library. We do this by boosting objects of
|
||||
// type SXXX with relocations to type SXXXRELRO.
|
||||
for _, symnro := range sym.ReadOnly {
|
||||
symnrelro := sym.RelROMap[symnro]
|
||||
|
||||
ro := []*sym.Symbol{}
|
||||
relro := state.data[symnrelro]
|
||||
|
||||
for _, s := range state.data[symnro] {
|
||||
isRelro := len(s.R) > 0
|
||||
switch s.Type {
|
||||
case sym.STYPE, sym.STYPERELRO, sym.SGOFUNCRELRO:
|
||||
// Symbols are not sorted yet, so it is possible
|
||||
// that an Outer symbol has been changed to a
|
||||
// relro Type before it reaches here.
|
||||
isRelro = true
|
||||
case sym.SFUNCTAB:
|
||||
if target.IsAIX() && s.Name == "runtime.etypes" {
|
||||
// runtime.etypes must be at the end of
|
||||
// the relro datas.
|
||||
isRelro = true
|
||||
}
|
||||
}
|
||||
if isRelro {
|
||||
s.Type = symnrelro
|
||||
if s.Outer != nil {
|
||||
s.Outer.Type = s.Type
|
||||
}
|
||||
relro = append(relro, s)
|
||||
} else {
|
||||
ro = append(ro, s)
|
||||
}
|
||||
}
|
||||
|
||||
// Check that we haven't made two symbols with the same .Outer into
|
||||
// different types (because references two symbols with non-nil Outer
|
||||
// become references to the outer symbol + offset it's vital that the
|
||||
// symbol and the outer end up in the same section).
|
||||
for _, s := range relro {
|
||||
if s.Outer != nil && s.Outer.Type != s.Type {
|
||||
Errorf(s, "inconsistent types for symbol and its Outer %s (%v != %v)",
|
||||
s.Outer.Name, s.Type, s.Outer.Type)
|
||||
}
|
||||
}
|
||||
|
||||
state.data[symnro] = ro
|
||||
state.data[symnrelro] = relro
|
||||
}
|
||||
}
|
||||
|
||||
func dynrelocsym(ctxt *Link, s *sym.Symbol) {
|
||||
target := &ctxt.Target
|
||||
ldr := ctxt.loader
|
||||
syms := &ctxt.ArchSyms
|
||||
for ri := range s.R {
|
||||
r := &s.R[ri]
|
||||
if ctxt.BuildMode == BuildModePIE && ctxt.LinkMode == LinkInternal {
|
||||
// It's expected that some relocations will be done
|
||||
// later by relocsym (R_TLS_LE, R_ADDROFF), so
|
||||
// don't worry if Adddynrel returns false.
|
||||
thearch.Adddynrel(target, ldr, syms, s, r)
|
||||
continue
|
||||
}
|
||||
|
||||
if r.Sym != nil && r.Sym.Type == sym.SDYNIMPORT || r.Type >= objabi.ElfRelocOffset {
|
||||
if r.Sym != nil && !r.Sym.Attr.Reachable() {
|
||||
Errorf(s, "dynamic relocation to unreachable symbol %s", r.Sym.Name)
|
||||
}
|
||||
if !thearch.Adddynrel(target, ldr, syms, s, r) {
|
||||
Errorf(s, "unsupported dynamic relocation for symbol %s (type=%d (%s) stype=%d (%s))", r.Sym.Name, r.Type, sym.RelocName(ctxt.Arch, r.Type), r.Sym.Type, r.Sym.Type)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (state *dodataState) dynreloc(ctxt *Link) {
|
||||
if ctxt.HeadType == objabi.Hwindows {
|
||||
return
|
||||
}
|
||||
// -d suppresses dynamic loader format, so we may as well not
|
||||
// compute these sections or mark their symbols as reachable.
|
||||
if *FlagD {
|
||||
return
|
||||
}
|
||||
|
||||
for _, s := range ctxt.Textp {
|
||||
dynrelocsym(ctxt, s)
|
||||
}
|
||||
for _, syms := range state.data {
|
||||
for _, s := range syms {
|
||||
dynrelocsym(ctxt, s)
|
||||
}
|
||||
}
|
||||
if ctxt.IsELF {
|
||||
elfdynhash(ctxt)
|
||||
}
|
||||
}
|
||||
|
||||
func Addstring(s *sym.Symbol, str string) int64 {
|
||||
if s.Type == 0 {
|
||||
s.Type = sym.SNOPTRDATA
|
||||
}
|
||||
s.Attr |= sym.AttrReachable
|
||||
r := s.Size
|
||||
if s.Name == ".shstrtab" {
|
||||
elfsetstring(s, str, int(r))
|
||||
}
|
||||
s.P = append(s.P, str...)
|
||||
s.P = append(s.P, 0)
|
||||
s.Size = int64(len(s.P))
|
||||
return r
|
||||
}
|
||||
|
||||
// symalign returns the required alignment for the given symbol s.
|
||||
func symalign(s *sym.Symbol) int32 {
|
||||
min := int32(thearch.Minalign)
|
||||
if s.Align >= min {
|
||||
return s.Align
|
||||
} else if s.Align != 0 {
|
||||
return min
|
||||
}
|
||||
if strings.HasPrefix(s.Name, "go.string.") || strings.HasPrefix(s.Name, "type..namedata.") {
|
||||
// String data is just bytes.
|
||||
// If we align it, we waste a lot of space to padding.
|
||||
return min
|
||||
}
|
||||
align := int32(thearch.Maxalign)
|
||||
for int64(align) > s.Size && align > min {
|
||||
align >>= 1
|
||||
}
|
||||
s.Align = align
|
||||
return align
|
||||
}
|
||||
|
||||
func aligndatsize(datsize int64, s *sym.Symbol) int64 {
|
||||
return Rnd(datsize, int64(symalign(s)))
|
||||
}
|
||||
|
||||
type GCProg struct {
|
||||
ctxt *Link
|
||||
sym *sym.Symbol
|
||||
w gcprog.Writer
|
||||
}
|
||||
|
||||
func (p *GCProg) Init(ctxt *Link, name string) {
|
||||
p.ctxt = ctxt
|
||||
p.sym = ctxt.Syms.Lookup(name, 0)
|
||||
p.w.Init(p.writeByte(ctxt))
|
||||
if debugGCProg {
|
||||
fmt.Fprintf(os.Stderr, "ld: start GCProg %s\n", name)
|
||||
p.w.Debug(os.Stderr)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *GCProg) writeByte(ctxt *Link) func(x byte) {
|
||||
return func(x byte) {
|
||||
p.sym.AddUint8(x)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *GCProg) End(size int64) {
|
||||
p.w.ZeroUntil(size / int64(p.ctxt.Arch.PtrSize))
|
||||
p.w.End()
|
||||
if debugGCProg {
|
||||
fmt.Fprintf(os.Stderr, "ld: end GCProg\n")
|
||||
}
|
||||
}
|
||||
|
||||
func (p *GCProg) AddSym(s *sym.Symbol) {
|
||||
typ := s.Gotype
|
||||
// Things without pointers should be in sym.SNOPTRDATA or sym.SNOPTRBSS;
|
||||
// everything we see should have pointers and should therefore have a type.
|
||||
if typ == nil {
|
||||
switch s.Name {
|
||||
case "runtime.data", "runtime.edata", "runtime.bss", "runtime.ebss":
|
||||
// Ignore special symbols that are sometimes laid out
|
||||
// as real symbols. See comment about dyld on darwin in
|
||||
// the address function.
|
||||
return
|
||||
}
|
||||
Errorf(s, "missing Go type information for global symbol: size %d", s.Size)
|
||||
return
|
||||
}
|
||||
|
||||
ptrsize := int64(p.ctxt.Arch.PtrSize)
|
||||
nptr := decodetypePtrdata(p.ctxt.Arch, typ.P) / ptrsize
|
||||
|
||||
if debugGCProg {
|
||||
fmt.Fprintf(os.Stderr, "gcprog sym: %s at %d (ptr=%d+%d)\n", s.Name, s.Value, s.Value/ptrsize, nptr)
|
||||
}
|
||||
|
||||
if decodetypeUsegcprog(p.ctxt.Arch, typ.P) == 0 {
|
||||
// Copy pointers from mask into program.
|
||||
mask := decodetypeGcmask(p.ctxt, typ)
|
||||
for i := int64(0); i < nptr; i++ {
|
||||
if (mask[i/8]>>uint(i%8))&1 != 0 {
|
||||
p.w.Ptr(s.Value/ptrsize + i)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Copy program.
|
||||
prog := decodetypeGcprog(p.ctxt, typ)
|
||||
p.w.ZeroUntil(s.Value / ptrsize)
|
||||
p.w.Append(prog[4:], nptr)
|
||||
}
|
||||
|
||||
// dataSortKey is used to sort a slice of data symbol *sym.Symbol pointers.
|
||||
// The sort keys are kept inline to improve cache behavior while sorting.
|
||||
type dataSortKey struct {
|
||||
size int64
|
||||
name string
|
||||
sym *sym.Symbol
|
||||
symIdx loader.Sym
|
||||
}
|
||||
|
||||
type bySizeAndName []dataSortKey
|
||||
|
||||
func (d bySizeAndName) Len() int { return len(d) }
|
||||
func (d bySizeAndName) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
|
||||
func (d bySizeAndName) Less(i, j int) bool {
|
||||
s1, s2 := d[i], d[j]
|
||||
if s1.size != s2.size {
|
||||
return s1.size < s2.size
|
||||
}
|
||||
if s1.name != s2.name {
|
||||
return s1.name < s2.name
|
||||
}
|
||||
return s1.symIdx < s2.symIdx
|
||||
}
|
||||
|
||||
// fixZeroSizedSymbols gives a few special symbols with zero size some space.
|
||||
func fixZeroSizedSymbols(ctxt *Link) {
|
||||
// The values in moduledata are filled out by relocations
|
||||
// pointing to the addresses of these special symbols.
|
||||
// Typically these symbols have no size and are not laid
|
||||
// out with their matching section.
|
||||
//
|
||||
// However on darwin, dyld will find the special symbol
|
||||
// in the first loaded module, even though it is local.
|
||||
//
|
||||
// (An hypothesis, formed without looking in the dyld sources:
|
||||
// these special symbols have no size, so their address
|
||||
// matches a real symbol. The dynamic linker assumes we
|
||||
// want the normal symbol with the same address and finds
|
||||
// it in the other module.)
|
||||
//
|
||||
// To work around this we lay out the symbls whose
|
||||
// addresses are vital for multi-module programs to work
|
||||
// as normal symbols, and give them a little size.
|
||||
//
|
||||
// On AIX, as all DATA sections are merged together, ld might not put
|
||||
// these symbols at the beginning of their respective section if there
|
||||
// aren't real symbols, their alignment might not match the
|
||||
// first symbol alignment. Therefore, there are explicitly put at the
|
||||
// beginning of their section with the same alignment.
|
||||
if !(ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin) && !(ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal) {
|
||||
return
|
||||
}
|
||||
|
||||
bss := ctxt.Syms.Lookup("runtime.bss", 0)
|
||||
bss.Size = 8
|
||||
bss.Attr.Set(sym.AttrSpecial, false)
|
||||
|
||||
ctxt.Syms.Lookup("runtime.ebss", 0).Attr.Set(sym.AttrSpecial, false)
|
||||
|
||||
data := ctxt.Syms.Lookup("runtime.data", 0)
|
||||
data.Size = 8
|
||||
data.Attr.Set(sym.AttrSpecial, false)
|
||||
|
||||
edata := ctxt.Syms.Lookup("runtime.edata", 0)
|
||||
edata.Attr.Set(sym.AttrSpecial, false)
|
||||
if ctxt.HeadType == objabi.Haix {
|
||||
// XCOFFTOC symbols are part of .data section.
|
||||
edata.Type = sym.SXCOFFTOC
|
||||
}
|
||||
|
||||
types := ctxt.Syms.Lookup("runtime.types", 0)
|
||||
types.Type = sym.STYPE
|
||||
types.Size = 8
|
||||
types.Attr.Set(sym.AttrSpecial, false)
|
||||
|
||||
etypes := ctxt.Syms.Lookup("runtime.etypes", 0)
|
||||
etypes.Type = sym.SFUNCTAB
|
||||
etypes.Attr.Set(sym.AttrSpecial, false)
|
||||
|
||||
if ctxt.HeadType == objabi.Haix {
|
||||
rodata := ctxt.Syms.Lookup("runtime.rodata", 0)
|
||||
rodata.Type = sym.SSTRING
|
||||
rodata.Size = 8
|
||||
rodata.Attr.Set(sym.AttrSpecial, false)
|
||||
|
||||
ctxt.Syms.Lookup("runtime.erodata", 0).Attr.Set(sym.AttrSpecial, false)
|
||||
}
|
||||
}
|
||||
|
||||
// allocateDataSectionForSym creates a new sym.Section into which a a
|
||||
// single symbol will be placed. Here "seg" is the segment into which
|
||||
// the section will go, "s" is the symbol to be placed into the new
|
||||
// section, and "rwx" contains permissions for the section.
|
||||
func (state *dodataState) allocateDataSectionForSym(seg *sym.Segment, s *sym.Symbol, rwx int) *sym.Section {
|
||||
sect := addsection(state.ctxt.loader, state.ctxt.Arch, seg, s.Name, rwx)
|
||||
sect.Align = symalign(s)
|
||||
state.datsize = Rnd(state.datsize, int64(sect.Align))
|
||||
sect.Vaddr = uint64(state.datsize)
|
||||
return sect
|
||||
}
|
||||
|
||||
// assignDsymsToSection assigns a collection of data symbols to a
|
||||
// newly created section. "sect" is the section into which to place
|
||||
// the symbols, "syms" holds the list of symbols to assign,
|
||||
// "forceType" (if non-zero) contains a new sym type to apply to each
|
||||
// sym during the assignment, and "aligner" is a hook to call to
|
||||
// handle alignment during the assignment process.
|
||||
func (state *dodataState) assignDsymsToSection(sect *sym.Section, syms []*sym.Symbol, forceType sym.SymKind, aligner func(datsize int64, s *sym.Symbol) int64) {
|
||||
for _, s := range syms {
|
||||
state.datsize = aligner(state.datsize, s)
|
||||
s.Sect = sect
|
||||
if forceType != sym.Sxxx {
|
||||
s.Type = forceType
|
||||
}
|
||||
s.Value = int64(uint64(state.datsize) - sect.Vaddr)
|
||||
state.datsize += s.Size
|
||||
}
|
||||
sect.Length = uint64(state.datsize) - sect.Vaddr
|
||||
}
|
||||
|
||||
func (state *dodataState) assignToSection(sect *sym.Section, symn sym.SymKind, forceType sym.SymKind) {
|
||||
state.assignDsymsToSection(sect, state.data[symn], forceType, aligndatsize)
|
||||
state.checkdatsize(symn)
|
||||
}
|
||||
|
||||
// allocateSingleSymSections walks through the bucketed data symbols
|
||||
// with type 'symn', creates a new section for each sym, and assigns
|
||||
// the sym to a newly created section. Section name is set from the
|
||||
// symbol name. "Seg" is the segment into which to place the new
|
||||
// section, "forceType" is the new sym.SymKind to assign to the symbol
|
||||
// within the section, and "rwx" holds section permissions.
|
||||
func (state *dodataState) allocateSingleSymSections(seg *sym.Segment, symn sym.SymKind, forceType sym.SymKind, rwx int) {
|
||||
for _, s := range state.data[symn] {
|
||||
sect := state.allocateDataSectionForSym(seg, s, rwx)
|
||||
s.Sect = sect
|
||||
s.Type = forceType
|
||||
s.Value = int64(uint64(state.datsize) - sect.Vaddr)
|
||||
state.datsize += s.Size
|
||||
sect.Length = uint64(state.datsize) - sect.Vaddr
|
||||
}
|
||||
state.checkdatsize(symn)
|
||||
}
|
||||
|
||||
// allocateNamedSectionAndAssignSyms creates a new section with the
|
||||
// specified name, then walks through the bucketed data symbols with
|
||||
// type 'symn' and assigns each of them to this new section. "Seg" is
|
||||
// the segment into which to place the new section, "secName" is the
|
||||
// name to give to the new section, "forceType" (if non-zero) contains
|
||||
// a new sym type to apply to each sym during the assignment, and
|
||||
// "rwx" holds section permissions.
|
||||
func (state *dodataState) allocateNamedSectionAndAssignSyms(seg *sym.Segment, secName string, symn sym.SymKind, forceType sym.SymKind, rwx int) *sym.Section {
|
||||
|
||||
sect := state.allocateNamedDataSection(seg, secName, []sym.SymKind{symn}, rwx)
|
||||
state.assignDsymsToSection(sect, state.data[symn], forceType, aligndatsize)
|
||||
return sect
|
||||
}
|
||||
|
||||
// allocateDataSections allocates sym.Section objects for data/rodata
|
||||
// (and related) symbols, and then assigns symbols to those sections.
|
||||
func (state *dodataState) allocateDataSections(ctxt *Link) {
|
||||
// Allocate sections.
|
||||
// Data is processed before segtext, because we need
|
||||
// to see all symbols in the .data and .bss sections in order
|
||||
// to generate garbage collection information.
|
||||
|
||||
// Writable data sections that do not need any specialized handling.
|
||||
writable := []sym.SymKind{
|
||||
sym.SBUILDINFO,
|
||||
sym.SELFSECT,
|
||||
sym.SMACHO,
|
||||
sym.SMACHOGOT,
|
||||
sym.SWINDOWS,
|
||||
}
|
||||
for _, symn := range writable {
|
||||
state.allocateSingleSymSections(&Segdata, symn, sym.SDATA, 06)
|
||||
}
|
||||
|
||||
// .got (and .toc on ppc64)
|
||||
if len(state.data[sym.SELFGOT]) > 0 {
|
||||
sect := state.allocateNamedSectionAndAssignSyms(&Segdata, ".got", sym.SELFGOT, sym.SDATA, 06)
|
||||
if ctxt.IsPPC64() {
|
||||
for _, s := range state.data[sym.SELFGOT] {
|
||||
// Resolve .TOC. symbol for this object file (ppc64)
|
||||
toc := ctxt.Syms.ROLookup(".TOC.", int(s.Version))
|
||||
if toc != nil {
|
||||
toc.Sect = sect
|
||||
toc.Outer = s
|
||||
toc.Sub = s.Sub
|
||||
s.Sub = toc
|
||||
|
||||
toc.Value = 0x8000
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* pointer-free data */
|
||||
sect := state.allocateNamedSectionAndAssignSyms(&Segdata, ".noptrdata", sym.SNOPTRDATA, sym.SDATA, 06)
|
||||
ctxt.Syms.Lookup("runtime.noptrdata", 0).Sect = sect
|
||||
ctxt.Syms.Lookup("runtime.enoptrdata", 0).Sect = sect
|
||||
|
||||
hasinitarr := ctxt.linkShared
|
||||
|
||||
/* shared library initializer */
|
||||
switch ctxt.BuildMode {
|
||||
case BuildModeCArchive, BuildModeCShared, BuildModeShared, BuildModePlugin:
|
||||
hasinitarr = true
|
||||
}
|
||||
|
||||
if ctxt.HeadType == objabi.Haix {
|
||||
if len(state.data[sym.SINITARR]) > 0 {
|
||||
Errorf(nil, "XCOFF format doesn't allow .init_array section")
|
||||
}
|
||||
}
|
||||
|
||||
if hasinitarr && len(state.data[sym.SINITARR]) > 0 {
|
||||
state.allocateNamedSectionAndAssignSyms(&Segdata, ".init_array", sym.SINITARR, sym.Sxxx, 06)
|
||||
}
|
||||
|
||||
/* data */
|
||||
sect = state.allocateNamedSectionAndAssignSyms(&Segdata, ".data", sym.SDATA, sym.SDATA, 06)
|
||||
ctxt.Syms.Lookup("runtime.data", 0).Sect = sect
|
||||
ctxt.Syms.Lookup("runtime.edata", 0).Sect = sect
|
||||
dataGcEnd := state.datsize - int64(sect.Vaddr)
|
||||
|
||||
// On AIX, TOC entries must be the last of .data
|
||||
// These aren't part of gc as they won't change during the runtime.
|
||||
state.assignToSection(sect, sym.SXCOFFTOC, sym.SDATA)
|
||||
state.checkdatsize(sym.SDATA)
|
||||
sect.Length = uint64(state.datsize) - sect.Vaddr
|
||||
|
||||
/* bss */
|
||||
sect = state.allocateNamedSectionAndAssignSyms(&Segdata, ".bss", sym.SBSS, sym.Sxxx, 06)
|
||||
ctxt.Syms.Lookup("runtime.bss", 0).Sect = sect
|
||||
ctxt.Syms.Lookup("runtime.ebss", 0).Sect = sect
|
||||
bssGcEnd := state.datsize - int64(sect.Vaddr)
|
||||
|
||||
// Emit gcdata for bcc symbols now that symbol values have been assigned.
|
||||
gcsToEmit := []struct {
|
||||
symName string
|
||||
symKind sym.SymKind
|
||||
gcEnd int64
|
||||
}{
|
||||
{"runtime.gcdata", sym.SDATA, dataGcEnd},
|
||||
{"runtime.gcbss", sym.SBSS, bssGcEnd},
|
||||
}
|
||||
for _, g := range gcsToEmit {
|
||||
var gc GCProg
|
||||
gc.Init(ctxt, g.symName)
|
||||
for _, s := range state.data[g.symKind] {
|
||||
gc.AddSym(s)
|
||||
}
|
||||
gc.End(g.gcEnd)
|
||||
}
|
||||
|
||||
/* pointer-free bss */
|
||||
sect = state.allocateNamedSectionAndAssignSyms(&Segdata, ".noptrbss", sym.SNOPTRBSS, sym.Sxxx, 06)
|
||||
ctxt.Syms.Lookup("runtime.noptrbss", 0).Sect = sect
|
||||
ctxt.Syms.Lookup("runtime.enoptrbss", 0).Sect = sect
|
||||
ctxt.Syms.Lookup("runtime.end", 0).Sect = sect
|
||||
|
||||
// Coverage instrumentation counters for libfuzzer.
|
||||
if len(state.data[sym.SLIBFUZZER_EXTRA_COUNTER]) > 0 {
|
||||
state.allocateNamedSectionAndAssignSyms(&Segdata, "__libfuzzer_extra_counters", sym.SLIBFUZZER_EXTRA_COUNTER, sym.Sxxx, 06)
|
||||
}
|
||||
|
||||
if len(state.data[sym.STLSBSS]) > 0 {
|
||||
var sect *sym.Section
|
||||
// FIXME: not clear why it is sometimes necessary to suppress .tbss section creation.
|
||||
if (ctxt.IsELF || ctxt.HeadType == objabi.Haix) && (ctxt.LinkMode == LinkExternal || !*FlagD) {
|
||||
sect = addsection(ctxt.loader, ctxt.Arch, &Segdata, ".tbss", 06)
|
||||
sect.Align = int32(ctxt.Arch.PtrSize)
|
||||
// FIXME: why does this need to be set to zero?
|
||||
sect.Vaddr = 0
|
||||
}
|
||||
state.datsize = 0
|
||||
|
||||
for _, s := range state.data[sym.STLSBSS] {
|
||||
state.datsize = aligndatsize(state.datsize, s)
|
||||
s.Sect = sect
|
||||
s.Value = state.datsize
|
||||
state.datsize += s.Size
|
||||
}
|
||||
state.checkdatsize(sym.STLSBSS)
|
||||
|
||||
if sect != nil {
|
||||
sect.Length = uint64(state.datsize)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We finished data, begin read-only data.
|
||||
* Not all systems support a separate read-only non-executable data section.
|
||||
* ELF and Windows PE systems do.
|
||||
* OS X and Plan 9 do not.
|
||||
* And if we're using external linking mode, the point is moot,
|
||||
* since it's not our decision; that code expects the sections in
|
||||
* segtext.
|
||||
*/
|
||||
var segro *sym.Segment
|
||||
if ctxt.IsELF && ctxt.LinkMode == LinkInternal {
|
||||
segro = &Segrodata
|
||||
} else if ctxt.HeadType == objabi.Hwindows {
|
||||
segro = &Segrodata
|
||||
} else {
|
||||
segro = &Segtext
|
||||
}
|
||||
|
||||
state.datsize = 0
|
||||
|
||||
/* read-only executable ELF, Mach-O sections */
|
||||
if len(state.data[sym.STEXT]) != 0 {
|
||||
Errorf(nil, "dodata found an sym.STEXT symbol: %s", state.data[sym.STEXT][0].Name)
|
||||
}
|
||||
state.allocateSingleSymSections(&Segtext, sym.SELFRXSECT, sym.SRODATA, 04)
|
||||
|
||||
/* read-only data */
|
||||
sect = state.allocateNamedDataSection(segro, ".rodata", sym.ReadOnly, 04)
|
||||
ctxt.Syms.Lookup("runtime.rodata", 0).Sect = sect
|
||||
ctxt.Syms.Lookup("runtime.erodata", 0).Sect = sect
|
||||
if !ctxt.UseRelro() {
|
||||
ctxt.Syms.Lookup("runtime.types", 0).Sect = sect
|
||||
ctxt.Syms.Lookup("runtime.etypes", 0).Sect = sect
|
||||
}
|
||||
for _, symn := range sym.ReadOnly {
|
||||
symnStartValue := state.datsize
|
||||
state.assignToSection(sect, symn, sym.SRODATA)
|
||||
if ctxt.HeadType == objabi.Haix {
|
||||
// Read-only symbols might be wrapped inside their outer
|
||||
// symbol.
|
||||
// XCOFF symbol table needs to know the size of
|
||||
// these outer symbols.
|
||||
xcoffUpdateOuterSize(ctxt, state.datsize-symnStartValue, symn)
|
||||
}
|
||||
}
|
||||
|
||||
/* read-only ELF, Mach-O sections */
|
||||
state.allocateSingleSymSections(segro, sym.SELFROSECT, sym.SRODATA, 04)
|
||||
state.allocateSingleSymSections(segro, sym.SMACHOPLT, sym.SRODATA, 04)
|
||||
|
||||
// There is some data that are conceptually read-only but are written to by
|
||||
// relocations. On GNU systems, we can arrange for the dynamic linker to
|
||||
// mprotect sections after relocations are applied by giving them write
|
||||
// permissions in the object file and calling them ".data.rel.ro.FOO". We
|
||||
// divide the .rodata section between actual .rodata and .data.rel.ro.rodata,
|
||||
// but for the other sections that this applies to, we just write a read-only
|
||||
// .FOO section or a read-write .data.rel.ro.FOO section depending on the
|
||||
// situation.
|
||||
// TODO(mwhudson): It would make sense to do this more widely, but it makes
|
||||
// the system linker segfault on darwin.
|
||||
const relroPerm = 06
|
||||
const fallbackPerm = 04
|
||||
relroSecPerm := fallbackPerm
|
||||
genrelrosecname := func(suffix string) string {
|
||||
return suffix
|
||||
}
|
||||
seg := segro
|
||||
|
||||
if ctxt.UseRelro() {
|
||||
segrelro := &Segrelrodata
|
||||
if ctxt.LinkMode == LinkExternal && ctxt.HeadType != objabi.Haix {
|
||||
// Using a separate segment with an external
|
||||
// linker results in some programs moving
|
||||
// their data sections unexpectedly, which
|
||||
// corrupts the moduledata. So we use the
|
||||
// rodata segment and let the external linker
|
||||
// sort out a rel.ro segment.
|
||||
segrelro = segro
|
||||
} else {
|
||||
// Reset datsize for new segment.
|
||||
state.datsize = 0
|
||||
}
|
||||
|
||||
genrelrosecname = func(suffix string) string {
|
||||
return ".data.rel.ro" + suffix
|
||||
}
|
||||
relroReadOnly := []sym.SymKind{}
|
||||
for _, symnro := range sym.ReadOnly {
|
||||
symn := sym.RelROMap[symnro]
|
||||
relroReadOnly = append(relroReadOnly, symn)
|
||||
}
|
||||
seg = segrelro
|
||||
relroSecPerm = relroPerm
|
||||
|
||||
/* data only written by relocations */
|
||||
sect = state.allocateNamedDataSection(segrelro, genrelrosecname(""), relroReadOnly, relroSecPerm)
|
||||
|
||||
ctxt.Syms.Lookup("runtime.types", 0).Sect = sect
|
||||
ctxt.Syms.Lookup("runtime.etypes", 0).Sect = sect
|
||||
|
||||
for i, symnro := range sym.ReadOnly {
|
||||
if i == 0 && symnro == sym.STYPE && ctxt.HeadType != objabi.Haix {
|
||||
// Skip forward so that no type
|
||||
// reference uses a zero offset.
|
||||
// This is unlikely but possible in small
|
||||
// programs with no other read-only data.
|
||||
state.datsize++
|
||||
}
|
||||
|
||||
symn := sym.RelROMap[symnro]
|
||||
symnStartValue := state.datsize
|
||||
|
||||
for _, s := range state.data[symn] {
|
||||
if s.Outer != nil && s.Outer.Sect != nil && s.Outer.Sect != sect {
|
||||
Errorf(s, "s.Outer (%s) in different section from s, %s != %s", s.Outer.Name, s.Outer.Sect.Name, sect.Name)
|
||||
}
|
||||
}
|
||||
state.assignToSection(sect, symn, sym.SRODATA)
|
||||
if ctxt.HeadType == objabi.Haix {
|
||||
// Read-only symbols might be wrapped inside their outer
|
||||
// symbol.
|
||||
// XCOFF symbol table needs to know the size of
|
||||
// these outer symbols.
|
||||
xcoffUpdateOuterSize(ctxt, state.datsize-symnStartValue, symn)
|
||||
}
|
||||
}
|
||||
|
||||
sect.Length = uint64(state.datsize) - sect.Vaddr
|
||||
}
|
||||
|
||||
/* typelink */
|
||||
sect = state.allocateNamedDataSection(seg, genrelrosecname(".typelink"), []sym.SymKind{sym.STYPELINK}, relroSecPerm)
|
||||
typelink := ctxt.Syms.Lookup("runtime.typelink", 0)
|
||||
typelink.Sect = sect
|
||||
typelink.Type = sym.SRODATA
|
||||
state.datsize += typelink.Size
|
||||
state.checkdatsize(sym.STYPELINK)
|
||||
sect.Length = uint64(state.datsize) - sect.Vaddr
|
||||
|
||||
/* itablink */
|
||||
sect = state.allocateNamedSectionAndAssignSyms(seg, genrelrosecname(".itablink"), sym.SITABLINK, sym.Sxxx, relroSecPerm)
|
||||
ctxt.Syms.Lookup("runtime.itablink", 0).Sect = sect
|
||||
ctxt.Syms.Lookup("runtime.eitablink", 0).Sect = sect
|
||||
if ctxt.HeadType == objabi.Haix {
|
||||
// Store .itablink size because its symbols are wrapped
|
||||
// under an outer symbol: runtime.itablink.
|
||||
xcoffUpdateOuterSize(ctxt, int64(sect.Length), sym.SITABLINK)
|
||||
}
|
||||
|
||||
/* gosymtab */
|
||||
sect = state.allocateNamedSectionAndAssignSyms(seg, genrelrosecname(".gosymtab"), sym.SSYMTAB, sym.SRODATA, relroSecPerm)
|
||||
ctxt.Syms.Lookup("runtime.symtab", 0).Sect = sect
|
||||
ctxt.Syms.Lookup("runtime.esymtab", 0).Sect = sect
|
||||
|
||||
/* gopclntab */
|
||||
sect = state.allocateNamedSectionAndAssignSyms(seg, genrelrosecname(".gopclntab"), sym.SPCLNTAB, sym.SRODATA, relroSecPerm)
|
||||
ctxt.Syms.Lookup("runtime.pclntab", 0).Sect = sect
|
||||
ctxt.Syms.Lookup("runtime.epclntab", 0).Sect = sect
|
||||
|
||||
// 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits.
|
||||
if state.datsize != int64(uint32(state.datsize)) {
|
||||
Errorf(nil, "read-only data segment too large: %d", state.datsize)
|
||||
}
|
||||
|
||||
for symn := sym.SELFRXSECT; symn < sym.SXREF; symn++ {
|
||||
ctxt.datap = append(ctxt.datap, state.data[symn]...)
|
||||
}
|
||||
}
|
||||
|
||||
// allocateDwarfSections allocates sym.Section objects for DWARF
|
||||
// symbols, and assigns symbols to sections.
|
||||
func (state *dodataState) allocateDwarfSections(ctxt *Link) {
|
||||
|
||||
alignOne := func(datsize int64, s *sym.Symbol) int64 { return datsize }
|
||||
|
||||
for i := 0; i < len(dwarfp); i++ {
|
||||
// First the section symbol.
|
||||
s := dwarfp[i].secSym()
|
||||
sect := state.allocateNamedDataSection(&Segdwarf, s.Name, []sym.SymKind{}, 04)
|
||||
sect.Sym = s
|
||||
s.Sect = sect
|
||||
curType := s.Type
|
||||
s.Type = sym.SRODATA
|
||||
s.Value = int64(uint64(state.datsize) - sect.Vaddr)
|
||||
state.datsize += s.Size
|
||||
|
||||
// Then any sub-symbols for the section symbol.
|
||||
subSyms := dwarfp[i].subSyms()
|
||||
state.assignDsymsToSection(sect, subSyms, sym.SRODATA, alignOne)
|
||||
|
||||
for j := 0; j < len(subSyms); j++ {
|
||||
s := subSyms[j]
|
||||
if ctxt.HeadType == objabi.Haix && curType == sym.SDWARFLOC {
|
||||
// Update the size of .debug_loc for this symbol's
|
||||
// package.
|
||||
addDwsectCUSize(".debug_loc", s.File, uint64(s.Size))
|
||||
}
|
||||
}
|
||||
sect.Length = uint64(state.datsize) - sect.Vaddr
|
||||
state.checkdatsize(curType)
|
||||
}
|
||||
}
|
||||
|
||||
func dodataSect(ctxt *Link, symn sym.SymKind, syms []*sym.Symbol, symToIdx map[*sym.Symbol]loader.Sym) (result []*sym.Symbol, maxAlign int32) {
|
||||
if ctxt.HeadType == objabi.Hdarwin {
|
||||
// Some symbols may no longer belong in syms
|
||||
// due to movement in machosymorder.
|
||||
newSyms := make([]*sym.Symbol, 0, len(syms))
|
||||
for _, s := range syms {
|
||||
if s.Type == symn {
|
||||
newSyms = append(newSyms, s)
|
||||
}
|
||||
}
|
||||
syms = newSyms
|
||||
}
|
||||
|
||||
var head, tail *sym.Symbol
|
||||
symsSort := make([]dataSortKey, 0, len(syms))
|
||||
for _, s := range syms {
|
||||
if s.Attr.OnList() {
|
||||
log.Fatalf("symbol %s listed multiple times", s.Name)
|
||||
}
|
||||
s.Attr |= sym.AttrOnList
|
||||
switch {
|
||||
case s.Size < int64(len(s.P)):
|
||||
Errorf(s, "initialize bounds (%d < %d)", s.Size, len(s.P))
|
||||
case s.Size < 0:
|
||||
Errorf(s, "negative size (%d bytes)", s.Size)
|
||||
case s.Size > cutoff:
|
||||
Errorf(s, "symbol too large (%d bytes)", s.Size)
|
||||
}
|
||||
|
||||
// If the usually-special section-marker symbols are being laid
|
||||
// out as regular symbols, put them either at the beginning or
|
||||
// end of their section.
|
||||
if (ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin) || (ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal) {
|
||||
switch s.Name {
|
||||
case "runtime.text", "runtime.bss", "runtime.data", "runtime.types", "runtime.rodata":
|
||||
head = s
|
||||
continue
|
||||
case "runtime.etext", "runtime.ebss", "runtime.edata", "runtime.etypes", "runtime.erodata":
|
||||
tail = s
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
key := dataSortKey{
|
||||
size: s.Size,
|
||||
name: s.Name,
|
||||
sym: s,
|
||||
symIdx: symToIdx[s],
|
||||
}
|
||||
|
||||
switch s.Type {
|
||||
case sym.SELFGOT:
|
||||
// For ppc64, we want to interleave the .got and .toc sections
|
||||
// from input files. Both are type sym.SELFGOT, so in that case
|
||||
// we skip size comparison and fall through to the name
|
||||
// comparison (conveniently, .got sorts before .toc).
|
||||
key.size = 0
|
||||
}
|
||||
|
||||
symsSort = append(symsSort, key)
|
||||
}
|
||||
|
||||
sort.Sort(bySizeAndName(symsSort))
|
||||
|
||||
off := 0
|
||||
if head != nil {
|
||||
syms[0] = head
|
||||
off++
|
||||
}
|
||||
for i, symSort := range symsSort {
|
||||
syms[i+off] = symSort.sym
|
||||
align := symalign(symSort.sym)
|
||||
if maxAlign < align {
|
||||
maxAlign = align
|
||||
}
|
||||
}
|
||||
if tail != nil {
|
||||
syms[len(syms)-1] = tail
|
||||
}
|
||||
|
||||
if ctxt.IsELF && symn == sym.SELFROSECT {
|
||||
// Make .rela and .rela.plt contiguous, the ELF ABI requires this
|
||||
// and Solaris actually cares.
|
||||
reli, plti := -1, -1
|
||||
for i, s := range syms {
|
||||
switch s.Name {
|
||||
case ".rel.plt", ".rela.plt":
|
||||
plti = i
|
||||
case ".rel", ".rela":
|
||||
reli = i
|
||||
}
|
||||
}
|
||||
if reli >= 0 && plti >= 0 && plti != reli+1 {
|
||||
var first, second int
|
||||
if plti > reli {
|
||||
first, second = reli, plti
|
||||
} else {
|
||||
first, second = plti, reli
|
||||
}
|
||||
rel, plt := syms[reli], syms[plti]
|
||||
copy(syms[first+2:], syms[first+1:second])
|
||||
syms[first+0] = rel
|
||||
syms[first+1] = plt
|
||||
|
||||
// Make sure alignment doesn't introduce a gap.
|
||||
// Setting the alignment explicitly prevents
|
||||
// symalign from basing it on the size and
|
||||
// getting it wrong.
|
||||
rel.Align = int32(ctxt.Arch.RegSize)
|
||||
plt.Align = int32(ctxt.Arch.RegSize)
|
||||
}
|
||||
}
|
||||
|
||||
return syms, maxAlign
|
||||
}
|
@ -628,9 +628,9 @@ func elfwriteshdrs(out *OutBuf) uint32 {
|
||||
return uint32(ehdr.shnum) * ELF32SHDRSIZE
|
||||
}
|
||||
|
||||
func elfsetstring(s *sym.Symbol, str string, off int) {
|
||||
func elfsetstring2(ctxt *Link, s loader.Sym, str string, off int) {
|
||||
if nelfstr >= len(elfstr) {
|
||||
Errorf(s, "too many elf strings")
|
||||
ctxt.Errorf(s, "too many elf strings")
|
||||
errorexit()
|
||||
}
|
||||
|
||||
@ -753,8 +753,8 @@ func elfWriteDynEnt(arch *sys.Arch, s *sym.Symbol, tag int, val uint64) {
|
||||
}
|
||||
}
|
||||
|
||||
func elfWriteDynEntSym(arch *sys.Arch, s *sym.Symbol, tag int, t *sym.Symbol) {
|
||||
Elfwritedynentsymplus(arch, s, tag, t, 0)
|
||||
func elfWriteDynEntSym2(ctxt *Link, s *loader.SymbolBuilder, tag int, t loader.Sym) {
|
||||
Elfwritedynentsymplus2(ctxt, s, tag, t, 0)
|
||||
}
|
||||
|
||||
func Elfwritedynentsymplus(arch *sys.Arch, s *sym.Symbol, tag int, t *sym.Symbol, add int64) {
|
||||
@ -1057,15 +1057,16 @@ havelib:
|
||||
return aux
|
||||
}
|
||||
|
||||
func elfdynhash(ctxt *Link) {
|
||||
func elfdynhash2(ctxt *Link) {
|
||||
if !ctxt.IsELF {
|
||||
return
|
||||
}
|
||||
|
||||
nsym := Nelfsym
|
||||
s := ctxt.Syms.Lookup(".hash", 0)
|
||||
s.Type = sym.SELFROSECT
|
||||
s.Attr |= sym.AttrReachable
|
||||
ldr := ctxt.loader
|
||||
s := ldr.CreateSymForUpdate(".hash", 0)
|
||||
s.SetType(sym.SELFROSECT)
|
||||
s.SetReachable(true)
|
||||
|
||||
i := nsym
|
||||
nbucket := 1
|
||||
@ -1079,21 +1080,19 @@ func elfdynhash(ctxt *Link) {
|
||||
chain := make([]uint32, nsym)
|
||||
buckets := make([]uint32, nbucket)
|
||||
|
||||
for _, sy := range ctxt.Syms.Allsym {
|
||||
if sy.Dynid <= 0 {
|
||||
continue
|
||||
for _, sy := range ldr.DynidSyms() {
|
||||
|
||||
dynid := ldr.SymDynid(sy)
|
||||
if ldr.SymDynimpvers(sy) != "" {
|
||||
need[dynid] = addelflib(&needlib, ldr.SymDynimplib(sy), ldr.SymDynimpvers(sy))
|
||||
}
|
||||
|
||||
if sy.Dynimpvers() != "" {
|
||||
need[sy.Dynid] = addelflib(&needlib, sy.Dynimplib(), sy.Dynimpvers())
|
||||
}
|
||||
|
||||
name := sy.Extname()
|
||||
name := ldr.SymExtname(sy)
|
||||
hc := elfhash(name)
|
||||
|
||||
b := hc % uint32(nbucket)
|
||||
chain[sy.Dynid] = buckets[b]
|
||||
buckets[b] = uint32(sy.Dynid)
|
||||
chain[dynid] = buckets[b]
|
||||
buckets[b] = uint32(dynid)
|
||||
}
|
||||
|
||||
// s390x (ELF64) hash table entries are 8 bytes
|
||||
@ -1117,10 +1116,11 @@ func elfdynhash(ctxt *Link) {
|
||||
}
|
||||
}
|
||||
|
||||
// version symbols
|
||||
dynstr := ctxt.Syms.Lookup(".dynstr", 0)
|
||||
dynstr := ldr.CreateSymForUpdate(".dynstr", 0)
|
||||
|
||||
s = ctxt.Syms.Lookup(".gnu.version_r", 0)
|
||||
// version symbols
|
||||
gnuVersionR := ldr.CreateSymForUpdate(".gnu.version_r", 0)
|
||||
s = gnuVersionR
|
||||
i = 2
|
||||
nfile := 0
|
||||
for l := needlib; l != nil; l = l.next {
|
||||
@ -1132,9 +1132,9 @@ func elfdynhash(ctxt *Link) {
|
||||
for x := l.aux; x != nil; x = x.next {
|
||||
j++
|
||||
}
|
||||
s.AddUint16(ctxt.Arch, uint16(j)) // aux count
|
||||
s.AddUint32(ctxt.Arch, uint32(Addstring(dynstr, l.file))) // file string offset
|
||||
s.AddUint32(ctxt.Arch, 16) // offset from header to first aux
|
||||
s.AddUint16(ctxt.Arch, uint16(j)) // aux count
|
||||
s.AddUint32(ctxt.Arch, uint32(dynstr.Addstring(l.file))) // file string offset
|
||||
s.AddUint32(ctxt.Arch, 16) // offset from header to first aux
|
||||
if l.next != nil {
|
||||
s.AddUint32(ctxt.Arch, 16+uint32(j)*16) // offset from this header to next
|
||||
} else {
|
||||
@ -1146,10 +1146,10 @@ func elfdynhash(ctxt *Link) {
|
||||
i++
|
||||
|
||||
// aux struct
|
||||
s.AddUint32(ctxt.Arch, elfhash(x.vers)) // hash
|
||||
s.AddUint16(ctxt.Arch, 0) // flags
|
||||
s.AddUint16(ctxt.Arch, uint16(x.num)) // other - index we refer to this by
|
||||
s.AddUint32(ctxt.Arch, uint32(Addstring(dynstr, x.vers))) // version string offset
|
||||
s.AddUint32(ctxt.Arch, elfhash(x.vers)) // hash
|
||||
s.AddUint16(ctxt.Arch, 0) // flags
|
||||
s.AddUint16(ctxt.Arch, uint16(x.num)) // other - index we refer to this by
|
||||
s.AddUint32(ctxt.Arch, uint32(dynstr.Addstring(x.vers))) // version string offset
|
||||
if x.next != nil {
|
||||
s.AddUint32(ctxt.Arch, 16) // offset from this aux to next
|
||||
} else {
|
||||
@ -1159,7 +1159,8 @@ func elfdynhash(ctxt *Link) {
|
||||
}
|
||||
|
||||
// version references
|
||||
s = ctxt.Syms.Lookup(".gnu.version", 0)
|
||||
gnuVersion := ldr.CreateSymForUpdate(".gnu.version", 0)
|
||||
s = gnuVersion
|
||||
|
||||
for i := 0; i < nsym; i++ {
|
||||
if i == 0 {
|
||||
@ -1171,26 +1172,26 @@ func elfdynhash(ctxt *Link) {
|
||||
}
|
||||
}
|
||||
|
||||
s = ctxt.Syms.Lookup(".dynamic", 0)
|
||||
s = ldr.CreateSymForUpdate(".dynamic", 0)
|
||||
elfverneed = nfile
|
||||
if elfverneed != 0 {
|
||||
elfWriteDynEntSym(ctxt.Arch, s, DT_VERNEED, ctxt.Syms.Lookup(".gnu.version_r", 0))
|
||||
elfWriteDynEnt(ctxt.Arch, s, DT_VERNEEDNUM, uint64(nfile))
|
||||
elfWriteDynEntSym(ctxt.Arch, s, DT_VERSYM, ctxt.Syms.Lookup(".gnu.version", 0))
|
||||
elfWriteDynEntSym2(ctxt, s, DT_VERNEED, gnuVersionR.Sym())
|
||||
Elfwritedynent2(ctxt.Arch, s, DT_VERNEEDNUM, uint64(nfile))
|
||||
elfWriteDynEntSym2(ctxt, s, DT_VERSYM, gnuVersion.Sym())
|
||||
}
|
||||
|
||||
sy := ctxt.Syms.Lookup(elfRelType+".plt", 0)
|
||||
if sy.Size > 0 {
|
||||
sy := ldr.CreateSymForUpdate(elfRelType+".plt", 0)
|
||||
if sy.Size() > 0 {
|
||||
if elfRelType == ".rela" {
|
||||
elfWriteDynEnt(ctxt.Arch, s, DT_PLTREL, DT_RELA)
|
||||
Elfwritedynent2(ctxt.Arch, s, DT_PLTREL, DT_RELA)
|
||||
} else {
|
||||
elfWriteDynEnt(ctxt.Arch, s, DT_PLTREL, DT_REL)
|
||||
Elfwritedynent2(ctxt.Arch, s, DT_PLTREL, DT_REL)
|
||||
}
|
||||
elfWriteDynEntSymSize(ctxt.Arch, s, DT_PLTRELSZ, sy)
|
||||
elfWriteDynEntSym(ctxt.Arch, s, DT_JMPREL, sy)
|
||||
elfwritedynentsymsize2(ctxt, s, DT_PLTRELSZ, sy.Sym())
|
||||
elfWriteDynEntSym2(ctxt, s, DT_JMPREL, sy.Sym())
|
||||
}
|
||||
|
||||
elfWriteDynEnt(ctxt.Arch, s, DT_NULL, 0)
|
||||
Elfwritedynent2(ctxt.Arch, s, DT_NULL, 0)
|
||||
}
|
||||
|
||||
func elfphload(seg *sym.Segment) *ElfPhdr {
|
||||
|
166
src/cmd/link/internal/ld/elf2.go
Normal file
166
src/cmd/link/internal/ld/elf2.go
Normal file
@ -0,0 +1,166 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ld
|
||||
|
||||
import (
|
||||
"cmd/internal/sys"
|
||||
"cmd/link/internal/sym"
|
||||
)
|
||||
|
||||
// Temporary dumping around for sym.Symbol version of helper
|
||||
// functions in elf.go, still being used for some archs/oses.
|
||||
// FIXME: get rid of this file when dodata() is completely
|
||||
// converted and the sym.Symbol functions are not needed.
|
||||
|
||||
func elfsetstring(s *sym.Symbol, str string, off int) {
|
||||
if nelfstr >= len(elfstr) {
|
||||
Errorf(s, "too many elf strings")
|
||||
errorexit()
|
||||
}
|
||||
|
||||
elfstr[nelfstr].s = str
|
||||
elfstr[nelfstr].off = off
|
||||
nelfstr++
|
||||
}
|
||||
|
||||
func elfWriteDynEntSym(arch *sys.Arch, s *sym.Symbol, tag int, t *sym.Symbol) {
|
||||
Elfwritedynentsymplus(arch, s, tag, t, 0)
|
||||
}
|
||||
|
||||
func elfdynhash(ctxt *Link) {
|
||||
if !ctxt.IsELF {
|
||||
return
|
||||
}
|
||||
|
||||
nsym := Nelfsym
|
||||
s := ctxt.Syms.Lookup(".hash", 0)
|
||||
s.Type = sym.SELFROSECT
|
||||
s.Attr |= sym.AttrReachable
|
||||
|
||||
i := nsym
|
||||
nbucket := 1
|
||||
for i > 0 {
|
||||
nbucket++
|
||||
i >>= 1
|
||||
}
|
||||
|
||||
var needlib *Elflib
|
||||
need := make([]*Elfaux, nsym)
|
||||
chain := make([]uint32, nsym)
|
||||
buckets := make([]uint32, nbucket)
|
||||
|
||||
for _, sy := range ctxt.Syms.Allsym {
|
||||
if sy.Dynid <= 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if sy.Dynimpvers() != "" {
|
||||
need[sy.Dynid] = addelflib(&needlib, sy.Dynimplib(), sy.Dynimpvers())
|
||||
}
|
||||
|
||||
name := sy.Extname()
|
||||
hc := elfhash(name)
|
||||
|
||||
b := hc % uint32(nbucket)
|
||||
chain[sy.Dynid] = buckets[b]
|
||||
buckets[b] = uint32(sy.Dynid)
|
||||
}
|
||||
|
||||
// s390x (ELF64) hash table entries are 8 bytes
|
||||
if ctxt.Arch.Family == sys.S390X {
|
||||
s.AddUint64(ctxt.Arch, uint64(nbucket))
|
||||
s.AddUint64(ctxt.Arch, uint64(nsym))
|
||||
for i := 0; i < nbucket; i++ {
|
||||
s.AddUint64(ctxt.Arch, uint64(buckets[i]))
|
||||
}
|
||||
for i := 0; i < nsym; i++ {
|
||||
s.AddUint64(ctxt.Arch, uint64(chain[i]))
|
||||
}
|
||||
} else {
|
||||
s.AddUint32(ctxt.Arch, uint32(nbucket))
|
||||
s.AddUint32(ctxt.Arch, uint32(nsym))
|
||||
for i := 0; i < nbucket; i++ {
|
||||
s.AddUint32(ctxt.Arch, buckets[i])
|
||||
}
|
||||
for i := 0; i < nsym; i++ {
|
||||
s.AddUint32(ctxt.Arch, chain[i])
|
||||
}
|
||||
}
|
||||
|
||||
// version symbols
|
||||
dynstr := ctxt.Syms.Lookup(".dynstr", 0)
|
||||
|
||||
s = ctxt.Syms.Lookup(".gnu.version_r", 0)
|
||||
i = 2
|
||||
nfile := 0
|
||||
for l := needlib; l != nil; l = l.next {
|
||||
nfile++
|
||||
|
||||
// header
|
||||
s.AddUint16(ctxt.Arch, 1) // table version
|
||||
j := 0
|
||||
for x := l.aux; x != nil; x = x.next {
|
||||
j++
|
||||
}
|
||||
s.AddUint16(ctxt.Arch, uint16(j)) // aux count
|
||||
s.AddUint32(ctxt.Arch, uint32(Addstring(dynstr, l.file))) // file string offset
|
||||
s.AddUint32(ctxt.Arch, 16) // offset from header to first aux
|
||||
if l.next != nil {
|
||||
s.AddUint32(ctxt.Arch, 16+uint32(j)*16) // offset from this header to next
|
||||
} else {
|
||||
s.AddUint32(ctxt.Arch, 0)
|
||||
}
|
||||
|
||||
for x := l.aux; x != nil; x = x.next {
|
||||
x.num = i
|
||||
i++
|
||||
|
||||
// aux struct
|
||||
s.AddUint32(ctxt.Arch, elfhash(x.vers)) // hash
|
||||
s.AddUint16(ctxt.Arch, 0) // flags
|
||||
s.AddUint16(ctxt.Arch, uint16(x.num)) // other - index we refer to this by
|
||||
s.AddUint32(ctxt.Arch, uint32(Addstring(dynstr, x.vers))) // version string offset
|
||||
if x.next != nil {
|
||||
s.AddUint32(ctxt.Arch, 16) // offset from this aux to next
|
||||
} else {
|
||||
s.AddUint32(ctxt.Arch, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// version references
|
||||
s = ctxt.Syms.Lookup(".gnu.version", 0)
|
||||
|
||||
for i := 0; i < nsym; i++ {
|
||||
if i == 0 {
|
||||
s.AddUint16(ctxt.Arch, 0) // first entry - no symbol
|
||||
} else if need[i] == nil {
|
||||
s.AddUint16(ctxt.Arch, 1) // global
|
||||
} else {
|
||||
s.AddUint16(ctxt.Arch, uint16(need[i].num))
|
||||
}
|
||||
}
|
||||
|
||||
s = ctxt.Syms.Lookup(".dynamic", 0)
|
||||
elfverneed = nfile
|
||||
if elfverneed != 0 {
|
||||
elfWriteDynEntSym(ctxt.Arch, s, DT_VERNEED, ctxt.Syms.Lookup(".gnu.version_r", 0))
|
||||
elfWriteDynEnt(ctxt.Arch, s, DT_VERNEEDNUM, uint64(nfile))
|
||||
elfWriteDynEntSym(ctxt.Arch, s, DT_VERSYM, ctxt.Syms.Lookup(".gnu.version", 0))
|
||||
}
|
||||
|
||||
sy := ctxt.Syms.Lookup(elfRelType+".plt", 0)
|
||||
if sy.Size > 0 {
|
||||
if elfRelType == ".rela" {
|
||||
elfWriteDynEnt(ctxt.Arch, s, DT_PLTREL, DT_RELA)
|
||||
} else {
|
||||
elfWriteDynEnt(ctxt.Arch, s, DT_PLTREL, DT_REL)
|
||||
}
|
||||
elfWriteDynEntSymSize(ctxt.Arch, s, DT_PLTRELSZ, sy)
|
||||
elfWriteDynEntSym(ctxt.Arch, s, DT_JMPREL, sy)
|
||||
}
|
||||
|
||||
elfWriteDynEnt(ctxt.Arch, s, DT_NULL, 0)
|
||||
}
|
@ -331,7 +331,7 @@ func adddynlib(ctxt *Link, lib string) {
|
||||
}
|
||||
}
|
||||
|
||||
func Adddynsym2(ldr *loader.Loader, reporter *ErrorReporter, target *Target, syms *ArchSyms, s loader.Sym) {
|
||||
func Adddynsym2(ldr *loader.Loader, target *Target, syms *ArchSyms, s loader.Sym) {
|
||||
if ldr.SymDynid(s) >= 0 || target.LinkMode == LinkExternal {
|
||||
return
|
||||
}
|
||||
@ -339,11 +339,11 @@ func Adddynsym2(ldr *loader.Loader, reporter *ErrorReporter, target *Target, sym
|
||||
if target.IsELF {
|
||||
elfadddynsym2(ldr, target, syms, s)
|
||||
} else if target.HeadType == objabi.Hdarwin {
|
||||
reporter.Errorf(s, "adddynsym: missed symbol (Extname=%s)", ldr.SymExtname(s))
|
||||
ldr.Errorf(s, "adddynsym: missed symbol (Extname=%s)", ldr.SymExtname(s))
|
||||
} else if target.HeadType == objabi.Hwindows {
|
||||
// already taken care of
|
||||
} else {
|
||||
reporter.Errorf(s, "adddynsym: unsupported binary format")
|
||||
ldr.Errorf(s, "adddynsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
@ -425,7 +425,7 @@ func (ctxt *Link) addexport() {
|
||||
}
|
||||
|
||||
for _, exp := range ctxt.dynexp2 {
|
||||
Adddynsym2(ctxt.loader, &ctxt.ErrorReporter, &ctxt.Target, &ctxt.ArchSyms, exp)
|
||||
Adddynsym2(ctxt.loader, &ctxt.Target, &ctxt.ArchSyms, exp)
|
||||
}
|
||||
for _, lib := range dynlib {
|
||||
adddynlib(ctxt, lib)
|
||||
|
@ -232,6 +232,7 @@ type Arch struct {
|
||||
Dragonflydynld string
|
||||
Solarisdynld string
|
||||
Adddynrel func(*Target, *loader.Loader, *ArchSyms, *sym.Symbol, *sym.Reloc) bool
|
||||
Adddynrel2 func(*Target, *loader.Loader, *ArchSyms, loader.Sym, *loader.Reloc2, int) bool
|
||||
Archinit func(*Link)
|
||||
// Archreloc is an arch-specific hook that assists in
|
||||
// relocation processing (invoked by 'relocsym'); it handles
|
||||
@ -2800,7 +2801,7 @@ func addToTextp(ctxt *Link) {
|
||||
ctxt.Textp = textp
|
||||
}
|
||||
|
||||
func (ctxt *Link) loadlibfull() {
|
||||
func (ctxt *Link) loadlibfull(symGroupType []sym.SymKind) {
|
||||
|
||||
// Load full symbol contents, resolve indexed references.
|
||||
ctxt.loader.LoadFull(ctxt.Arch, ctxt.Syms)
|
||||
@ -2841,12 +2842,41 @@ func (ctxt *Link) loadlibfull() {
|
||||
dwarfp = append(dwarfp, dwarfSecInfo2{syms: syms})
|
||||
}
|
||||
|
||||
// Populate datap from datap2
|
||||
ctxt.datap = make([]*sym.Symbol, len(ctxt.datap2))
|
||||
for i, symIdx := range ctxt.datap2 {
|
||||
s := ctxt.loader.Syms[symIdx]
|
||||
if s == nil {
|
||||
panic(fmt.Sprintf("nil sym for datap2 element %d", symIdx))
|
||||
}
|
||||
ctxt.datap[i] = s
|
||||
}
|
||||
|
||||
// Populate the sym.Section 'Sym' fields based on their 'Sym2'
|
||||
// fields.
|
||||
allSegments := []*sym.Segment{&Segtext, &Segrodata, &Segrelrodata, &Segdata, &Segdwarf}
|
||||
for _, seg := range allSegments {
|
||||
for _, sect := range seg.Sections {
|
||||
if sect.Sym2 != 0 {
|
||||
s := ctxt.loader.Syms[sect.Sym2]
|
||||
if s == nil {
|
||||
panic(fmt.Sprintf("nil sym for sect %s sym %d", sect.Name, sect.Sym2))
|
||||
}
|
||||
sect.Sym = s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For now, overwrite symbol type with its "group" type, as dodata
|
||||
// expected. Once we converted dodata, this will probably not be
|
||||
// needed.
|
||||
for i, t := range symGroupType {
|
||||
if t != sym.Sxxx {
|
||||
ctxt.loader.Syms[i].Type = t
|
||||
s := ctxt.loader.Syms[i]
|
||||
if s == nil {
|
||||
panic(fmt.Sprintf("nil sym for symGroupType t=%s entry %d", t.String(), i))
|
||||
}
|
||||
s.Type = t
|
||||
}
|
||||
}
|
||||
symGroupType = nil
|
||||
|
@ -92,6 +92,7 @@ type Link struct {
|
||||
cgo_export_dynamic map[string]bool
|
||||
|
||||
datap []*sym.Symbol
|
||||
datap2 []loader.Sym
|
||||
dynexp2 []loader.Sym
|
||||
|
||||
// Elf symtab variables.
|
||||
|
@ -95,6 +95,7 @@ var (
|
||||
cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`")
|
||||
memprofile = flag.String("memprofile", "", "write memory profile to `file`")
|
||||
memprofilerate = flag.Int64("memprofilerate", 0, "set runtime.MemProfileRate to `rate`")
|
||||
flagnewDoData = flag.Bool("newdodata", true, "New style dodata")
|
||||
|
||||
benchmarkFlag = flag.String("benchmark", "", "set to 'mem' or 'cpu' to enable phase benchmarking")
|
||||
benchmarkFileFlag = flag.String("benchmarkprofile", "", "emit phase profiles to `base`_phase.{cpu,mem}prof")
|
||||
@ -155,6 +156,13 @@ func Main(arch *sys.Arch, theArch Arch) {
|
||||
}
|
||||
}
|
||||
|
||||
if *flagnewDoData {
|
||||
// New dodata() is currently only implemented for linux/amd64.
|
||||
if !(ctxt.IsElf() && ctxt.IsAMD64()) {
|
||||
*flagnewDoData = false
|
||||
}
|
||||
}
|
||||
|
||||
checkStrictDups = *FlagStrictDups
|
||||
|
||||
startProfile()
|
||||
@ -297,11 +305,17 @@ func Main(arch *sys.Arch, theArch Arch) {
|
||||
bench.Start("dwarfGenerateDebugSyms")
|
||||
dwarfGenerateDebugSyms(ctxt)
|
||||
bench.Start("symtab")
|
||||
ctxt.symtab()
|
||||
symGroupType := ctxt.symtab()
|
||||
if *flagnewDoData {
|
||||
bench.Start("dodata")
|
||||
ctxt.dodata2(symGroupType)
|
||||
}
|
||||
bench.Start("loadlibfull")
|
||||
ctxt.loadlibfull() // XXX do it here for now
|
||||
bench.Start("dodata")
|
||||
ctxt.dodata()
|
||||
ctxt.loadlibfull(symGroupType) // XXX do it here for now
|
||||
if !*flagnewDoData {
|
||||
bench.Start("dodata")
|
||||
ctxt.dodata()
|
||||
}
|
||||
bench.Start("address")
|
||||
order := ctxt.address()
|
||||
bench.Start("dwarfcompress")
|
||||
|
@ -327,9 +327,7 @@ func textsectionmap(ctxt *Link) (loader.Sym, uint32) {
|
||||
return t.Sym(), uint32(n)
|
||||
}
|
||||
|
||||
var symGroupType []sym.SymKind // temporarily assign a symbol's "group" type
|
||||
|
||||
func (ctxt *Link) symtab() {
|
||||
func (ctxt *Link) symtab() []sym.SymKind {
|
||||
ldr := ctxt.loader
|
||||
|
||||
if !ctxt.IsAIX() {
|
||||
@ -441,7 +439,7 @@ func (ctxt *Link) symtab() {
|
||||
// just defined above will be first.
|
||||
// hide the specific symbols.
|
||||
nsym := loader.Sym(ldr.NSym())
|
||||
symGroupType = make([]sym.SymKind, nsym)
|
||||
symGroupType := make([]sym.SymKind, nsym)
|
||||
for s := loader.Sym(1); s < nsym; s++ {
|
||||
name := ldr.SymName(s)
|
||||
if !ctxt.IsExternal() && isStaticTemp(name) {
|
||||
@ -709,6 +707,7 @@ func (ctxt *Link) symtab() {
|
||||
lastmoduledatap.SetData(nil)
|
||||
lastmoduledatap.AddAddr(ctxt.Arch, moduledata.Sym())
|
||||
}
|
||||
return symGroupType
|
||||
}
|
||||
|
||||
func isStaticTemp(name string) bool {
|
||||
|
@ -567,11 +567,12 @@ var (
|
||||
|
||||
// xcoffUpdateOuterSize stores the size of outer symbols in order to have it
|
||||
// in the symbol table.
|
||||
func xcoffUpdateOuterSize(ctxt *Link, size int64, stype sym.SymKind) {
|
||||
func xcoffUpdateOuterSize2(ctxt *Link, size int64, stype sym.SymKind) {
|
||||
if size == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
ldr := ctxt.loader
|
||||
switch stype {
|
||||
default:
|
||||
Errorf(nil, "unknown XCOFF outer symbol for type %s", stype.String())
|
||||
@ -580,14 +581,16 @@ func xcoffUpdateOuterSize(ctxt *Link, size int64, stype sym.SymKind) {
|
||||
case sym.STYPERELRO:
|
||||
if ctxt.UseRelro() && (ctxt.BuildMode == BuildModeCArchive || ctxt.BuildMode == BuildModeCShared || ctxt.BuildMode == BuildModePIE) {
|
||||
// runtime.types size must be removed, as it's a real symbol.
|
||||
outerSymSize["typerel.*"] = size - ctxt.Syms.ROLookup("runtime.types", 0).Size
|
||||
tsize := ldr.SymSize(ldr.Lookup("runtime.types", 0))
|
||||
outerSymSize["typerel.*"] = size - tsize
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
case sym.STYPE:
|
||||
if !ctxt.DynlinkingGo() {
|
||||
// runtime.types size must be removed, as it's a real symbol.
|
||||
outerSymSize["type.*"] = size - ctxt.Syms.ROLookup("runtime.types", 0).Size
|
||||
tsize := ldr.SymSize(ldr.Lookup("runtime.types", 0))
|
||||
outerSymSize["type.*"] = size - tsize
|
||||
}
|
||||
case sym.SGOSTRING:
|
||||
outerSymSize["go.string.*"] = size
|
||||
@ -603,7 +606,6 @@ func xcoffUpdateOuterSize(ctxt *Link, size int64, stype sym.SymKind) {
|
||||
outerSymSize["runtime.itablink"] = size
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// addSymbol writes a symbol or an auxiliary symbol entry on ctxt.out.
|
||||
|
52
src/cmd/link/internal/ld/xcoff2.go
Normal file
52
src/cmd/link/internal/ld/xcoff2.go
Normal file
@ -0,0 +1,52 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ld
|
||||
|
||||
import "cmd/link/internal/sym"
|
||||
|
||||
// Temporary dumping around for sym.Symbol version of helper
|
||||
// functions in xcoff.go, still being used for some archs/oses.
|
||||
// FIXME: get rid of this file when dodata() is completely
|
||||
// converted.
|
||||
|
||||
// xcoffUpdateOuterSize stores the size of outer symbols in order to have it
|
||||
// in the symbol table.
|
||||
func xcoffUpdateOuterSize(ctxt *Link, size int64, stype sym.SymKind) {
|
||||
if size == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
switch stype {
|
||||
default:
|
||||
Errorf(nil, "unknown XCOFF outer symbol for type %s", stype.String())
|
||||
case sym.SRODATA, sym.SRODATARELRO, sym.SFUNCTAB, sym.SSTRING:
|
||||
// Nothing to do
|
||||
case sym.STYPERELRO:
|
||||
if ctxt.UseRelro() && (ctxt.BuildMode == BuildModeCArchive || ctxt.BuildMode == BuildModeCShared || ctxt.BuildMode == BuildModePIE) {
|
||||
// runtime.types size must be removed, as it's a real symbol.
|
||||
outerSymSize["typerel.*"] = size - ctxt.Syms.ROLookup("runtime.types", 0).Size
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
case sym.STYPE:
|
||||
if !ctxt.DynlinkingGo() {
|
||||
// runtime.types size must be removed, as it's a real symbol.
|
||||
outerSymSize["type.*"] = size - ctxt.Syms.ROLookup("runtime.types", 0).Size
|
||||
}
|
||||
case sym.SGOSTRING:
|
||||
outerSymSize["go.string.*"] = size
|
||||
case sym.SGOFUNC:
|
||||
if !ctxt.DynlinkingGo() {
|
||||
outerSymSize["go.func.*"] = size
|
||||
}
|
||||
case sym.SGOFUNCRELRO:
|
||||
outerSymSize["go.funcrel.*"] = size
|
||||
case sym.SGCBITS:
|
||||
outerSymSize["runtime.gcbits.*"] = size
|
||||
case sym.SITABLINK:
|
||||
outerSymSize["runtime.itablink"] = size
|
||||
|
||||
}
|
||||
}
|
@ -1268,6 +1268,17 @@ func (l *Loader) SetSymDynid(i Sym, val int32) {
|
||||
}
|
||||
}
|
||||
|
||||
// DynIdSyms returns the set of symbols for which dynID is set to an
|
||||
// interesting (non-default) value. This is expected to be a fairly
|
||||
// small set.
|
||||
func (l *Loader) DynidSyms() []Sym {
|
||||
sl := make([]Sym, 0, len(l.dynid))
|
||||
for s := range l.dynid {
|
||||
sl = append(sl, s)
|
||||
}
|
||||
return sl
|
||||
}
|
||||
|
||||
// SymGoType returns the 'Gotype' property for a given symbol (set by
|
||||
// the Go compiler for variable symbols). This version relies on
|
||||
// reading aux symbols for the target sym -- it could be that a faster
|
||||
@ -2255,6 +2266,30 @@ func (l *Loader) addNewSym(i Sym, name string, ver int, unit *sym.CompilationUni
|
||||
return s
|
||||
}
|
||||
|
||||
// TopLevelSym tests a symbol (by name and kind) to determine whether
|
||||
// the symbol first class sym (participating in the link) or is an
|
||||
// anonymous aux or sub-symbol containing some sub-part or payload of
|
||||
// another symbol.
|
||||
func (l *Loader) TopLevelSym(s Sym) bool {
|
||||
return topLevelSym(l.RawSymName(s), l.SymType(s))
|
||||
}
|
||||
|
||||
// topLevelSym tests a symbol name and kind to determine whether
|
||||
// the symbol first class sym (participating in the link) or is an
|
||||
// anonymous aux or sub-symbol containing some sub-part or payload of
|
||||
// another symbol.
|
||||
func topLevelSym(sname string, skind sym.SymKind) bool {
|
||||
if sname != "" {
|
||||
return true
|
||||
}
|
||||
switch skind {
|
||||
case sym.SDWARFINFO, sym.SDWARFRANGE, sym.SDWARFLOC, sym.SDWARFLINES, sym.SGOFUNC:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// loadObjSyms creates sym.Symbol objects for the live Syms in the
|
||||
// object corresponding to object reader "r". Return value is the
|
||||
// number of sym.Reloc entries required for all the new symbols.
|
||||
@ -2268,16 +2303,11 @@ func loadObjSyms(l *Loader, syms *sym.Symbols, r *oReader) int {
|
||||
osym := r.Sym(i)
|
||||
name := strings.Replace(osym.Name(r.Reader), "\"\".", r.pkgprefix, -1)
|
||||
t := sym.AbiSymKindToSymKind[objabi.SymKind(osym.Type())]
|
||||
// NB: for the test below, we can skip most anonymous symbols
|
||||
// since they will never be turned into sym.Symbols (eg:
|
||||
// funcdata). DWARF symbols are an exception however -- we
|
||||
// want to include all reachable but nameless DWARF symbols.
|
||||
if name == "" {
|
||||
switch t {
|
||||
case sym.SDWARFINFO, sym.SDWARFRANGE, sym.SDWARFLOC, sym.SDWARFLINES:
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
// Skip non-dwarf anonymous symbols (e.g. funcdata),
|
||||
// since they will never be turned into sym.Symbols.
|
||||
if !topLevelSym(name, t) {
|
||||
continue
|
||||
}
|
||||
ver := abiToVer(osym.ABI(), r.version)
|
||||
if t == sym.SXREF {
|
||||
|
@ -447,3 +447,10 @@ func GenAddAddrPlusFunc(internalExec bool) func(s *SymbolBuilder, arch *sys.Arch
|
||||
return (*SymbolBuilder).AddAddrPlus
|
||||
}
|
||||
}
|
||||
|
||||
func (sb *SymbolBuilder) MakeWritable() {
|
||||
if sb.ReadOnly() {
|
||||
sb.data = append([]byte(nil), sb.data...)
|
||||
sb.l.SetAttrReadOnly(sb.symIdx, false)
|
||||
}
|
||||
}
|
||||
|
@ -972,7 +972,7 @@ func addpltsym2(ctxt *ld.Link, ldr *loader.Loader, s loader.Sym) {
|
||||
return
|
||||
}
|
||||
|
||||
ld.Adddynsym2(ldr, &ctxt.ErrorReporter, &ctxt.Target, &ctxt.ArchSyms, s)
|
||||
ld.Adddynsym2(ldr, &ctxt.Target, &ctxt.ArchSyms, s)
|
||||
|
||||
if ctxt.IsELF {
|
||||
plt := ldr.MakeSymbolUpdater(ctxt.PLT2)
|
||||
|
@ -55,6 +55,7 @@ type Section struct {
|
||||
Elfsect interface{} // an *ld.ElfShdr
|
||||
Reloff uint64
|
||||
Rellen uint64
|
||||
Sym *Symbol // symbol for the section, if any
|
||||
Index uint16 // each section has a unique index, used internally
|
||||
Sym *Symbol // symbol for the section, if any
|
||||
Sym2 LoaderSym // symbol for the section, if any
|
||||
Index uint16 // each section has a unique index, used internally
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user