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