From: Job Noorman Date: Fri, 9 Jun 2023 09:57:49 +0000 (+0200) Subject: [JITLink][AArch64] Implement R_AARCH64_ADR_PREL_LO21 X-Git-Tag: upstream/17.0.6~5634 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e967638947603d5c4260696af79f965a426e8a46;p=platform%2Fupstream%2Fllvm.git [JITLink][AArch64] Implement R_AARCH64_ADR_PREL_LO21 This relocation is used for the 21-bit immediate in ADR instructions. Reviewed By: lhames Differential Revision: https://reviews.llvm.org/D151305 --- diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/aarch64.h b/llvm/include/llvm/ExecutionEngine/JITLink/aarch64.h index e7e8b99..50bebf3 100644 --- a/llvm/include/llvm/ExecutionEngine/JITLink/aarch64.h +++ b/llvm/include/llvm/ExecutionEngine/JITLink/aarch64.h @@ -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. /// @@ -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. // @@ -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(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"); diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_aarch64.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_aarch64.cpp index a062a66..fac3207 100644 --- a/llvm/lib/ExecutionEngine/JITLink/ELF_aarch64.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/ELF_aarch64.cpp @@ -47,6 +47,7 @@ class ELFLinkGraphBuilder_aarch64 : public ELFLinkGraphBuilder { private: enum ELFAArch64RelocationKind : Edge::Kind { ELFCall26 = Edge::FirstRelocation, + ELFAdrLo21, ELFAdrPage21, ELFAddAbs12, ELFLdSt8Abs12, @@ -79,6 +80,8 @@ private: 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: @@ -186,6 +189,15 @@ private: Kind = aarch64::Branch26PCRel; break; } + case ELFAdrLo21: { + uint32_t Instr = *(const ulittle32_t *)FixupContent; + if (!aarch64::isADR(Instr)) + return make_error( + "R_AARCH64_ADR_PREL_LO21 target is not an ADR instruction"); + + Kind = aarch64::ADRLiteral21; + break; + } case ELFAdrPage21: { Kind = aarch64::Page21; break; diff --git a/llvm/lib/ExecutionEngine/JITLink/aarch64.cpp b/llvm/lib/ExecutionEngine/JITLink/aarch64.cpp index 785e8cc..cc58255 100644 --- a/llvm/lib/ExecutionEngine/JITLink/aarch64.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/aarch64.cpp @@ -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: diff --git a/llvm/test/ExecutionEngine/JITLink/AArch64/ELF_relocations.s b/llvm/test/ExecutionEngine/JITLink/AArch64/ELF_relocations.s index e6185bf..b260961 100644 --- a/llvm/test/ExecutionEngine/JITLink/AArch64/ELF_relocations.s +++ b/llvm/test/ExecutionEngine/JITLink/AArch64/ELF_relocations.s @@ -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