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:
parent
f9ed846a46
commit
d5c9327628
@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
|
246
src/cmd/link/internal/arm/asm2.go
Normal file
246
src/cmd/link/internal/arm/asm2.go
Normal 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")
|
||||
}
|
||||
}
|
@ -47,6 +47,7 @@ func Init() (*sys.Arch, ld.Arch) {
|
||||
Dwarfreglr: dwarfRegLR,
|
||||
|
||||
Adddynrel: adddynrel,
|
||||
Adddynrel2: adddynrel2,
|
||||
Archinit: archinit,
|
||||
Archreloc: archreloc,
|
||||
Archrelocvariant: archrelocvariant,
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
|
312
src/cmd/link/internal/arm64/asm2.go
Normal file
312
src/cmd/link/internal/arm64/asm2.go
Normal 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")
|
||||
}
|
||||
}
|
@ -47,6 +47,7 @@ func Init() (*sys.Arch, ld.Arch) {
|
||||
Dwarfreglr: dwarfRegLR,
|
||||
|
||||
Adddynrel: adddynrel,
|
||||
Adddynrel2: adddynrel2,
|
||||
Archinit: archinit,
|
||||
Archreloc: archreloc,
|
||||
Archrelocvariant: archrelocvariant,
|
||||
|
@ -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():
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user