mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.link] cmd/link: stream external relocations on ARM64 and on Darwin
Support streaming external relocations on ARM64. Support architecture-specific relocations. Also support streaming external relocations on Darwin. Do it in the same CL so ARM64's archreloc doesn't need to support both streaming and non-streaming. Change-Id: Ia7fee9957892f98c065022c69a51f47402f4d6e2 Reviewed-on: https://go-review.googlesource.com/c/go/+/243644 Reviewed-by: Jeremy Faller <jeremy@golang.org>
This commit is contained in:
parent
936a2d6966
commit
bf1816c7b7
6 changed files with 72 additions and 23 deletions
|
|
@ -456,15 +456,14 @@ func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loade
|
||||||
|
|
||||||
// set up addend for eventual relocation via outer symbol.
|
// set up addend for eventual relocation via outer symbol.
|
||||||
rs, off := ld.FoldSubSymbolOffset(ldr, rs)
|
rs, off := ld.FoldSubSymbolOffset(ldr, rs)
|
||||||
rr.Xadd = r.Add() + off
|
xadd := r.Add() + off
|
||||||
rst := ldr.SymType(rs)
|
rst := ldr.SymType(rs)
|
||||||
if rst != sym.SHOSTOBJ && rst != sym.SDYNIMPORT && ldr.SymSect(rs) == nil {
|
if rst != sym.SHOSTOBJ && rst != sym.SDYNIMPORT && ldr.SymSect(rs) == nil {
|
||||||
ldr.Errorf(s, "missing section for %s", ldr.SymName(rs))
|
ldr.Errorf(s, "missing section for %s", ldr.SymName(rs))
|
||||||
}
|
}
|
||||||
rr.Xsym = rs
|
|
||||||
|
|
||||||
nExtReloc = 2 // need two ELF/Mach-O relocations. see elfreloc1/machoreloc1
|
nExtReloc = 2 // need two ELF/Mach-O relocations. see elfreloc1/machoreloc1
|
||||||
if target.IsDarwin() && rt == objabi.R_ADDRARM64 && rr.Xadd != 0 {
|
if target.IsDarwin() && rt == objabi.R_ADDRARM64 && xadd != 0 {
|
||||||
nExtReloc = 4 // need another two relocations for non-zero addend
|
nExtReloc = 4 // need another two relocations for non-zero addend
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -488,9 +487,8 @@ func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loade
|
||||||
// can only encode 24-bit of signed addend, but the instructions
|
// can only encode 24-bit of signed addend, but the instructions
|
||||||
// supports 33-bit of signed addend, so we always encode the
|
// supports 33-bit of signed addend, so we always encode the
|
||||||
// addend in place.
|
// addend in place.
|
||||||
o0 |= (uint32((rr.Xadd>>12)&3) << 29) | (uint32((rr.Xadd>>12>>2)&0x7ffff) << 5)
|
o0 |= (uint32((xadd>>12)&3) << 29) | (uint32((xadd>>12>>2)&0x7ffff) << 5)
|
||||||
o1 |= uint32(rr.Xadd&0xfff) << 10
|
o1 |= uint32(xadd&0xfff) << 10
|
||||||
rr.Xadd = 0
|
|
||||||
|
|
||||||
// when laid out, the instruction order must always be o1, o2.
|
// when laid out, the instruction order must always be o1, o2.
|
||||||
if target.IsBigEndian() {
|
if target.IsBigEndian() {
|
||||||
|
|
@ -508,8 +506,6 @@ func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loade
|
||||||
if rt == objabi.R_ARM64_TLS_IE {
|
if rt == objabi.R_ARM64_TLS_IE {
|
||||||
nExtReloc = 2 // need two ELF relocations. see elfreloc1
|
nExtReloc = 2 // need two ELF relocations. see elfreloc1
|
||||||
}
|
}
|
||||||
rr.Xsym = rs
|
|
||||||
rr.Xadd = r.Add()
|
|
||||||
return val, nExtReloc, isOk
|
return val, nExtReloc, isOk
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -693,6 +689,42 @@ func archrelocvariant(*ld.Target, *loader.Loader, loader.Reloc2, sym.RelocVarian
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func extreloc(target *ld.Target, ldr *loader.Loader, r loader.Reloc2, s loader.Sym) (loader.ExtReloc, bool) {
|
||||||
|
rs := ldr.ResolveABIAlias(r.Sym())
|
||||||
|
var rr loader.ExtReloc
|
||||||
|
switch rt := r.Type(); rt {
|
||||||
|
case objabi.R_ARM64_GOTPCREL,
|
||||||
|
objabi.R_ADDRARM64:
|
||||||
|
|
||||||
|
// set up addend for eventual relocation via outer symbol.
|
||||||
|
rs, off := ld.FoldSubSymbolOffset(ldr, rs)
|
||||||
|
rr.Xadd = r.Add() + off
|
||||||
|
rr.Xsym = rs
|
||||||
|
|
||||||
|
// Note: ld64 currently has a bug that any non-zero addend for BR26 relocation
|
||||||
|
// will make the linking fail because it thinks the code is not PIC even though
|
||||||
|
// 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 && target.IsDarwin() {
|
||||||
|
// Mach-O wants the addend to be encoded in the instruction
|
||||||
|
// Note that although Mach-O supports ARM64_RELOC_ADDEND, it
|
||||||
|
// can only encode 24-bit of signed addend, but the instructions
|
||||||
|
// supports 33-bit of signed addend, so we always encode the
|
||||||
|
// addend in place.
|
||||||
|
rr.Xadd = 0
|
||||||
|
}
|
||||||
|
return rr, true
|
||||||
|
case objabi.R_CALLARM64,
|
||||||
|
objabi.R_ARM64_TLS_LE,
|
||||||
|
objabi.R_ARM64_TLS_IE:
|
||||||
|
rr.Xsym = rs
|
||||||
|
rr.Xadd = r.Add()
|
||||||
|
return rr, true
|
||||||
|
}
|
||||||
|
return rr, false
|
||||||
|
}
|
||||||
|
|
||||||
func elfsetupplt(ctxt *ld.Link, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) {
|
func elfsetupplt(ctxt *ld.Link, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) {
|
||||||
if plt.Size() == 0 {
|
if plt.Size() == 0 {
|
||||||
// stp x16, x30, [sp, #-16]!
|
// stp x16, x30, [sp, #-16]!
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ func Init() (*sys.Arch, ld.Arch) {
|
||||||
Archinit: archinit,
|
Archinit: archinit,
|
||||||
Archreloc: archreloc,
|
Archreloc: archreloc,
|
||||||
Archrelocvariant: archrelocvariant,
|
Archrelocvariant: archrelocvariant,
|
||||||
|
Extreloc: extreloc,
|
||||||
Elfreloc1: elfreloc1,
|
Elfreloc1: elfreloc1,
|
||||||
ElfrelocSize: 24,
|
ElfrelocSize: 24,
|
||||||
Elfsetupplt: elfsetupplt,
|
Elfsetupplt: elfsetupplt,
|
||||||
|
|
|
||||||
|
|
@ -264,7 +264,7 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) {
|
||||||
o = int64(target.Arch.ByteOrder.Uint64(P[off:]))
|
o = int64(target.Arch.ByteOrder.Uint64(P[off:]))
|
||||||
}
|
}
|
||||||
var rp *loader.ExtReloc
|
var rp *loader.ExtReloc
|
||||||
if target.IsExternal() {
|
if target.IsExternal() && !target.StreamExtRelocs() {
|
||||||
// Don't pass &rr directly to Archreloc, which will escape rr
|
// Don't pass &rr directly to Archreloc, which will escape rr
|
||||||
// even if this case is not taken. Instead, as Archreloc will
|
// even if this case is not taken. Instead, as Archreloc will
|
||||||
// likely return true, we speculatively add rr to extRelocs
|
// likely return true, we speculatively add rr to extRelocs
|
||||||
|
|
@ -274,12 +274,16 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) {
|
||||||
}
|
}
|
||||||
out, nExtReloc, ok := thearch.Archreloc(target, ldr, syms, r, rp, s, o)
|
out, nExtReloc, ok := thearch.Archreloc(target, ldr, syms, r, rp, s, o)
|
||||||
if target.IsExternal() {
|
if target.IsExternal() {
|
||||||
if nExtReloc == 0 {
|
if target.StreamExtRelocs() {
|
||||||
// No external relocation needed. Speculation failed. Undo the append.
|
extraExtReloc += nExtReloc
|
||||||
extRelocs = extRelocs[:len(extRelocs)-1]
|
|
||||||
} else {
|
} else {
|
||||||
// Account for the difference between host relocations and Go relocations.
|
if nExtReloc == 0 {
|
||||||
extraExtReloc += nExtReloc - 1
|
// No external relocation needed. Speculation failed. Undo the append.
|
||||||
|
extRelocs = extRelocs[:len(extRelocs)-1]
|
||||||
|
} else {
|
||||||
|
// Account for the difference between host relocations and Go relocations.
|
||||||
|
extraExtReloc += nExtReloc - 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
needExtReloc = false // already appended
|
needExtReloc = false // already appended
|
||||||
|
|
@ -638,8 +642,7 @@ func extreloc(ctxt *Link, ldr *loader.Loader, s loader.Sym, r loader.Reloc2, ri
|
||||||
|
|
||||||
switch rt {
|
switch rt {
|
||||||
default:
|
default:
|
||||||
// TODO: handle arch-specific relocations
|
return thearch.Extreloc(&target, ldr, r, s)
|
||||||
panic("unsupported")
|
|
||||||
|
|
||||||
case objabi.R_TLS_LE, objabi.R_TLS_IE:
|
case objabi.R_TLS_LE, objabi.R_TLS_IE:
|
||||||
if target.IsElf() {
|
if target.IsElf() {
|
||||||
|
|
|
||||||
|
|
@ -239,6 +239,11 @@ type Arch struct {
|
||||||
Asmb func(*Link, *loader.Loader)
|
Asmb func(*Link, *loader.Loader)
|
||||||
Asmb2 func(*Link, *loader.Loader)
|
Asmb2 func(*Link, *loader.Loader)
|
||||||
|
|
||||||
|
// Extreloc is an arch-specific hook that converts a Go relocation to an
|
||||||
|
// external relocation. Return the external relocation and whether it is
|
||||||
|
// needed.
|
||||||
|
Extreloc func(*Target, *loader.Loader, loader.Reloc2, loader.Sym) (loader.ExtReloc, bool)
|
||||||
|
|
||||||
Elfreloc1 func(*Link, *OutBuf, *loader.Loader, loader.Sym, loader.ExtRelocView, int64) bool
|
Elfreloc1 func(*Link, *OutBuf, *loader.Loader, loader.Sym, loader.ExtRelocView, int64) bool
|
||||||
ElfrelocSize uint32 // size of an ELF relocation record, must match Elfreloc1.
|
ElfrelocSize uint32 // size of an ELF relocation record, must match Elfreloc1.
|
||||||
Elfsetupplt func(ctxt *Link, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym)
|
Elfsetupplt func(ctxt *Link, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym)
|
||||||
|
|
|
||||||
|
|
@ -1045,17 +1045,25 @@ func machorelocsect(ctxt *Link, out *OutBuf, sect *sym.Section, syms []loader.Sy
|
||||||
if ldr.SymValue(s) >= int64(eaddr) {
|
if ldr.SymValue(s) >= int64(eaddr) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
relocs := ldr.ExtRelocs(s)
|
|
||||||
|
// Compute external relocations on the go, and pass to Machoreloc1
|
||||||
|
// to stream out.
|
||||||
|
relocs := ldr.Relocs(s)
|
||||||
for ri := 0; ri < relocs.Count(); ri++ {
|
for ri := 0; ri < relocs.Count(); ri++ {
|
||||||
r := relocs.At(ri)
|
r := relocs.At2(ri)
|
||||||
if r.Xsym == 0 {
|
rr, ok := extreloc(ctxt, ldr, s, r, ri)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if rr.Xsym == 0 {
|
||||||
ldr.Errorf(s, "missing xsym in relocation")
|
ldr.Errorf(s, "missing xsym in relocation")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !ldr.AttrReachable(r.Xsym) {
|
if !ldr.AttrReachable(rr.Xsym) {
|
||||||
ldr.Errorf(s, "unreachable reloc %d (%s) target %v", r.Type(), sym.RelocName(ctxt.Arch, r.Type()), ldr.SymName(r.Xsym))
|
ldr.Errorf(s, "unreachable reloc %d (%s) target %v", r.Type(), sym.RelocName(ctxt.Arch, r.Type()), ldr.SymName(rr.Xsym))
|
||||||
}
|
}
|
||||||
if !thearch.Machoreloc1(ctxt.Arch, out, ldr, s, r, int64(uint64(ldr.SymValue(s)+int64(r.Off()))-sect.Vaddr)) {
|
rv := loader.ExtRelocView{Reloc2: r, ExtReloc: rr}
|
||||||
|
if !thearch.Machoreloc1(ctxt.Arch, out, ldr, s, rv, int64(uint64(ldr.SymValue(s)+int64(r.Off()))-sect.Vaddr)) {
|
||||||
ldr.Errorf(s, "unsupported obj reloc %d (%s)/%d to %s", r.Type(), sym.RelocName(ctxt.Arch, r.Type()), r.Siz(), ldr.SymName(r.Sym()))
|
ldr.Errorf(s, "unsupported obj reloc %d (%s)/%d to %s", r.Type(), sym.RelocName(ctxt.Arch, r.Type()), r.Siz(), ldr.SymName(r.Sym()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -184,5 +184,5 @@ func (t *Target) IsBigEndian() bool {
|
||||||
|
|
||||||
// Temporary helper.
|
// Temporary helper.
|
||||||
func (t *Target) StreamExtRelocs() bool {
|
func (t *Target) StreamExtRelocs() bool {
|
||||||
return t.IsELF && (t.IsAMD64() || t.Is386())
|
return (t.IsELF || t.IsDarwin()) && (t.IsAMD64() || t.Is386() || t.IsARM64())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue