/// 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.
///
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.
//
*(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");
private:
enum ELFAArch64RelocationKind : Edge::Kind {
ELFCall26 = Edge::FirstRelocation,
+ ELFAdrLo21,
ELFAdrPage21,
ELFAddAbs12,
ELFLdSt8Abs12,
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:
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;
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