diff --git a/src/cmd/link/internal/arm/asm.go b/src/cmd/link/internal/arm/asm.go index 446691f318..e1edc9e45d 100644 --- a/src/cmd/link/internal/arm/asm.go +++ b/src/cmd/link/internal/arm/asm.go @@ -103,24 +103,30 @@ func braddoff(a int32, b int32) int32 { return int32((uint32(a))&0xff000000 | 0x00ffffff&uint32(a+b)) } -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 { - switch r.Type { + targ := r.Sym() + var targType sym.SymKind + if targ != 0 { + targType = ldr.SymType(targ) + } + + 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_ARM_PLT32): - r.Type = objabi.R_CALLARM + su := ldr.MakeSymbolUpdater(s) + su.SetRelocType(rIdx, objabi.R_CALLARM) - if targ.Type == sym.SDYNIMPORT { - addpltsym(target, syms, targ) - r.Sym = syms.PLT - r.Add = int64(braddoff(int32(r.Add), targ.Plt()/4)) + if targType == sym.SDYNIMPORT { + addpltsym2(target, ldr, syms, targ) + su.SetRelocSym(rIdx, syms.PLT2) + su.SetRelocAdd(rIdx, int64(braddoff(int32(r.Add()), ldr.SymPlt(targ)/4))) } return true @@ -130,113 +136,112 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym. return false case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_GOT32): // R_ARM_GOT_BREL - if targ.Type != sym.SDYNIMPORT { - addgotsyminternal(target, syms, targ) + if targType != sym.SDYNIMPORT { + addgotsyminternal2(target, ldr, syms, targ) } else { - addgotsym(target, syms, targ) + addgotsym2(target, ldr, syms, targ) } - r.Type = objabi.R_CONST // write r->add during relocsym - r.Sym = nil - r.Add += int64(targ.Got()) + su := ldr.MakeSymbolUpdater(s) + 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_ARM_GOT_PREL): // GOT(nil) + A - nil - if targ.Type != sym.SDYNIMPORT { - addgotsyminternal(target, syms, targ) + if targType != sym.SDYNIMPORT { + addgotsyminternal2(target, ldr, syms, targ) } else { - addgotsym(target, syms, targ) + addgotsym2(target, ldr, syms, targ) } - - r.Type = objabi.R_PCREL - r.Sym = syms.GOT - r.Add += int64(targ.Got()) + 4 + su := ldr.MakeSymbolUpdater(s) + 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_ARM_GOTOFF): // R_ARM_GOTOFF32 - r.Type = objabi.R_GOTOFF - + su := ldr.MakeSymbolUpdater(s) + su.SetRelocType(rIdx, objabi.R_GOTOFF) return true case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_GOTPC): // R_ARM_BASE_PREL - 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_ARM_CALL): - r.Type = objabi.R_CALLARM - if targ.Type == sym.SDYNIMPORT { - addpltsym(target, syms, targ) - r.Sym = syms.PLT - r.Add = int64(braddoff(int32(r.Add), targ.Plt()/4)) + su := ldr.MakeSymbolUpdater(s) + su.SetRelocType(rIdx, objabi.R_CALLARM) + if targType == sym.SDYNIMPORT { + addpltsym2(target, ldr, syms, targ) + su.SetRelocSym(rIdx, syms.PLT2) + su.SetRelocAdd(rIdx, int64(braddoff(int32(r.Add()), ldr.SymPlt(targ)/4))) } - return true case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_REL32): // R_ARM_REL32 - 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_ARM_ABS32): - if targ.Type == sym.SDYNIMPORT { - ld.Errorf(s, "unexpected R_ARM_ABS32 relocation for dynamic symbol %s", targ.Name) + if targType == sym.SDYNIMPORT { + ldr.Errorf(s, "unexpected R_ARM_ABS32 relocation for dynamic symbol %s", ldr.SymName(targ)) } - r.Type = objabi.R_ADDR - return true - - // we can just ignore this, because we are targeting ARM V5+ anyway - case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_V4BX): - if r.Sym != nil { - // R_ARM_V4BX is ABS relocation, so this symbol is a dummy symbol, ignore it - r.Sym.Type = 0 - } - - r.Sym = nil + su := ldr.MakeSymbolUpdater(s) + su.SetRelocType(rIdx, objabi.R_ADDR) return true case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_PC24), objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_JUMP24): - r.Type = objabi.R_CALLARM - if targ.Type == sym.SDYNIMPORT { - addpltsym(target, syms, targ) - r.Sym = syms.PLT - r.Add = int64(braddoff(int32(r.Add), targ.Plt()/4)) + su := ldr.MakeSymbolUpdater(s) + su.SetRelocType(rIdx, objabi.R_CALLARM) + if targType == sym.SDYNIMPORT { + addpltsym2(target, ldr, syms, targ) + su.SetRelocSym(rIdx, syms.PLT2) + su.SetRelocAdd(rIdx, int64(braddoff(int32(r.Add()), ldr.SymPlt(targ)/4))) } 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_CALLARM: 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_ARM_GLOB_DAT))) // we need a nil + A dynamic reloc - 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_ARM_GLOB_DAT))) // we need a nil + A dynamic reloc + su := ldr.MakeSymbolUpdater(s) + su.SetRelocType(rIdx, objabi.R_CONST) // write r->add during relocsym + su.SetRelocSym(rIdx, 0) return true } } @@ -592,90 +597,88 @@ func archrelocvariant(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym return t } -func addpltreloc(plt *sym.Symbol, got *sym.Symbol, s *sym.Symbol, typ objabi.RelocType) { - r := plt.AddRel() - r.Sym = got - r.Off = int32(plt.Size) - r.Siz = 4 - r.Type = typ - r.Add = int64(s.Got()) - 8 +func addpltreloc2(ldr *loader.Loader, plt *loader.SymbolBuilder, got *loader.SymbolBuilder, s loader.Sym, typ objabi.RelocType) { + r, _ := plt.AddRel(typ) + r.SetSym(got.Sym()) + r.SetOff(int32(plt.Size())) + r.SetSiz(4) + r.SetAdd(int64(ldr.SymGot(s)) - 8) - plt.Attr |= sym.AttrReachable - plt.Size += 4 - plt.Grow(plt.Size) + plt.SetReachable(true) + plt.SetSize(plt.Size() + 4) + plt.Grow(plt.Size()) } -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") } // .got entry - s.SetGot(int32(got.Size)) + ldr.SetGot(s, int32(got.Size())) // In theory, all GOT should point to the first PLT entry, // Linux/ARM's dynamic linker will do that for us, but FreeBSD/ARM's // dynamic linker won't, so we'd better do it ourselves. - got.AddAddrPlus(target.Arch, plt, 0) + got.AddAddrPlus(target.Arch, plt.Sym(), 0) // .plt entry, this depends on the .got entry - s.SetPlt(int32(plt.Size)) + ldr.SetPlt(s, int32(plt.Size())) - addpltreloc(plt, got, s, objabi.R_PLT0) // add lr, pc, #0xXX00000 - addpltreloc(plt, got, s, objabi.R_PLT1) // add lr, lr, #0xYY000 - addpltreloc(plt, got, s, objabi.R_PLT2) // ldr pc, [lr, #0xZZZ]! + addpltreloc2(ldr, plt, got, s, objabi.R_PLT0) // add lr, pc, #0xXX00000 + addpltreloc2(ldr, plt, got, s, objabi.R_PLT1) // add lr, lr, #0xYY000 + addpltreloc2(ldr, plt, got, s, objabi.R_PLT2) // ldr pc, [lr, #0xZZZ]! // rel - rel.AddAddrPlus(target.Arch, got, int64(s.Got())) + rel.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s))) - rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(s.Dynid), uint32(elf.R_ARM_JUMP_SLOT))) + rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(ldr.SymDynid(s)), uint32(elf.R_ARM_JUMP_SLOT))) } else { - ld.Errorf(s, "addpltsym: unsupported binary format") + ldr.Errorf(s, "addpltsym: unsupported binary format") } } -func addgotsyminternal(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) { - if s.Got() >= 0 { +func addgotsyminternal2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) { + if ldr.SymGot(s) >= 0 { return } - got := syms.GOT - s.SetGot(int32(got.Size)) - + got := ldr.MakeSymbolUpdater(syms.GOT2) + ldr.SetGot(s, int32(got.Size())) got.AddAddrPlus(target.Arch, s, 0) if target.IsElf() { } else { - ld.Errorf(s, "addgotsyminternal: unsupported binary format") + ldr.Errorf(s, "addgotsyminternal: 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)) - got.AddUint32(target.Arch, 0) + 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() { - 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_ARM_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_ARM_GLOB_DAT))) } else { - ld.Errorf(s, "addgotsym: unsupported binary format") + ldr.Errorf(s, "addgotsym: unsupported binary format") } } diff --git a/src/cmd/link/internal/arm/asm2.go b/src/cmd/link/internal/arm/asm2.go new file mode 100644 index 0000000000..a8c26c67b4 --- /dev/null +++ b/src/cmd/link/internal/arm/asm2.go @@ -0,0 +1,246 @@ +// 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 arm + +import ( + "cmd/internal/objabi" + "cmd/link/internal/ld" + "cmd/link/internal/loader" + "cmd/link/internal/sym" + "debug/elf" +) + +// Temporary dumping ground 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_ARM_PLT32): + r.Type = objabi.R_CALLARM + + if targ.Type == sym.SDYNIMPORT { + addpltsym(target, syms, targ) + r.Sym = syms.PLT + r.Add = int64(braddoff(int32(r.Add), targ.Plt()/4)) + } + + return true + + case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_THM_PC22): // R_ARM_THM_CALL + ld.Exitf("R_ARM_THM_CALL, are you using -marm?") + return false + + case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_GOT32): // R_ARM_GOT_BREL + if targ.Type != sym.SDYNIMPORT { + addgotsyminternal(target, syms, targ) + } else { + 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_ARM_GOT_PREL): // GOT(nil) + A - nil + if targ.Type != sym.SDYNIMPORT { + addgotsyminternal(target, syms, targ) + } else { + addgotsym(target, syms, targ) + } + + r.Type = objabi.R_PCREL + r.Sym = syms.GOT + r.Add += int64(targ.Got()) + 4 + return true + + case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_GOTOFF): // R_ARM_GOTOFF32 + r.Type = objabi.R_GOTOFF + + return true + + case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_GOTPC): // R_ARM_BASE_PREL + r.Type = objabi.R_PCREL + + r.Sym = syms.GOT + r.Add += 4 + return true + + case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_CALL): + r.Type = objabi.R_CALLARM + if targ.Type == sym.SDYNIMPORT { + addpltsym(target, syms, targ) + r.Sym = syms.PLT + r.Add = int64(braddoff(int32(r.Add), targ.Plt()/4)) + } + + return true + + case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_REL32): // R_ARM_REL32 + r.Type = objabi.R_PCREL + + r.Add += 4 + return true + + case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_ABS32): + if targ.Type == sym.SDYNIMPORT { + ld.Errorf(s, "unexpected R_ARM_ABS32 relocation for dynamic symbol %s", targ.Name) + } + r.Type = objabi.R_ADDR + return true + + // we can just ignore this, because we are targeting ARM V5+ anyway + case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_V4BX): + if r.Sym != nil { + // R_ARM_V4BX is ABS relocation, so this symbol is a dummy symbol, ignore it + r.Sym.Type = 0 + } + + r.Sym = nil + return true + + case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_PC24), + objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_JUMP24): + r.Type = objabi.R_CALLARM + if targ.Type == sym.SDYNIMPORT { + addpltsym(target, syms, targ) + r.Sym = syms.PLT + r.Add = int64(braddoff(int32(r.Add), targ.Plt()/4)) + } + + 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_CALLARM: + 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_ARM_GLOB_DAT))) // we need a nil + A dynamic reloc + r.Type = objabi.R_CONST // write r->add during relocsym + r.Sym = nil + 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") + } + + // .got entry + s.SetGot(int32(got.Size)) + + // In theory, all GOT should point to the first PLT entry, + // Linux/ARM's dynamic linker will do that for us, but FreeBSD/ARM's + // dynamic linker won't, so we'd better do it ourselves. + got.AddAddrPlus(target.Arch, plt, 0) + + // .plt entry, this depends on the .got entry + s.SetPlt(int32(plt.Size)) + + addpltreloc(plt, got, s, objabi.R_PLT0) // add lr, pc, #0xXX00000 + addpltreloc(plt, got, s, objabi.R_PLT1) // add lr, lr, #0xYY000 + addpltreloc(plt, got, s, objabi.R_PLT2) // ldr pc, [lr, #0xZZZ]! + + // rel + rel.AddAddrPlus(target.Arch, got, int64(s.Got())) + + rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(s.Dynid), uint32(elf.R_ARM_JUMP_SLOT))) + } else { + ld.Errorf(s, "addpltsym: unsupported binary format") + } +} + +func addpltreloc(plt *sym.Symbol, got *sym.Symbol, s *sym.Symbol, typ objabi.RelocType) { + r := plt.AddRel() + r.Sym = got + r.Off = int32(plt.Size) + r.Siz = 4 + r.Type = typ + r.Add = int64(s.Got()) - 8 + + plt.Attr |= sym.AttrReachable + plt.Size += 4 + plt.Grow(plt.Size) +} + +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_ARM_GLOB_DAT))) + } else { + ld.Errorf(s, "addgotsym: unsupported binary format") + } +} + +func addgotsyminternal(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) { + if s.Got() >= 0 { + return + } + + got := syms.GOT + s.SetGot(int32(got.Size)) + + got.AddAddrPlus(target.Arch, s, 0) + + if target.IsElf() { + } else { + ld.Errorf(s, "addgotsyminternal: unsupported binary format") + } +} diff --git a/src/cmd/link/internal/arm/obj.go b/src/cmd/link/internal/arm/obj.go index b277fb2a43..d6fa64de66 100644 --- a/src/cmd/link/internal/arm/obj.go +++ b/src/cmd/link/internal/arm/obj.go @@ -47,6 +47,7 @@ func Init() (*sys.Arch, ld.Arch) { Dwarfreglr: dwarfRegLR, Adddynrel: adddynrel, + Adddynrel2: adddynrel2, Archinit: archinit, Archreloc: archreloc, Archrelocvariant: archrelocvariant, diff --git a/src/cmd/link/internal/arm64/asm.go b/src/cmd/link/internal/arm64/asm.go index 46bda74c4c..a0f06b6aa6 100644 --- a/src/cmd/link/internal/arm64/asm.go +++ b/src/cmd/link/internal/arm64/asm.go @@ -78,86 +78,97 @@ func gentext2(ctxt *ld.Link, ldr *loader.Loader) { initfunc.AddReloc(rel2) } -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 { - switch r.Type { + targ := r.Sym() + var targType sym.SymKind + if targ != 0 { + targType = ldr.SymType(targ) + } + + 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_AARCH64_PREL32): - if targ.Type == sym.SDYNIMPORT { - ld.Errorf(s, "unexpected R_AARCH64_PREL32 relocation for dynamic symbol %s", targ.Name) + if targType == sym.SDYNIMPORT { + ldr.Errorf(s, "unexpected R_AARCH64_PREL32 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_AARCH64_PREL64): - if targ.Type == sym.SDYNIMPORT { - ld.Errorf(s, "unexpected R_AARCH64_PREL64 relocation for dynamic symbol %s", targ.Name) + if targType == sym.SDYNIMPORT { + ldr.Errorf(s, "unexpected R_AARCH64_PREL64 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 := ldr.MakeSymbolUpdater(s) + su.SetRelocType(rIdx, objabi.R_PCREL) + su.SetRelocAdd(rIdx, r.Add()+8) return true case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_CALL26), objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_JUMP26): - if targ.Type == sym.SDYNIMPORT { - addpltsym(target, syms, targ) - r.Sym = syms.PLT - r.Add += int64(targ.Plt()) + if targType == sym.SDYNIMPORT { + addpltsym2(target, ldr, syms, targ) + su := ldr.MakeSymbolUpdater(s) + su.SetRelocSym(rIdx, syms.PLT2) + su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ))) } - if (targ.Type == 0 || targ.Type == sym.SXREF) && !targ.Attr.VisibilityHidden() { - ld.Errorf(s, "unknown symbol %s in callarm64", targ.Name) + if (targType == 0 || targType == sym.SXREF) && !ldr.AttrVisibilityHidden(targ) { + ldr.Errorf(s, "unknown symbol %s in callarm64", ldr.SymName(targ)) } - r.Type = objabi.R_CALLARM64 + su := ldr.MakeSymbolUpdater(s) + su.SetRelocType(rIdx, objabi.R_CALLARM64) return true case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ADR_GOT_PAGE), objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LD64_GOT_LO12_NC): - if targ.Type != sym.SDYNIMPORT { + if targType != sym.SDYNIMPORT { // have symbol // TODO: turn LDR of GOT entry into ADR of symbol itself } // fall back to using GOT // TODO: just needs relocation, no need to put in .dynsym - addgotsym(target, syms, targ) - - r.Type = objabi.R_ARM64_GOT - r.Sym = syms.GOT - r.Add += int64(targ.Got()) + addgotsym2(target, ldr, syms, targ) + su := ldr.MakeSymbolUpdater(s) + su.SetRelocType(rIdx, objabi.R_ARM64_GOT) + su.SetRelocSym(rIdx, syms.GOT2) + su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ))) return true case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ADR_PREL_PG_HI21), objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ADD_ABS_LO12_NC): - if targ.Type == sym.SDYNIMPORT { - ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name) + if targType == sym.SDYNIMPORT { + ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ)) } - if targ.Type == 0 || targ.Type == sym.SXREF { - ld.Errorf(s, "unknown symbol %s", targ.Name) + if targType == 0 || targType == sym.SXREF { + ldr.Errorf(s, "unknown symbol %s", ldr.SymName(targ)) } - r.Type = objabi.R_ARM64_PCREL + su := ldr.MakeSymbolUpdater(s) + su.SetRelocType(rIdx, objabi.R_ARM64_PCREL) return true case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ABS64): - if targ.Type == sym.SDYNIMPORT { - ld.Errorf(s, "unexpected R_AARCH64_ABS64 relocation for dynamic symbol %s", targ.Name) + if targType == sym.SDYNIMPORT { + ldr.Errorf(s, "unexpected R_AARCH64_ABS64 relocation for dynamic symbol %s", ldr.SymName(targ)) } - r.Type = objabi.R_ADDR + su := ldr.MakeSymbolUpdater(s) + 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 @@ -167,39 +178,48 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym. return true case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST8_ABS_LO12_NC): - if targ.Type == sym.SDYNIMPORT { - ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name) + if targType == sym.SDYNIMPORT { + ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ)) } - r.Type = objabi.R_ARM64_LDST8 + su := ldr.MakeSymbolUpdater(s) + su.SetRelocType(rIdx, objabi.R_ARM64_LDST8) return true case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST32_ABS_LO12_NC): - if targ.Type == sym.SDYNIMPORT { - ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name) + if targType == sym.SDYNIMPORT { + ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ)) } - r.Type = objabi.R_ARM64_LDST32 + su := ldr.MakeSymbolUpdater(s) + su.SetRelocType(rIdx, objabi.R_ARM64_LDST32) return true case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST64_ABS_LO12_NC): - if targ.Type == sym.SDYNIMPORT { - ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name) + if targType == sym.SDYNIMPORT { + ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ)) } - r.Type = objabi.R_ARM64_LDST64 + su := ldr.MakeSymbolUpdater(s) + su.SetRelocType(rIdx, objabi.R_ARM64_LDST64) + return true case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST128_ABS_LO12_NC): - if targ.Type == sym.SDYNIMPORT { - ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name) + if targType == sym.SDYNIMPORT { + ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ)) } - r.Type = objabi.R_ARM64_LDST128 + su := ldr.MakeSymbolUpdater(s) + su.SetRelocType(rIdx, objabi.R_ARM64_LDST128) 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, objabi.R_CALLARM64: - if targ.Type != sym.SDYNIMPORT { + if targType != sym.SDYNIMPORT { // nothing to do, the relocation will be laid out in reloc return true } @@ -209,14 +229,14 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym. } case objabi.R_ADDR: - if s.Type == sym.STEXT && target.IsElf() { + if ldr.SymType(s) == sym.STEXT && target.IsElf() { // 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()) + addgotsym2(target, ldr, syms, targ) + su := ldr.MakeSymbolUpdater(s) + su.SetRelocSym(rIdx, syms.GOT2) + su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ))) return true } @@ -253,7 +273,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 } @@ -264,7 +284,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 } } @@ -287,14 +307,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_AARCH64_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 @@ -737,71 +757,76 @@ func elfsetupplt(ctxt *ld.Link, plt, gotplt *loader.SymbolBuilder, dynamic loade } } -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 - gotplt := syms.GOTPLT - rela := syms.RelaPLT - if plt.Size == 0 { + plt := ldr.MakeSymbolUpdater(syms.PLT2) + gotplt := ldr.MakeSymbolUpdater(syms.GOTPLT2) + rela := ldr.MakeSymbolUpdater(syms.RelaPLT2) + if plt.Size() == 0 { panic("plt is not set up") } // adrp x16, &got.plt[0] - plt.AddAddrPlus4(gotplt, gotplt.Size) - plt.SetUint32(target.Arch, plt.Size-4, 0x90000010) - plt.R[len(plt.R)-1].Type = objabi.R_ARM64_GOT + plt.AddAddrPlus4(target.Arch, gotplt.Sym(), gotplt.Size()) + plt.SetUint32(target.Arch, plt.Size()-4, 0x90000010) + relocs := plt.Relocs() + plt.SetRelocType(relocs.Count()-1, objabi.R_ARM64_GOT) // is the offset value of &got.plt[n] to &got.plt[0] // ldr x17, [x16, ] - plt.AddAddrPlus4(gotplt, gotplt.Size) - plt.SetUint32(target.Arch, plt.Size-4, 0xf9400211) - plt.R[len(plt.R)-1].Type = objabi.R_ARM64_GOT + plt.AddAddrPlus4(target.Arch, gotplt.Sym(), gotplt.Size()) + plt.SetUint32(target.Arch, plt.Size()-4, 0xf9400211) + relocs = plt.Relocs() + plt.SetRelocType(relocs.Count()-1, objabi.R_ARM64_GOT) // add x16, x16, - plt.AddAddrPlus4(gotplt, gotplt.Size) - plt.SetUint32(target.Arch, plt.Size-4, 0x91000210) - plt.R[len(plt.R)-1].Type = objabi.R_ARM64_PCREL + plt.AddAddrPlus4(target.Arch, gotplt.Sym(), gotplt.Size()) + plt.SetUint32(target.Arch, plt.Size()-4, 0x91000210) + relocs = plt.Relocs() + plt.SetRelocType(relocs.Count()-1, objabi.R_ARM64_PCREL) // br x17 plt.AddUint32(target.Arch, 0xd61f0220) // add to got.plt: pointer to plt[0] - gotplt.AddAddrPlus(target.Arch, plt, 0) + gotplt.AddAddrPlus(target.Arch, plt.Sym(), 0) // rela - rela.AddAddrPlus(target.Arch, gotplt, gotplt.Size-8) - rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_AARCH64_JUMP_SLOT))) + rela.AddAddrPlus(target.Arch, gotplt.Sym(), gotplt.Size()-8) + sDynid := ldr.SymDynid(s) + + rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(sDynid), uint32(elf.R_AARCH64_JUMP_SLOT))) rela.AddUint64(target.Arch, 0) - s.SetPlt(int32(plt.Size - 16)) + ldr.SetPlt(s, int32(plt.Size()-16)) } 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_AARCH64_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_AARCH64_GLOB_DAT))) rela.AddUint64(target.Arch, 0) } else { - ld.Errorf(s, "addgotsym: unsupported binary format") + ldr.Errorf(s, "addgotsym: unsupported binary format") } } diff --git a/src/cmd/link/internal/arm64/asm2.go b/src/cmd/link/internal/arm64/asm2.go new file mode 100644 index 0000000000..b093958cb8 --- /dev/null +++ b/src/cmd/link/internal/arm64/asm2.go @@ -0,0 +1,312 @@ +// 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 arm64 + +import ( + "cmd/internal/objabi" + "cmd/link/internal/ld" + "cmd/link/internal/loader" + "cmd/link/internal/sym" + "debug/elf" +) + +// Temporary dumping ground 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_AARCH64_PREL32): + if targ.Type == sym.SDYNIMPORT { + ld.Errorf(s, "unexpected R_AARCH64_PREL32 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_AARCH64_PREL64): + if targ.Type == sym.SDYNIMPORT { + ld.Errorf(s, "unexpected R_AARCH64_PREL64 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_AARCH64_CALL26), + objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_JUMP26): + if targ.Type == sym.SDYNIMPORT { + addpltsym(target, syms, targ) + r.Sym = syms.PLT + r.Add += int64(targ.Plt()) + } + if (targ.Type == 0 || targ.Type == sym.SXREF) && !targ.Attr.VisibilityHidden() { + ld.Errorf(s, "unknown symbol %s in callarm64", targ.Name) + } + r.Type = objabi.R_CALLARM64 + return true + + case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ADR_GOT_PAGE), + objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LD64_GOT_LO12_NC): + if targ.Type != sym.SDYNIMPORT { + // have symbol + // TODO: turn LDR of GOT entry into ADR of symbol itself + } + + // fall back to using GOT + // TODO: just needs relocation, no need to put in .dynsym + addgotsym(target, syms, targ) + + r.Type = objabi.R_ARM64_GOT + r.Sym = syms.GOT + r.Add += int64(targ.Got()) + return true + + case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ADR_PREL_PG_HI21), + objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ADD_ABS_LO12_NC): + if targ.Type == sym.SDYNIMPORT { + ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name) + } + if targ.Type == 0 || targ.Type == sym.SXREF { + ld.Errorf(s, "unknown symbol %s", targ.Name) + } + r.Type = objabi.R_ARM64_PCREL + return true + + case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ABS64): + if targ.Type == sym.SDYNIMPORT { + ld.Errorf(s, "unexpected R_AARCH64_ABS64 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 + + case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST8_ABS_LO12_NC): + if targ.Type == sym.SDYNIMPORT { + ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name) + } + r.Type = objabi.R_ARM64_LDST8 + return true + + case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST32_ABS_LO12_NC): + if targ.Type == sym.SDYNIMPORT { + ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name) + } + r.Type = objabi.R_ARM64_LDST32 + return true + + case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST64_ABS_LO12_NC): + if targ.Type == sym.SDYNIMPORT { + ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name) + } + r.Type = objabi.R_ARM64_LDST64 + return true + + case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST128_ABS_LO12_NC): + if targ.Type == sym.SDYNIMPORT { + ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name) + } + r.Type = objabi.R_ARM64_LDST128 + return true + } + + switch r.Type { + case objabi.R_CALL, + objabi.R_PCREL, + objabi.R_CALLARM64: + 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 + } + + case objabi.R_ADDR: + if s.Type == sym.STEXT && target.IsElf() { + // 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_AARCH64_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_AARCH64_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_AARCH64_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 + } + } + 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 + gotplt := syms.GOTPLT + rela := syms.RelaPLT + if plt.Size == 0 { + panic("plt is not set up") + } + + // adrp x16, &got.plt[0] + plt.AddAddrPlus4(gotplt, gotplt.Size) + plt.SetUint32(target.Arch, plt.Size-4, 0x90000010) + plt.R[len(plt.R)-1].Type = objabi.R_ARM64_GOT + + // is the offset value of &got.plt[n] to &got.plt[0] + // ldr x17, [x16, ] + plt.AddAddrPlus4(gotplt, gotplt.Size) + plt.SetUint32(target.Arch, plt.Size-4, 0xf9400211) + plt.R[len(plt.R)-1].Type = objabi.R_ARM64_GOT + + // add x16, x16, + plt.AddAddrPlus4(gotplt, gotplt.Size) + plt.SetUint32(target.Arch, plt.Size-4, 0x91000210) + plt.R[len(plt.R)-1].Type = objabi.R_ARM64_PCREL + + // br x17 + plt.AddUint32(target.Arch, 0xd61f0220) + + // add to got.plt: pointer to plt[0] + gotplt.AddAddrPlus(target.Arch, plt, 0) + + // rela + rela.AddAddrPlus(target.Arch, gotplt, gotplt.Size-8) + rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_AARCH64_JUMP_SLOT))) + rela.AddUint64(target.Arch, 0) + + s.SetPlt(int32(plt.Size - 16)) + } 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_AARCH64_GLOB_DAT))) + rela.AddUint64(target.Arch, 0) + } else { + ld.Errorf(s, "addgotsym: unsupported binary format") + } +} diff --git a/src/cmd/link/internal/arm64/obj.go b/src/cmd/link/internal/arm64/obj.go index c2ac6e7ad1..1895fbe0c2 100644 --- a/src/cmd/link/internal/arm64/obj.go +++ b/src/cmd/link/internal/arm64/obj.go @@ -47,6 +47,7 @@ func Init() (*sys.Arch, ld.Arch) { Dwarfreglr: dwarfRegLR, Adddynrel: adddynrel, + Adddynrel2: adddynrel2, Archinit: archinit, Archreloc: archreloc, Archrelocvariant: archrelocvariant, diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go index 96860ce4d8..8744291d71 100644 --- a/src/cmd/link/internal/ld/main.go +++ b/src/cmd/link/internal/ld/main.go @@ -204,7 +204,8 @@ func Main(arch *sys.Arch, theArch Arch) { // New dodata() is currently only implemented for selected targets. switch { case ctxt.IsElf(): - if !(ctxt.IsAMD64() || ctxt.Is386()) { + if !(ctxt.IsAMD64() || ctxt.Is386() || + ctxt.IsARM() || ctxt.IsARM64()) { *flagnewDoData = false } case ctxt.IsDarwin(): diff --git a/src/cmd/link/internal/ld/target.go b/src/cmd/link/internal/ld/target.go index 8c07d77fd8..78e41f09be 100644 --- a/src/cmd/link/internal/ld/target.go +++ b/src/cmd/link/internal/ld/target.go @@ -92,6 +92,10 @@ func (t *Target) IsARM() bool { return t.Arch.Family == sys.ARM } +func (t *Target) IsARM64() bool { + return t.Arch.Family == sys.ARM64 +} + func (t *Target) IsAMD64() bool { return t.Arch.Family == sys.AMD64 }