Skip to content

Commit d395b56

Browse files
authored
[JITLink][AArch64] Implement R_AARCH64_LDR_PREL_LO19 (llvm#82172)
This relocation is used for the 32-bit aligned 21-bit immediate in LDR Literal instructions.
1 parent 5d8354c commit d395b56

File tree

3 files changed

+39
-6
lines changed

3 files changed

+39
-6
lines changed

llvm/include/llvm/ExecutionEngine/JITLink/aarch64.h

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,14 @@ enum EdgeKind_aarch64 : Edge::Kind {
171171
///
172172
/// Fixup expression:
173173
///
174-
/// Fixup <- (Target - Fixup) >> 2 : int19
174+
/// Fixup <- (Target - Fixup + Addend) >> 2 : int19
175+
///
176+
/// Notes:
177+
/// The '19' in the name refers to the number operand bits and follows the
178+
/// naming convention used by the corresponding ELF relocation.
179+
/// Since the low two bits must be zero (because of the 32-bit alignment of
180+
/// the target) the operand is effectively a signed 21-bit number.
181+
///
175182
///
176183
/// Errors:
177184
/// - The result of the unshifted part of the fixup expression must be
@@ -377,6 +384,11 @@ inline bool isADR(uint32_t Instr) {
377384
return (Instr & ADRMask) == 0x10000000;
378385
}
379386

387+
inline bool isLDRLiteral(uint32_t Instr) {
388+
constexpr uint32_t LDRLitMask = 0x3b000000;
389+
return (Instr & LDRLitMask) == 0x18000000;
390+
}
391+
380392
// Returns the amount the address operand of LD/ST (imm12)
381393
// should be shifted right by.
382394
//
@@ -494,16 +506,14 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E) {
494506
}
495507
case LDRLiteral19: {
496508
assert((FixupAddress.getValue() & 0x3) == 0 && "LDR is not 32-bit aligned");
497-
assert(E.getAddend() == 0 && "LDRLiteral19 with non-zero addend");
498509
uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
499-
assert(RawInstr == 0x58000010 && "RawInstr isn't a 64-bit LDR literal");
500-
int64_t Delta = E.getTarget().getAddress() - FixupAddress;
510+
assert(isLDRLiteral(RawInstr) && "RawInstr is not an LDR Literal");
511+
int64_t Delta = E.getTarget().getAddress() + E.getAddend() - FixupAddress;
501512
if (Delta & 0x3)
502513
return make_error<JITLinkError>("LDR literal target is not 32-bit "
503514
"aligned");
504-
if (Delta < -(1 << 20) || Delta > ((1 << 20) - 1))
515+
if (!isInt<21>(Delta))
505516
return makeTargetOutOfRangeError(G, B, E);
506-
507517
uint32_t EncodedImm = ((static_cast<uint32_t>(Delta) >> 2) & 0x7ffff) << 5;
508518
uint32_t FixedInstr = RawInstr | EncodedImm;
509519
*(ulittle32_t *)FixupPtr = FixedInstr;

llvm/lib/ExecutionEngine/JITLink/ELF_aarch64.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ class ELFLinkGraphBuilder_aarch64 : public ELFLinkGraphBuilder<ELFT> {
4949
private:
5050
enum ELFAArch64RelocationKind : Edge::Kind {
5151
ELFCall26 = Edge::FirstRelocation,
52+
ELFLdrLo19,
5253
ELFAdrLo21,
5354
ELFAdrPage21,
5455
ELFAddAbs12,
@@ -82,6 +83,8 @@ class ELFLinkGraphBuilder_aarch64 : public ELFLinkGraphBuilder<ELFT> {
8283
case ELF::R_AARCH64_CALL26:
8384
case ELF::R_AARCH64_JUMP26:
8485
return ELFCall26;
86+
case ELF::R_AARCH64_LD_PREL_LO19:
87+
return ELFLdrLo19;
8588
case ELF::R_AARCH64_ADR_PREL_LO21:
8689
return ELFAdrLo21;
8790
case ELF::R_AARCH64_ADR_PREL_PG_HI21:
@@ -191,6 +194,15 @@ class ELFLinkGraphBuilder_aarch64 : public ELFLinkGraphBuilder<ELFT> {
191194
Kind = aarch64::Branch26PCRel;
192195
break;
193196
}
197+
case ELFLdrLo19: {
198+
uint32_t Instr = *(const ulittle32_t *)FixupContent;
199+
if (!aarch64::isLDRLiteral(Instr))
200+
return make_error<JITLinkError>(
201+
"R_AARCH64_LDR_PREL_LO19 target is not an LDR Literal instruction");
202+
203+
Kind = aarch64::LDRLiteral19;
204+
break;
205+
}
194206
case ELFAdrLo21: {
195207
uint32_t Instr = *(const ulittle32_t *)FixupContent;
196208
if (!aarch64::isADR(Instr))

llvm/test/ExecutionEngine/JITLink/AArch64/ELF_relocations.s

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,17 @@ test_adr_prel_lo21:
5151
## to test this bit better
5252
adr_data = test_adr_prel_lo21 + 0xe46f2
5353

54+
# Check R_AARCH64_LD_PREL_LO19 relocation of a local symbol
55+
#
56+
# jitlink-check: decode_operand(test_ldr_prel_lo19 + 0, 1)[19:0] = \
57+
# jitlink-check: (ldr_data - test_ldr_prel_lo19 + 0x4)[21:2]
58+
.globl test_ldr_prel_lo19, ldr_data
59+
.p2align 2
60+
test_ldr_prel_lo19:
61+
ldr x0, ldr_data + 0x4
62+
.size test_ldr_prel_lo19, .-test_ldr_prel_lo19
63+
ldr_data = test_ldr_prel_lo19 + 4
64+
5465
# Check R_AARCH64_ADR_PREL_PG_HI21 / R_AARCH64_ADD_ABS_LO12_NC relocation of a local symbol
5566
#
5667
# For the ADR_PREL_PG_HI21/ADRP instruction we have the 21-bit delta to the 4k page

0 commit comments

Comments
 (0)