| 1 | //===----- ELF_aarch64.cpp - JIT linker implementation for ELF/aarch64 ----===// |
| 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/aarch64 jit-link implementation. |
| 10 | // |
| 11 | //===----------------------------------------------------------------------===// |
| 12 | |
| 13 | #include "llvm/ExecutionEngine/JITLink/ELF_aarch64.h" |
| 14 | #include "llvm/BinaryFormat/ELF.h" |
| 15 | #include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h" |
| 16 | #include "llvm/ExecutionEngine/JITLink/aarch64.h" |
| 17 | #include "llvm/Object/ELFObjectFile.h" |
| 18 | #include "llvm/Support/Endian.h" |
| 19 | |
| 20 | #include "DefineExternalSectionStartAndEndSymbols.h" |
| 21 | #include "EHFrameSupportImpl.h" |
| 22 | #include "ELFLinkGraphBuilder.h" |
| 23 | #include "JITLinkGeneric.h" |
| 24 | |
| 25 | #define DEBUG_TYPE "jitlink" |
| 26 | |
| 27 | using namespace llvm; |
| 28 | using namespace llvm::jitlink; |
| 29 | |
| 30 | namespace { |
| 31 | |
| 32 | constexpr StringRef ELFGOTSymbolName = "_GLOBAL_OFFSET_TABLE_" ; |
| 33 | |
| 34 | class ELFJITLinker_aarch64 : public JITLinker<ELFJITLinker_aarch64> { |
| 35 | friend class JITLinker<ELFJITLinker_aarch64>; |
| 36 | |
| 37 | public: |
| 38 | ELFJITLinker_aarch64(std::unique_ptr<JITLinkContext> Ctx, |
| 39 | std::unique_ptr<LinkGraph> G, |
| 40 | PassConfiguration PassConfig) |
| 41 | : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) { |
| 42 | if (shouldAddDefaultTargetPasses(TT: getGraph().getTargetTriple())) |
| 43 | getPassConfig().PostAllocationPasses.push_back( |
| 44 | x: [this](LinkGraph &G) { return getOrCreateGOTSymbol(G); }); |
| 45 | } |
| 46 | |
| 47 | private: |
| 48 | Symbol *GOTSymbol = nullptr; |
| 49 | |
| 50 | Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const { |
| 51 | return aarch64::applyFixup(G, B, E, GOTSymbol); |
| 52 | } |
| 53 | |
| 54 | Error getOrCreateGOTSymbol(LinkGraph &G) { |
| 55 | auto InteredGOTSymbolName = |
| 56 | G.getSymbolStringPool()->intern(S: ELFGOTSymbolName); |
| 57 | |
| 58 | auto DefineExternalGOTSymbolIfPresent = |
| 59 | createDefineExternalSectionStartAndEndSymbolsPass( |
| 60 | F: [&](LinkGraph &LG, Symbol &Sym) -> SectionRangeSymbolDesc { |
| 61 | if (*Sym.getName() == ELFGOTSymbolName) |
| 62 | if (auto *GOTSection = G.findSectionByName( |
| 63 | Name: aarch64::GOTTableManager::getSectionName())) { |
| 64 | GOTSymbol = &Sym; |
| 65 | return {*GOTSection, true}; |
| 66 | } |
| 67 | return {}; |
| 68 | }); |
| 69 | |
| 70 | // Try to attach _GLOBAL_OFFSET_TABLE_ to the GOT if it's defined as an |
| 71 | // external. |
| 72 | if (auto Err = DefineExternalGOTSymbolIfPresent(G)) |
| 73 | return Err; |
| 74 | |
| 75 | // If we succeeded then we're done. |
| 76 | if (GOTSymbol) |
| 77 | return Error::success(); |
| 78 | |
| 79 | // Otherwise look for a GOT section: If it already has a start symbol we'll |
| 80 | // record it, otherwise we'll create our own. |
| 81 | // If there's a GOT section but we didn't find an external GOT symbol... |
| 82 | if (auto *GOTSection = |
| 83 | G.findSectionByName(Name: aarch64::GOTTableManager::getSectionName())) { |
| 84 | |
| 85 | // Check for an existing defined symbol. |
| 86 | for (auto *Sym : GOTSection->symbols()) |
| 87 | if (Sym->getName() == InteredGOTSymbolName) { |
| 88 | GOTSymbol = Sym; |
| 89 | return Error::success(); |
| 90 | } |
| 91 | |
| 92 | // If there's no defined symbol then create one. |
| 93 | SectionRange SR(*GOTSection); |
| 94 | if (SR.empty()) |
| 95 | GOTSymbol = |
| 96 | // FIXME: we should only do this once |
| 97 | &G.addAbsoluteSymbol(Name: InteredGOTSymbolName, Address: orc::ExecutorAddr(), Size: 0, |
| 98 | L: Linkage::Strong, S: Scope::Local, IsLive: true); |
| 99 | else |
| 100 | GOTSymbol = |
| 101 | &G.addDefinedSymbol(Content&: *SR.getFirstBlock(), Offset: 0, Name: InteredGOTSymbolName, Size: 0, |
| 102 | L: Linkage::Strong, S: Scope::Local, IsCallable: false, IsLive: true); |
| 103 | } |
| 104 | |
| 105 | // If we still haven't found a GOT symbol then double check the externals. |
| 106 | // We may have a GOT-relative reference but no GOT section, in which case |
| 107 | // we just need to point the GOT symbol at some address in this graph. |
| 108 | if (!GOTSymbol) { |
| 109 | for (auto *Sym : G.external_symbols()) { |
| 110 | if (*Sym->getName() == ELFGOTSymbolName) { |
| 111 | auto Blocks = G.blocks(); |
| 112 | if (!Blocks.empty()) { |
| 113 | G.makeAbsolute(Sym&: *Sym, Address: (*Blocks.begin())->getAddress()); |
| 114 | GOTSymbol = Sym; |
| 115 | break; |
| 116 | } |
| 117 | } |
| 118 | } |
| 119 | } |
| 120 | |
| 121 | return Error::success(); |
| 122 | } |
| 123 | }; |
| 124 | |
| 125 | template <typename ELFT> |
| 126 | class ELFLinkGraphBuilder_aarch64 : public ELFLinkGraphBuilder<ELFT> { |
| 127 | private: |
| 128 | enum ELFAArch64RelocationKind : Edge::Kind { |
| 129 | ELFCall26 = Edge::FirstRelocation, |
| 130 | ELFLdrLo19, |
| 131 | ELFAdrLo21, |
| 132 | ELFAdrPage21, |
| 133 | ELFAddAbs12, |
| 134 | ELFLdSt8Abs12, |
| 135 | ELFLdSt16Abs12, |
| 136 | ELFLdSt32Abs12, |
| 137 | ELFLdSt64Abs12, |
| 138 | ELFLdSt128Abs12, |
| 139 | ELFMovwAbsG0, |
| 140 | ELFMovwAbsG1, |
| 141 | ELFMovwAbsG2, |
| 142 | ELFMovwAbsG3, |
| 143 | ELFTstBr14, |
| 144 | ELFCondBr19, |
| 145 | ELFAbs32, |
| 146 | ELFAbs64, |
| 147 | ELFPrel32, |
| 148 | ELFPrel64, |
| 149 | ELFAdrGOTPage21, |
| 150 | ELFLd64GOTLo12, |
| 151 | ELFLd64GOTPAGELo15, |
| 152 | ELFTLSDescAdrPage21, |
| 153 | ELFTLSDescAddLo12, |
| 154 | ELFTLSDescLd64Lo12, |
| 155 | ELFTLSDescCall, |
| 156 | }; |
| 157 | |
| 158 | static Expected<ELFAArch64RelocationKind> |
| 159 | getRelocationKind(const uint32_t Type) { |
| 160 | using namespace aarch64; |
| 161 | switch (Type) { |
| 162 | case ELF::R_AARCH64_CALL26: |
| 163 | case ELF::R_AARCH64_JUMP26: |
| 164 | return ELFCall26; |
| 165 | case ELF::R_AARCH64_LD_PREL_LO19: |
| 166 | return ELFLdrLo19; |
| 167 | case ELF::R_AARCH64_ADR_PREL_LO21: |
| 168 | return ELFAdrLo21; |
| 169 | case ELF::R_AARCH64_ADR_PREL_PG_HI21: |
| 170 | return ELFAdrPage21; |
| 171 | case ELF::R_AARCH64_ADD_ABS_LO12_NC: |
| 172 | return ELFAddAbs12; |
| 173 | case ELF::R_AARCH64_LDST8_ABS_LO12_NC: |
| 174 | return ELFLdSt8Abs12; |
| 175 | case ELF::R_AARCH64_LDST16_ABS_LO12_NC: |
| 176 | return ELFLdSt16Abs12; |
| 177 | case ELF::R_AARCH64_LDST32_ABS_LO12_NC: |
| 178 | return ELFLdSt32Abs12; |
| 179 | case ELF::R_AARCH64_LDST64_ABS_LO12_NC: |
| 180 | return ELFLdSt64Abs12; |
| 181 | case ELF::R_AARCH64_LDST128_ABS_LO12_NC: |
| 182 | return ELFLdSt128Abs12; |
| 183 | case ELF::R_AARCH64_MOVW_UABS_G0_NC: |
| 184 | return ELFMovwAbsG0; |
| 185 | case ELF::R_AARCH64_MOVW_UABS_G1_NC: |
| 186 | return ELFMovwAbsG1; |
| 187 | case ELF::R_AARCH64_MOVW_UABS_G2_NC: |
| 188 | return ELFMovwAbsG2; |
| 189 | case ELF::R_AARCH64_MOVW_UABS_G3: |
| 190 | return ELFMovwAbsG3; |
| 191 | case ELF::R_AARCH64_TSTBR14: |
| 192 | return ELFTstBr14; |
| 193 | case ELF::R_AARCH64_CONDBR19: |
| 194 | return ELFCondBr19; |
| 195 | case ELF::R_AARCH64_ABS32: |
| 196 | return ELFAbs32; |
| 197 | case ELF::R_AARCH64_ABS64: |
| 198 | return ELFAbs64; |
| 199 | case ELF::R_AARCH64_PREL32: |
| 200 | return ELFPrel32; |
| 201 | case ELF::R_AARCH64_PREL64: |
| 202 | return ELFPrel64; |
| 203 | case ELF::R_AARCH64_ADR_GOT_PAGE: |
| 204 | return ELFAdrGOTPage21; |
| 205 | case ELF::R_AARCH64_LD64_GOT_LO12_NC: |
| 206 | return ELFLd64GOTLo12; |
| 207 | case ELF::R_AARCH64_LD64_GOTPAGE_LO15: |
| 208 | return ELFLd64GOTPAGELo15; |
| 209 | case ELF::R_AARCH64_TLSDESC_ADR_PAGE21: |
| 210 | return ELFTLSDescAdrPage21; |
| 211 | case ELF::R_AARCH64_TLSDESC_ADD_LO12: |
| 212 | return ELFTLSDescAddLo12; |
| 213 | case ELF::R_AARCH64_TLSDESC_LD64_LO12: |
| 214 | return ELFTLSDescLd64Lo12; |
| 215 | case ELF::R_AARCH64_TLSDESC_CALL: |
| 216 | return ELFTLSDescCall; |
| 217 | } |
| 218 | |
| 219 | return make_error<JITLinkError>( |
| 220 | Args: "Unsupported aarch64 relocation:" + formatv(Fmt: "{0:d}: " , Vals: Type) + |
| 221 | object::getELFRelocationTypeName(Machine: ELF::EM_AARCH64, Type)); |
| 222 | } |
| 223 | |
| 224 | Error addRelocations() override { |
| 225 | LLVM_DEBUG(dbgs() << "Processing relocations:\n" ); |
| 226 | |
| 227 | using Base = ELFLinkGraphBuilder<ELFT>; |
| 228 | using Self = ELFLinkGraphBuilder_aarch64<ELFT>; |
| 229 | for (const auto &RelSect : Base::Sections) |
| 230 | if (Error Err = Base::forEachRelaRelocation(RelSect, this, |
| 231 | &Self::addSingleRelocation)) |
| 232 | return Err; |
| 233 | |
| 234 | return Error::success(); |
| 235 | } |
| 236 | |
| 237 | Error addSingleRelocation(const typename ELFT::Rela &Rel, |
| 238 | const typename ELFT::Shdr &FixupSect, |
| 239 | Block &BlockToFix) { |
| 240 | using support::ulittle32_t; |
| 241 | using Base = ELFLinkGraphBuilder<ELFT>; |
| 242 | |
| 243 | uint32_t SymbolIndex = Rel.getSymbol(false); |
| 244 | auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec); |
| 245 | if (!ObjSymbol) |
| 246 | return ObjSymbol.takeError(); |
| 247 | |
| 248 | Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex); |
| 249 | if (!GraphSymbol) |
| 250 | return make_error<StringError>( |
| 251 | formatv("Could not find symbol at given index, did you add it to " |
| 252 | "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}" , |
| 253 | SymbolIndex, (*ObjSymbol)->st_shndx, |
| 254 | Base::GraphSymbols.size()), |
| 255 | inconvertibleErrorCode()); |
| 256 | |
| 257 | uint32_t Type = Rel.getType(false); |
| 258 | Expected<ELFAArch64RelocationKind> RelocKind = getRelocationKind(Type); |
| 259 | if (!RelocKind) |
| 260 | return RelocKind.takeError(); |
| 261 | |
| 262 | int64_t Addend = Rel.r_addend; |
| 263 | orc::ExecutorAddr FixupAddress = |
| 264 | orc::ExecutorAddr(FixupSect.sh_addr) + Rel.r_offset; |
| 265 | Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress(); |
| 266 | |
| 267 | // Get a pointer to the fixup content. |
| 268 | const void *FixupContent = BlockToFix.getContent().data() + |
| 269 | (FixupAddress - BlockToFix.getAddress()); |
| 270 | |
| 271 | Edge::Kind Kind = Edge::Invalid; |
| 272 | |
| 273 | switch (*RelocKind) { |
| 274 | case ELFCall26: { |
| 275 | Kind = aarch64::Branch26PCRel; |
| 276 | break; |
| 277 | } |
| 278 | case ELFLdrLo19: { |
| 279 | uint32_t Instr = *(const ulittle32_t *)FixupContent; |
| 280 | if (!aarch64::isLDRLiteral(Instr)) |
| 281 | return make_error<JITLinkError>( |
| 282 | Args: "R_AARCH64_LDR_PREL_LO19 target is not an LDR Literal instruction" ); |
| 283 | |
| 284 | Kind = aarch64::LDRLiteral19; |
| 285 | break; |
| 286 | } |
| 287 | case ELFAdrLo21: { |
| 288 | uint32_t Instr = *(const ulittle32_t *)FixupContent; |
| 289 | if (!aarch64::isADR(Instr)) |
| 290 | return make_error<JITLinkError>( |
| 291 | Args: "R_AARCH64_ADR_PREL_LO21 target is not an ADR instruction" ); |
| 292 | |
| 293 | Kind = aarch64::ADRLiteral21; |
| 294 | break; |
| 295 | } |
| 296 | case ELFAdrPage21: { |
| 297 | Kind = aarch64::Page21; |
| 298 | break; |
| 299 | } |
| 300 | case ELFAddAbs12: { |
| 301 | Kind = aarch64::PageOffset12; |
| 302 | break; |
| 303 | } |
| 304 | case ELFLdSt8Abs12: { |
| 305 | uint32_t Instr = *(const ulittle32_t *)FixupContent; |
| 306 | if (!aarch64::isLoadStoreImm12(Instr) || |
| 307 | aarch64::getPageOffset12Shift(Instr) != 0) |
| 308 | return make_error<JITLinkError>( |
| 309 | Args: "R_AARCH64_LDST8_ABS_LO12_NC target is not a " |
| 310 | "LDRB/STRB (imm12) instruction" ); |
| 311 | |
| 312 | Kind = aarch64::PageOffset12; |
| 313 | break; |
| 314 | } |
| 315 | case ELFLdSt16Abs12: { |
| 316 | uint32_t Instr = *(const ulittle32_t *)FixupContent; |
| 317 | if (!aarch64::isLoadStoreImm12(Instr) || |
| 318 | aarch64::getPageOffset12Shift(Instr) != 1) |
| 319 | return make_error<JITLinkError>( |
| 320 | Args: "R_AARCH64_LDST16_ABS_LO12_NC target is not a " |
| 321 | "LDRH/STRH (imm12) instruction" ); |
| 322 | |
| 323 | Kind = aarch64::PageOffset12; |
| 324 | break; |
| 325 | } |
| 326 | case ELFLdSt32Abs12: { |
| 327 | uint32_t Instr = *(const ulittle32_t *)FixupContent; |
| 328 | if (!aarch64::isLoadStoreImm12(Instr) || |
| 329 | aarch64::getPageOffset12Shift(Instr) != 2) |
| 330 | return make_error<JITLinkError>( |
| 331 | Args: "R_AARCH64_LDST32_ABS_LO12_NC target is not a " |
| 332 | "LDR/STR (imm12, 32 bit) instruction" ); |
| 333 | |
| 334 | Kind = aarch64::PageOffset12; |
| 335 | break; |
| 336 | } |
| 337 | case ELFLdSt64Abs12: { |
| 338 | uint32_t Instr = *(const ulittle32_t *)FixupContent; |
| 339 | if (!aarch64::isLoadStoreImm12(Instr) || |
| 340 | aarch64::getPageOffset12Shift(Instr) != 3) |
| 341 | return make_error<JITLinkError>( |
| 342 | Args: "R_AARCH64_LDST64_ABS_LO12_NC target is not a " |
| 343 | "LDR/STR (imm12, 64 bit) instruction" ); |
| 344 | |
| 345 | Kind = aarch64::PageOffset12; |
| 346 | break; |
| 347 | } |
| 348 | case ELFLdSt128Abs12: { |
| 349 | uint32_t Instr = *(const ulittle32_t *)FixupContent; |
| 350 | if (!aarch64::isLoadStoreImm12(Instr) || |
| 351 | aarch64::getPageOffset12Shift(Instr) != 4) |
| 352 | return make_error<JITLinkError>( |
| 353 | Args: "R_AARCH64_LDST128_ABS_LO12_NC target is not a " |
| 354 | "LDR/STR (imm12, 128 bit) instruction" ); |
| 355 | |
| 356 | Kind = aarch64::PageOffset12; |
| 357 | break; |
| 358 | } |
| 359 | case ELFMovwAbsG0: { |
| 360 | uint32_t Instr = *(const ulittle32_t *)FixupContent; |
| 361 | if (!aarch64::isMoveWideImm16(Instr) || |
| 362 | aarch64::getMoveWide16Shift(Instr) != 0) |
| 363 | return make_error<JITLinkError>( |
| 364 | Args: "R_AARCH64_MOVW_UABS_G0_NC target is not a " |
| 365 | "MOVK/MOVZ (imm16, LSL #0) instruction" ); |
| 366 | |
| 367 | Kind = aarch64::MoveWide16; |
| 368 | break; |
| 369 | } |
| 370 | case ELFMovwAbsG1: { |
| 371 | uint32_t Instr = *(const ulittle32_t *)FixupContent; |
| 372 | if (!aarch64::isMoveWideImm16(Instr) || |
| 373 | aarch64::getMoveWide16Shift(Instr) != 16) |
| 374 | return make_error<JITLinkError>( |
| 375 | Args: "R_AARCH64_MOVW_UABS_G1_NC target is not a " |
| 376 | "MOVK/MOVZ (imm16, LSL #16) instruction" ); |
| 377 | |
| 378 | Kind = aarch64::MoveWide16; |
| 379 | break; |
| 380 | } |
| 381 | case ELFMovwAbsG2: { |
| 382 | uint32_t Instr = *(const ulittle32_t *)FixupContent; |
| 383 | if (!aarch64::isMoveWideImm16(Instr) || |
| 384 | aarch64::getMoveWide16Shift(Instr) != 32) |
| 385 | return make_error<JITLinkError>( |
| 386 | Args: "R_AARCH64_MOVW_UABS_G2_NC target is not a " |
| 387 | "MOVK/MOVZ (imm16, LSL #32) instruction" ); |
| 388 | |
| 389 | Kind = aarch64::MoveWide16; |
| 390 | break; |
| 391 | } |
| 392 | case ELFMovwAbsG3: { |
| 393 | uint32_t Instr = *(const ulittle32_t *)FixupContent; |
| 394 | if (!aarch64::isMoveWideImm16(Instr) || |
| 395 | aarch64::getMoveWide16Shift(Instr) != 48) |
| 396 | return make_error<JITLinkError>( |
| 397 | Args: "R_AARCH64_MOVW_UABS_G3 target is not a " |
| 398 | "MOVK/MOVZ (imm16, LSL #48) instruction" ); |
| 399 | |
| 400 | Kind = aarch64::MoveWide16; |
| 401 | break; |
| 402 | } |
| 403 | case ELFTstBr14: { |
| 404 | uint32_t Instr = *(const ulittle32_t *)FixupContent; |
| 405 | if (!aarch64::isTestAndBranchImm14(Instr)) |
| 406 | return make_error<JITLinkError>(Args: "R_AARCH64_TSTBR14 target is not a " |
| 407 | "test and branch instruction" ); |
| 408 | |
| 409 | Kind = aarch64::TestAndBranch14PCRel; |
| 410 | break; |
| 411 | } |
| 412 | case ELFCondBr19: { |
| 413 | uint32_t Instr = *(const ulittle32_t *)FixupContent; |
| 414 | if (!aarch64::isCondBranchImm19(Instr) && |
| 415 | !aarch64::isCompAndBranchImm19(Instr)) |
| 416 | return make_error<JITLinkError>(Args: "R_AARCH64_CONDBR19 target is not a " |
| 417 | "conditional branch instruction" ); |
| 418 | |
| 419 | Kind = aarch64::CondBranch19PCRel; |
| 420 | break; |
| 421 | } |
| 422 | case ELFAbs32: { |
| 423 | Kind = aarch64::Pointer32; |
| 424 | break; |
| 425 | } |
| 426 | case ELFAbs64: { |
| 427 | Kind = aarch64::Pointer64; |
| 428 | break; |
| 429 | } |
| 430 | case ELFPrel32: { |
| 431 | Kind = aarch64::Delta32; |
| 432 | break; |
| 433 | } |
| 434 | case ELFPrel64: { |
| 435 | Kind = aarch64::Delta64; |
| 436 | break; |
| 437 | } |
| 438 | case ELFAdrGOTPage21: { |
| 439 | Kind = aarch64::RequestGOTAndTransformToPage21; |
| 440 | break; |
| 441 | } |
| 442 | case ELFLd64GOTLo12: { |
| 443 | Kind = aarch64::RequestGOTAndTransformToPageOffset12; |
| 444 | break; |
| 445 | } |
| 446 | case ELFLd64GOTPAGELo15: { |
| 447 | Kind = aarch64::RequestGOTAndTransformToPageOffset15; |
| 448 | break; |
| 449 | } |
| 450 | case ELFTLSDescAdrPage21: { |
| 451 | Kind = aarch64::RequestTLSDescEntryAndTransformToPage21; |
| 452 | break; |
| 453 | } |
| 454 | case ELFTLSDescAddLo12: |
| 455 | case ELFTLSDescLd64Lo12: { |
| 456 | Kind = aarch64::RequestTLSDescEntryAndTransformToPageOffset12; |
| 457 | break; |
| 458 | } |
| 459 | case ELFTLSDescCall: { |
| 460 | return Error::success(); |
| 461 | } |
| 462 | }; |
| 463 | |
| 464 | Edge GE(Kind, Offset, *GraphSymbol, Addend); |
| 465 | LLVM_DEBUG({ |
| 466 | dbgs() << " " ; |
| 467 | printEdge(dbgs(), BlockToFix, GE, aarch64::getEdgeKindName(Kind)); |
| 468 | dbgs() << "\n" ; |
| 469 | }); |
| 470 | |
| 471 | BlockToFix.addEdge(E: std::move(GE)); |
| 472 | |
| 473 | return Error::success(); |
| 474 | } |
| 475 | |
| 476 | /// Return the string name of the given ELF aarch64 edge kind. |
| 477 | const char *getELFAArch64RelocationKindName(Edge::Kind R) { |
| 478 | switch (R) { |
| 479 | case ELFCall26: |
| 480 | return "ELFCall26" ; |
| 481 | case ELFAdrPage21: |
| 482 | return "ELFAdrPage21" ; |
| 483 | case ELFAddAbs12: |
| 484 | return "ELFAddAbs12" ; |
| 485 | case ELFLdSt8Abs12: |
| 486 | return "ELFLdSt8Abs12" ; |
| 487 | case ELFLdSt16Abs12: |
| 488 | return "ELFLdSt16Abs12" ; |
| 489 | case ELFLdSt32Abs12: |
| 490 | return "ELFLdSt32Abs12" ; |
| 491 | case ELFLdSt64Abs12: |
| 492 | return "ELFLdSt64Abs12" ; |
| 493 | case ELFLdSt128Abs12: |
| 494 | return "ELFLdSt128Abs12" ; |
| 495 | case ELFMovwAbsG0: |
| 496 | return "ELFMovwAbsG0" ; |
| 497 | case ELFMovwAbsG1: |
| 498 | return "ELFMovwAbsG1" ; |
| 499 | case ELFMovwAbsG2: |
| 500 | return "ELFMovwAbsG2" ; |
| 501 | case ELFMovwAbsG3: |
| 502 | return "ELFMovwAbsG3" ; |
| 503 | case ELFAbs32: |
| 504 | return "ELFAbs32" ; |
| 505 | case ELFAbs64: |
| 506 | return "ELFAbs64" ; |
| 507 | case ELFPrel32: |
| 508 | return "ELFPrel32" ; |
| 509 | case ELFPrel64: |
| 510 | return "ELFPrel64" ; |
| 511 | case ELFAdrGOTPage21: |
| 512 | return "ELFAdrGOTPage21" ; |
| 513 | case ELFLd64GOTLo12: |
| 514 | return "ELFLd64GOTLo12" ; |
| 515 | case ELFLd64GOTPAGELo15: |
| 516 | return "ELFLd64GOTPAGELo15" ; |
| 517 | case ELFTLSDescAdrPage21: |
| 518 | return "ELFTLSDescAdrPage21" ; |
| 519 | case ELFTLSDescAddLo12: |
| 520 | return "ELFTLSDescAddLo12" ; |
| 521 | case ELFTLSDescLd64Lo12: |
| 522 | return "ELFTLSDescLd64Lo12" ; |
| 523 | case ELFTLSDescCall: |
| 524 | return "ELFTLSDescCall" ; |
| 525 | default: |
| 526 | return getGenericEdgeKindName(K: R); |
| 527 | } |
| 528 | } |
| 529 | |
| 530 | public: |
| 531 | ELFLinkGraphBuilder_aarch64(StringRef FileName, |
| 532 | const object::ELFFile<ELFT> &Obj, |
| 533 | std::shared_ptr<orc::SymbolStringPool> SSP, |
| 534 | Triple TT, SubtargetFeatures Features) |
| 535 | |
| 536 | : ELFLinkGraphBuilder<ELFT>(Obj, std::move(SSP), std::move(TT), |
| 537 | std::move(Features), FileName, |
| 538 | aarch64::getEdgeKindName) {} |
| 539 | }; |
| 540 | |
| 541 | // TLS Info Builder. |
| 542 | class TLSInfoTableManager_ELF_aarch64 |
| 543 | : public TableManager<TLSInfoTableManager_ELF_aarch64> { |
| 544 | public: |
| 545 | static StringRef getSectionName() { return "$__TLSINFO" ; } |
| 546 | |
| 547 | static const uint8_t TLSInfoEntryContent[16]; |
| 548 | |
| 549 | bool visitEdge(LinkGraph &G, Block *B, Edge &E) { return false; } |
| 550 | |
| 551 | Symbol &createEntry(LinkGraph &G, Symbol &Target) { |
| 552 | // the TLS Info entry's key value will be written by the fixTLVSectionByName |
| 553 | // pass, so create mutable content. |
| 554 | auto &TLSInfoEntry = G.createMutableContentBlock( |
| 555 | Parent&: getTLSInfoSection(G), MutableContent: G.allocateContent(Source: getTLSInfoEntryContent()), |
| 556 | Address: orc::ExecutorAddr(), Alignment: 8, AlignmentOffset: 0); |
| 557 | TLSInfoEntry.addEdge(K: aarch64::Pointer64, Offset: 8, Target, Addend: 0); |
| 558 | return G.addAnonymousSymbol(Content&: TLSInfoEntry, Offset: 0, Size: 16, IsCallable: false, IsLive: false); |
| 559 | } |
| 560 | |
| 561 | private: |
| 562 | Section &getTLSInfoSection(LinkGraph &G) { |
| 563 | if (!TLSInfoTable) |
| 564 | TLSInfoTable = &G.createSection(Name: getSectionName(), Prot: orc::MemProt::Read); |
| 565 | return *TLSInfoTable; |
| 566 | } |
| 567 | |
| 568 | ArrayRef<char> getTLSInfoEntryContent() const { |
| 569 | return {reinterpret_cast<const char *>(TLSInfoEntryContent), |
| 570 | sizeof(TLSInfoEntryContent)}; |
| 571 | } |
| 572 | |
| 573 | Section *TLSInfoTable = nullptr; |
| 574 | }; |
| 575 | |
| 576 | const uint8_t TLSInfoTableManager_ELF_aarch64::TLSInfoEntryContent[16] = { |
| 577 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*pthread key */ |
| 578 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /*data address*/ |
| 579 | }; |
| 580 | |
| 581 | // TLS Descriptor Builder. |
| 582 | class TLSDescTableManager_ELF_aarch64 |
| 583 | : public TableManager<TLSDescTableManager_ELF_aarch64> { |
| 584 | public: |
| 585 | TLSDescTableManager_ELF_aarch64( |
| 586 | TLSInfoTableManager_ELF_aarch64 &TLSInfoTableManager) |
| 587 | : TLSInfoTableManager(TLSInfoTableManager) {} |
| 588 | |
| 589 | static StringRef getSectionName() { return "$__TLSDESC" ; } |
| 590 | |
| 591 | static const uint8_t TLSDescEntryContent[16]; |
| 592 | |
| 593 | bool visitEdge(LinkGraph &G, Block *B, Edge &E) { |
| 594 | Edge::Kind KindToSet = Edge::Invalid; |
| 595 | switch (E.getKind()) { |
| 596 | case aarch64::RequestTLSDescEntryAndTransformToPage21: { |
| 597 | KindToSet = aarch64::Page21; |
| 598 | break; |
| 599 | } |
| 600 | case aarch64::RequestTLSDescEntryAndTransformToPageOffset12: { |
| 601 | KindToSet = aarch64::PageOffset12; |
| 602 | break; |
| 603 | } |
| 604 | default: |
| 605 | return false; |
| 606 | } |
| 607 | assert(KindToSet != Edge::Invalid && |
| 608 | "Fell through switch, but no new kind to set" ); |
| 609 | DEBUG_WITH_TYPE("jitlink" , { |
| 610 | dbgs() << " Fixing " << G.getEdgeKindName(E.getKind()) << " edge at " |
| 611 | << B->getFixupAddress(E) << " (" << B->getAddress() << " + " |
| 612 | << formatv("{0:x}" , E.getOffset()) << ")\n" ; |
| 613 | }); |
| 614 | E.setKind(KindToSet); |
| 615 | E.setTarget(getEntryForTarget(G, Target&: E.getTarget())); |
| 616 | return true; |
| 617 | } |
| 618 | |
| 619 | Symbol &createEntry(LinkGraph &G, Symbol &Target) { |
| 620 | auto &EntryBlock = |
| 621 | G.createContentBlock(Parent&: getTLSDescSection(G), Content: getTLSDescBlockContent(), |
| 622 | Address: orc::ExecutorAddr(), Alignment: 8, AlignmentOffset: 0); |
| 623 | EntryBlock.addEdge(K: aarch64::Pointer64, Offset: 0, Target&: getTLSDescResolver(G), Addend: 0); |
| 624 | EntryBlock.addEdge(K: aarch64::Pointer64, Offset: 8, |
| 625 | Target&: TLSInfoTableManager.getEntryForTarget(G, Target), Addend: 0); |
| 626 | return G.addAnonymousSymbol(Content&: EntryBlock, Offset: 0, Size: 8, IsCallable: false, IsLive: false); |
| 627 | } |
| 628 | |
| 629 | private: |
| 630 | Section &getTLSDescSection(LinkGraph &G) { |
| 631 | if (!GOTSection) |
| 632 | GOTSection = &G.createSection(Name: getSectionName(), Prot: orc::MemProt::Read); |
| 633 | return *GOTSection; |
| 634 | } |
| 635 | |
| 636 | Symbol &getTLSDescResolver(LinkGraph &G) { |
| 637 | if (!TLSDescResolver) |
| 638 | TLSDescResolver = &G.addExternalSymbol(Name: "__tlsdesc_resolver" , Size: 8, IsWeaklyReferenced: false); |
| 639 | return *TLSDescResolver; |
| 640 | } |
| 641 | |
| 642 | ArrayRef<char> getTLSDescBlockContent() { |
| 643 | return {reinterpret_cast<const char *>(TLSDescEntryContent), |
| 644 | sizeof(TLSDescEntryContent)}; |
| 645 | } |
| 646 | |
| 647 | Section *GOTSection = nullptr; |
| 648 | Symbol *TLSDescResolver = nullptr; |
| 649 | TLSInfoTableManager_ELF_aarch64 &TLSInfoTableManager; |
| 650 | }; |
| 651 | |
| 652 | const uint8_t TLSDescTableManager_ELF_aarch64::TLSDescEntryContent[16] = { |
| 653 | 0x00, 0x00, 0x00, 0x00, |
| 654 | 0x00, 0x00, 0x00, 0x00, /*resolver function pointer*/ |
| 655 | 0x00, 0x00, 0x00, 0x00, |
| 656 | 0x00, 0x00, 0x00, 0x00 /*pointer to tls info*/ |
| 657 | }; |
| 658 | |
| 659 | Error buildTables_ELF_aarch64(LinkGraph &G) { |
| 660 | LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n" ); |
| 661 | |
| 662 | aarch64::GOTTableManager GOT(G); |
| 663 | aarch64::PLTTableManager PLT(G, GOT); |
| 664 | TLSInfoTableManager_ELF_aarch64 TLSInfo; |
| 665 | TLSDescTableManager_ELF_aarch64 TLSDesc(TLSInfo); |
| 666 | visitExistingEdges(G, Vs&: GOT, Vs&: PLT, Vs&: TLSDesc, Vs&: TLSInfo); |
| 667 | return Error::success(); |
| 668 | } |
| 669 | |
| 670 | } // namespace |
| 671 | |
| 672 | namespace llvm { |
| 673 | namespace jitlink { |
| 674 | |
| 675 | Expected<std::unique_ptr<LinkGraph>> createLinkGraphFromELFObject_aarch64( |
| 676 | MemoryBufferRef ObjectBuffer, std::shared_ptr<orc::SymbolStringPool> SSP) { |
| 677 | LLVM_DEBUG({ |
| 678 | dbgs() << "Building jitlink graph for new input " |
| 679 | << ObjectBuffer.getBufferIdentifier() << "...\n" ; |
| 680 | }); |
| 681 | |
| 682 | auto ELFObj = object::ObjectFile::createELFObjectFile(Object: ObjectBuffer); |
| 683 | if (!ELFObj) |
| 684 | return ELFObj.takeError(); |
| 685 | |
| 686 | auto Features = (*ELFObj)->getFeatures(); |
| 687 | if (!Features) |
| 688 | return Features.takeError(); |
| 689 | |
| 690 | assert((*ELFObj)->getArch() == Triple::aarch64 && |
| 691 | "Only AArch64 (little endian) is supported for now" ); |
| 692 | |
| 693 | auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(Val&: **ELFObj); |
| 694 | return ELFLinkGraphBuilder_aarch64<object::ELF64LE>( |
| 695 | (*ELFObj)->getFileName(), ELFObjFile.getELFFile(), std::move(SSP), |
| 696 | (*ELFObj)->makeTriple(), std::move(*Features)) |
| 697 | .buildGraph(); |
| 698 | } |
| 699 | |
| 700 | void link_ELF_aarch64(std::unique_ptr<LinkGraph> G, |
| 701 | std::unique_ptr<JITLinkContext> Ctx) { |
| 702 | PassConfiguration Config; |
| 703 | const Triple &TT = G->getTargetTriple(); |
| 704 | if (Ctx->shouldAddDefaultTargetPasses(TT)) { |
| 705 | // Add eh-frame passes. |
| 706 | Config.PrePrunePasses.push_back(x: DWARFRecordSectionSplitter(".eh_frame" )); |
| 707 | Config.PrePrunePasses.push_back(x: EHFrameEdgeFixer( |
| 708 | ".eh_frame" , 8, aarch64::Pointer32, aarch64::Pointer64, |
| 709 | aarch64::Delta32, aarch64::Delta64, aarch64::NegDelta32)); |
| 710 | Config.PrePrunePasses.push_back(x: EHFrameNullTerminator(".eh_frame" )); |
| 711 | |
| 712 | // Add a mark-live pass. |
| 713 | if (auto MarkLive = Ctx->getMarkLivePass(TT)) |
| 714 | Config.PrePrunePasses.push_back(x: std::move(MarkLive)); |
| 715 | else |
| 716 | Config.PrePrunePasses.push_back(x: markAllSymbolsLive); |
| 717 | |
| 718 | // Resolve any external section start / end symbols. |
| 719 | Config.PostAllocationPasses.push_back( |
| 720 | x: createDefineExternalSectionStartAndEndSymbolsPass( |
| 721 | F&: identifyELFSectionStartAndEndSymbols)); |
| 722 | |
| 723 | // Add an in-place GOT/TLS/Stubs build pass. |
| 724 | Config.PostPrunePasses.push_back(x: buildTables_ELF_aarch64); |
| 725 | } |
| 726 | |
| 727 | if (auto Err = Ctx->modifyPassConfig(G&: *G, Config)) |
| 728 | return Ctx->notifyFailed(Err: std::move(Err)); |
| 729 | |
| 730 | ELFJITLinker_aarch64::link(Args: std::move(Ctx), Args: std::move(G), Args: std::move(Config)); |
| 731 | } |
| 732 | |
| 733 | } // namespace jitlink |
| 734 | } // namespace llvm |
| 735 | |