Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 47 additions & 32 deletions lib/Target/AArch64/AArch64Relocator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
// SPDX-License-Identifier: BSD-3-Clause
//===----------------------------------------------------------------------===//


#include "AArch64Relocator.h"
#include "AArch64InsnHelpers.h"
#include "AArch64PLT.h"
Expand Down Expand Up @@ -52,8 +51,7 @@ static uint64_t getSigningSchema(const Relocation &pReloc) {
/// helper_DynRel - Get an relocation entry in .rela.dyn
Relocation *helper_DynRel_init(ELFObjectFile *Obj, Relocation *R,
ResolveInfo *pSym, Fragment *F, uint32_t pOffset,
Relocator::Type pType,
AArch64LDBackend &B) {
Relocator::Type pType, AArch64LDBackend &B) {
Relocation *rela_entry = nullptr;

if (pType == R_AARCH64_TLSDESC)
Expand Down Expand Up @@ -190,9 +188,8 @@ bool AArch64Relocator::relocNeedsDynRel(Relocation &pReloc) const {
pReloc.type() == llvm::ELF::R_AARCH64_ABS32 ||
pReloc.type() == llvm::ELF::R_AARCH64_ABS16 ||
pReloc.type() == llvm::ELF::R_AARCH64_AUTH_ABS64;
return getTarget().symbolNeedsDynRel(
*rsym, (rsym->reserved() & ReservePLT),
isAbsReloc);
return getTarget().symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT),
isAbsReloc);
}

Relocator::Result AArch64Relocator::applyRelocation(Relocation &pRelocation) {
Expand Down Expand Up @@ -252,12 +249,10 @@ void AArch64Relocator::scanLocalReloc(InputFile &pInput, Relocation &pReloc,
rsym->setReserved(rsym->reserved() | ReserveRel);
getTarget().checkAndSetHasTextRel(pSection);
// set up the dyn rel directly
Relocation::Type relType =
isAuthAbs ? llvm::ELF::R_AARCH64_AUTH_RELATIVE
: llvm::ELF::R_AARCH64_RELATIVE;
Relocation::Type relType = isAuthAbs ? llvm::ELF::R_AARCH64_AUTH_RELATIVE
: llvm::ELF::R_AARCH64_RELATIVE;
helper_DynRel_init(Obj, &pReloc, rsym, pReloc.targetRef()->frag(),
pReloc.targetRef()->offset(), relType,
m_Target);
pReloc.targetRef()->offset(), relType, m_Target);
}
}
return;
Expand Down Expand Up @@ -330,6 +325,14 @@ void AArch64Relocator::scanLocalReloc(InputFile &pInput, Relocation &pReloc,
G->setValueType(GOT::TLSStaticSymbolValue);
return;
}
if (config().options().isPIE()) {
// PIE executable: relax TLSDESC to IE
AArch64GOT *G = m_Target.createGOT(GOT::TLS_IE, Obj, rsym);
helper_DynRel_init(Obj, &pReloc, rsym, G, 0x0,
llvm::ELF::R_AARCH64_TLS_TPREL64, m_Target);
rsym->setReserved(rsym->reserved() | ReserveGOT);
return;
}
AArch64GOT *G = m_Target.createGOT(GOT::TLS_DESC, Obj, rsym);
helper_DynRel_init(Obj, &pReloc, rsym, G->getFirst(), 0x0,
llvm::ELF::R_AARCH64_TLSDESC, m_Target);
Expand Down Expand Up @@ -382,8 +385,8 @@ void AArch64Relocator::scanGlobalReloc(InputFile &pInput, Relocation &pReloc,
// for signed pointers"
if (isAuthAbs) {
config().raise(Diag::non_pic_relocation)
<< getName(pReloc.type()) << pReloc.symInfo()->name()
<< pReloc.getSourcePath(config().options());
<< getName(pReloc.type()) << pReloc.symInfo()->name()
<< pReloc.getSourcePath(config().options());
m_Target.getModule().setFailure(true);
return;
}
Expand All @@ -409,10 +412,8 @@ void AArch64Relocator::scanGlobalReloc(InputFile &pInput, Relocation &pReloc,
relType = isAuthAbs ? llvm::ELF::R_AARCH64_AUTH_RELATIVE
: llvm::ELF::R_AARCH64_RELATIVE;
}
helper_DynRel_init(
Obj, &pReloc, rsym, pReloc.targetRef()->frag(),
pReloc.targetRef()->offset(),
relType, m_Target);
helper_DynRel_init(Obj, &pReloc, rsym, pReloc.targetRef()->frag(),
pReloc.targetRef()->offset(), relType, m_Target);
}
}
}
Expand Down Expand Up @@ -562,6 +563,14 @@ void AArch64Relocator::scanGlobalReloc(InputFile &pInput, Relocation &pReloc,
G->setValueType(GOT::TLSStaticSymbolValue);
return;
}
if (config().options().isPIE()) {
// PIE executable: relax TLSDESC to IE
AArch64GOT *G = m_Target.createGOT(GOT::TLS_IE, Obj, rsym);
helper_DynRel_init(Obj, &pReloc, rsym, G, 0x0,
llvm::ELF::R_AARCH64_TLS_TPREL64, m_Target);
rsym->setReserved(rsym->reserved() | ReserveGOT);
return;
}
AArch64GOT *G = m_Target.createGOT(GOT::TLS_DESC, Obj, rsym);
helper_DynRel_init(Obj, &pReloc, rsym, G->getFirst(), 0x0,
llvm::ELF::R_AARCH64_TLSDESC, m_Target);
Expand Down Expand Up @@ -1023,7 +1032,8 @@ Relocator::Result ld64_got_lo12(Relocation &pReloc, AArch64Relocator &pParent) {
}

// R_AARCH64_LD64_GOTPAGE_LO15: G(GDAT(S)) - Page(GOT)
Relocator::Result ld64_gotpage_lo15(Relocation &pReloc, AArch64Relocator &pParent) {
Relocator::Result ld64_gotpage_lo15(Relocation &pReloc,
AArch64Relocator &pParent) {
if (!(pReloc.symInfo()->reserved() & Relocator::ReserveGOT)) {
return Relocator::BadReloc;
}
Expand Down Expand Up @@ -1148,7 +1158,8 @@ Relocator::Result tls_gottprel_page(Relocation &pReloc,
DiagnosticEngine *DiagEngine = pParent.config().getDiagEngine();
Relocator::DWord A = pReloc.addend();

if (!(pReloc.symInfo()->reserved() & Relocator::ReserveGOT)) {
if (!(pReloc.symInfo()->reserved() & Relocator::ReserveGOT) ||
pParent.config().isCodeStatic()) {
Relocator::DWord X =
pParent.getSymValue(&pReloc) + AArch64LDBackend::getStaticTCBSize();
// Convert to movz
Expand All @@ -1173,7 +1184,8 @@ Relocator::Result tls_gottprel_lo(Relocation &pReloc,
AArch64Relocator &pParent) {
Relocator::DWord A = pReloc.addend();

if (!(pReloc.symInfo()->reserved() & Relocator::ReserveGOT)) {
if (!(pReloc.symInfo()->reserved() & Relocator::ReserveGOT) ||
pParent.config().isCodeStatic()) {
Relocator::DWord X =
pParent.getSymValue(&pReloc) + AArch64LDBackend::getStaticTCBSize();
// Convert to movk
Expand Down Expand Up @@ -1216,7 +1228,8 @@ Relocator::Result tls_tlsdesc_page(Relocation &pReloc,
AArch64Relocator &pParent) {
Relocator::DWord A = pReloc.addend();

if (!(pReloc.symInfo()->reserved() & Relocator::ReserveGOT)) {
if (!(pReloc.symInfo()->reserved() & Relocator::ReserveGOT) ||
pParent.config().isCodeStatic()) {
Relocator::DWord X =
pParent.getSymValue(&pReloc) + AArch64LDBackend::getStaticTCBSize();
// Convert to movz
Expand All @@ -1241,34 +1254,36 @@ Relocator::Result tls_tlsdesc_page(Relocation &pReloc,
Relocator::Result tls_tlsdesc_lo(Relocation &pReloc,
AArch64Relocator &pParent) {
Relocator::DWord A = pReloc.addend();

if (!(pReloc.symInfo()->reserved() & Relocator::ReserveGOT)) {
if (!(pReloc.symInfo()->reserved() & Relocator::ReserveGOT) ||
pParent.config().isCodeStatic()) {
Relocator::DWord X =
pParent.getSymValue(&pReloc) + AArch64LDBackend::getStaticTCBSize();
// Convert to movk, save to x0
uint32_t movk = 0xF2800000;
pReloc.target() = helper_reencode_movzk_imm(movk, X);
return Relocator::OK;
}

if (pParent.config().options().isPIE()) {
uint32_t insn = 0xF9400000; // ldr x0, [x0, #0]
Relocator::Address GOT_S = pParent.getTarget()
.findEntryInGOT(pReloc.symInfo())
->getAddr(pParent.config().getDiagEngine());
Relocator::DWord GX = helper_get_page_offset(GOT_S + A);
pReloc.target() = helper_reencode_ldst_pos_imm(insn, GX >> 3);
return Relocator::OK;
}
Relocator::Address GOT_S = pParent.getTarget()
.findEntryInGOT(pReloc.symInfo())
->getAddr(pParent.config().getDiagEngine());
Relocator::DWord GX = helper_get_page_offset(GOT_S + A);
pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(), GX >> 3);

// Convert Rt to X0 if static
if (pParent.config().isCodeStatic())
pReloc.target() = pReloc.target() & ~0x1F;

return Relocator::OK;
}

// R_AARCH64_TLSDESC_ADD_LO12_NC : G(GTLSDESC(S+A))
Relocator::Result tls_tlsdesc_add(Relocation &pReloc,
AArch64Relocator &pParent) {
Relocator::DWord A = pReloc.addend();
if (pParent.config().isCodeStatic()) {
if (pParent.config().isCodeStatic() || pParent.config().options().isPIE()) {
// Convert to nop
pReloc.target() = 0xD503201F;
return Relocator::OK;
Expand All @@ -1285,7 +1300,7 @@ Relocator::Result tls_tlsdesc_add(Relocation &pReloc,

// R_AARCH64_TLSDESC_CALL
Relocator::Result tls_call(Relocation &pReloc, AArch64Relocator &pParent) {
if (pParent.config().isCodeStatic()) {
if (pParent.config().isCodeStatic() || pParent.config().options().isPIE()) {
// Convert to nop
pReloc.target() = 0xD503201F;
return Relocator::OK;
Expand Down
18 changes: 11 additions & 7 deletions test/AArch64/standalone/TLS_DESC/DESC.test
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
RUN: %clangas %clangasopts -filetype obj -target-cpu generic -target-feature +neon -mrelax-all %p/Inputs/t.s -o %t.o
RUN: %link %linkopts -march aarch64 -static %t.o -z max-page-size=0x1000 -o %t.out
RUN: %link %linkopts -march aarch64 -static -z max-page-size=0x1000 %t.o -o %t.out
RUN: llvm-objdump -d %t.out | %filecheck %s

#CHECK: {{.*}} <_test_tls_desc>:
#CHECK: {{.*}} adrp x0, 0x1000
#CHECK: {{.*}} ldr x0, [x0]
#CHECK: {{.*}} <_test_tls_desc_local>:
#CHECK: {{.*}} adrp x0, 0x1000
#CHECK: {{.*}} ldr x0, [x0, #0x8]
CHECK: _test_tls_desc
CHECK: d2a00000 movz
CHECK: f2800200 movk
CHECK: d503201f nop
CHECK: d503201f nop
CHECK: _test_tls_desc_local
CHECK: d2a00000 movz
CHECK: f2800280 movk
CHECK: d503201f nop
CHECK: d503201f nop
14 changes: 14 additions & 0 deletions test/AArch64/standalone/TLS_DESC/TLS_DESC.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
RUN: %clangas %clangasopts -filetype obj -target-cpu generic -target-feature +neon -mrelax-all %p/Inputs/t.s -o %t.o
RUN: %link %linkopts -march aarch64 -static -z max-page-size=0x1000 %t.o -o %t.out
RUN: llvm-objdump -d %t.out | %filecheck %s

CHECK: _test_tls_desc
CHECK: d2a00000 movz
CHECK: f2800200 movk
CHECK: d503201f nop
CHECK: d503201f nop
CHECK: _test_tls_desc_local
CHECK: d2a00000 movz
CHECK: f2800280 movk
CHECK: d503201f nop
CHECK: d503201f nop
14 changes: 14 additions & 0 deletions test/AArch64/standalone/TLS_DESC/TLS_DESC_PIE.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
RUN: %clangas %clangasopts -filetype obj -target-cpu generic -target-feature +neon -mrelax-all %p/Inputs/t.s -o %t.o
RUN: %link %linkopts -march aarch64 -pie -z max-page-size=0x1000 %t.o -o %t.out
RUN: llvm-objdump -d %t.out | %filecheck %s

CHECK: _test_tls_desc
CHECK: b0000000 adrp
CHECK: f9408000 ldr
CHECK: d503201f nop
CHECK: d503201f nop
CHECK: _test_tls_desc_local
CHECK: b0000000 adrp
CHECK: f9408400 ldr
CHECK: d503201f nop
CHECK: d503201f nop
4 changes: 2 additions & 2 deletions test/AArch64/standalone/TLS_IE/IE.test
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ RUN: %clang %clangopts -target aarch64 %p/Inputs/f.c -c -o %t3.o
RUN: %link %linkopts -static -march aarch64 %t2.o %t3.o -z max-page-size=0x1000 -o %t2.out

CHECK: _test_tls_IE
CHECK: b0000000 adrp
CHECK: f9400000 ldr
CHECK: d2a00000 movz
CHECK: f2800200 movk
CHECK: _test_tls_IE_local
CHECK: d2a00000 movz
CHECK: f2800280 movk
Expand Down
12 changes: 12 additions & 0 deletions test/AArch64/standalone/TLS_IE_PIE/IE_PIE.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Verify that IE TLS relocations remain as GOT-indirect adrp+ldr
# in PIE executables (IE stays as IE, no relaxation to LE).
RUN: %clangas %clangasopts -filetype obj -target-cpu generic -target-feature +neon -mrelax-all %p/Inputs/ie.s -o %t.o
RUN: %link %linkopts -march aarch64 -pie -z max-page-size=0x1000 %t.o -o %t.out
RUN: llvm-objdump -d %t.out | %filecheck %s

CHECK: _test_tls_IE
CHECK: b0000000 adrp
CHECK: f9408000 ldr
CHECK: _test_tls_IE_local
CHECK: b0000000 adrp
CHECK: f9408400 ldr
29 changes: 29 additions & 0 deletions test/AArch64/standalone/TLS_IE_PIE/Inputs/ie.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
.global tlsievar
.section .tbss,"awT",%nobits
.align 2
.type tlsievar, %object
.size tlsievar, 4
tlsievar:
.zero 4

.align 2
.type l_tlsievar, %object
.size l_tlsievar, 4
l_tlsievar:
.zero 4

.text
_test_tls_IE:

// R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 tlsievar
adrp x0, :gottprel:tlsievar
// R_AARCH64_TLSIE_GOTTPREL_LO12_NC tlsievar
ldr x0, [x0, :gottprel_lo12:tlsievar]

_test_tls_IE_local:

// R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 l_tlsievar
adrp x0, :gottprel:l_tlsievar
// R_AARCH64_TLSIE_GOTTPREL_LO12_NC l_tlsievar
ldr x0, [x0, :gottprel_lo12:l_tlsievar]

10 changes: 10 additions & 0 deletions test/AArch64/standalone/TLS_Relaxation_Verify/Inputs/tls_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/* Verify TLS relaxations for AArch64.
* Global-dynamic (TLSDESC) should be relaxed to:
* - Local Exec (movz+movk) for static executables
* - Initial Exec (adrp+ldr) for PIE executables
*/
__thread int tls_global = 42;
static __thread int tls_local = 100;

int get_global() { return tls_global; }
int get_local() { return tls_local; }
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
RUN: %clang %clangopts -target aarch64-unknown-none-elf \
RUN: -ftls-model=global-dynamic -fPIC \
RUN: -c %p/Inputs/tls_test.c -o %t.o
RUN: %link %linkopts -march aarch64 -static \
RUN: -z max-page-size=0x1000 %t.o -o %t.static.out
RUN: llvm-objdump -d %t.static.out | %filecheck %s --check-prefix=STATIC
RUN: %link %linkopts -march aarch64 -pie \
RUN: -z max-page-size=0x1000 %t.o -o %t.pie.out
RUN: llvm-objdump -d %t.pie.out | %filecheck %s --check-prefix=PIE
RUN: %readelf -r %t.pie.out | %filecheck %s --check-prefix=PIE-RELOC

STATIC: <get_global>:
STATIC: d2a00000 movz
STATIC: f2800200 movk
STATIC: d503201f nop
STATIC: d503201f nop
STATIC: <get_local>:
STATIC: d2a00000 movz
STATIC: f2800280 movk
STATIC: d503201f nop
STATIC: d503201f nop

PIE: <get_global>:
PIE: b0000000 adrp
PIE: f9408400 ldr
PIE: d503201f nop
PIE: d503201f nop
PIE: <get_local>:
PIE: b0000000 adrp
PIE: f9408800 ldr
PIE: d503201f nop
PIE: d503201f nop

PIE-RELOC: R_AARCH64_TLS_TPREL64