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

[dev.link] cmd/link: support new dodata for elf/386

Add elf/386 arch support for the new dodata() phase.

Change-Id: I78341dfe70a90719d95c0044183980f348a3369f
Reviewed-on: https://go-review.googlesource.com/c/go/+/229797
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:
Than McIntosh 2020-04-23 20:54:04 -04:00
parent 3b32a44699
commit f790533d9f
4 changed files with 428 additions and 112 deletions

View File

@ -157,8 +157,9 @@ func Main(arch *sys.Arch, theArch Arch) {
}
if *flagnewDoData {
// New dodata() is currently only implemented for linux/amd64.
if !(ctxt.IsElf() && ctxt.IsAMD64()) {
// New dodata() is currently only implemented for selected targets.
if !(ctxt.IsElf() &&
(ctxt.IsAMD64() || ctxt.Is386())) {
*flagnewDoData = false
}
}

View File

@ -129,161 +129,189 @@ func gentext2(ctxt *ld.Link, ldr *loader.Loader) {
o(0xc3)
}
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 {
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_386_PC32):
if targ.Type == sym.SDYNIMPORT {
ld.Errorf(s, "unexpected R_386_PC32 relocation for dynamic symbol %s", targ.Name)
if targType == sym.SDYNIMPORT {
ldr.Errorf(s, "unexpected R_386_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 := ldr.MakeSymbolUpdater(s)
su.SetRelocType(rIdx, objabi.R_PCREL)
su.SetRelocAdd(rIdx, r.Add()+4)
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_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 := ldr.MakeSymbolUpdater(s)
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
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOT32),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOT32X):
if targ.Type != sym.SDYNIMPORT {
su := ldr.MakeSymbolUpdater(s)
if targType != sym.SDYNIMPORT {
// have symbol
if r.Off >= 2 && s.P[r.Off-2] == 0x8b {
// turn MOVL of GOT entry into LEAL of symbol address, relative to GOT.
s.P[r.Off-2] = 0x8d
sData := ldr.Data(s)
r.Type = objabi.R_GOTOFF
if r.Off() >= 2 && sData[r.Off()-2] == 0x8b {
su.MakeWritable()
// turn MOVL of GOT entry into LEAL of symbol address, relative to GOT.
writeableData := su.Data()
writeableData[r.Off()-2] = 0x8d
su.SetRelocType(rIdx, objabi.R_GOTOFF)
return true
}
if r.Off >= 2 && s.P[r.Off-2] == 0xff && s.P[r.Off-1] == 0xb3 {
if r.Off() >= 2 && sData[r.Off()-2] == 0xff && sData[r.Off()-1] == 0xb3 {
su.MakeWritable()
// turn PUSHL of GOT entry into PUSHL of symbol itself.
// use unnecessary SS prefix to keep instruction same length.
s.P[r.Off-2] = 0x36
s.P[r.Off-1] = 0x68
r.Type = objabi.R_ADDR
writeableData := su.Data()
writeableData[r.Off()-2] = 0x36
writeableData[r.Off()-1] = 0x68
su.SetRelocType(rIdx, objabi.R_ADDR)
return true
}
ld.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
ldr.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", ldr.SymName(targ))
return false
}
addgotsym(target, syms, targ)
r.Type = objabi.R_CONST // write r->add during relocsym
r.Sym = nil
r.Add += int64(targ.Got())
addgotsym2(target, ldr, syms, targ)
su.SetRelocType(rIdx, objabi.R_CONST) // write r->add during relocsym
su.SetRelocSym(rIdx, 0)
su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOTOFF):
r.Type = objabi.R_GOTOFF
su := ldr.MakeSymbolUpdater(s)
su.SetRelocType(rIdx, objabi.R_GOTOFF)
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOTPC):
r.Type = objabi.R_PCREL
r.Sym = syms.GOT
r.Add += 4
su := ldr.MakeSymbolUpdater(s)
su.SetRelocType(rIdx, objabi.R_PCREL)
su.SetRelocSym(rIdx, syms.GOT2)
su.SetRelocAdd(rIdx, r.Add()+4)
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_32):
if targ.Type == sym.SDYNIMPORT {
ld.Errorf(s, "unexpected R_386_32 relocation for dynamic symbol %s", targ.Name)
if targType == sym.SDYNIMPORT {
ldr.Errorf(s, "unexpected R_386_32 relocation for dynamic symbol %s", ldr.SymName(targ))
}
r.Type = objabi.R_ADDR
su := ldr.MakeSymbolUpdater(s)
su.SetRelocType(rIdx, objabi.R_ADDR)
return true
case objabi.MachoRelocOffset + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 0:
r.Type = objabi.R_ADDR
if targ.Type == sym.SDYNIMPORT {
ld.Errorf(s, "unexpected reloc for dynamic symbol %s", targ.Name)
su := ldr.MakeSymbolUpdater(s)
su.SetRelocType(rIdx, objabi.R_ADDR)
if targType == sym.SDYNIMPORT {
ldr.Errorf(s, "unexpected reloc for dynamic symbol %s", ldr.SymName(targ))
}
return true
case objabi.MachoRelocOffset + ld.MACHO_GENERIC_RELOC_VANILLA*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
su := ldr.MakeSymbolUpdater(s)
if targType == sym.SDYNIMPORT {
addpltsym2(target, ldr, syms, targ)
su.SetRelocSym(rIdx, syms.PLT2)
su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
su.SetRelocType(rIdx, objabi.R_PCREL)
return true
}
r.Type = objabi.R_PCREL
su.SetRelocType(rIdx, objabi.R_PCREL)
return true
case objabi.MachoRelocOffset + ld.MACHO_FAKE_GOTPCREL:
if targ.Type != sym.SDYNIMPORT {
su := ldr.MakeSymbolUpdater(s)
if targType != sym.SDYNIMPORT {
// have symbol
// turn MOVL of GOT entry into LEAL of symbol itself
if r.Off < 2 || s.P[r.Off-2] != 0x8b {
ld.Errorf(s, "unexpected GOT 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 reloc for non-dynamic symbol %s", ldr.SymName(targ))
return false
}
s.P[r.Off-2] = 0x8d
r.Type = objabi.R_PCREL
su.MakeWritable()
writeableData := su.Data()
writeableData[r.Off()-2] = 0x8d
su.SetRelocType(rIdx, objabi.R_PCREL)
return true
}
addgotsym(target, syms, targ)
r.Sym = syms.GOT
r.Add += int64(targ.Got())
r.Type = objabi.R_PCREL
addgotsym2(target, ldr, syms, targ)
su.SetRelocSym(rIdx, syms.GOT2)
su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
su.SetRelocType(rIdx, objabi.R_PCREL)
return true
}
// Handle references to ELF symbols from our own object files.
if targ.Type != sym.SDYNIMPORT {
if targType != sym.SDYNIMPORT {
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 target.IsExternal() {
// External linker will do this relocation.
return true
}
addpltsym(target, syms, targ)
r.Sym = syms.PLT
r.Add = int64(targ.Plt())
addpltsym2(target, ldr, syms, targ)
su := ldr.MakeSymbolUpdater(s)
su.SetRelocSym(rIdx, syms.PLT2)
su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
return true
case objabi.R_ADDR:
if s.Type != sym.SDATA {
if ldr.SymType(s) != sym.SDATA {
break
}
if target.IsElf() {
ld.Adddynsym(target, syms, targ)
rel := syms.Rel
rel.AddAddrPlus(target.Arch, s, int64(r.Off))
rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(targ.Dynid), uint32(elf.R_386_32)))
r.Type = objabi.R_CONST // write r->add during relocsym
r.Sym = nil
ld.Adddynsym2(ldr, target, syms, targ)
rel := ldr.MakeSymbolUpdater(syms.Rel2)
rel.AddAddrPlus(target.Arch, s, int64(r.Off()))
rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(ldr.SymDynid(targ)), uint32(elf.R_386_32)))
su := ldr.MakeSymbolUpdater(s)
su.SetRelocType(rIdx, objabi.R_CONST) // write r->add during relocsym
su.SetRelocSym(rIdx, 0)
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.
@ -294,18 +322,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.AddUint32(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
}
}
@ -452,18 +479,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
rel := syms.RelPLT
if plt.Size == 0 {
plt := ldr.MakeSymbolUpdater(syms.PLT2)
got := ldr.MakeSymbolUpdater(syms.GOTPLT2)
rel := ldr.MakeSymbolUpdater(syms.RelPLT2)
if plt.Size() == 0 {
panic("plt is not set up")
}
@ -471,65 +498,69 @@ func addpltsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
plt.AddUint8(0xff)
plt.AddUint8(0x25)
plt.AddAddrPlus(target.Arch, got, got.Size)
plt.AddAddrPlus(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())
// pushl $x
plt.AddUint8(0x68)
plt.AddUint32(target.Arch, uint32(rel.Size))
plt.AddUint32(target.Arch, uint32(rel.Size()))
// jmp .plt
plt.AddUint8(0xe9)
plt.AddUint32(target.Arch, uint32(-(plt.Size + 4)))
plt.AddUint32(target.Arch, uint32(-(plt.Size() + 4)))
// rel
rel.AddAddrPlus(target.Arch, got, got.Size-4)
rel.AddAddrPlus(target.Arch, got.Sym(), got.Size()-4)
rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(s.Dynid), uint32(elf.R_386_JMP_SLOT)))
sDynid := ldr.SymDynid(s)
rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(sDynid), uint32(elf.R_386_JMP_SLOT)))
s.SetPlt(int32(plt.Size - 16))
ldr.SetPlt(s, int32(plt.Size()-16))
} else if target.IsDarwin() {
// Same laziness as in 6l.
plt := syms.PLT
plt := ldr.MakeSymbolUpdater(syms.PLT2)
addgotsym(target, syms, s)
addgotsym2(target, ldr, syms, s)
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.AddAddrPlus(target.Arch, syms.GOT, int64(s.Got()))
plt.AddAddrPlus(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.AddUint32(target.Arch, 0)
if target.IsElf() {
rel := syms.Rel
rel.AddAddrPlus(target.Arch, got, int64(s.Got()))
rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(s.Dynid), uint32(elf.R_386_GLOB_DAT)))
rel := ldr.MakeSymbolUpdater(syms.Rel2)
rel.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(ldr.SymDynid(s)), uint32(elf.R_386_GLOB_DAT)))
} 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")
}
}

View File

@ -0,0 +1,283 @@
// 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 x86
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_386_PC32):
if targ.Type == sym.SDYNIMPORT {
ld.Errorf(s, "unexpected R_386_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_386_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_386_GOT32),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOT32X):
if targ.Type != sym.SDYNIMPORT {
// have symbol
if r.Off >= 2 && s.P[r.Off-2] == 0x8b {
// turn MOVL of GOT entry into LEAL of symbol address, relative to GOT.
s.P[r.Off-2] = 0x8d
r.Type = objabi.R_GOTOFF
return true
}
if r.Off >= 2 && s.P[r.Off-2] == 0xff && s.P[r.Off-1] == 0xb3 {
// turn PUSHL of GOT entry into PUSHL of symbol itself.
// use unnecessary SS prefix to keep instruction same length.
s.P[r.Off-2] = 0x36
s.P[r.Off-1] = 0x68
r.Type = objabi.R_ADDR
return true
}
ld.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
return false
}
addgotsym(target, syms, targ)
r.Type = objabi.R_CONST // write r->add during relocsym
r.Sym = nil
r.Add += int64(targ.Got())
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOTOFF):
r.Type = objabi.R_GOTOFF
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOTPC):
r.Type = objabi.R_PCREL
r.Sym = syms.GOT
r.Add += 4
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_32):
if targ.Type == sym.SDYNIMPORT {
ld.Errorf(s, "unexpected R_386_32 relocation for dynamic symbol %s", targ.Name)
}
r.Type = objabi.R_ADDR
return true
case objabi.MachoRelocOffset + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 0:
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_GENERIC_RELOC_VANILLA*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
}
r.Type = objabi.R_PCREL
return true
case objabi.MachoRelocOffset + ld.MACHO_FAKE_GOTPCREL:
if targ.Type != sym.SDYNIMPORT {
// have symbol
// turn MOVL of GOT entry into LEAL of symbol itself
if r.Off < 2 || s.P[r.Off-2] != 0x8b {
ld.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
return false
}
s.P[r.Off-2] = 0x8d
r.Type = objabi.R_PCREL
return true
}
addgotsym(target, syms, targ)
r.Sym = syms.GOT
r.Add += int64(targ.Got())
r.Type = objabi.R_PCREL
return true
}
// Handle references to ELF symbols from our own object files.
if targ.Type != sym.SDYNIMPORT {
return true
}
switch r.Type {
case objabi.R_CALL,
objabi.R_PCREL:
if target.IsExternal() {
// External linker will do this relocation.
return true
}
addpltsym(target, syms, targ)
r.Sym = syms.PLT
r.Add = int64(targ.Plt())
return true
case objabi.R_ADDR:
if s.Type != sym.SDATA {
break
}
if target.IsElf() {
ld.Adddynsym(target, syms, targ)
rel := syms.Rel
rel.AddAddrPlus(target.Arch, s, int64(r.Off))
rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(targ.Dynid), uint32(elf.R_386_32)))
r.Type = objabi.R_CONST // write r->add during relocsym
r.Sym = nil
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.AddUint32(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
rel := syms.RelPLT
if plt.Size == 0 {
panic("plt is not set up")
}
// jmpq *got+size
plt.AddUint8(0xff)
plt.AddUint8(0x25)
plt.AddAddrPlus(target.Arch, got, got.Size)
// add to got: pointer to current pos in plt
got.AddAddrPlus(target.Arch, plt, plt.Size)
// pushl $x
plt.AddUint8(0x68)
plt.AddUint32(target.Arch, uint32(rel.Size))
// jmp .plt
plt.AddUint8(0xe9)
plt.AddUint32(target.Arch, uint32(-(plt.Size + 4)))
// rel
rel.AddAddrPlus(target.Arch, got, got.Size-4)
rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(s.Dynid), uint32(elf.R_386_JMP_SLOT)))
s.SetPlt(int32(plt.Size - 16))
} else if target.IsDarwin() {
// Same laziness as in 6l.
plt := syms.PLT
addgotsym(target, syms, s)
syms.LinkEditPLT.AddUint32(target.Arch, uint32(s.Dynid))
// jmpq *got+size(IP)
s.SetPlt(int32(plt.Size))
plt.AddUint8(0xff)
plt.AddUint8(0x25)
plt.AddAddrPlus(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.AddUint32(target.Arch, 0)
if target.IsElf() {
rel := syms.Rel
rel.AddAddrPlus(target.Arch, got, int64(s.Got()))
rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(s.Dynid), uint32(elf.R_386_GLOB_DAT)))
} else if target.IsDarwin() {
syms.LinkEditGOT.AddUint32(target.Arch, uint32(s.Dynid))
} else {
ld.Errorf(s, "addgotsym: unsupported binary format")
}
}

View File

@ -47,6 +47,7 @@ func Init() (*sys.Arch, ld.Arch) {
Dwarfreglr: dwarfRegLR,
Adddynrel: adddynrel,
Adddynrel2: adddynrel2,
Archinit: archinit,
Archreloc: archreloc,
Archrelocvariant: archrelocvariant,