| 1 | //===----- ELF_aarch32.cpp - JIT linker implementation for arm/thumb ------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // |
| 9 | // ELF/aarch32 jit-link implementation. |
| 10 | // |
| 11 | //===----------------------------------------------------------------------===// |
| 12 | |
| 13 | #include "llvm/ExecutionEngine/JITLink/ELF_aarch32.h" |
| 14 | |
| 15 | #include "llvm/BinaryFormat/ELF.h" |
| 16 | #include "llvm/ExecutionEngine/JITLink/JITLink.h" |
| 17 | #include "llvm/ExecutionEngine/JITLink/aarch32.h" |
| 18 | #include "llvm/Object/ELF.h" |
| 19 | #include "llvm/Object/ELFObjectFile.h" |
| 20 | #include "llvm/Support/Compiler.h" |
| 21 | #include "llvm/Support/ErrorHandling.h" |
| 22 | #include "llvm/TargetParser/ARMTargetParser.h" |
| 23 | |
| 24 | #include "ELFLinkGraphBuilder.h" |
| 25 | #include "JITLinkGeneric.h" |
| 26 | |
| 27 | #define DEBUG_TYPE "jitlink" |
| 28 | |
| 29 | using namespace llvm::object; |
| 30 | |
| 31 | namespace llvm { |
| 32 | namespace jitlink { |
| 33 | |
| 34 | /// Translate from ELF relocation type to JITLink-internal edge kind. |
| 35 | LLVM_ABI Expected<aarch32::EdgeKind_aarch32> |
| 36 | getJITLinkEdgeKind(uint32_t ELFType, const aarch32::ArmConfig &ArmCfg) { |
| 37 | switch (ELFType) { |
| 38 | case ELF::R_ARM_ABS32: |
| 39 | return aarch32::Data_Pointer32; |
| 40 | case ELF::R_ARM_GOT_PREL: |
| 41 | return aarch32::Data_RequestGOTAndTransformToDelta32; |
| 42 | case ELF::R_ARM_REL32: |
| 43 | return aarch32::Data_Delta32; |
| 44 | case ELF::R_ARM_CALL: |
| 45 | return aarch32::Arm_Call; |
| 46 | case ELF::R_ARM_JUMP24: |
| 47 | return aarch32::Arm_Jump24; |
| 48 | case ELF::R_ARM_MOVW_ABS_NC: |
| 49 | return aarch32::Arm_MovwAbsNC; |
| 50 | case ELF::R_ARM_MOVT_ABS: |
| 51 | return aarch32::Arm_MovtAbs; |
| 52 | case ELF::R_ARM_NONE: |
| 53 | return aarch32::None; |
| 54 | case ELF::R_ARM_PREL31: |
| 55 | return aarch32::Data_PRel31; |
| 56 | case ELF::R_ARM_TARGET1: |
| 57 | return (ArmCfg.Target1Rel) ? aarch32::Data_Delta32 |
| 58 | : aarch32::Data_Pointer32; |
| 59 | case ELF::R_ARM_THM_CALL: |
| 60 | return aarch32::Thumb_Call; |
| 61 | case ELF::R_ARM_THM_JUMP24: |
| 62 | return aarch32::Thumb_Jump24; |
| 63 | case ELF::R_ARM_THM_MOVW_ABS_NC: |
| 64 | return aarch32::Thumb_MovwAbsNC; |
| 65 | case ELF::R_ARM_THM_MOVT_ABS: |
| 66 | return aarch32::Thumb_MovtAbs; |
| 67 | case ELF::R_ARM_THM_MOVW_PREL_NC: |
| 68 | return aarch32::Thumb_MovwPrelNC; |
| 69 | case ELF::R_ARM_THM_MOVT_PREL: |
| 70 | return aarch32::Thumb_MovtPrel; |
| 71 | } |
| 72 | |
| 73 | return make_error<JITLinkError>( |
| 74 | Args: "Unsupported aarch32 relocation " + formatv(Fmt: "{0:d}: " , Vals&: ELFType) + |
| 75 | object::getELFRelocationTypeName(Machine: ELF::EM_ARM, Type: ELFType)); |
| 76 | } |
| 77 | |
| 78 | /// Translate from JITLink-internal edge kind back to ELF relocation type. |
| 79 | LLVM_ABI Expected<uint32_t> getELFRelocationType(Edge::Kind Kind) { |
| 80 | switch (static_cast<aarch32::EdgeKind_aarch32>(Kind)) { |
| 81 | case aarch32::Data_Delta32: |
| 82 | return ELF::R_ARM_REL32; |
| 83 | case aarch32::Data_Pointer32: |
| 84 | return ELF::R_ARM_ABS32; |
| 85 | case aarch32::Data_PRel31: |
| 86 | return ELF::R_ARM_PREL31; |
| 87 | case aarch32::Data_RequestGOTAndTransformToDelta32: |
| 88 | return ELF::R_ARM_GOT_PREL; |
| 89 | case aarch32::Arm_Call: |
| 90 | return ELF::R_ARM_CALL; |
| 91 | case aarch32::Arm_Jump24: |
| 92 | return ELF::R_ARM_JUMP24; |
| 93 | case aarch32::Arm_MovwAbsNC: |
| 94 | return ELF::R_ARM_MOVW_ABS_NC; |
| 95 | case aarch32::Arm_MovtAbs: |
| 96 | return ELF::R_ARM_MOVT_ABS; |
| 97 | case aarch32::Thumb_Call: |
| 98 | return ELF::R_ARM_THM_CALL; |
| 99 | case aarch32::Thumb_Jump24: |
| 100 | return ELF::R_ARM_THM_JUMP24; |
| 101 | case aarch32::Thumb_MovwAbsNC: |
| 102 | return ELF::R_ARM_THM_MOVW_ABS_NC; |
| 103 | case aarch32::Thumb_MovtAbs: |
| 104 | return ELF::R_ARM_THM_MOVT_ABS; |
| 105 | case aarch32::Thumb_MovwPrelNC: |
| 106 | return ELF::R_ARM_THM_MOVW_PREL_NC; |
| 107 | case aarch32::Thumb_MovtPrel: |
| 108 | return ELF::R_ARM_THM_MOVT_PREL; |
| 109 | case aarch32::None: |
| 110 | return ELF::R_ARM_NONE; |
| 111 | } |
| 112 | |
| 113 | return make_error<JITLinkError>(Args: formatv(Fmt: "Invalid aarch32 edge {0:d}: " , |
| 114 | Vals&: Kind)); |
| 115 | } |
| 116 | |
| 117 | /// Get a human-readable name for the given ELF AArch32 edge kind. |
| 118 | const char *getELFAArch32EdgeKindName(Edge::Kind R) { |
| 119 | // No ELF-specific edge kinds yet |
| 120 | return aarch32::getEdgeKindName(K: R); |
| 121 | } |
| 122 | |
| 123 | class ELFJITLinker_aarch32 : public JITLinker<ELFJITLinker_aarch32> { |
| 124 | friend class JITLinker<ELFJITLinker_aarch32>; |
| 125 | |
| 126 | public: |
| 127 | ELFJITLinker_aarch32(std::unique_ptr<JITLinkContext> Ctx, |
| 128 | std::unique_ptr<LinkGraph> G, PassConfiguration PassCfg, |
| 129 | aarch32::ArmConfig ArmCfg) |
| 130 | : JITLinker(std::move(Ctx), std::move(G), std::move(PassCfg)), |
| 131 | ArmCfg(std::move(ArmCfg)) {} |
| 132 | |
| 133 | private: |
| 134 | aarch32::ArmConfig ArmCfg; |
| 135 | |
| 136 | Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const { |
| 137 | return aarch32::applyFixup(G, B, E, ArmCfg); |
| 138 | } |
| 139 | }; |
| 140 | |
| 141 | template <llvm::endianness DataEndianness> |
| 142 | class ELFLinkGraphBuilder_aarch32 |
| 143 | : public ELFLinkGraphBuilder<ELFType<DataEndianness, false>> { |
| 144 | private: |
| 145 | using ELFT = ELFType<DataEndianness, false>; |
| 146 | using Base = ELFLinkGraphBuilder<ELFT>; |
| 147 | |
| 148 | Error addRelocations() override { |
| 149 | LLVM_DEBUG(dbgs() << "Processing relocations:\n" ); |
| 150 | using Self = ELFLinkGraphBuilder_aarch32<DataEndianness>; |
| 151 | for (const auto &RelSect : Base::Sections) { |
| 152 | if (Error Err = Base::forEachRelRelocation(RelSect, this, |
| 153 | &Self::addSingleRelRelocation)) |
| 154 | return Err; |
| 155 | } |
| 156 | return Error::success(); |
| 157 | } |
| 158 | |
| 159 | Error addSingleRelRelocation(const typename ELFT::Rel &Rel, |
| 160 | const typename ELFT::Shdr &FixupSect, |
| 161 | Block &BlockToFix) { |
| 162 | uint32_t SymbolIndex = Rel.getSymbol(false); |
| 163 | auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec); |
| 164 | if (!ObjSymbol) |
| 165 | return ObjSymbol.takeError(); |
| 166 | |
| 167 | Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex); |
| 168 | if (!GraphSymbol) |
| 169 | return make_error<StringError>( |
| 170 | formatv("Could not find symbol at given index, did you add it to " |
| 171 | "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}" , |
| 172 | SymbolIndex, (*ObjSymbol)->st_shndx, |
| 173 | Base::GraphSymbols.size()), |
| 174 | inconvertibleErrorCode()); |
| 175 | |
| 176 | uint32_t Type = Rel.getType(false); |
| 177 | Expected<aarch32::EdgeKind_aarch32> Kind = getJITLinkEdgeKind(ELFType: Type, ArmCfg); |
| 178 | if (!Kind) |
| 179 | return Kind.takeError(); |
| 180 | |
| 181 | auto FixupAddress = orc::ExecutorAddr(FixupSect.sh_addr) + Rel.r_offset; |
| 182 | Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress(); |
| 183 | |
| 184 | Expected<int64_t> Addend = |
| 185 | aarch32::readAddend(G&: *Base::G, B&: BlockToFix, Offset, Kind: *Kind, ArmCfg); |
| 186 | if (!Addend) |
| 187 | return Addend.takeError(); |
| 188 | |
| 189 | Edge E(*Kind, Offset, *GraphSymbol, *Addend); |
| 190 | LLVM_DEBUG({ |
| 191 | dbgs() << " " ; |
| 192 | printEdge(dbgs(), BlockToFix, E, getELFAArch32EdgeKindName(*Kind)); |
| 193 | dbgs() << "\n" ; |
| 194 | }); |
| 195 | |
| 196 | BlockToFix.addEdge(E: std::move(E)); |
| 197 | return Error::success(); |
| 198 | } |
| 199 | |
| 200 | aarch32::ArmConfig ArmCfg; |
| 201 | |
| 202 | protected: |
| 203 | TargetFlagsType makeTargetFlags(const typename ELFT::Sym &Sym) override { |
| 204 | // Only emit target flag for callable symbols |
| 205 | if (Sym.getType() != ELF::STT_FUNC) |
| 206 | return TargetFlagsType{}; |
| 207 | if (Sym.getValue() & 0x01) |
| 208 | return aarch32::ThumbSymbol; |
| 209 | return TargetFlagsType{}; |
| 210 | } |
| 211 | |
| 212 | orc::ExecutorAddrDiff getRawOffset(const typename ELFT::Sym &Sym, |
| 213 | TargetFlagsType Flags) override { |
| 214 | assert((makeTargetFlags(Sym) & Flags) == Flags); |
| 215 | static constexpr uint64_t ThumbBit = 0x01; |
| 216 | if (Sym.getType() == ELF::STT_FUNC) |
| 217 | return Sym.getValue() & ~ThumbBit; |
| 218 | return Sym.getValue(); |
| 219 | } |
| 220 | |
| 221 | public: |
| 222 | ELFLinkGraphBuilder_aarch32(StringRef FileName, |
| 223 | const llvm::object::ELFFile<ELFT> &Obj, |
| 224 | std::shared_ptr<orc::SymbolStringPool> SSP, |
| 225 | Triple TT, SubtargetFeatures Features, |
| 226 | aarch32::ArmConfig ArmCfg) |
| 227 | : ELFLinkGraphBuilder<ELFT>(Obj, std::move(SSP), std::move(TT), |
| 228 | std::move(Features), FileName, |
| 229 | getELFAArch32EdgeKindName), |
| 230 | ArmCfg(std::move(ArmCfg)) {} |
| 231 | }; |
| 232 | |
| 233 | template <typename StubsManagerType> |
| 234 | Error buildTables_ELF_aarch32(LinkGraph &G) { |
| 235 | LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n" ); |
| 236 | |
| 237 | StubsManagerType StubsManager; |
| 238 | visitExistingEdges(G, StubsManager); |
| 239 | aarch32::GOTBuilder GOT; |
| 240 | visitExistingEdges(G, Vs&: GOT); |
| 241 | |
| 242 | return Error::success(); |
| 243 | } |
| 244 | |
| 245 | Expected<std::unique_ptr<LinkGraph>> createLinkGraphFromELFObject_aarch32( |
| 246 | MemoryBufferRef ObjectBuffer, std::shared_ptr<orc::SymbolStringPool> SSP) { |
| 247 | LLVM_DEBUG({ |
| 248 | dbgs() << "Building jitlink graph for new input " |
| 249 | << ObjectBuffer.getBufferIdentifier() << "...\n" ; |
| 250 | }); |
| 251 | |
| 252 | auto ELFObj = ObjectFile::createELFObjectFile(Object: ObjectBuffer); |
| 253 | if (!ELFObj) |
| 254 | return ELFObj.takeError(); |
| 255 | |
| 256 | auto Features = (*ELFObj)->getFeatures(); |
| 257 | if (!Features) |
| 258 | return Features.takeError(); |
| 259 | |
| 260 | // Find out what exact AArch32 instruction set and features we target. |
| 261 | auto TT = (*ELFObj)->makeTriple(); |
| 262 | ARM::ArchKind AK = ARM::parseArch(Arch: TT.getArchName()); |
| 263 | if (AK == ARM::ArchKind::INVALID) |
| 264 | return make_error<JITLinkError>( |
| 265 | Args: "Failed to build ELF link graph: Invalid ARM ArchKind" ); |
| 266 | |
| 267 | // Resolve our internal configuration for the target. If at some point the |
| 268 | // CPUArch alone becomes too unprecise, we can find more details in the |
| 269 | // Tag_CPU_arch_profile. |
| 270 | auto Arch = static_cast<ARMBuildAttrs::CPUArch>(ARM::getArchAttr(AK)); |
| 271 | aarch32::ArmConfig ArmCfg = aarch32::getArmConfigForCPUArch(CPUArch: Arch); |
| 272 | |
| 273 | // Populate the link-graph. |
| 274 | switch (TT.getArch()) { |
| 275 | case Triple::arm: |
| 276 | case Triple::thumb: { |
| 277 | auto &ELFFile = cast<ELFObjectFile<ELF32LE>>(Val&: **ELFObj).getELFFile(); |
| 278 | return ELFLinkGraphBuilder_aarch32<llvm::endianness::little>( |
| 279 | (*ELFObj)->getFileName(), ELFFile, std::move(SSP), TT, |
| 280 | std::move(*Features), ArmCfg) |
| 281 | .buildGraph(); |
| 282 | } |
| 283 | case Triple::armeb: |
| 284 | case Triple::thumbeb: { |
| 285 | auto &ELFFile = cast<ELFObjectFile<ELF32BE>>(Val&: **ELFObj).getELFFile(); |
| 286 | return ELFLinkGraphBuilder_aarch32<llvm::endianness::big>( |
| 287 | (*ELFObj)->getFileName(), ELFFile, std::move(SSP), TT, |
| 288 | std::move(*Features), ArmCfg) |
| 289 | .buildGraph(); |
| 290 | } |
| 291 | default: |
| 292 | return make_error<JITLinkError>( |
| 293 | Args: "Failed to build ELF/aarch32 link graph: Invalid target triple " + |
| 294 | TT.getTriple()); |
| 295 | } |
| 296 | } |
| 297 | |
| 298 | void link_ELF_aarch32(std::unique_ptr<LinkGraph> G, |
| 299 | std::unique_ptr<JITLinkContext> Ctx) { |
| 300 | const Triple &TT = G->getTargetTriple(); |
| 301 | |
| 302 | using namespace ARMBuildAttrs; |
| 303 | ARM::ArchKind AK = ARM::parseArch(Arch: TT.getArchName()); |
| 304 | auto CPU = static_cast<CPUArch>(ARM::getArchAttr(AK)); |
| 305 | aarch32::ArmConfig ArmCfg = aarch32::getArmConfigForCPUArch(CPUArch: CPU); |
| 306 | |
| 307 | PassConfiguration PassCfg; |
| 308 | if (Ctx->shouldAddDefaultTargetPasses(TT)) { |
| 309 | // Add a mark-live pass. |
| 310 | if (auto MarkLive = Ctx->getMarkLivePass(TT)) |
| 311 | PassCfg.PrePrunePasses.push_back(x: std::move(MarkLive)); |
| 312 | else |
| 313 | PassCfg.PrePrunePasses.push_back(x: markAllSymbolsLive); |
| 314 | |
| 315 | switch (ArmCfg.Stubs) { |
| 316 | case aarch32::StubsFlavor::pre_v7: |
| 317 | PassCfg.PostPrunePasses.push_back( |
| 318 | x: buildTables_ELF_aarch32<aarch32::StubsManager_prev7>); |
| 319 | break; |
| 320 | case aarch32::StubsFlavor::v7: |
| 321 | PassCfg.PostPrunePasses.push_back( |
| 322 | x: buildTables_ELF_aarch32<aarch32::StubsManager_v7>); |
| 323 | break; |
| 324 | case aarch32::StubsFlavor::Undefined: |
| 325 | llvm_unreachable("Check before building graph" ); |
| 326 | } |
| 327 | } |
| 328 | |
| 329 | if (auto Err = Ctx->modifyPassConfig(G&: *G, Config&: PassCfg)) |
| 330 | return Ctx->notifyFailed(Err: std::move(Err)); |
| 331 | |
| 332 | ELFJITLinker_aarch32::link(Args: std::move(Ctx), Args: std::move(G), Args: std::move(PassCfg), |
| 333 | Args: std::move(ArmCfg)); |
| 334 | } |
| 335 | |
| 336 | } // namespace jitlink |
| 337 | } // namespace llvm |
| 338 | |