aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/link/internal/arm64/asm.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/link/internal/arm64/asm.go')
-rw-r--r--src/cmd/link/internal/arm64/asm.go182
1 files changed, 89 insertions, 93 deletions
diff --git a/src/cmd/link/internal/arm64/asm.go b/src/cmd/link/internal/arm64/asm.go
index 9c3f442238..66fa1c3a56 100644
--- a/src/cmd/link/internal/arm64/asm.go
+++ b/src/cmd/link/internal/arm64/asm.go
@@ -34,11 +34,12 @@ import (
"cmd/internal/objabi"
"cmd/internal/sys"
"cmd/link/internal/ld"
+ "cmd/link/internal/loader"
"cmd/link/internal/sym"
"debug/elf"
- "encoding/binary"
"fmt"
"log"
+ "sync"
)
func gentext(ctxt *ld.Link) {
@@ -92,13 +93,13 @@ func gentext(ctxt *ld.Link) {
initarray_entry.AddAddr(ctxt.Arch, initfunc)
}
-func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool {
+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(ctxt.Arch, r.Type))
+ ld.Errorf(s, "unexpected relocation type %d (%s)", r.Type, sym.RelocName(target.Arch, r.Type))
return false
}
@@ -130,8 +131,8 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool {
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_CALL26),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_JUMP26):
if targ.Type == sym.SDYNIMPORT {
- addpltsym(ctxt, targ)
- r.Sym = ctxt.Syms.Lookup(".plt", 0)
+ addpltsym(target, syms, targ)
+ r.Sym = syms.PLT
r.Add += int64(targ.Plt())
}
if (targ.Type == 0 || targ.Type == sym.SXREF) && !targ.Attr.VisibilityHidden() {
@@ -149,10 +150,10 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool {
// fall back to using GOT
// TODO: just needs relocation, no need to put in .dynsym
- addgotsym(ctxt, targ)
+ addgotsym(target, syms, targ)
r.Type = objabi.R_ARM64_GOT
- r.Sym = ctxt.Syms.Lookup(".got", 0)
+ r.Sym = syms.GOT
r.Add += int64(targ.Got())
return true
@@ -172,7 +173,7 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool {
ld.Errorf(s, "unexpected R_AARCH64_ABS64 relocation for dynamic symbol %s", targ.Name)
}
r.Type = objabi.R_ADDR
- if ctxt.BuildMode == ld.BuildModePIE && ctxt.LinkMode == ld.LinkInternal {
+ 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.
@@ -217,25 +218,25 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool {
// nothing to do, the relocation will be laid out in reloc
return true
}
- if ctxt.LinkMode == ld.LinkExternal {
+ if target.IsExternal() {
// External linker will do this relocation.
return true
}
case objabi.R_ADDR:
- if s.Type == sym.STEXT && ctxt.IsELF {
+ 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(ctxt, targ)
+ addgotsym(target, syms, targ)
- r.Sym = ctxt.Syms.Lookup(".got", 0)
+ r.Sym = syms.GOT
r.Add += int64(targ.Got())
return true
}
// Process dynamic relocations for the data sections.
- if ctxt.BuildMode == ld.BuildModePIE && ctxt.LinkMode == ld.LinkInternal {
+ 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
@@ -283,7 +284,7 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool {
}
}
- if ctxt.IsELF {
+ if target.IsElf() {
// Generate R_AARCH64_RELATIVE relocations for best
// efficiency in the dynamic linker.
//
@@ -301,14 +302,14 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool {
// 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 := ctxt.Syms.Lookup(".rela", 0)
- rela.AddAddrPlus(ctxt.Arch, s, int64(r.Off))
+ rela := syms.Rela
+ rela.AddAddrPlus(target.Arch, s, int64(r.Off))
if r.Siz == 8 {
- rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(0, uint32(elf.R_AARCH64_RELATIVE)))
+ 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(ctxt.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
@@ -434,14 +435,14 @@ func machoreloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, se
return true
}
-func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) {
- if ctxt.LinkMode == ld.LinkExternal {
+func archreloc(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) {
+ if target.IsExternal() {
switch r.Type {
default:
return val, false
case objabi.R_ARM64_GOTPCREL:
var o1, o2 uint32
- if ctxt.Arch.ByteOrder == binary.BigEndian {
+ if target.IsBigEndian() {
o1 = uint32(val >> 32)
o2 = uint32(val)
} else {
@@ -456,14 +457,14 @@ func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bo
// (https://sourceware.org/bugzilla/show_bug.cgi?id=18270). So
// we convert the adrp; ld64 + R_ARM64_GOTPCREL into adrp;
// add + R_ADDRARM64.
- if !(r.Sym.IsFileLocal() || r.Sym.Attr.VisibilityHidden() || r.Sym.Attr.Local()) && r.Sym.Type == sym.STEXT && ctxt.DynlinkingGo() {
+ if !(r.Sym.IsFileLocal() || r.Sym.Attr.VisibilityHidden() || r.Sym.Attr.Local()) && r.Sym.Type == sym.STEXT && target.IsDynlinkingGo() {
if o2&0xffc00000 != 0xf9400000 {
ld.Errorf(s, "R_ARM64_GOTPCREL against unexpected instruction %x", o2)
}
o2 = 0x91000000 | (o2 & 0x000003ff)
r.Type = objabi.R_ADDRARM64
}
- if ctxt.Arch.ByteOrder == binary.BigEndian {
+ if target.IsBigEndian() {
val = int64(o1)<<32 | int64(o2)
} else {
val = int64(o2)<<32 | int64(o1)
@@ -490,10 +491,10 @@ func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bo
// the BR26 relocation should be fully resolved at link time.
// That is the reason why the next if block is disabled. When the bug in ld64
// is fixed, we can enable this block and also enable duff's device in cmd/7g.
- if false && ctxt.HeadType == objabi.Hdarwin {
+ if false && target.IsDarwin() {
var o0, o1 uint32
- if ctxt.Arch.ByteOrder == binary.BigEndian {
+ if target.IsBigEndian() {
o0 = uint32(val >> 32)
o1 = uint32(val)
} else {
@@ -510,7 +511,7 @@ func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bo
r.Xadd = 0
// when laid out, the instruction order must always be o1, o2.
- if ctxt.Arch.ByteOrder == binary.BigEndian {
+ if target.IsBigEndian() {
val = int64(o0)<<32 | int64(o1)
} else {
val = int64(o1)<<32 | int64(o0)
@@ -533,7 +534,7 @@ func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bo
return r.Add, true
case objabi.R_GOTOFF:
- return ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0)), true
+ return ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(syms.GOT), true
case objabi.R_ADDRARM64:
t := ld.Symaddr(r.Sym) + r.Add - ((s.Value + int64(r.Off)) &^ 0xfff)
@@ -543,7 +544,7 @@ func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bo
var o0, o1 uint32
- if ctxt.Arch.ByteOrder == binary.BigEndian {
+ if target.IsBigEndian() {
o0 = uint32(val >> 32)
o1 = uint32(val)
} else {
@@ -555,42 +556,42 @@ func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bo
o1 |= uint32(t&0xfff) << 10
// when laid out, the instruction order must always be o1, o2.
- if ctxt.Arch.ByteOrder == binary.BigEndian {
+ if target.IsBigEndian() {
return int64(o0)<<32 | int64(o1), true
}
return int64(o1)<<32 | int64(o0), true
case objabi.R_ARM64_TLS_LE:
r.Done = false
- if ctxt.HeadType == objabi.Hdarwin {
- ld.Errorf(s, "TLS reloc on unsupported OS %v", ctxt.HeadType)
+ if target.IsDarwin() {
+ ld.Errorf(s, "TLS reloc on unsupported OS %v", target.HeadType)
}
// The TCB is two pointers. This is not documented anywhere, but is
// de facto part of the ABI.
- v := r.Sym.Value + int64(2*ctxt.Arch.PtrSize)
+ v := r.Sym.Value + int64(2*target.Arch.PtrSize)
if v < 0 || v >= 32678 {
ld.Errorf(s, "TLS offset out of range %d", v)
}
return val | (v << 5), true
case objabi.R_ARM64_TLS_IE:
- if ctxt.BuildMode == ld.BuildModePIE && ctxt.IsELF {
+ if target.IsPIE() && target.IsElf() {
// We are linking the final executable, so we
// can optimize any TLS IE relocation to LE.
r.Done = false
- if ctxt.HeadType != objabi.Hlinux {
- ld.Errorf(s, "TLS reloc on unsupported OS %v", ctxt.HeadType)
+ if !target.IsLinux() {
+ ld.Errorf(s, "TLS reloc on unsupported OS %v", target.HeadType)
}
// The TCB is two pointers. This is not documented anywhere, but is
// de facto part of the ABI.
- v := ld.Symaddr(r.Sym) + int64(2*ctxt.Arch.PtrSize) + r.Add
+ v := ld.Symaddr(r.Sym) + int64(2*target.Arch.PtrSize) + r.Add
if v < 0 || v >= 32678 {
ld.Errorf(s, "TLS offset out of range %d", v)
}
var o0, o1 uint32
- if ctxt.Arch.ByteOrder == binary.BigEndian {
+ if target.IsBigEndian() {
o0 = uint32(val >> 32)
o1 = uint32(val)
} else {
@@ -609,7 +610,7 @@ func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bo
o1 = 0xf2800000 | uint32(o1&0x1f) | (uint32(v&0xffff) << 5)
// when laid out, the instruction order must always be o0, o1.
- if ctxt.Arch.ByteOrder == binary.BigEndian {
+ if target.IsBigEndian() {
return int64(o0)<<32 | int64(o1), true
}
return int64(o1)<<32 | int64(o0), true
@@ -620,7 +621,7 @@ func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bo
case objabi.R_CALLARM64:
var t int64
if r.Sym.Type == sym.SDYNIMPORT {
- t = (ld.Symaddr(ctxt.Syms.Lookup(".plt", 0)) + r.Add) - (s.Value + int64(r.Off))
+ t = (ld.Symaddr(syms.PLT) + r.Add) - (s.Value + int64(r.Off))
} else {
t = (ld.Symaddr(r.Sym) + r.Add) - (s.Value + int64(r.Off))
}
@@ -707,35 +708,30 @@ func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bo
return val, false
}
-func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 {
+func archrelocvariant(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym.Symbol, t int64) int64 {
log.Fatalf("unexpected relocation variant")
return -1
}
-func elfsetupplt(ctxt *ld.Link) {
- plt := ctxt.Syms.Lookup(".plt", 0)
- gotplt := ctxt.Syms.Lookup(".got.plt", 0)
- if plt.Size == 0 {
+func elfsetupplt(ctxt *ld.Link, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) {
+ if plt.Size() == 0 {
// stp x16, x30, [sp, #-16]!
// identifying information
plt.AddUint32(ctxt.Arch, 0xa9bf7bf0)
// the following two instructions (adrp + ldr) load *got[2] into x17
// adrp x16, &got[0]
- plt.AddAddrPlus4(gotplt, 16)
- plt.SetUint32(ctxt.Arch, plt.Size-4, 0x90000010)
- plt.R[len(plt.R)-1].Type = objabi.R_ARM64_GOT
+ plt.AddSymRef(ctxt.Arch, gotplt.Sym(), 16, objabi.R_ARM64_GOT, 4)
+ plt.SetUint32(ctxt.Arch, plt.Size()-4, 0x90000010)
// <imm> is the offset value of &got[2] to &got[0], the same below
// ldr x17, [x16, <imm>]
- plt.AddAddrPlus4(gotplt, 16)
- plt.SetUint32(ctxt.Arch, plt.Size-4, 0xf9400211)
- plt.R[len(plt.R)-1].Type = objabi.R_ARM64_GOT
+ plt.AddSymRef(ctxt.Arch, gotplt.Sym(), 16, objabi.R_ARM64_GOT, 4)
+ plt.SetUint32(ctxt.Arch, plt.Size()-4, 0xf9400211)
// add x16, x16, <imm>
- plt.AddAddrPlus4(gotplt, 16)
- plt.SetUint32(ctxt.Arch, plt.Size-4, 0x91000210)
- plt.R[len(plt.R)-1].Type = objabi.R_ARM64_PCREL
+ plt.AddSymRef(ctxt.Arch, gotplt.Sym(), 16, objabi.R_ARM64_PCREL, 4)
+ plt.SetUint32(ctxt.Arch, plt.Size()-4, 0x91000210)
// br x17
plt.AddUint32(ctxt.Arch, 0xd61f0220)
@@ -746,57 +742,57 @@ func elfsetupplt(ctxt *ld.Link) {
plt.AddUint32(ctxt.Arch, 0xd503201f)
// check gotplt.size == 0
- if gotplt.Size != 0 {
- ld.Errorf(gotplt, "got.plt is not empty at the very beginning")
+ if gotplt.Size() != 0 {
+ ctxt.Errorf(gotplt.Sym(), "got.plt is not empty at the very beginning")
}
- gotplt.AddAddrPlus(ctxt.Arch, ctxt.Syms.Lookup(".dynamic", 0), 0)
+ gotplt.AddAddrPlus(ctxt.Arch, dynamic, 0)
gotplt.AddUint64(ctxt.Arch, 0)
gotplt.AddUint64(ctxt.Arch, 0)
}
}
-func addpltsym(ctxt *ld.Link, s *sym.Symbol) {
+func addpltsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
if s.Plt() >= 0 {
return
}
- ld.Adddynsym(ctxt, s)
+ ld.Adddynsym(target, syms, s)
- if ctxt.IsELF {
- plt := ctxt.Syms.Lookup(".plt", 0)
- gotplt := ctxt.Syms.Lookup(".got.plt", 0)
- rela := ctxt.Syms.Lookup(".rela.plt", 0)
+ if target.IsElf() {
+ plt := syms.PLT
+ gotplt := syms.GOTPLT
+ rela := syms.RelaPLT
if plt.Size == 0 {
- elfsetupplt(ctxt)
+ panic("plt is not set up")
}
// adrp x16, &got.plt[0]
plt.AddAddrPlus4(gotplt, gotplt.Size)
- plt.SetUint32(ctxt.Arch, plt.Size-4, 0x90000010)
+ 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(ctxt.Arch, plt.Size-4, 0xf9400211)
+ 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(ctxt.Arch, plt.Size-4, 0x91000210)
+ plt.SetUint32(target.Arch, plt.Size-4, 0x91000210)
plt.R[len(plt.R)-1].Type = objabi.R_ARM64_PCREL
// br x17
- plt.AddUint32(ctxt.Arch, 0xd61f0220)
+ plt.AddUint32(target.Arch, 0xd61f0220)
// add to got.plt: pointer to plt[0]
- gotplt.AddAddrPlus(ctxt.Arch, plt, 0)
+ gotplt.AddAddrPlus(target.Arch, plt, 0)
// rela
- rela.AddAddrPlus(ctxt.Arch, gotplt, gotplt.Size-8)
- rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_AARCH64_JUMP_SLOT)))
- rela.AddUint64(ctxt.Arch, 0)
+ 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 {
@@ -804,21 +800,21 @@ func addpltsym(ctxt *ld.Link, s *sym.Symbol) {
}
}
-func addgotsym(ctxt *ld.Link, s *sym.Symbol) {
+func addgotsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
if s.Got() >= 0 {
return
}
- ld.Adddynsym(ctxt, s)
- got := ctxt.Syms.Lookup(".got", 0)
+ ld.Adddynsym(target, syms, s)
+ got := syms.GOT
s.SetGot(int32(got.Size))
- got.AddUint64(ctxt.Arch, 0)
+ got.AddUint64(target.Arch, 0)
- if ctxt.IsELF {
- rela := ctxt.Syms.Lookup(".rela", 0)
- rela.AddAddrPlus(ctxt.Arch, got, int64(s.Got()))
- rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_AARCH64_GLOB_DAT)))
- rela.AddUint64(ctxt.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")
}
@@ -829,28 +825,28 @@ func asmb(ctxt *ld.Link) {
ld.Asmbelfsetup()
}
+ var wg sync.WaitGroup
sect := ld.Segtext.Sections[0]
- ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
- ld.Codeblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
- for _, sect = range ld.Segtext.Sections[1:] {
- ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
- ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
+ offset := sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff
+ ld.WriteParallel(&wg, ld.Codeblk, ctxt, offset, sect.Vaddr, sect.Length)
+
+ for _, sect := range ld.Segtext.Sections[1:] {
+ offset := sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff
+ ld.WriteParallel(&wg, ld.Datblk, ctxt, offset, sect.Vaddr, sect.Length)
}
if ld.Segrodata.Filelen > 0 {
- ctxt.Out.SeekSet(int64(ld.Segrodata.Fileoff))
- ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
+ ld.WriteParallel(&wg, ld.Datblk, ctxt, ld.Segrodata.Fileoff, ld.Segrodata.Vaddr, ld.Segrodata.Filelen)
}
+
if ld.Segrelrodata.Filelen > 0 {
- ctxt.Out.SeekSet(int64(ld.Segrelrodata.Fileoff))
- ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
+ ld.WriteParallel(&wg, ld.Datblk, ctxt, ld.Segrelrodata.Fileoff, ld.Segrelrodata.Vaddr, ld.Segrelrodata.Filelen)
}
- ctxt.Out.SeekSet(int64(ld.Segdata.Fileoff))
- ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
+ ld.WriteParallel(&wg, ld.Datblk, ctxt, ld.Segdata.Fileoff, ld.Segdata.Vaddr, ld.Segdata.Filelen)
- ctxt.Out.SeekSet(int64(ld.Segdwarf.Fileoff))
- ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
+ ld.WriteParallel(&wg, ld.Dwarfblk, ctxt, ld.Segdwarf.Fileoff, ld.Segdwarf.Vaddr, ld.Segdwarf.Filelen)
+ wg.Wait()
}
func asmb2(ctxt *ld.Link) {