Skip to content

Commit 9577806

Browse files
[JITLink][AArch32] Implement R_ARM_PREL31 and process .ARM.exidx sections (#79044)
`R_ARM_PREL31` is a 31-bits relative data relocation where the most-significant bit is preserved. It's used primarily in `.ARM.exidx` sections, which we skipped processing until now, because we didn't support the relocation type. This was implemented in RuntimeDyld with https://reviews.llvm.org/D25069 and I implemented it in a similar way in JITLink in order to reach feature parity.
1 parent afc229b commit 9577806

File tree

5 files changed

+47
-17
lines changed

5 files changed

+47
-17
lines changed

llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ enum EdgeKind_aarch32 : Edge::Kind {
4141
/// Absolute 32-bit value relocation
4242
Data_Pointer32,
4343

44+
/// Relative 31-bit value relocation that preserves the most-significant bit
45+
Data_PRel31,
46+
4447
/// Create GOT entry and store offset
4548
Data_RequestGOTAndTransformToDelta32,
4649

llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,12 @@ template <typename ELFT> Error ELFLinkGraphBuilder<ELFT>::graphifySections() {
397397
orc::ExecutorAddr(Sec.sh_addr),
398398
Sec.sh_addralign, 0);
399399

400+
if (Sec.sh_type == ELF::SHT_ARM_EXIDX) {
401+
// Add live symbol to avoid dead-stripping for .ARM.exidx sections
402+
G->addAnonymousSymbol(*B, orc::ExecutorAddrDiff(),
403+
orc::ExecutorAddrDiff(), false, true);
404+
}
405+
400406
setGraphBlock(SecIndex, B);
401407
}
402408

llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ getJITLinkEdgeKind(uint32_t ELFType, const aarch32::ArmConfig &ArmCfg) {
5050
return aarch32::Arm_MovtAbs;
5151
case ELF::R_ARM_NONE:
5252
return aarch32::None;
53+
case ELF::R_ARM_PREL31:
54+
return aarch32::Data_PRel31;
5355
case ELF::R_ARM_TARGET1:
5456
return (ArmCfg.Target1Rel) ? aarch32::Data_Delta32
5557
: aarch32::Data_Pointer32;
@@ -79,6 +81,8 @@ Expected<uint32_t> getELFRelocationType(Edge::Kind Kind) {
7981
return ELF::R_ARM_REL32;
8082
case aarch32::Data_Pointer32:
8183
return ELF::R_ARM_ABS32;
84+
case aarch32::Data_PRel31:
85+
return ELF::R_ARM_PREL31;
8286
case aarch32::Data_RequestGOTAndTransformToDelta32:
8387
return ELF::R_ARM_GOT_PREL;
8488
case aarch32::Arm_Call:
@@ -140,16 +144,6 @@ class ELFLinkGraphBuilder_aarch32
140144
using ELFT = ELFType<DataEndianness, false>;
141145
using Base = ELFLinkGraphBuilder<ELFT>;
142146

143-
bool excludeSection(const typename ELFT::Shdr &Sect) const override {
144-
// TODO: An .ARM.exidx (Exception Index table) entry is 8-bytes in size and
145-
// consists of 2 words. It might be sufficient to process only relocations
146-
// in the the second word (offset 4). Please find more details in: Exception
147-
// Handling ABI for the Arm® Architecture -> Index table entries
148-
if (Sect.sh_type == ELF::SHT_ARM_EXIDX)
149-
return true;
150-
return false;
151-
}
152-
153147
Error addRelocations() override {
154148
LLVM_DEBUG(dbgs() << "Processing relocations:\n");
155149
using Self = ELFLinkGraphBuilder_aarch32<DataEndianness>;

llvm/lib/ExecutionEngine/JITLink/aarch32.cpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,8 @@ Expected<int64_t> readAddendData(LinkGraph &G, Block &B, Edge::OffsetT Offset,
398398
case Data_Pointer32:
399399
case Data_RequestGOTAndTransformToDelta32:
400400
return SignExtend64<32>(support::endian::read32(FixupPtr, Endian));
401+
case Data_PRel31:
402+
return SignExtend64<31>(support::endian::read32(FixupPtr, Endian));
401403
default:
402404
return make_error<JITLinkError>(
403405
"In graph " + G.getName() + ", section " + B.getSection().getName() +
@@ -472,9 +474,8 @@ Error applyFixupData(LinkGraph &G, Block &B, const Edge &E) {
472474
Symbol &TargetSymbol = E.getTarget();
473475
uint64_t TargetAddress = TargetSymbol.getAddress().getValue();
474476

475-
// Regular data relocations have size 4, alignment 1 and write the full 32-bit
476-
// result to the place; no need for overflow checking. There are three
477-
// exceptions: R_ARM_ABS8, R_ARM_ABS16, R_ARM_PREL31
477+
// Data relocations have alignment 1, size 4 (except R_ARM_ABS8 and
478+
// R_ARM_ABS16) and write the full 32-bit result (except R_ARM_PREL31).
478479
switch (Kind) {
479480
case Data_Delta32: {
480481
int64_t Value = TargetAddress - FixupAddress + Addend;
@@ -496,6 +497,19 @@ Error applyFixupData(LinkGraph &G, Block &B, const Edge &E) {
496497
endian::write32be(FixupPtr, Value);
497498
return Error::success();
498499
}
500+
case Data_PRel31: {
501+
int64_t Value = TargetAddress - FixupAddress + Addend;
502+
if (!isInt<31>(Value))
503+
return makeTargetOutOfRangeError(G, B, E);
504+
if (LLVM_LIKELY(G.getEndianness() == endianness::little)) {
505+
uint32_t MSB = endian::read32le(FixupPtr) & 0x80000000;
506+
endian::write32le(FixupPtr, MSB | (Value & ~0x80000000));
507+
} else {
508+
uint32_t MSB = endian::read32be(FixupPtr) & 0x80000000;
509+
endian::write32be(FixupPtr, MSB | (Value & ~0x80000000));
510+
}
511+
return Error::success();
512+
}
499513
case Data_RequestGOTAndTransformToDelta32:
500514
llvm_unreachable("Should be transformed");
501515
default:
@@ -856,6 +870,7 @@ const char *getEdgeKindName(Edge::Kind K) {
856870
switch (K) {
857871
KIND_NAME_CASE(Data_Delta32)
858872
KIND_NAME_CASE(Data_Pointer32)
873+
KIND_NAME_CASE(Data_PRel31)
859874
KIND_NAME_CASE(Data_RequestGOTAndTransformToDelta32)
860875
KIND_NAME_CASE(Arm_Call)
861876
KIND_NAME_CASE(Arm_Jump24)

llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_data.s

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,16 +64,27 @@ got_prel_offset:
6464
.size got_prel_offset, .-got_prel_offset
6565
.size got_prel, .-got_prel
6666

67-
# EH personality routine
67+
# EH personality routine in .ARM.exidx
6868
# CHECK-TYPE: {{[0-9a-f]+}} R_ARM_NONE __aeabi_unwind_cpp_pr0
6969
.globl __aeabi_unwind_cpp_pr0
7070
.type __aeabi_unwind_cpp_pr0,%function
7171
.align 2
7272
__aeabi_unwind_cpp_pr0:
7373
bx lr
7474

75-
# Generate reference to EH personality (right now we ignore the resulting
76-
# R_ARM_PREL31 relocation since it's in .ARM.exidx)
75+
# CHECK-TYPE: {{[0-9a-f]+}} R_ARM_PREL31 .text
76+
#
77+
# An .ARM.exidx table entry is 8-bytes in size, made up of 2 4-byte entries.
78+
# First word contains offset to function for this entry:
79+
# jitlink-check: (*{4}section_addr(out.o, .ARM.exidx))[31:0] = prel31 - section_addr(out.o, .ARM.exidx)
80+
#
81+
# Most-significant bit in second word denotes inline entry when set (and
82+
# relocation to .ARM.extab otherwise). Inline entry with compact model index 0:
83+
# 0x9b vsp = r11
84+
# 0x84 0x80 pop {r11, r14}
85+
#
86+
# jitlink-check: *{4}(section_addr(out.o, .ARM.exidx) + 4) = 0x809b8480
87+
#
7788
.globl prel31
7889
.type prel31,%function
7990
.align 2
@@ -85,8 +96,8 @@ prel31:
8596
mov r11, sp
8697
pop {r11, lr}
8798
mov pc, lr
88-
.size prel31,.-prel31
8999
.fnend
100+
.size prel31,.-prel31
90101

91102
# This test is executable with any 4-byte external target:
92103
# > echo "unsigned target = 42;" | clang -target armv7-linux-gnueabihf -o target.o -c -xc -
@@ -98,5 +109,6 @@ prel31:
98109
main:
99110
push {lr}
100111
bl got_prel
112+
bl prel31
101113
pop {pc}
102114
.size main, .-main

0 commit comments

Comments
 (0)