forked from OSchip/llvm-project
[PPC32] Support GD/LD/IE/LE TLS models and their relaxations
Reviewed By: ruiu Differential Revision: https://reviews.llvm.org/D62940 llvm-svn: 362722
This commit is contained in:
parent
82442adfc0
commit
7ccfdad7ab
|
@ -39,12 +39,27 @@ public:
|
|||
RelExpr getRelExpr(RelType Type, const Symbol &S,
|
||||
const uint8_t *Loc) const override;
|
||||
void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
|
||||
RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data,
|
||||
RelExpr Expr) const override;
|
||||
int getTlsGdRelaxSkip(RelType Type) const override;
|
||||
void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
|
||||
void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
|
||||
void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
|
||||
void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
static uint16_t lo(uint32_t V) { return V; }
|
||||
static uint16_t ha(uint32_t V) { return (V + 0x8000) >> 16; }
|
||||
|
||||
static uint32_t readFromHalf16(const uint8_t *Loc) {
|
||||
return read32(Loc - (Config->EKind == ELF32BEKind ? 2 : 0));
|
||||
}
|
||||
|
||||
static void writeFromHalf16(uint8_t *Loc, uint32_t Insn) {
|
||||
write32(Loc - (Config->EKind == ELF32BEKind ? 2 : 0), Insn);
|
||||
}
|
||||
|
||||
void elf::writePPC32GlinkSection(uint8_t *Buf, size_t NumEntries) {
|
||||
// On PPC Secure PLT ABI, bl foo@plt jumps to a call stub, which loads an
|
||||
// absolute address from a specific .plt slot (usually called .got.plt on
|
||||
|
@ -128,6 +143,10 @@ PPC::PPC() {
|
|||
|
||||
NeedsThunks = true;
|
||||
|
||||
TlsModuleIndexRel = R_PPC_DTPMOD32;
|
||||
TlsOffsetRel = R_PPC_DTPREL32;
|
||||
TlsGotRel = R_PPC_TPREL32;
|
||||
|
||||
DefaultMaxPageSize = 65536;
|
||||
DefaultImageBase = 0x10000000;
|
||||
|
||||
|
@ -169,6 +188,12 @@ bool PPC::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const {
|
|||
RelExpr PPC::getRelExpr(RelType Type, const Symbol &S,
|
||||
const uint8_t *Loc) const {
|
||||
switch (Type) {
|
||||
case R_PPC_DTPREL16:
|
||||
case R_PPC_DTPREL16_HA:
|
||||
case R_PPC_DTPREL16_HI:
|
||||
case R_PPC_DTPREL16_LO:
|
||||
case R_PPC_DTPREL32:
|
||||
return R_DTPREL;
|
||||
case R_PPC_REL14:
|
||||
case R_PPC_REL32:
|
||||
case R_PPC_LOCAL24PC:
|
||||
|
@ -182,28 +207,84 @@ RelExpr PPC::getRelExpr(RelType Type, const Symbol &S,
|
|||
return R_PLT_PC;
|
||||
case R_PPC_PLTREL24:
|
||||
return R_PPC32_PLTREL;
|
||||
case R_PPC_GOT_TLSGD16:
|
||||
return R_TLSGD_GOT;
|
||||
case R_PPC_GOT_TLSLD16:
|
||||
return R_TLSLD_GOT;
|
||||
case R_PPC_GOT_TPREL16:
|
||||
return R_GOT_OFF;
|
||||
case R_PPC_TLS:
|
||||
return R_TLSIE_HINT;
|
||||
case R_PPC_TLSGD:
|
||||
return R_TLSDESC_CALL;
|
||||
case R_PPC_TLSLD:
|
||||
return R_TLSLD_HINT;
|
||||
case R_PPC_TPREL16:
|
||||
case R_PPC_TPREL16_HA:
|
||||
case R_PPC_TPREL16_LO:
|
||||
case R_PPC_TPREL16_HI:
|
||||
return R_TLS;
|
||||
default:
|
||||
return R_ABS;
|
||||
}
|
||||
}
|
||||
|
||||
void PPC::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
|
||||
static std::pair<RelType, uint64_t> fromDTPREL(RelType Type, uint64_t Val) {
|
||||
uint64_t DTPBiasedVal = Val - 0x8000;
|
||||
switch (Type) {
|
||||
case R_PPC_DTPREL16:
|
||||
return {R_PPC64_ADDR16, DTPBiasedVal};
|
||||
case R_PPC_DTPREL16_HA:
|
||||
return {R_PPC_ADDR16_HA, DTPBiasedVal};
|
||||
case R_PPC_DTPREL16_HI:
|
||||
return {R_PPC_ADDR16_HI, DTPBiasedVal};
|
||||
case R_PPC_DTPREL16_LO:
|
||||
return {R_PPC_ADDR16_LO, DTPBiasedVal};
|
||||
case R_PPC_DTPREL32:
|
||||
return {R_PPC_ADDR32, DTPBiasedVal};
|
||||
default:
|
||||
return {Type, Val};
|
||||
}
|
||||
}
|
||||
|
||||
void PPC::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
|
||||
RelType NewType;
|
||||
std::tie(NewType, Val) = fromDTPREL(Type, Val);
|
||||
switch (NewType) {
|
||||
case R_PPC_ADDR16:
|
||||
case R_PPC_GOT16:
|
||||
case R_PPC_GOT_TLSGD16:
|
||||
case R_PPC_GOT_TLSLD16:
|
||||
case R_PPC_GOT_TPREL16:
|
||||
case R_PPC_TPREL16:
|
||||
checkInt(Loc, Val, 16, Type);
|
||||
write16(Loc, Val);
|
||||
break;
|
||||
case R_PPC_ADDR16_HA:
|
||||
case R_PPC_DTPREL16_HA:
|
||||
case R_PPC_GOT_TLSGD16_HA:
|
||||
case R_PPC_GOT_TLSLD16_HA:
|
||||
case R_PPC_GOT_TPREL16_HA:
|
||||
case R_PPC_REL16_HA:
|
||||
case R_PPC_TPREL16_HA:
|
||||
write16(Loc, ha(Val));
|
||||
break;
|
||||
case R_PPC_ADDR16_HI:
|
||||
case R_PPC_DTPREL16_HI:
|
||||
case R_PPC_GOT_TLSGD16_HI:
|
||||
case R_PPC_GOT_TLSLD16_HI:
|
||||
case R_PPC_GOT_TPREL16_HI:
|
||||
case R_PPC_REL16_HI:
|
||||
case R_PPC_TPREL16_HI:
|
||||
write16(Loc, Val >> 16);
|
||||
break;
|
||||
case R_PPC_ADDR16_LO:
|
||||
case R_PPC_DTPREL16_LO:
|
||||
case R_PPC_GOT_TLSGD16_LO:
|
||||
case R_PPC_GOT_TLSLD16_LO:
|
||||
case R_PPC_GOT_TPREL16_LO:
|
||||
case R_PPC_REL16_LO:
|
||||
case R_PPC_TPREL16_LO:
|
||||
write16(Loc, Val);
|
||||
break;
|
||||
case R_PPC_ADDR32:
|
||||
|
@ -232,6 +313,109 @@ void PPC::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
|
|||
}
|
||||
}
|
||||
|
||||
RelExpr PPC::adjustRelaxExpr(RelType Type, const uint8_t *Data,
|
||||
RelExpr Expr) const {
|
||||
if (Expr == R_RELAX_TLS_GD_TO_IE)
|
||||
return R_RELAX_TLS_GD_TO_IE_GOT_OFF;
|
||||
if (Expr == R_RELAX_TLS_LD_TO_LE)
|
||||
return R_RELAX_TLS_LD_TO_LE_ABS;
|
||||
return Expr;
|
||||
}
|
||||
|
||||
int PPC::getTlsGdRelaxSkip(RelType Type) const {
|
||||
// A __tls_get_addr call instruction is marked with 2 relocations:
|
||||
//
|
||||
// R_PPC_TLSGD / R_PPC_TLSLD: marker relocation
|
||||
// R_PPC_REL24: __tls_get_addr
|
||||
//
|
||||
// After the relaxation we no longer call __tls_get_addr and should skip both
|
||||
// relocations to not create a false dependence on __tls_get_addr being
|
||||
// defined.
|
||||
if (Type == R_PPC_TLSGD || Type == R_PPC_TLSLD)
|
||||
return 2;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void PPC::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const {
|
||||
switch (Type) {
|
||||
case R_PPC_GOT_TLSGD16: {
|
||||
// addi rT, rA, x@got@tlsgd --> lwz rT, x@got@tprel(rA)
|
||||
uint32_t Insn = readFromHalf16(Loc);
|
||||
writeFromHalf16(Loc, 0x80000000 | (Insn & 0x03ff0000));
|
||||
relocateOne(Loc, R_PPC_GOT_TPREL16, Val);
|
||||
break;
|
||||
}
|
||||
case R_PPC_TLSGD:
|
||||
// bl __tls_get_addr(x@tldgd) --> add r3, r3, r2
|
||||
write32(Loc, 0x7c631214);
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("unsupported relocation for TLS GD to IE relaxation");
|
||||
}
|
||||
}
|
||||
|
||||
void PPC::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
|
||||
switch (Type) {
|
||||
case R_PPC_GOT_TLSGD16:
|
||||
// addi r3, r31, x@got@tlsgd --> addis r3, r2, x@tprel@ha
|
||||
writeFromHalf16(Loc, 0x3c620000 | ha(Val));
|
||||
break;
|
||||
case R_PPC_TLSGD:
|
||||
// bl __tls_get_addr(x@tldgd) --> add r3, r3, x@tprel@l
|
||||
write32(Loc, 0x38630000 | lo(Val));
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("unsupported relocation for TLS GD to LE relaxation");
|
||||
}
|
||||
}
|
||||
|
||||
void PPC::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
|
||||
switch (Type) {
|
||||
case R_PPC_GOT_TLSLD16:
|
||||
// addi r3, rA, x@got@tlsgd --> addis r3, r2, 0
|
||||
writeFromHalf16(Loc, 0x3c620000);
|
||||
break;
|
||||
case R_PPC_TLSLD:
|
||||
// r3+x@dtprel computes r3+x-0x8000, while we want it to compute r3+x@tprel
|
||||
// = r3+x-0x7000, so add 4096 to r3.
|
||||
// bl __tls_get_addr(x@tlsld) --> addi r3, r3, 4096
|
||||
write32(Loc, 0x38631000);
|
||||
break;
|
||||
case R_PPC_DTPREL16:
|
||||
case R_PPC_DTPREL16_HA:
|
||||
case R_PPC_DTPREL16_HI:
|
||||
case R_PPC_DTPREL16_LO:
|
||||
relocateOne(Loc, Type, Val);
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("unsupported relocation for TLS LD to LE relaxation");
|
||||
}
|
||||
}
|
||||
|
||||
void PPC::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
|
||||
switch (Type) {
|
||||
case R_PPC_GOT_TPREL16: {
|
||||
// lwz rT, x@got@tprel(rA) --> addis rT, r2, x@tprel@ha
|
||||
uint32_t RT = readFromHalf16(Loc) & 0x03e00000;
|
||||
writeFromHalf16(Loc, 0x3c020000 | RT | ha(Val));
|
||||
break;
|
||||
}
|
||||
case R_PPC_TLS: {
|
||||
uint32_t Insn = read32(Loc);
|
||||
if (Insn >> 26 != 31)
|
||||
error("unrecognized instruction for IE to LE R_PPC_TLS");
|
||||
// addi rT, rT, x@tls --> addi rT, rT, x@tprel@l
|
||||
uint32_t DFormOp = getPPCDFormOp((read32(Loc) & 0x000007fe) >> 1);
|
||||
if (DFormOp == 0)
|
||||
error("unrecognized instruction for IE to LE R_PPC_TLS");
|
||||
write32(Loc, (DFormOp << 26) | (Insn & 0x03ff0000) | lo(Val));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
llvm_unreachable("unsupported relocation for TLS IE to LE relaxation");
|
||||
}
|
||||
}
|
||||
|
||||
TargetInfo *elf::getPPCTargetInfo() {
|
||||
static PPC Target;
|
||||
return &Target;
|
||||
|
|
|
@ -452,7 +452,7 @@ void PPC64::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
|
|||
}
|
||||
}
|
||||
|
||||
static unsigned getDFormOp(unsigned SecondaryOp) {
|
||||
unsigned elf::getPPCDFormOp(unsigned SecondaryOp) {
|
||||
switch (SecondaryOp) {
|
||||
case LBZX:
|
||||
return LBZ;
|
||||
|
@ -473,7 +473,6 @@ static unsigned getDFormOp(unsigned SecondaryOp) {
|
|||
case ADD:
|
||||
return ADDI;
|
||||
default:
|
||||
error("unrecognized instruction for IE to LE R_PPC64_TLS");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -515,7 +514,9 @@ void PPC64::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
|
|||
if (PrimaryOp != 31)
|
||||
error("unrecognized instruction for IE to LE R_PPC64_TLS");
|
||||
uint32_t SecondaryOp = (read32(Loc) & 0x000007FE) >> 1; // bits 21-30
|
||||
uint32_t DFormOp = getDFormOp(SecondaryOp);
|
||||
uint32_t DFormOp = getPPCDFormOp(SecondaryOp);
|
||||
if (DFormOp == 0)
|
||||
error("unrecognized instruction for IE to LE R_PPC64_TLS");
|
||||
write32(Loc, ((DFormOp << 26) | (read32(Loc) & 0x03FFFFFF)));
|
||||
relocateOne(Loc + Offset, R_PPC64_TPREL16_LO, Val);
|
||||
break;
|
||||
|
|
|
@ -611,6 +611,7 @@ static int64_t getTlsTpOffset(const Symbol &S) {
|
|||
case EM_X86_64:
|
||||
// Variant 2. The TLS segment is located just before the thread pointer.
|
||||
return S.getVA(0) - alignTo(Out::TlsPhdr->p_memsz, Out::TlsPhdr->p_align);
|
||||
case EM_PPC:
|
||||
case EM_PPC64:
|
||||
// The thread pointer points to a fixed offset from the start of the
|
||||
// executable's TLS segment. An offset of 0x7000 allows a signed 16-bit
|
||||
|
|
|
@ -166,6 +166,7 @@ void writePPC32GlinkSection(uint8_t *Buf, size_t NumEntries);
|
|||
|
||||
bool tryRelaxPPC64TocIndirection(RelType Type, const Relocation &Rel,
|
||||
uint8_t *BufLoc);
|
||||
unsigned getPPCDFormOp(unsigned SecondaryOp);
|
||||
|
||||
// In the PowerPC64 Elf V2 abi a function can have 2 entry points. The first
|
||||
// is a global entry point (GEP) which typically is used to initialize the TOC
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
# REQUIES: ppc
|
||||
# RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o
|
||||
# RUN: echo '.tbss; .globl b, c; b: .zero 4; c:' | llvm-mc -filetype=obj -triple=powerpc - -o %t1.o
|
||||
# RUN: ld.lld -shared -soname=t1.so %t1.o -o %t1.so
|
||||
# RUN: echo '.globl __tls_get_addr; __tls_get_addr:' | llvm-mc -filetype=obj -triple=powerpc - -o %tga.o
|
||||
|
||||
# RUN: ld.lld -shared %t.o %t1.o -o %t.so
|
||||
# RUN: llvm-readobj -d %t.so | FileCheck --check-prefix=GD-DYN %s
|
||||
# RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=GD-REL %s
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck --check-prefix=GD %s
|
||||
|
||||
# RUN: ld.lld %t.o %t1.o %tga.o -o %t
|
||||
# RUN: llvm-readelf -r %t | FileCheck --check-prefix=NOREL %s
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=LE %s
|
||||
|
||||
# RUN: ld.lld %t.o %t1.so -o %t
|
||||
# RUN: llvm-readobj -r %t | FileCheck --check-prefix=IE-REL %s
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=IE %s
|
||||
|
||||
## DT_PPC_GOT represents the address of _GLOBAL_OFFSET_TABLE_.
|
||||
# GD-DYN: PPC_GOT 0x20078
|
||||
|
||||
# GD-REL: .rela.dyn {
|
||||
# GD-REL-NEXT: 0x20078 R_PPC_DTPMOD32 a 0x0
|
||||
# GD-REL-NEXT: 0x2007C R_PPC_DTPREL32 a 0x0
|
||||
# GD-REL-NEXT: 0x20080 R_PPC_DTPMOD32 b 0x0
|
||||
# GD-REL-NEXT: 0x20084 R_PPC_DTPREL32 b 0x0
|
||||
# GD-REL-NEXT: 0x20088 R_PPC_DTPMOD32 c 0x0
|
||||
# GD-REL-NEXT: 0x2008C R_PPC_DTPREL32 c 0x0
|
||||
# GD-REL-NEXT: }
|
||||
|
||||
## &DTPMOD(a) - _GLOBAL_OFFSET_TABLE_ = 0x20078 - 0x20078 = 0
|
||||
# GD: addi 3, 31, 0
|
||||
# GD-NEXT: bl .+32
|
||||
# GD-NEXT: lwz 3, 0(3)
|
||||
|
||||
## &DTPMOD(b) - _GLOBAL_OFFSET_TABLE_ = 0x20080 - 0x20078 = 8
|
||||
# GD-NEXT: addi 3, 31, 8
|
||||
# GD-NEXT: bl .+20
|
||||
# GD-NEXT: lwz 3, 0(3)
|
||||
|
||||
## &DTPMOD(c) - _GLOBAL_OFFSET_TABLE_ = 0x20088 - 0x20078 = 16
|
||||
# GD-NEXT: addi 3, 9, 16
|
||||
# GD-NEXT: bl .+8
|
||||
# GD-NEXT: lwz 3, 0(3)
|
||||
|
||||
# NOREL: no relocations
|
||||
|
||||
## a@tprel = 8-0x7000 = -28664
|
||||
# LE: addis 3, 2, 0
|
||||
# LE-NEXT: addi 3, 3, -28664
|
||||
# LE-NEXT: lwz 3, 0(3)
|
||||
## b@tprel = 12-0x7000 = -28660
|
||||
# LE-NEXT: addis 3, 2, 0
|
||||
# LE-NEXT: addi 3, 3, -28660
|
||||
# LE-NEXT: lwz 3, 0(3)
|
||||
## c@tprel = 16-0x7000 = -28656
|
||||
# LE-NEXT: addis 3, 2, 0
|
||||
# LE-NEXT: addi 3, 3, -28656
|
||||
# LE-NEXT: lwz 3, 0(3)
|
||||
|
||||
# IE-REL: .rela.dyn {
|
||||
# IE-REL-NEXT: 0x10020068 R_PPC_TPREL32 b 0x0
|
||||
# IE-REL-NEXT: 0x1002006C R_PPC_TPREL32 c 0x0
|
||||
# IE-REL-NEXT: }
|
||||
|
||||
## a is relaxed to use LE.
|
||||
## a@tprel = st_value(a)-0x8000 = -28664
|
||||
# IE: addis 3, 2, 0
|
||||
# IE-NEXT: addi 3, 3, -28664
|
||||
# IE-NEXT: lwz 3, 0(3)
|
||||
## &.got[0] - _GLOBAL_OFFSET_TABLE_ = 0
|
||||
# IE-NEXT: lwz 3, 0(31)
|
||||
# IE-NEXT: add 3, 3, 2
|
||||
# IE-NEXT: lwz 3, 0(3)
|
||||
## &.got[1] - _GLOBAL_OFFSET_TABLE_ = 4
|
||||
# IE-NEXT: lwz 3, 4(9)
|
||||
# IE-NEXT: add 3, 3, 2
|
||||
# IE-NEXT: lwz 3, 0(3)
|
||||
|
||||
addi 3, 31, a@got@tlsgd
|
||||
bl __tls_get_addr(a@tlsgd)
|
||||
lwz 3, 0(3)
|
||||
|
||||
addi 3, 31, b@got@tlsgd
|
||||
bl __tls_get_addr(b@tlsgd)
|
||||
lwz 3, 0(3)
|
||||
|
||||
## -fpic may use a different register (e.g. r9).
|
||||
addi 3, 9, c@got@tlsgd
|
||||
bl __tls_get_addr(c@tlsgd)
|
||||
lwz 3, 0(3)
|
||||
|
||||
.section .tbss
|
||||
.globl a
|
||||
.zero 8
|
||||
a:
|
||||
.zero 4
|
|
@ -0,0 +1,67 @@
|
|||
# REQUIES: ppc
|
||||
# RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o
|
||||
|
||||
# RUN: ld.lld -shared %t.o -o %t.so
|
||||
# RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=IE-REL %s
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck --check-prefix=IE %s
|
||||
|
||||
# RUN: ld.lld %t.o -o %t
|
||||
# RUN: llvm-readelf -r %t | FileCheck --check-prefix=NOREL %s
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=LE %s
|
||||
|
||||
## A non-preemptable symbol (b) has 0 st_shndx.
|
||||
# IE-REL: .rela.dyn {
|
||||
# IE-REL-NEXT: 0x2005C R_PPC_TPREL32 - 0xC
|
||||
# IE-REL-NEXT: 0x20058 R_PPC_TPREL32 a 0x0
|
||||
# IE-REL-NEXT: }
|
||||
|
||||
## &.got[0] - _GLOBAL_OFFSET_TABLE_ = 0
|
||||
# IE: lwz 10, 0(9)
|
||||
# IE-NEXT: add 10, 10, 2
|
||||
## &.got[1] - _GLOBAL_OFFSET_TABLE_ = 4
|
||||
# IE-NEXT: lwz 8, 4(7)
|
||||
# IE-NEXT: lbzx 10, 8, 2
|
||||
|
||||
# NOREL: no relocations
|
||||
|
||||
## a@tprel = st_value(a)-0x7000 = -28664
|
||||
## b@tprel = st_value(b)-0x7000 = -28660
|
||||
# LE: addis 10, 2, 0
|
||||
# LE-NEXT: addi 10, 10, -28664
|
||||
# LE-NEXT: addis 8, 2, 0
|
||||
# LE-NEXT: lbz 10, -28660(8)
|
||||
|
||||
lwz 10, a@got@tprel(9)
|
||||
add 10, 10, a@tls
|
||||
|
||||
lwz 8, c@got@tprel(7)
|
||||
lbzx 10, 8, c@tls
|
||||
|
||||
## In IE, these instructions (op rT, rA, x@tls) are not changed.
|
||||
# IE-NEXT: lhzx 12, 2, 2
|
||||
# IE-NEXT: lwzx 13, 3, 2
|
||||
# IE-NEXT: stbx 14, 4, 2
|
||||
# IE-NEXT: sthx 15, 5, 2
|
||||
# IE-NEXT: stwx 16, 6, 2
|
||||
|
||||
## In LE, these X-Form instructions are changed to their corresponding D-Form.
|
||||
# LE-NEXT: lhz 12, -28660(2)
|
||||
# LE-NEXT: lwz 13, -28660(3)
|
||||
# LE-NEXT: stb 14, -28660(4)
|
||||
# LE-NEXT: sth 15, -28660(5)
|
||||
# LE-NEXT: stw 16, -28660(6)
|
||||
|
||||
lhzx 12, 2, s@tls
|
||||
lwzx 13, 3, i@tls
|
||||
stbx 14, 4, c@tls
|
||||
sthx 15, 5, s@tls
|
||||
stwx 16, 6, i@tls
|
||||
|
||||
.section .tbss
|
||||
.globl a
|
||||
.zero 8
|
||||
a:
|
||||
.zero 4
|
||||
c:
|
||||
s:
|
||||
i:
|
|
@ -0,0 +1,82 @@
|
|||
# REQUIRES: ppc
|
||||
# RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o
|
||||
# RUN: echo '.globl __tls_get_addr; __tls_get_addr:' | llvm-mc -filetype=obj -triple=powerpc - -o %tga.o
|
||||
|
||||
# RUN: ld.lld -shared %t.o -o %t.so
|
||||
# RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=LD-REL %s
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck --check-prefix=LD %s
|
||||
|
||||
# RUN: ld.lld %t.o %tga.o -o %t
|
||||
# RUN: llvm-readelf -r %t | FileCheck --check-prefix=NOREL %s
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=LE %s
|
||||
|
||||
# LD-REL: .rela.dyn {
|
||||
# LD-REL-NEXT: 0x20078 R_PPC_DTPMOD32 - 0x0
|
||||
# LD-REL-NEXT: }
|
||||
|
||||
## .got - _GLOBAL_OFFSET_TABLE_ = 0
|
||||
# LD: addi 3, 30, 0
|
||||
# LD-NEXT: bl .+40
|
||||
## a@dtprel = st_value(a)-0x8000 = 65540-0x8000 = 65536*1-32764
|
||||
## b@dtprel = st_value(a)-0x8000 = 131080-0x8000 = 65536*2-32760
|
||||
# LD-NEXT: addis 9, 3, 1
|
||||
# LD-NEXT: addis 10, 3, 2
|
||||
# LD-NEXT: addi 9, 9, -32764
|
||||
# LD-NEXT: addi 10, 10, -32760
|
||||
## small@dtprel = st_value(small)-0x8000 = 4-0x8000 = -32764
|
||||
# LD-NEXT: addi 9, 3, -32764
|
||||
|
||||
## Check that b@got@tlsld does not allocate another GOT entry.
|
||||
## It shares In.Got->TlsIndexOff allocated when processing a@got@tlsld.
|
||||
## .got - _GLOBAL_OFFSET_TABLE_ = 0
|
||||
# LD-NEXT: addi 3, 9, 0
|
||||
# LD-NEXT: bl .+12
|
||||
## b@dtprel = st_value(a)-0x8000 = 131080-0x8000 = 65536*2-32760
|
||||
# LD-NEXT: addis 29, 3, 2
|
||||
# LD-NEXT: addi 29, 29, -32760
|
||||
|
||||
## When producing an executable, the LD code sequence can be relaxed to LE.
|
||||
## It is the same as GD->LE.
|
||||
## tpoff(_TLS_MODULE_BASE_) = 0, tpoff(a) = -8, tpoff(b) = -4
|
||||
|
||||
# NOREL: no relocations
|
||||
|
||||
## Set r3 to r2+4096
|
||||
# LE: addis 3, 2, 0
|
||||
# LE-NEXT: addi 3, 3, 4096
|
||||
## a@tprel = 65540-0x7000 = 65536*1-32764
|
||||
## b@tprel = 131080-0x7000 = 65536*2-32760
|
||||
# LE-NEXT: addis 9, 3, 1
|
||||
# LE-NEXT: addis 10, 3, 2
|
||||
# LE-NEXT: addi 9, 9, -32764
|
||||
# LE-NEXT: addi 10, 10, -32760
|
||||
## small@tprel = 4-0x7000 = -32764
|
||||
# LE-NEXT: addi 9, 3, -32764
|
||||
|
||||
## Set r3 to r2+4096
|
||||
# LE-NEXT: addis 3, 2, 0
|
||||
# LE-NEXT: addi 3, 3, 4096
|
||||
## b@tprel = 131080-0x7000 = 65536*2-32760
|
||||
# LE-NEXT: addis 29, 3, 2
|
||||
# LE-NEXT: addi 29, 29, -32760
|
||||
|
||||
addi 3, 30, a@got@tlsld
|
||||
bl __tls_get_addr(a@tlsld)
|
||||
addis 9, 3, a@dtprel@ha
|
||||
addis 10, 3, b@dtprel@ha
|
||||
addi 9, 9, a@dtprel@l
|
||||
addi 10, 10, b@dtprel@l
|
||||
addi 9, 3, small@dtprel
|
||||
|
||||
addi 3, 9, b@got@tlsld
|
||||
bl __tls_get_addr(b@tlsld)
|
||||
addis 29, 3, b@dtprel@ha
|
||||
addi 29, 29, b@dtprel@l
|
||||
|
||||
.section .tbss
|
||||
.zero 4
|
||||
small:
|
||||
.zero 65536
|
||||
a:
|
||||
.zero 65540
|
||||
b:
|
|
@ -0,0 +1,24 @@
|
|||
# REQUIES: ppc
|
||||
# RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o
|
||||
# RUN: ld.lld %t.o -o %t
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=LE %s
|
||||
|
||||
## a@tprel = st_value(a)-0x7000 = -28664
|
||||
## b@tprel = st_value(b)-0x7000 = -28660
|
||||
# LE: addis 9, 2, 0
|
||||
# LE-NEXT: addi 9, 9, -28664
|
||||
# LE-NEXT: addis 10, 2, 0
|
||||
# LE-NEXT: lwz 9, -28660(10)
|
||||
|
||||
addis 9, 2, a@tprel@ha
|
||||
addi 9, 9, a@tprel@l
|
||||
|
||||
addis 10, 2, b@tprel@ha
|
||||
lwz 9,b@tprel@l(10)
|
||||
|
||||
.section .tbss
|
||||
.globl a
|
||||
.zero 8
|
||||
a:
|
||||
.zero 4
|
||||
b:
|
Loading…
Reference in New Issue