From f790533d9ffd6d50c8efccf8f8edac0ef76b3da4 Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Thu, 23 Apr 2020 20:54:04 -0400 Subject: [PATCH] [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 TryBot-Result: Gobot Gobot Reviewed-by: Cherry Zhang --- src/cmd/link/internal/ld/main.go | 5 +- src/cmd/link/internal/x86/asm.go | 253 ++++++++++++++------------ src/cmd/link/internal/x86/asm2.go | 283 ++++++++++++++++++++++++++++++ src/cmd/link/internal/x86/obj.go | 1 + 4 files changed, 429 insertions(+), 113 deletions(-) create mode 100644 src/cmd/link/internal/x86/asm2.go diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go index 07ed057bf6..8b6b9b84a6 100644 --- a/src/cmd/link/internal/ld/main.go +++ b/src/cmd/link/internal/ld/main.go @@ -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 } } diff --git a/src/cmd/link/internal/x86/asm.go b/src/cmd/link/internal/x86/asm.go index 650fe12f94..03c73671b8 100644 --- a/src/cmd/link/internal/x86/asm.go +++ b/src/cmd/link/internal/x86/asm.go @@ -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) - - 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 + ld.Adddynsym2(ldr, target, syms, targ) + + 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") } } diff --git a/src/cmd/link/internal/x86/asm2.go b/src/cmd/link/internal/x86/asm2.go new file mode 100644 index 0000000000..16f1682dc1 --- /dev/null +++ b/src/cmd/link/internal/x86/asm2.go @@ -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") + } +} diff --git a/src/cmd/link/internal/x86/obj.go b/src/cmd/link/internal/x86/obj.go index 952113fbff..34babe9a72 100644 --- a/src/cmd/link/internal/x86/obj.go +++ b/src/cmd/link/internal/x86/obj.go @@ -47,6 +47,7 @@ func Init() (*sys.Arch, ld.Arch) { Dwarfreglr: dwarfRegLR, Adddynrel: adddynrel, + Adddynrel2: adddynrel2, Archinit: archinit, Archreloc: archreloc, Archrelocvariant: archrelocvariant, -- 2.48.1