Skip to content

Commit

Permalink
[JITLink][AArch64] Implement R_AARCH64_ADR_PREL_LO21
Browse files Browse the repository at this point in the history
This relocation is used for the 21-bit immediate in ADR instructions.

Reviewed By: lhames

Differential Revision: https://reviews.llvm.org/D151305
  • Loading branch information
mtvec committed Jun 9, 2023
1 parent ebf4ab1 commit e967638
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 0 deletions.
33 changes: 33 additions & 0 deletions llvm/include/llvm/ExecutionEngine/JITLink/aarch64.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,20 @@ enum EdgeKind_aarch64 : Edge::Kind {
/// out-of-range error will be returned.
LDRLiteral19,

/// The signed 21-bit delta from the fixup to the target.
///
/// Fixup expression:
///
/// Fixup <- Target - Fixup + Addend : int21
///
/// Notes:
/// For ADR fixups.
///
/// Errors:
/// - The result of the fixup expression must fit into an int21 otherwise an
/// out-of-range error will be returned.
ADRLiteral21,

/// The signed 21-bit delta from the fixup page to the page containing the
/// target.
///
Expand Down Expand Up @@ -358,6 +372,11 @@ inline bool isCompAndBranchImm19(uint32_t Instr) {
return (Instr & CompAndBranchImm19Mask) == 0x34000000;
}

inline bool isADR(uint32_t Instr) {
constexpr uint32_t ADRMask = 0x9f000000;
return (Instr & ADRMask) == 0x10000000;
}

// Returns the amount the address operand of LD/ST (imm12)
// should be shifted right by.
//
Expand Down Expand Up @@ -490,6 +509,20 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E) {
*(ulittle32_t *)FixupPtr = FixedInstr;
break;
}
case ADRLiteral21: {
assert((FixupAddress.getValue() & 0x3) == 0 && "ADR is not 32-bit aligned");
uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
assert(isADR(RawInstr) && "RawInstr is not an ADR");
int64_t Delta = E.getTarget().getAddress() + E.getAddend() - FixupAddress;
if (!isInt<21>(Delta))
return makeTargetOutOfRangeError(G, B, E);
auto UDelta = static_cast<uint32_t>(Delta);
uint32_t EncodedImmHi = ((UDelta >> 2) & 0x7ffff) << 5;
uint32_t EncodedImmLo = (UDelta & 0x3) << 29;
uint32_t FixedInstr = RawInstr | EncodedImmHi | EncodedImmLo;
*(ulittle32_t *)FixupPtr = FixedInstr;
break;
}
case TestAndBranch14PCRel: {
assert((FixupAddress.getValue() & 0x3) == 0 &&
"Test and branch is not 32-bit aligned");
Expand Down
12 changes: 12 additions & 0 deletions llvm/lib/ExecutionEngine/JITLink/ELF_aarch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class ELFLinkGraphBuilder_aarch64 : public ELFLinkGraphBuilder<ELFT> {
private:
enum ELFAArch64RelocationKind : Edge::Kind {
ELFCall26 = Edge::FirstRelocation,
ELFAdrLo21,
ELFAdrPage21,
ELFAddAbs12,
ELFLdSt8Abs12,
Expand Down Expand Up @@ -79,6 +80,8 @@ class ELFLinkGraphBuilder_aarch64 : public ELFLinkGraphBuilder<ELFT> {
case ELF::R_AARCH64_CALL26:
case ELF::R_AARCH64_JUMP26:
return ELFCall26;
case ELF::R_AARCH64_ADR_PREL_LO21:
return ELFAdrLo21;
case ELF::R_AARCH64_ADR_PREL_PG_HI21:
return ELFAdrPage21;
case ELF::R_AARCH64_ADD_ABS_LO12_NC:
Expand Down Expand Up @@ -186,6 +189,15 @@ class ELFLinkGraphBuilder_aarch64 : public ELFLinkGraphBuilder<ELFT> {
Kind = aarch64::Branch26PCRel;
break;
}
case ELFAdrLo21: {
uint32_t Instr = *(const ulittle32_t *)FixupContent;
if (!aarch64::isADR(Instr))
return make_error<JITLinkError>(
"R_AARCH64_ADR_PREL_LO21 target is not an ADR instruction");

Kind = aarch64::ADRLiteral21;
break;
}
case ELFAdrPage21: {
Kind = aarch64::Page21;
break;
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/ExecutionEngine/JITLink/aarch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ const char *getEdgeKindName(Edge::Kind R) {
return "TestAndBranch14PCRel";
case CondBranch19PCRel:
return "CondBranch19PCRel";
case ADRLiteral21:
return "ADRLiteral21";
case Page21:
return "Page21";
case PageOffset12:
Expand Down
12 changes: 12 additions & 0 deletions llvm/test/ExecutionEngine/JITLink/AArch64/ELF_relocations.s
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,18 @@ local_func_jump26:
b local_func
.size local_func_jump26, .-local_func_jump26

# Check R_AARCH64_ADR_PREL_LO21 relocation of a local symbol
#
# jitlink-check: decode_operand(test_adr_prel_lo21, 1) = (adr_data - test_adr_prel_lo21)[20:0]
.globl test_adr_prel_lo21, adr_data
.p2align 2
test_adr_prel_lo21:
adr x0, adr_data
.size test_adr_prel_lo21, .-test_adr_prel_lo21
## ADR encoding is a bit tricky so use an offset with an irregular bit pattern
## to test this bit better
adr_data = test_adr_prel_lo21 + 0xe46f2

# Check R_AARCH64_ADR_PREL_PG_HI21 / R_AARCH64_ADD_ABS_LO12_NC relocation of a local symbol
#
# For the ADR_PREL_PG_HI21/ADRP instruction we have the 21-bit delta to the 4k page
Expand Down

0 comments on commit e967638

Please sign in to comment.