1
0
mirror of https://github.com/golang/go synced 2024-09-30 22:28:34 -06:00

[dev.link] cmd/link: support new dodata for elf/{arm,arm64}

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

Change-Id: Iadd772b01036c6c5be95bcc6017f6c05d45a24c0
Reviewed-on: https://go-review.googlesource.com/c/go/+/229868
Reviewed-by: Cherry Zhang <cherryyz@google.com>
This commit is contained in:
Than McIntosh 2020-04-24 11:01:10 -04:00
parent f9ed846a46
commit d5c9327628
8 changed files with 798 additions and 205 deletions

View File

@ -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")
}
}

View File

@ -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")
}
}

View File

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

View File

@ -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)
// <offset> is the offset value of &got.plt[n] to &got.plt[0]
// ldr x17, [x16, <offset>]
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, <offset>
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")
}
}

View File

@ -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
// <offset> is the offset value of &got.plt[n] to &got.plt[0]
// ldr x17, [x16, <offset>]
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, <offset>
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")
}
}

View File

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

View File

@ -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():

View File

@ -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
}