mirror of
https://github.com/golang/go
synced 2024-11-17 10:04:43 -07:00
cmd/link: support PPC64 prefixed relocations for power10
Handle emitting (to ld) or resolving commonly used ELFv2 1.5 relocations. The new ISA provides PC relative addressing with 34 bit signed addresses, and many other relocations which can replace addis + d-form type relocations with a single prefixed instruction. Updates #44549 Change-Id: I7d4f4314d1082daa3938f4353826739be35b0e81 Reviewed-on: https://go-review.googlesource.com/c/go/+/355149 Reviewed-by: Cherry Mui <cherryyz@google.com> Reviewed-by: Lynn Boger <laboger@linux.vnet.ibm.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Paul Murphy <murp@ibm.com>
This commit is contained in:
parent
aa6240a445
commit
69abfab979
@ -208,6 +208,15 @@ const (
|
||||
// (usually called RB in X-form instructions) is assumed to be R13.
|
||||
R_POWER_TLS
|
||||
|
||||
// R_POWER_TLS_IE_PCREL34 is similar to R_POWER_TLS_IE, but marks a single MOVD
|
||||
// which has been assembled as a single prefixed load doubleword without using the
|
||||
// TOC.
|
||||
R_POWER_TLS_IE_PCREL34
|
||||
|
||||
// R_POWER_TLS_LE_TPREL34 is similar to R_POWER_TLS_LE, but computes an offset from
|
||||
// the thread pointer in one prefixed instruction.
|
||||
R_POWER_TLS_LE_TPREL34
|
||||
|
||||
// R_ADDRPOWER_DS is similar to R_ADDRPOWER above, but assumes the second
|
||||
// instruction is a "DS-form" instruction, which has an immediate field occupying
|
||||
// bits [15:2] of the instruction word. Bits [15:2] of the address of the
|
||||
@ -215,11 +224,14 @@ const (
|
||||
// bits of the address are not 0.
|
||||
R_ADDRPOWER_DS
|
||||
|
||||
// R_ADDRPOWER_PCREL relocates a D-form, DS-form instruction sequence like
|
||||
// R_ADDRPOWER_DS but inserts the offset of the GOT slot for the referenced symbol
|
||||
// from the TOC rather than the symbol's address.
|
||||
// R_ADDRPOWER_GOT relocates a D-form + DS-form instruction sequence by inserting
|
||||
// a relative displacement of referenced symbol's GOT entry to the TOC pointer.
|
||||
R_ADDRPOWER_GOT
|
||||
|
||||
// R_ADDRPOWER_GOT_PCREL34 is identical to R_ADDRPOWER_GOT, but uses a PC relative
|
||||
// sequence to generate a GOT symbol addresss.
|
||||
R_ADDRPOWER_GOT_PCREL34
|
||||
|
||||
// R_ADDRPOWER_PCREL relocates two D-form instructions like R_ADDRPOWER, but
|
||||
// inserts the displacement from the place being relocated to the address of the
|
||||
// relocated symbol instead of just its address.
|
||||
@ -235,6 +247,16 @@ const (
|
||||
// relocated symbol rather than the symbol's address.
|
||||
R_ADDRPOWER_TOCREL_DS
|
||||
|
||||
// R_ADDRPOWER_D34 relocates a single prefixed D-form load/store operation. All
|
||||
// prefixed forms are D form. The high 18 bits are stored in the prefix,
|
||||
// and the low 16 are stored in the suffix. The address is absolute.
|
||||
R_ADDRPOWER_D34
|
||||
|
||||
// R_ADDPOWER_PCREL34 relates a single prefixed D-form load/store/add operation.
|
||||
// All prefixed forms are D form. The resulting address is relative to the
|
||||
// PC. It is a signed 34 bit offset.
|
||||
R_ADDRPOWER_PCREL34
|
||||
|
||||
// RISC-V.
|
||||
|
||||
// R_RISCV_CALL relocates a J-type instruction with a 21 bit PC-relative
|
||||
|
@ -57,34 +57,39 @@ func _() {
|
||||
_ = x[R_POWER_TLS_LE-47]
|
||||
_ = x[R_POWER_TLS_IE-48]
|
||||
_ = x[R_POWER_TLS-49]
|
||||
_ = x[R_ADDRPOWER_DS-50]
|
||||
_ = x[R_ADDRPOWER_GOT-51]
|
||||
_ = x[R_ADDRPOWER_PCREL-52]
|
||||
_ = x[R_ADDRPOWER_TOCREL-53]
|
||||
_ = x[R_ADDRPOWER_TOCREL_DS-54]
|
||||
_ = x[R_RISCV_CALL-55]
|
||||
_ = x[R_RISCV_CALL_TRAMP-56]
|
||||
_ = x[R_RISCV_PCREL_ITYPE-57]
|
||||
_ = x[R_RISCV_PCREL_STYPE-58]
|
||||
_ = x[R_RISCV_TLS_IE_ITYPE-59]
|
||||
_ = x[R_RISCV_TLS_IE_STYPE-60]
|
||||
_ = x[R_PCRELDBL-61]
|
||||
_ = x[R_ADDRLOONG64-62]
|
||||
_ = x[R_ADDRLOONG64U-63]
|
||||
_ = x[R_ADDRLOONG64TLS-64]
|
||||
_ = x[R_ADDRLOONG64TLSU-65]
|
||||
_ = x[R_CALLLOONG64-66]
|
||||
_ = x[R_JMPLOONG64-67]
|
||||
_ = x[R_ADDRMIPSU-68]
|
||||
_ = x[R_ADDRMIPSTLS-69]
|
||||
_ = x[R_ADDRCUOFF-70]
|
||||
_ = x[R_WASMIMPORT-71]
|
||||
_ = x[R_XCOFFREF-72]
|
||||
_ = x[R_POWER_TLS_IE_PCREL34-50]
|
||||
_ = x[R_POWER_TLS_LE_TPREL34-51]
|
||||
_ = x[R_ADDRPOWER_DS-52]
|
||||
_ = x[R_ADDRPOWER_GOT-53]
|
||||
_ = x[R_ADDRPOWER_GOT_PCREL34-54]
|
||||
_ = x[R_ADDRPOWER_PCREL-55]
|
||||
_ = x[R_ADDRPOWER_TOCREL-56]
|
||||
_ = x[R_ADDRPOWER_TOCREL_DS-57]
|
||||
_ = x[R_ADDRPOWER_D34-58]
|
||||
_ = x[R_ADDRPOWER_PCREL34-59]
|
||||
_ = x[R_RISCV_CALL-60]
|
||||
_ = x[R_RISCV_CALL_TRAMP-61]
|
||||
_ = x[R_RISCV_PCREL_ITYPE-62]
|
||||
_ = x[R_RISCV_PCREL_STYPE-63]
|
||||
_ = x[R_RISCV_TLS_IE_ITYPE-64]
|
||||
_ = x[R_RISCV_TLS_IE_STYPE-65]
|
||||
_ = x[R_PCRELDBL-66]
|
||||
_ = x[R_ADDRLOONG64-67]
|
||||
_ = x[R_ADDRLOONG64U-68]
|
||||
_ = x[R_ADDRLOONG64TLS-69]
|
||||
_ = x[R_ADDRLOONG64TLSU-70]
|
||||
_ = x[R_CALLLOONG64-71]
|
||||
_ = x[R_JMPLOONG64-72]
|
||||
_ = x[R_ADDRMIPSU-73]
|
||||
_ = x[R_ADDRMIPSTLS-74]
|
||||
_ = x[R_ADDRCUOFF-75]
|
||||
_ = x[R_WASMIMPORT-76]
|
||||
_ = x[R_XCOFFREF-77]
|
||||
}
|
||||
|
||||
const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_USEIFACER_USEIFACEMETHODR_USEGENERICIFACEMETHODR_METHODOFFR_KEEPR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_ARM64_GOTR_ARM64_PCRELR_ARM64_PCREL_LDST8R_ARM64_PCREL_LDST16R_ARM64_PCREL_LDST32R_ARM64_PCREL_LDST64R_ARM64_LDST8R_ARM64_LDST16R_ARM64_LDST32R_ARM64_LDST64R_ARM64_LDST128R_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_RISCV_CALLR_RISCV_CALL_TRAMPR_RISCV_PCREL_ITYPER_RISCV_PCREL_STYPER_RISCV_TLS_IE_ITYPER_RISCV_TLS_IE_STYPER_PCRELDBLR_ADDRLOONG64R_ADDRLOONG64UR_ADDRLOONG64TLSR_ADDRLOONG64TLSUR_CALLLOONG64R_JMPLOONG64R_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFFR_WASMIMPORTR_XCOFFREF"
|
||||
const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_USEIFACER_USEIFACEMETHODR_USEGENERICIFACEMETHODR_METHODOFFR_KEEPR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_ARM64_GOTR_ARM64_PCRELR_ARM64_PCREL_LDST8R_ARM64_PCREL_LDST16R_ARM64_PCREL_LDST32R_ARM64_PCREL_LDST64R_ARM64_LDST8R_ARM64_LDST16R_ARM64_LDST32R_ARM64_LDST64R_ARM64_LDST128R_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_POWER_TLS_IE_PCREL34R_POWER_TLS_LE_TPREL34R_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_GOT_PCREL34R_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_ADDRPOWER_D34R_ADDRPOWER_PCREL34R_RISCV_CALLR_RISCV_CALL_TRAMPR_RISCV_PCREL_ITYPER_RISCV_PCREL_STYPER_RISCV_TLS_IE_ITYPER_RISCV_TLS_IE_STYPER_PCRELDBLR_ADDRLOONG64R_ADDRLOONG64UR_ADDRLOONG64TLSR_ADDRLOONG64TLSUR_CALLLOONG64R_JMPLOONG64R_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFFR_WASMIMPORTR_XCOFFREF"
|
||||
|
||||
var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 53, 59, 68, 79, 88, 99, 109, 116, 123, 131, 139, 147, 153, 159, 165, 175, 184, 194, 210, 233, 244, 250, 261, 271, 280, 293, 307, 321, 335, 351, 362, 375, 394, 414, 434, 454, 467, 481, 495, 509, 524, 538, 552, 563, 577, 592, 609, 627, 648, 660, 678, 697, 716, 736, 756, 766, 779, 793, 809, 826, 839, 851, 862, 875, 886, 898, 908}
|
||||
var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 53, 59, 68, 79, 88, 99, 109, 116, 123, 131, 139, 147, 153, 159, 165, 175, 184, 194, 210, 233, 244, 250, 261, 271, 280, 293, 307, 321, 335, 351, 362, 375, 394, 414, 434, 454, 467, 481, 495, 509, 524, 538, 552, 563, 585, 607, 621, 636, 659, 676, 694, 715, 730, 749, 761, 779, 798, 817, 837, 857, 867, 880, 894, 910, 927, 940, 952, 963, 976, 987, 999, 1009}
|
||||
|
||||
func (i RelocType) String() string {
|
||||
i -= 1
|
||||
|
@ -727,6 +727,10 @@ func elfreloc1(ctxt *ld.Link, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym,
|
||||
default:
|
||||
return false
|
||||
}
|
||||
case objabi.R_ADDRPOWER_D34:
|
||||
out.Write64(uint64(elf.R_PPC64_D34) | uint64(elfsym)<<32)
|
||||
case objabi.R_ADDRPOWER_PCREL34:
|
||||
out.Write64(uint64(elf.R_PPC64_PCREL34) | uint64(elfsym)<<32)
|
||||
case objabi.R_POWER_TLS:
|
||||
out.Write64(uint64(elf.R_PPC64_TLS) | uint64(elfsym)<<32)
|
||||
case objabi.R_POWER_TLS_LE:
|
||||
@ -734,6 +738,10 @@ func elfreloc1(ctxt *ld.Link, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym,
|
||||
out.Write64(uint64(r.Xadd))
|
||||
out.Write64(uint64(sectoff + 4))
|
||||
out.Write64(uint64(elf.R_PPC64_TPREL16_LO) | uint64(elfsym)<<32)
|
||||
case objabi.R_POWER_TLS_LE_TPREL34:
|
||||
out.Write64(uint64(elf.R_PPC64_TPREL34) | uint64(elfsym)<<32)
|
||||
case objabi.R_POWER_TLS_IE_PCREL34:
|
||||
out.Write64(uint64(elf.R_PPC64_GOT_TPREL_PCREL34) | uint64(elfsym)<<32)
|
||||
case objabi.R_POWER_TLS_IE:
|
||||
out.Write64(uint64(elf.R_PPC64_GOT_TPREL16_HA) | uint64(elfsym)<<32)
|
||||
out.Write64(uint64(r.Xadd))
|
||||
@ -888,48 +896,41 @@ func archrelocaddr(ldr *loader.Loader, target *ld.Target, syms *ld.ArchSyms, r l
|
||||
if target.IsAIX() {
|
||||
ldr.Errorf(s, "archrelocaddr called for %s relocation\n", ldr.SymName(rs))
|
||||
}
|
||||
var o1, o2 uint32
|
||||
if target.IsBigEndian() {
|
||||
o1 = uint32(val >> 32)
|
||||
o2 = uint32(val)
|
||||
} else {
|
||||
o1 = uint32(val)
|
||||
o2 = uint32(val >> 32)
|
||||
}
|
||||
|
||||
// We are spreading a 31-bit address across two instructions, putting the
|
||||
// high (adjusted) part in the low 16 bits of the first instruction and the
|
||||
// low part in the low 16 bits of the second instruction, or, in the DS case,
|
||||
// bits 15-2 (inclusive) of the address into bits 15-2 of the second
|
||||
// instruction (it is an error in this case if the low 2 bits of the address
|
||||
// are non-zero).
|
||||
o1, o2 := unpackInstPair(target, val)
|
||||
|
||||
// Verify resulting address fits within a 31 bit (2GB) address space.
|
||||
// This is a restriction arising from the usage of lis (HA) + d-form
|
||||
// (LO) instruction sequences used to implement absolute relocations
|
||||
// on PPC64 prior to ISA 3.1 (P10). For consistency, maintain this
|
||||
// restriction for ISA 3.1 unless it becomes problematic.
|
||||
t := ldr.SymAddr(rs) + r.Add()
|
||||
if t < 0 || t >= 1<<31 {
|
||||
ldr.Errorf(s, "relocation for %s is too big (>=2G): 0x%x", ldr.SymName(s), ldr.SymValue(rs))
|
||||
}
|
||||
if t&0x8000 != 0 {
|
||||
t += 0x10000
|
||||
}
|
||||
|
||||
switch r.Type() {
|
||||
case objabi.R_ADDRPOWER_PCREL34:
|
||||
// S + A - P
|
||||
t -= (ldr.SymValue(s) + int64(r.Off()))
|
||||
o1 |= computePrefix34HI(t)
|
||||
o2 |= computeLO(int32(t))
|
||||
case objabi.R_ADDRPOWER_D34:
|
||||
o1 |= computePrefix34HI(t)
|
||||
o2 |= computeLO(int32(t))
|
||||
case objabi.R_ADDRPOWER:
|
||||
o1 |= (uint32(t) >> 16) & 0xffff
|
||||
o2 |= uint32(t) & 0xffff
|
||||
o1 |= computeHA(int32(t))
|
||||
o2 |= computeLO(int32(t))
|
||||
case objabi.R_ADDRPOWER_DS:
|
||||
o1 |= (uint32(t) >> 16) & 0xffff
|
||||
o1 |= computeHA(int32(t))
|
||||
o2 |= computeLO(int32(t))
|
||||
if t&3 != 0 {
|
||||
ldr.Errorf(s, "bad DS reloc for %s: %d", ldr.SymName(s), ldr.SymValue(rs))
|
||||
}
|
||||
o2 |= uint32(t) & 0xfffc
|
||||
default:
|
||||
return -1
|
||||
}
|
||||
|
||||
if target.IsBigEndian() {
|
||||
return int64(o1)<<32 | int64(o2)
|
||||
}
|
||||
return int64(o2)<<32 | int64(o1)
|
||||
return packInstPair(target, o1, o2)
|
||||
}
|
||||
|
||||
// Determine if the code was compiled so that the TOC register R2 is initialized and maintained
|
||||
@ -1084,6 +1085,61 @@ func gentramp(ctxt *ld.Link, ldr *loader.Loader, tramp *loader.SymbolBuilder, ta
|
||||
tramp.SetData(P)
|
||||
}
|
||||
|
||||
// Unpack a pair of 32 bit instruction words from
|
||||
// a 64 bit relocation into instN and instN+1 in endian order.
|
||||
func unpackInstPair(target *ld.Target, r int64) (uint32, uint32) {
|
||||
if target.IsBigEndian() {
|
||||
return uint32(r >> 32), uint32(r)
|
||||
}
|
||||
return uint32(r), uint32(r >> 32)
|
||||
}
|
||||
|
||||
// Pack a pair of 32 bit instruction words o1, o2 into 64 bit relocation
|
||||
// in endian order.
|
||||
func packInstPair(target *ld.Target, o1, o2 uint32) int64 {
|
||||
if target.IsBigEndian() {
|
||||
return (int64(o1) << 32) | int64(o2)
|
||||
}
|
||||
return int64(o1) | (int64(o2) << 32)
|
||||
}
|
||||
|
||||
// Compute the high-adjusted value (always a signed 32b value) per the ELF ABI.
|
||||
// The returned value is always 0 <= x <= 0xFFFF.
|
||||
func computeHA(val int32) uint32 {
|
||||
return uint32(uint16((val + 0x8000) >> 16))
|
||||
}
|
||||
|
||||
// Compute the low value (the lower 16 bits of any 32b value) per the ELF ABI.
|
||||
// The returned value is always 0 <= x <= 0xFFFF.
|
||||
func computeLO(val int32) uint32 {
|
||||
return uint32(uint16(val))
|
||||
}
|
||||
|
||||
// Compute the high 18 bits of a signed 34b constant. Used to pack the high 18 bits
|
||||
// of a prefix34 relocation field. This assumes the input is already restricted to
|
||||
// 34 bits.
|
||||
func computePrefix34HI(val int64) uint32 {
|
||||
return uint32((val >> 16) & 0x3FFFF)
|
||||
}
|
||||
|
||||
func computeTLSLEReloc(target *ld.Target, ldr *loader.Loader, rs, s loader.Sym) int64 {
|
||||
// The thread pointer points 0x7000 bytes after the start of the
|
||||
// thread local storage area as documented in section "3.7.2 TLS
|
||||
// Runtime Handling" of "Power Architecture 64-Bit ELF V2 ABI
|
||||
// Specification".
|
||||
v := ldr.SymValue(rs) - 0x7000
|
||||
if target.IsAIX() {
|
||||
// On AIX, the thread pointer points 0x7800 bytes after
|
||||
// the TLS.
|
||||
v -= 0x800
|
||||
}
|
||||
|
||||
if int64(int32(v)) != v {
|
||||
ldr.Errorf(s, "TLS offset out of range %d", v)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loader.Reloc, s loader.Sym, val int64) (relocatedOffset int64, nExtReloc int, ok bool) {
|
||||
rs := r.Sym()
|
||||
if target.IsExternal() {
|
||||
@ -1094,7 +1150,7 @@ func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loade
|
||||
if !target.IsAIX() {
|
||||
return val, nExtReloc, false
|
||||
}
|
||||
case objabi.R_POWER_TLS:
|
||||
case objabi.R_POWER_TLS, objabi.R_POWER_TLS_IE_PCREL34, objabi.R_POWER_TLS_LE_TPREL34:
|
||||
nExtReloc = 1
|
||||
return val, nExtReloc, true
|
||||
case objabi.R_POWER_TLS_LE, objabi.R_POWER_TLS_IE:
|
||||
@ -1125,7 +1181,7 @@ func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loade
|
||||
if !target.IsAIX() {
|
||||
return val, nExtReloc, true
|
||||
}
|
||||
case objabi.R_CALLPOWER:
|
||||
case objabi.R_CALLPOWER, objabi.R_ADDRPOWER_D34, objabi.R_ADDRPOWER_PCREL34:
|
||||
nExtReloc = 1
|
||||
if !target.IsAIX() {
|
||||
return val, nExtReloc, true
|
||||
@ -1136,7 +1192,7 @@ func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loade
|
||||
switch r.Type() {
|
||||
case objabi.R_ADDRPOWER_TOCREL, objabi.R_ADDRPOWER_TOCREL_DS:
|
||||
return archreloctoc(ldr, target, syms, r, s, val), nExtReloc, true
|
||||
case objabi.R_ADDRPOWER, objabi.R_ADDRPOWER_DS:
|
||||
case objabi.R_ADDRPOWER, objabi.R_ADDRPOWER_DS, objabi.R_ADDRPOWER_D34, objabi.R_ADDRPOWER_PCREL34:
|
||||
return archrelocaddr(ldr, target, syms, r, s, val), nExtReloc, true
|
||||
case objabi.R_CALLPOWER:
|
||||
// Bits 6 through 29 = (S + A - P) >> 2
|
||||
@ -1169,16 +1225,10 @@ func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loade
|
||||
|
||||
case objabi.R_ADDRPOWER_PCREL: // S + A - P
|
||||
t := ldr.SymValue(rs) + r.Add() - (ldr.SymValue(s) + int64(r.Off()))
|
||||
ha := uint16(((t + 0x8000) >> 16) & 0xFFFF)
|
||||
l := uint16(t)
|
||||
if target.IsBigEndian() {
|
||||
val |= int64(l)
|
||||
val |= int64(ha) << 32
|
||||
} else {
|
||||
val |= int64(ha)
|
||||
val |= int64(l) << 32
|
||||
}
|
||||
return val, nExtReloc, true
|
||||
ha, l := unpackInstPair(target, val)
|
||||
l |= computeLO(int32(t))
|
||||
ha |= computeHA(int32(t))
|
||||
return packInstPair(target, ha, l), nExtReloc, true
|
||||
|
||||
case objabi.R_POWER_TLS:
|
||||
const OP_ADD = 31<<26 | 266<<1
|
||||
@ -1210,50 +1260,48 @@ func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loade
|
||||
const OP_ADDI = 14 << 26
|
||||
const OP_MASK = 0x3F << 26
|
||||
const OP_RA_MASK = 0x1F << 16
|
||||
uval := uint64(val)
|
||||
// convert r2 to r0, and ld to addi
|
||||
if target.IsBigEndian() {
|
||||
uval = uval &^ (OP_RA_MASK << 32)
|
||||
uval = (uval &^ OP_MASK) | OP_ADDI
|
||||
} else {
|
||||
uval = uval &^ (OP_RA_MASK)
|
||||
uval = (uval &^ (OP_MASK << 32)) | (OP_ADDI << 32)
|
||||
}
|
||||
val = int64(uval)
|
||||
// Treat this like an R_POWER_TLS_LE relocation now.
|
||||
mask := packInstPair(target, OP_RA_MASK, OP_MASK)
|
||||
addi_op := packInstPair(target, 0, OP_ADDI)
|
||||
val &^= mask
|
||||
val |= addi_op
|
||||
fallthrough
|
||||
|
||||
case objabi.R_POWER_TLS_LE:
|
||||
// The thread pointer points 0x7000 bytes after the start of the
|
||||
// thread local storage area as documented in section "3.7.2 TLS
|
||||
// Runtime Handling" of "Power Architecture 64-Bit ELF V2 ABI
|
||||
// Specification".
|
||||
v := ldr.SymValue(rs) - 0x7000
|
||||
if target.IsAIX() {
|
||||
// On AIX, the thread pointer points 0x7800 bytes after
|
||||
// the TLS.
|
||||
v -= 0x800
|
||||
v := computeTLSLEReloc(target, ldr, rs, s)
|
||||
o1, o2 := unpackInstPair(target, val)
|
||||
o1 |= computeHA(int32(v))
|
||||
o2 |= computeLO(int32(v))
|
||||
return packInstPair(target, o1, o2), nExtReloc, true
|
||||
|
||||
case objabi.R_POWER_TLS_IE_PCREL34:
|
||||
// Convert TLS_IE relocation to TLS_LE if supported.
|
||||
if !(target.IsPIE() && target.IsElf()) {
|
||||
log.Fatalf("cannot handle R_POWER_TLS_IE (sym %s) when linking non-PIE, non-ELF binaries internally", ldr.SymName(s))
|
||||
}
|
||||
|
||||
var o1, o2 uint32
|
||||
if int64(int32(v)) != v {
|
||||
ldr.Errorf(s, "TLS offset out of range %d", v)
|
||||
}
|
||||
if target.IsBigEndian() {
|
||||
o1 = uint32(val >> 32)
|
||||
o2 = uint32(val)
|
||||
} else {
|
||||
o1 = uint32(val)
|
||||
o2 = uint32(val >> 32)
|
||||
}
|
||||
// We are an ELF binary, we can safely convert to TLS_LE_TPREL34 from:
|
||||
// pld rX, x@got@tprel@pcrel
|
||||
//
|
||||
// to TLS_LE_TPREL32 by converting to:
|
||||
// pla rX, x@tprel
|
||||
|
||||
o1 |= uint32(((v + 0x8000) >> 16) & 0xFFFF)
|
||||
o2 |= uint32(v & 0xFFFF)
|
||||
const OP_MASK_PFX = 0xFFFFFFFF // Discard prefix word
|
||||
const OP_MASK = (0x3F << 26) | 0xFFFF // Preserve RT, RA
|
||||
const OP_PFX = 1<<26 | 2<<24
|
||||
const OP_PLA = 14 << 26
|
||||
mask := packInstPair(target, OP_MASK_PFX, OP_MASK)
|
||||
pla_op := packInstPair(target, OP_PFX, OP_PLA)
|
||||
val &^= mask
|
||||
val |= pla_op
|
||||
fallthrough
|
||||
|
||||
if target.IsBigEndian() {
|
||||
return int64(o1)<<32 | int64(o2), nExtReloc, true
|
||||
}
|
||||
return int64(o2)<<32 | int64(o1), nExtReloc, true
|
||||
case objabi.R_POWER_TLS_LE_TPREL34:
|
||||
v := computeTLSLEReloc(target, ldr, rs, s)
|
||||
o1, o2 := unpackInstPair(target, val)
|
||||
o1 |= computePrefix34HI(v)
|
||||
o2 |= computeLO(int32(v))
|
||||
return packInstPair(target, o1, o2), nExtReloc, true
|
||||
}
|
||||
|
||||
return val, nExtReloc, false
|
||||
@ -1354,14 +1402,16 @@ overflow:
|
||||
|
||||
func extreloc(target *ld.Target, ldr *loader.Loader, r loader.Reloc, s loader.Sym) (loader.ExtReloc, bool) {
|
||||
switch r.Type() {
|
||||
case objabi.R_POWER_TLS, objabi.R_POWER_TLS_LE, objabi.R_POWER_TLS_IE, objabi.R_CALLPOWER:
|
||||
case objabi.R_POWER_TLS, objabi.R_POWER_TLS_LE, objabi.R_POWER_TLS_IE, objabi.R_POWER_TLS_IE_PCREL34, objabi.R_POWER_TLS_LE_TPREL34, objabi.R_CALLPOWER:
|
||||
return ld.ExtrelocSimple(ldr, r), true
|
||||
case objabi.R_ADDRPOWER,
|
||||
objabi.R_ADDRPOWER_DS,
|
||||
objabi.R_ADDRPOWER_TOCREL,
|
||||
objabi.R_ADDRPOWER_TOCREL_DS,
|
||||
objabi.R_ADDRPOWER_GOT,
|
||||
objabi.R_ADDRPOWER_PCREL:
|
||||
objabi.R_ADDRPOWER_PCREL,
|
||||
objabi.R_ADDRPOWER_D34,
|
||||
objabi.R_ADDRPOWER_PCREL34:
|
||||
return ld.ExtrelocViaOuterSym(ldr, r, s), true
|
||||
}
|
||||
return loader.ExtReloc{}, false
|
||||
|
Loading…
Reference in New Issue
Block a user