| 1 | //===-- ELF_mips.cpp - JIT linker implementation for ELF/MIPS ------------===// |
| 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 | #include "llvm/ExecutionEngine/JITLink/ELF_mips.h" |
| 10 | |
| 11 | #include "EHFrameSupportImpl.h" |
| 12 | #include "ELFLinkGraphBuilder.h" |
| 13 | #include "JITLinkGeneric.h" |
| 14 | #include "llvm/ADT/DenseMap.h" |
| 15 | #include "llvm/ADT/STLExtras.h" |
| 16 | #include "llvm/ADT/SmallVector.h" |
| 17 | #include "llvm/BinaryFormat/ELF.h" |
| 18 | #include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h" |
| 19 | #include "llvm/ExecutionEngine/JITLink/mips.h" |
| 20 | #include "llvm/Object/ELF.h" |
| 21 | #include "llvm/Object/ELFObjectFile.h" |
| 22 | #include "llvm/Support/Endian.h" |
| 23 | #include "llvm/Support/ErrorHandling.h" |
| 24 | #include "llvm/Support/MathExtras.h" |
| 25 | #include "llvm/Support/MipsABIFlags.h" |
| 26 | #include "llvm/Support/raw_ostream.h" |
| 27 | |
| 28 | #include <tuple> |
| 29 | |
| 30 | #define DEBUG_TYPE "jitlink" |
| 31 | |
| 32 | using namespace llvm; |
| 33 | using namespace llvm::jitlink; |
| 34 | using namespace llvm::jitlink::mips; |
| 35 | |
| 36 | namespace { |
| 37 | |
| 38 | constexpr StringRef GOTSectionName = "$__GOT" ; |
| 39 | constexpr StringRef StubsSectionName = "$__STUBS" ; |
| 40 | constexpr StringRef TLSInfoSectionName = "$__TLSINFO" ; |
| 41 | constexpr StringRef TLSBaseName = "__jitlink_mips_tls_base" ; |
| 42 | constexpr StringRef GOTSymbolName = "_GLOBAL_OFFSET_TABLE_" ; |
| 43 | constexpr StringRef GPName = "_gp" ; |
| 44 | constexpr StringRef GPDispName = "_gp_disp" ; |
| 45 | constexpr StringRef LocalGPName = "__gnu_local_gp" ; |
| 46 | constexpr unsigned RelocationTypeBits = 8; |
| 47 | constexpr unsigned MaxRelocationOperations = 3; |
| 48 | constexpr int64_t CompactBranchPCBias = InstructionSize; |
| 49 | // The MIPS psABI defines $gp as 0x7ff0 bytes past the GOT base. |
| 50 | constexpr uint64_t GPAnchorOffset = 0x7ff0; |
| 51 | |
| 52 | enum class MipsABI { O32, N32, N64 }; |
| 53 | |
| 54 | static Edge::Kind getPagePointerEdgeKind(const LinkGraph &G) { |
| 55 | return G.getPointerSize() == 8 ? PagePointer64 : PagePointer32; |
| 56 | } |
| 57 | |
| 58 | template <unsigned Bits, unsigned Shift> |
| 59 | static int64_t decodeInstructionImmediate(uint32_t Instruction) { |
| 60 | static_assert(Bits + Shift <= 32); |
| 61 | uint32_t Value = (Instruction & maskTrailingOnes<uint32_t>(N: Bits)) << Shift; |
| 62 | return SignExtend64<Bits + Shift>(Value); |
| 63 | } |
| 64 | |
| 65 | static uint8_t getPackedRelocationField(uint32_t Packed, unsigned Index) { |
| 66 | return static_cast<uint8_t>((Packed >> (Index * RelocationTypeBits)) & |
| 67 | maskTrailingOnes<uint32_t>(N: RelocationTypeBits)); |
| 68 | } |
| 69 | |
| 70 | static std::string getRelocationChainName(ArrayRef<uint8_t> Types) { |
| 71 | std::string Result; |
| 72 | raw_string_ostream OS(Result); |
| 73 | for (auto [Index, Type] : llvm::enumerate(First&: Types)) { |
| 74 | if (Index) |
| 75 | OS << '/'; |
| 76 | OS << object::getELFRelocationTypeName(Machine: ELF::EM_MIPS, Type); |
| 77 | } |
| 78 | return Result; |
| 79 | } |
| 80 | |
| 81 | static unsigned getFixupSize(Edge::Kind K) { |
| 82 | switch (K) { |
| 83 | case Abs16: |
| 84 | return sizeof(uint16_t); |
| 85 | case Pointer64: |
| 86 | case PagePointer64: |
| 87 | case Delta64: |
| 88 | case GPRel64: |
| 89 | case DTPRel64: |
| 90 | return sizeof(uint64_t); |
| 91 | case Pointer32: |
| 92 | case PagePointer32: |
| 93 | case Delta32: |
| 94 | case NegDelta32: |
| 95 | case Hi16: |
| 96 | case Lo16: |
| 97 | case Higher16: |
| 98 | case Highest16: |
| 99 | case Jump26: |
| 100 | case PC16: |
| 101 | case PC32: |
| 102 | case PC18S3: |
| 103 | case PC19S2: |
| 104 | case PC21S2: |
| 105 | case PC26S2: |
| 106 | case PCHi16: |
| 107 | case PCLo16: |
| 108 | case GPDispHi16: |
| 109 | case GPDispLo16: |
| 110 | case GPRel16: |
| 111 | case GPRel32: |
| 112 | case GOTOffset16: |
| 113 | case GOTOffsetHi16: |
| 114 | case GOTOffsetLo16: |
| 115 | case GOTPageOffset16: |
| 116 | case DTPRelHi16: |
| 117 | case DTPRelLo16: |
| 118 | case DTPRel32: |
| 119 | case NegGPRelHi16: |
| 120 | case NegGPRelLo16: |
| 121 | case RequestGOTAndTransformToOffset16: |
| 122 | case RequestGOTPageAndTransformToOffset16: |
| 123 | case RequestGOTAndTransformToOffsetHi16: |
| 124 | case RequestGOTAndTransformToOffsetLo16: |
| 125 | case RequestTLSGDAndTransformToOffset16: |
| 126 | case RequestTLSLDMAndTransformToOffset16: |
| 127 | return sizeof(uint32_t); |
| 128 | default: |
| 129 | llvm_unreachable("not a MIPS relocation edge" ); |
| 130 | } |
| 131 | } |
| 132 | |
| 133 | class ELFJITLinker_mips : public JITLinker<ELFJITLinker_mips> { |
| 134 | friend class JITLinker<ELFJITLinker_mips>; |
| 135 | |
| 136 | public: |
| 137 | ELFJITLinker_mips(std::unique_ptr<JITLinkContext> Ctx, |
| 138 | std::unique_ptr<LinkGraph> G, PassConfiguration PassConfig) |
| 139 | : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) { |
| 140 | getPassConfig().PreFixupPasses.push_back(x: [this](LinkGraph &G) { |
| 141 | GPSymbol = G.findDefinedSymbolByName(Name: G.intern(SymbolName: GPName)); |
| 142 | TLSBaseSymbol = G.findDefinedSymbolByName(Name: G.intern(SymbolName: TLSBaseName)); |
| 143 | return Error::success(); |
| 144 | }); |
| 145 | } |
| 146 | |
| 147 | private: |
| 148 | Symbol *GPSymbol = nullptr; |
| 149 | Symbol *TLSBaseSymbol = nullptr; |
| 150 | |
| 151 | Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const { |
| 152 | return mips::applyFixup(G, B, E, GPSymbol, TLSBaseSymbol); |
| 153 | } |
| 154 | }; |
| 155 | |
| 156 | template <typename ELFT> |
| 157 | class ELFLinkGraphBuilder_mips : public ELFLinkGraphBuilder<ELFT> { |
| 158 | using Base = ELFLinkGraphBuilder<ELFT>; |
| 159 | using Rel = typename ELFT::Rel; |
| 160 | using Rela = typename ELFT::Rela; |
| 161 | |
| 162 | struct Reloc { |
| 163 | uint64_t Offset; |
| 164 | uint32_t Symbol; |
| 165 | SmallVector<uint8_t, MaxRelocationOperations> Types; |
| 166 | int64_t Addend; |
| 167 | }; |
| 168 | |
| 169 | public: |
| 170 | ELFLinkGraphBuilder_mips(StringRef FileName, const object::ELFFile<ELFT> &Obj, |
| 171 | std::shared_ptr<orc::SymbolStringPool> SSP, |
| 172 | Triple TT, SubtargetFeatures Features, MipsABI ABI) |
| 173 | : Base(Obj, std::move(SSP), std::move(TT), std::move(Features), FileName, |
| 174 | mips::getEdgeKindName), |
| 175 | ABI(ABI) {} |
| 176 | |
| 177 | private: |
| 178 | MipsABI ABI; |
| 179 | |
| 180 | bool excludeSection(const typename ELFT::Shdr &Sec) const override { |
| 181 | return Sec.sh_type == ELF::SHT_MIPS_ABIFLAGS || |
| 182 | Sec.sh_type == ELF::SHT_MIPS_REGINFO || |
| 183 | Sec.sh_type == ELF::SHT_MIPS_OPTIONS; |
| 184 | } |
| 185 | |
| 186 | Error error(const typename ELFT::Shdr &FixupSect, uint64_t Offset, |
| 187 | const Twine &Message) const { |
| 188 | auto Name = Base::Obj.getSectionName(FixupSect); |
| 189 | if (!Name) |
| 190 | return Name.takeError(); |
| 191 | return make_error<JITLinkError>(Base::G->getName() + ": section " + *Name + |
| 192 | "+0x" + utohexstr(X: Offset) + ": " + Message); |
| 193 | } |
| 194 | |
| 195 | Expected<int64_t> implicitAddend(const typename ELFT::Shdr &RelSect, |
| 196 | uint8_t Type, const Block &B, |
| 197 | uint64_t Offset) const { |
| 198 | if (Type == ELF::R_MIPS_NONE || Type == ELF::R_MIPS_JALR) |
| 199 | return 0; |
| 200 | |
| 201 | unsigned FixupSize = Type == ELF::R_MIPS_16 ? sizeof(uint16_t) |
| 202 | : Type == ELF::R_MIPS_64 ? sizeof(uint64_t) |
| 203 | : sizeof(uint32_t); |
| 204 | if (Offset > B.getSize() || FixupSize > B.getSize() - Offset) |
| 205 | return error(FixupSect: RelSect, Offset, |
| 206 | Message: "relocation fixup extends past the end of its block" ); |
| 207 | |
| 208 | const char *P = B.getContent().data() + Offset; |
| 209 | if (Type == ELF::R_MIPS_16) |
| 210 | return SignExtend64<16>(support::endian::read16<ELFT::Endianness>(P)); |
| 211 | |
| 212 | if (Type == ELF::R_MIPS_64) |
| 213 | return support::endian::read64<ELFT::Endianness>(P); |
| 214 | |
| 215 | uint32_t W = support::endian::read32<ELFT::Endianness>(P); |
| 216 | switch (Type) { |
| 217 | case ELF::R_MIPS_32: |
| 218 | case ELF::R_MIPS_GPREL32: |
| 219 | case ELF::R_MIPS_PC32: |
| 220 | case ELF::R_MIPS_TLS_DTPREL32: |
| 221 | return SignExtend64<32>(x: W); |
| 222 | case ELF::R_MIPS_26: |
| 223 | return decodeInstructionImmediate<26, 2>(Instruction: W); |
| 224 | case ELF::R_MIPS_HI16: |
| 225 | case ELF::R_MIPS_PCHI16: |
| 226 | case ELF::R_MIPS_GOT16: |
| 227 | case ELF::R_MIPS_GOT_HI16: |
| 228 | case ELF::R_MIPS_CALL_HI16: |
| 229 | return decodeInstructionImmediate<16, 16>(Instruction: W); |
| 230 | case ELF::R_MIPS_PC16: |
| 231 | return decodeInstructionImmediate<16, 2>(Instruction: W); |
| 232 | case ELF::R_MIPS_PC18_S3: |
| 233 | return decodeInstructionImmediate<18, 3>(Instruction: W); |
| 234 | case ELF::R_MIPS_PC19_S2: |
| 235 | return decodeInstructionImmediate<19, 2>(Instruction: W); |
| 236 | case ELF::R_MIPS_PC21_S2: |
| 237 | return decodeInstructionImmediate<21, 2>(Instruction: W); |
| 238 | case ELF::R_MIPS_PC26_S2: |
| 239 | return decodeInstructionImmediate<26, 2>(Instruction: W); |
| 240 | default: |
| 241 | return decodeInstructionImmediate<16, 0>(Instruction: W); |
| 242 | } |
| 243 | } |
| 244 | |
| 245 | static uint8_t matchingLow(uint8_t Type, bool IsLocal) { |
| 246 | switch (Type) { |
| 247 | case ELF::R_MIPS_HI16: |
| 248 | return ELF::R_MIPS_LO16; |
| 249 | case ELF::R_MIPS_PCHI16: |
| 250 | return ELF::R_MIPS_PCLO16; |
| 251 | case ELF::R_MIPS_GOT16: |
| 252 | return IsLocal ? ELF::R_MIPS_LO16 : ELF::R_MIPS_NONE; |
| 253 | default: |
| 254 | return ELF::R_MIPS_NONE; |
| 255 | } |
| 256 | } |
| 257 | |
| 258 | Error validateSymbols() { |
| 259 | if (!Base::SymTabSec) |
| 260 | return Error::success(); |
| 261 | auto Symbols = Base::Obj.symbols(Base::SymTabSec); |
| 262 | if (!Symbols) |
| 263 | return Symbols.takeError(); |
| 264 | for (const auto &Sym : *Symbols) |
| 265 | if ((Sym.st_other & ELF::STO_MIPS_MICROMIPS) || |
| 266 | (Sym.st_other & ELF::STO_MIPS_MIPS16) == ELF::STO_MIPS_MIPS16) |
| 267 | return make_error<JITLinkError>( |
| 268 | Base::G->getName() + |
| 269 | ": compact-mode MIPS16/microMIPS symbols are unsupported" ); |
| 270 | return Error::success(); |
| 271 | } |
| 272 | |
| 273 | Error collectRelocs(const typename ELFT::Shdr &RelSect, Block &B, |
| 274 | SmallVectorImpl<Reloc> &Out) { |
| 275 | if (RelSect.sh_type == ELF::SHT_RELA) { |
| 276 | auto Rs = Base::Obj.relas(RelSect); |
| 277 | if (!Rs) |
| 278 | return Rs.takeError(); |
| 279 | for (auto I = Rs->begin(), E = Rs->end(); I != E;) { |
| 280 | const Rela &R = *I++; |
| 281 | if (ABI == MipsABI::N32) { |
| 282 | Reloc RR{R.r_offset, R.getSymbol(false), {}, R.r_addend}; |
| 283 | RR.Types.push_back(R.getType(false)); |
| 284 | while (I != E && I->r_offset == R.r_offset) { |
| 285 | if (RR.Types.size() == MaxRelocationOperations) |
| 286 | return error(FixupSect: RelSect, Offset: R.r_offset, |
| 287 | Message: "more than three N32 relocation operations" ); |
| 288 | if (I->getSymbol(false) != 0) |
| 289 | return error(FixupSect: RelSect, Offset: R.r_offset, |
| 290 | Message: "non-zero symbol in a secondary N32 relocation" ); |
| 291 | RR.Types.push_back(I->getType(false)); |
| 292 | ++I; |
| 293 | } |
| 294 | Out.push_back(std::move(RR)); |
| 295 | } else { |
| 296 | uint32_t PackedType = R.getType(Base::Obj.isMips64EL()); |
| 297 | Reloc RR{ |
| 298 | R.r_offset, R.getSymbol(Base::Obj.isMips64EL()), {}, R.r_addend}; |
| 299 | uint8_t T2 = getPackedRelocationField(Packed: PackedType, Index: 1); |
| 300 | uint8_t T3 = getPackedRelocationField(Packed: PackedType, Index: 2); |
| 301 | RR.Types.push_back(getPackedRelocationField(Packed: PackedType, Index: 0)); |
| 302 | if (T2 || T3) |
| 303 | RR.Types.push_back(T2); |
| 304 | if (T3) |
| 305 | RR.Types.push_back(T3); |
| 306 | uint8_t SSym = getPackedRelocationField(Packed: PackedType, Index: 3); |
| 307 | if (SSym != ELF::RSS_UNDEF) |
| 308 | return error(FixupSect: RelSect, Offset: R.r_offset, |
| 309 | Message: "unsupported packed relocation special symbol " + |
| 310 | Twine(SSym)); |
| 311 | Out.push_back(std::move(RR)); |
| 312 | } |
| 313 | } |
| 314 | return Error::success(); |
| 315 | } |
| 316 | |
| 317 | auto Rs = Base::Obj.rels(RelSect); |
| 318 | if (!Rs) |
| 319 | return Rs.takeError(); |
| 320 | for (auto I = Rs->begin(), E = Rs->end(); I != E;) { |
| 321 | const Rel &R = *I++; |
| 322 | Reloc RR{R.r_offset, R.getSymbol(false), {}, 0}; |
| 323 | RR.Types.push_back(R.getType(false)); |
| 324 | if (ABI == MipsABI::N32) { |
| 325 | while (I != E && I->r_offset == R.r_offset) { |
| 326 | if (RR.Types.size() == MaxRelocationOperations) |
| 327 | return error(FixupSect: RelSect, Offset: R.r_offset, |
| 328 | Message: "more than three N32 relocation operations" ); |
| 329 | if (I->getSymbol(false) != 0) |
| 330 | return error(FixupSect: RelSect, Offset: R.r_offset, |
| 331 | Message: "non-zero symbol in a secondary N32 relocation" ); |
| 332 | RR.Types.push_back(I->getType(false)); |
| 333 | ++I; |
| 334 | } |
| 335 | } |
| 336 | Out.push_back(std::move(RR)); |
| 337 | } |
| 338 | |
| 339 | for (size_t I = 0; I != Out.size(); ++I) { |
| 340 | auto &R = Out[I]; |
| 341 | uint8_t FinalType = R.Types.back(); |
| 342 | auto Addend = implicitAddend(RelSect, Type: FinalType, B, Offset: R.Offset); |
| 343 | if (!Addend) |
| 344 | return Addend.takeError(); |
| 345 | R.Addend = *Addend; |
| 346 | bool IsLocal = false; |
| 347 | if (auto *S = Base::getGraphSymbol(R.Symbol)) |
| 348 | IsLocal = S->getScope() == Scope::Local; |
| 349 | uint8_t LowType = matchingLow(Type: R.Types.front(), IsLocal); |
| 350 | if (LowType == ELF::R_MIPS_NONE) |
| 351 | continue; |
| 352 | bool Found = false; |
| 353 | for (size_t J = I + 1; J != Out.size(); ++J) |
| 354 | if (Out[J].Types.front() == LowType && Out[J].Symbol == R.Symbol) { |
| 355 | auto LowAddend = implicitAddend(RelSect, Type: LowType, B, Offset: Out[J].Offset); |
| 356 | if (!LowAddend) |
| 357 | return LowAddend.takeError(); |
| 358 | R.Addend += *LowAddend; |
| 359 | Found = true; |
| 360 | break; |
| 361 | } |
| 362 | if (!Found) |
| 363 | return error(FixupSect: RelSect, Offset: R.Offset, |
| 364 | Message: "unmatched " + |
| 365 | Twine(object::getELFRelocationTypeName( |
| 366 | Machine: ELF::EM_MIPS, Type: R.Types.front())) + |
| 367 | " relocation" ); |
| 368 | } |
| 369 | return Error::success(); |
| 370 | } |
| 371 | |
| 372 | Expected<Edge::Kind> edgeKind(const Reloc &R, Symbol &Target) const { |
| 373 | if (R.Types.size() > 1) { |
| 374 | if (R.Types.size() == 2 && R.Types[1] == ELF::R_MIPS_64) { |
| 375 | switch (R.Types[0]) { |
| 376 | case ELF::R_MIPS_32: |
| 377 | case ELF::R_MIPS_64: |
| 378 | return Pointer64; |
| 379 | case ELF::R_MIPS_PC32: |
| 380 | return Delta64; |
| 381 | case ELF::R_MIPS_GPREL32: |
| 382 | return GPRel64; |
| 383 | default: |
| 384 | break; |
| 385 | } |
| 386 | } |
| 387 | if (R.Types.size() == 3 && R.Types[0] == ELF::R_MIPS_GPREL16 && |
| 388 | R.Types[1] == ELF::R_MIPS_SUB && R.Types[2] == ELF::R_MIPS_HI16) |
| 389 | return NegGPRelHi16; |
| 390 | if (R.Types.size() == 3 && R.Types[0] == ELF::R_MIPS_GPREL16 && |
| 391 | R.Types[1] == ELF::R_MIPS_SUB && R.Types[2] == ELF::R_MIPS_LO16) |
| 392 | return NegGPRelLo16; |
| 393 | return make_error<JITLinkError>("unsupported packed MIPS relocation " + |
| 394 | getRelocationChainName(R.Types)); |
| 395 | } |
| 396 | |
| 397 | StringRef Name = Target.hasName() ? *Target.getName() : StringRef(); |
| 398 | switch (R.Types.front()) { |
| 399 | case ELF::R_MIPS_16: |
| 400 | return Abs16; |
| 401 | case ELF::R_MIPS_32: |
| 402 | return Pointer32; |
| 403 | case ELF::R_MIPS_64: |
| 404 | return Pointer64; |
| 405 | case ELF::R_MIPS_HI16: |
| 406 | return Name == GPDispName ? GPDispHi16 : Hi16; |
| 407 | case ELF::R_MIPS_LO16: |
| 408 | return Name == GPDispName ? GPDispLo16 : Lo16; |
| 409 | case ELF::R_MIPS_HIGHER: |
| 410 | return Higher16; |
| 411 | case ELF::R_MIPS_HIGHEST: |
| 412 | return Highest16; |
| 413 | case ELF::R_MIPS_26: |
| 414 | return Jump26; |
| 415 | case ELF::R_MIPS_PC16: |
| 416 | return PC16; |
| 417 | case ELF::R_MIPS_PC32: |
| 418 | return PC32; |
| 419 | case ELF::R_MIPS_PC18_S3: |
| 420 | return PC18S3; |
| 421 | case ELF::R_MIPS_PC19_S2: |
| 422 | return PC19S2; |
| 423 | case ELF::R_MIPS_PC21_S2: |
| 424 | return PC21S2; |
| 425 | case ELF::R_MIPS_PC26_S2: |
| 426 | return PC26S2; |
| 427 | case ELF::R_MIPS_PCHI16: |
| 428 | return PCHi16; |
| 429 | case ELF::R_MIPS_PCLO16: |
| 430 | return PCLo16; |
| 431 | case ELF::R_MIPS_GPREL16: |
| 432 | return GPRel16; |
| 433 | case ELF::R_MIPS_GPREL32: |
| 434 | return GPRel32; |
| 435 | case ELF::R_MIPS_GOT16: |
| 436 | return Target.getScope() == Scope::Local |
| 437 | ? RequestGOTPageAndTransformToOffset16 |
| 438 | : RequestGOTAndTransformToOffset16; |
| 439 | case ELF::R_MIPS_CALL16: |
| 440 | case ELF::R_MIPS_GOT_DISP: |
| 441 | return RequestGOTAndTransformToOffset16; |
| 442 | case ELF::R_MIPS_GOT_PAGE: |
| 443 | return RequestGOTPageAndTransformToOffset16; |
| 444 | case ELF::R_MIPS_GOT_OFST: |
| 445 | return GOTPageOffset16; |
| 446 | case ELF::R_MIPS_GOT_HI16: |
| 447 | case ELF::R_MIPS_CALL_HI16: |
| 448 | return RequestGOTAndTransformToOffsetHi16; |
| 449 | case ELF::R_MIPS_GOT_LO16: |
| 450 | case ELF::R_MIPS_CALL_LO16: |
| 451 | return RequestGOTAndTransformToOffsetLo16; |
| 452 | case ELF::R_MIPS_TLS_GD: |
| 453 | return RequestTLSGDAndTransformToOffset16; |
| 454 | case ELF::R_MIPS_TLS_LDM: |
| 455 | return RequestTLSLDMAndTransformToOffset16; |
| 456 | case ELF::R_MIPS_TLS_DTPREL_HI16: |
| 457 | return DTPRelHi16; |
| 458 | case ELF::R_MIPS_TLS_DTPREL_LO16: |
| 459 | return DTPRelLo16; |
| 460 | case ELF::R_MIPS_TLS_DTPREL32: |
| 461 | return DTPRel32; |
| 462 | case ELF::R_MIPS_TLS_DTPREL64: |
| 463 | return DTPRel64; |
| 464 | case ELF::R_MIPS_TLS_GOTTPREL: |
| 465 | case ELF::R_MIPS_TLS_TPREL32: |
| 466 | case ELF::R_MIPS_TLS_TPREL64: |
| 467 | case ELF::R_MIPS_TLS_TPREL_HI16: |
| 468 | case ELF::R_MIPS_TLS_TPREL_LO16: |
| 469 | return make_error<JITLinkError>( |
| 470 | Args: "initial/local-exec MIPS TLS relocations are unsupported" ); |
| 471 | default: |
| 472 | return make_error<JITLinkError>(Args: "unsupported MIPS relocation " + |
| 473 | Twine(object::getELFRelocationTypeName( |
| 474 | Machine: ELF::EM_MIPS, Type: R.Types.front()))); |
| 475 | } |
| 476 | } |
| 477 | |
| 478 | Error addRelocations() override { |
| 479 | if (auto Err = validateSymbols()) |
| 480 | return Err; |
| 481 | for (const auto &RelSect : Base::Sections) { |
| 482 | if (RelSect.sh_type != ELF::SHT_REL && RelSect.sh_type != ELF::SHT_RELA) |
| 483 | continue; |
| 484 | if ((ABI != MipsABI::O32) != (RelSect.sh_type == ELF::SHT_RELA)) |
| 485 | return make_error<JITLinkError>( |
| 486 | Base::G->getName() + |
| 487 | ": invalid MIPS relocation-section format for ABI" ); |
| 488 | auto FixupSect = Base::Obj.getSection(RelSect.sh_info); |
| 489 | if (!FixupSect) |
| 490 | return FixupSect.takeError(); |
| 491 | Block *B = Base::getGraphBlock(RelSect.sh_info); |
| 492 | if (!B) |
| 493 | continue; |
| 494 | SmallVector<Reloc> Rs; |
| 495 | if (auto Err = collectRelocs(RelSect, B&: *B, Out&: Rs)) |
| 496 | return Err; |
| 497 | for (const Reloc &R : Rs) { |
| 498 | uint8_t Primary = R.Types.front(); |
| 499 | if (Primary == ELF::R_MIPS_NONE || Primary == ELF::R_MIPS_JALR) |
| 500 | continue; |
| 501 | Symbol *Target = Base::getGraphSymbol(R.Symbol); |
| 502 | if (!Target) |
| 503 | return error(FixupSect: **FixupSect, Offset: R.Offset, |
| 504 | Message: "relocation references missing symbol index " + |
| 505 | Twine(R.Symbol)); |
| 506 | auto Kind = edgeKind(R, Target&: *Target); |
| 507 | if (!Kind) |
| 508 | return joinErrors( |
| 509 | error(FixupSect: **FixupSect, Offset: R.Offset, Message: "cannot lower relocation" ), |
| 510 | Kind.takeError()); |
| 511 | auto FixupAddress = orc::ExecutorAddr((*FixupSect)->sh_addr) + R.Offset; |
| 512 | Edge::OffsetT Offset = FixupAddress - B->getAddress(); |
| 513 | unsigned FixupSize = getFixupSize(*Kind); |
| 514 | if (Offset > B->getSize() || FixupSize > B->getSize() - Offset) |
| 515 | return error(FixupSect: **FixupSect, Offset: R.Offset, |
| 516 | Message: "relocation fixup extends past the end of its block" ); |
| 517 | B->addEdge(*Kind, Offset, *Target, R.Addend); |
| 518 | } |
| 519 | } |
| 520 | return Error::success(); |
| 521 | } |
| 522 | }; |
| 523 | |
| 524 | static Symbol &getOrCreateTLSBase(LinkGraph &G) { |
| 525 | auto Name = G.intern(SymbolName: TLSBaseName); |
| 526 | if (auto *S = G.findDefinedSymbolByName(Name)) |
| 527 | return *S; |
| 528 | Section *TLS = G.findSectionByName(Name: ".tdata" ); |
| 529 | if (!TLS || TLS->empty()) |
| 530 | TLS = G.findSectionByName(Name: ".tbss" ); |
| 531 | if (!TLS || TLS->empty()) { |
| 532 | auto &S = |
| 533 | G.createSection(Name: ".tdata" , Prot: orc::MemProt::Read | orc::MemProt::Write); |
| 534 | auto &B = G.createMutableContentBlock(Parent&: S, ContentSize: 0, Address: orc::ExecutorAddr(), Alignment: 1, AlignmentOffset: 0); |
| 535 | return G.addDefinedSymbol(Content&: B, Offset: 0, Name, Size: 0, L: Linkage::Strong, S: Scope::Local, |
| 536 | IsCallable: false, IsLive: true); |
| 537 | } |
| 538 | auto &B = **TLS->blocks().begin(); |
| 539 | return G.addDefinedSymbol(Content&: B, Offset: 0, Name, Size: 0, L: Linkage::Strong, S: Scope::Local, IsCallable: false, |
| 540 | IsLive: true); |
| 541 | } |
| 542 | |
| 543 | class MipsTableManager { |
| 544 | public: |
| 545 | explicit MipsTableManager(LinkGraph &G) : G(G) {} |
| 546 | |
| 547 | bool visitEdge(LinkGraph &, Block *, Edge &E) { |
| 548 | switch (E.getKind()) { |
| 549 | case RequestGOTAndTransformToOffset16: |
| 550 | rewriteGOT(E, EntryKind: GOTEntryKind::Exact, NewKind: GOTOffset16); |
| 551 | return true; |
| 552 | case RequestGOTPageAndTransformToOffset16: |
| 553 | rewriteGOT(E, EntryKind: GOTEntryKind::Page, NewKind: GOTOffset16); |
| 554 | return true; |
| 555 | case RequestGOTAndTransformToOffsetHi16: |
| 556 | rewriteGOT(E, EntryKind: GOTEntryKind::Exact, NewKind: GOTOffsetHi16); |
| 557 | return true; |
| 558 | case RequestGOTAndTransformToOffsetLo16: |
| 559 | rewriteGOT(E, EntryKind: GOTEntryKind::Exact, NewKind: GOTOffsetLo16); |
| 560 | return true; |
| 561 | case RequestTLSGDAndTransformToOffset16: |
| 562 | rewriteTLS(E, Kind: TLSDescriptorKind::GeneralDynamic); |
| 563 | return true; |
| 564 | case RequestTLSLDMAndTransformToOffset16: |
| 565 | rewriteTLS(E, Kind: TLSDescriptorKind::LocalDynamic); |
| 566 | return true; |
| 567 | case Jump26: |
| 568 | if (!E.getTarget().isDefined()) { |
| 569 | rewriteBranchToStub(E); |
| 570 | return true; |
| 571 | } |
| 572 | return false; |
| 573 | case PC26S2: |
| 574 | if (mips::isR6(G) && !E.getTarget().isDefined()) { |
| 575 | rewriteBranchToStub(E); |
| 576 | return true; |
| 577 | } |
| 578 | return false; |
| 579 | default: |
| 580 | return false; |
| 581 | } |
| 582 | } |
| 583 | |
| 584 | private: |
| 585 | enum class GOTEntryKind { Exact, Page }; |
| 586 | enum class TLSDescriptorKind { GeneralDynamic, LocalDynamic }; |
| 587 | |
| 588 | using GOTKey = std::tuple<Symbol *, int64_t, GOTEntryKind>; |
| 589 | using StubKey = std::tuple<Symbol *, int64_t>; |
| 590 | LinkGraph &G; |
| 591 | DenseMap<GOTKey, Symbol *> GOTEntries; |
| 592 | DenseMap<StubKey, Symbol *> Stubs; |
| 593 | DenseMap<std::pair<Symbol *, int64_t>, Symbol *> TLSGDEntries; |
| 594 | Symbol *TLSLDMEntry = nullptr; |
| 595 | |
| 596 | Section &getSection(StringRef Name, orc::MemProt Prot) { |
| 597 | if (auto *S = G.findSectionByName(Name)) |
| 598 | return *S; |
| 599 | return G.createSection(Name, Prot); |
| 600 | } |
| 601 | |
| 602 | Symbol &getGOT(Symbol &Target, int64_t Addend, GOTEntryKind Kind) { |
| 603 | GOTKey Key{&Target, Addend, Kind}; |
| 604 | auto I = GOTEntries.find(Val: Key); |
| 605 | if (I != GOTEntries.end()) |
| 606 | return *I->second; |
| 607 | auto &Sec = |
| 608 | getSection(Name: GOTSectionName, Prot: orc::MemProt::Read | orc::MemProt::Write); |
| 609 | auto &Entry = mips::createAnonymousPointer(G, PointerSection&: Sec); |
| 610 | Edge::Kind PointerKind = Kind == GOTEntryKind::Page |
| 611 | ? getPagePointerEdgeKind(G) |
| 612 | : mips::getPointerEdgeKind(G); |
| 613 | Entry.getBlock().addEdge(K: PointerKind, Offset: 0, Target, Addend); |
| 614 | GOTEntries[Key] = &Entry; |
| 615 | return Entry; |
| 616 | } |
| 617 | |
| 618 | void rewriteGOT(Edge &E, GOTEntryKind EntryKind, Edge::Kind NewKind) { |
| 619 | Symbol &Entry = getGOT(Target&: E.getTarget(), Addend: E.getAddend(), Kind: EntryKind); |
| 620 | E.setKind(NewKind); |
| 621 | E.setTarget(Entry); |
| 622 | E.setAddend(0); |
| 623 | } |
| 624 | |
| 625 | Symbol &createTLSInfo(Symbol &Target, int64_t Addend) { |
| 626 | auto &Sec = getSection(Name: TLSInfoSectionName, |
| 627 | Prot: orc::MemProt::Read | orc::MemProt::Write); |
| 628 | auto &B = |
| 629 | G.createMutableContentBlock(Parent&: Sec, ContentSize: 2 * G.getPointerSize(), |
| 630 | Address: orc::ExecutorAddr(), Alignment: G.getPointerSize(), AlignmentOffset: 0); |
| 631 | B.addEdge(K: mips::getPointerEdgeKind(G), Offset: G.getPointerSize(), Target, Addend); |
| 632 | return G.addAnonymousSymbol(Content&: B, Offset: 0, Size: B.getSize(), IsCallable: false, IsLive: false); |
| 633 | } |
| 634 | |
| 635 | void rewriteTLS(Edge &E, TLSDescriptorKind Kind) { |
| 636 | Symbol *Entry = nullptr; |
| 637 | if (Kind == TLSDescriptorKind::LocalDynamic) { |
| 638 | if (!TLSLDMEntry) |
| 639 | TLSLDMEntry = &createTLSInfo(Target&: getOrCreateTLSBase(G), Addend: 0); |
| 640 | Entry = TLSLDMEntry; |
| 641 | } else { |
| 642 | auto Key = std::make_pair(x: &E.getTarget(), y: E.getAddend()); |
| 643 | auto I = TLSGDEntries.find(Val: Key); |
| 644 | if (I == TLSGDEntries.end()) |
| 645 | I = TLSGDEntries |
| 646 | .try_emplace(Key, Args: &createTLSInfo(Target&: E.getTarget(), Addend: E.getAddend())) |
| 647 | .first; |
| 648 | Entry = I->second; |
| 649 | } |
| 650 | E.setKind(GOTOffset16); |
| 651 | E.setTarget(*Entry); |
| 652 | E.setAddend(0); |
| 653 | } |
| 654 | |
| 655 | void rewriteBranchToStub(Edge &E) { |
| 656 | // PC26_S2 uses PC + 4; JITLink edges use the fixup address. |
| 657 | int64_t PointerAddend = E.getAddend(); |
| 658 | int64_t BranchAddend = 0; |
| 659 | if (E.getKind() == PC26S2) { |
| 660 | PointerAddend += CompactBranchPCBias; |
| 661 | BranchAddend = -CompactBranchPCBias; |
| 662 | } |
| 663 | |
| 664 | StubKey Key{&E.getTarget(), PointerAddend}; |
| 665 | auto I = Stubs.find(Val: Key); |
| 666 | if (I == Stubs.end()) { |
| 667 | auto &Ptr = getGOT(Target&: E.getTarget(), Addend: PointerAddend, Kind: GOTEntryKind::Exact); |
| 668 | auto &Sec = |
| 669 | getSection(Name: StubsSectionName, Prot: orc::MemProt::Read | orc::MemProt::Exec); |
| 670 | I = Stubs |
| 671 | .try_emplace(Key, |
| 672 | Args: &mips::createAnonymousPointerJumpStub(G, StubSection&: Sec, PointerSymbol&: Ptr)) |
| 673 | .first; |
| 674 | } |
| 675 | E.setTarget(*I->second); |
| 676 | E.setAddend(BranchAddend); |
| 677 | } |
| 678 | }; |
| 679 | |
| 680 | static Error buildTables(LinkGraph &G) { |
| 681 | MipsTableManager Tables(G); |
| 682 | visitExistingEdges(G, Vs&: Tables); |
| 683 | return Error::success(); |
| 684 | } |
| 685 | |
| 686 | static Symbol &defineMagic(LinkGraph &G, Block &Anchor, StringRef Name, |
| 687 | uint64_t Offset) { |
| 688 | auto N = G.intern(SymbolName: Name); |
| 689 | if (auto *S = G.findDefinedSymbolByName(Name: N)) { |
| 690 | S->setLive(true); |
| 691 | return *S; |
| 692 | } |
| 693 | if (auto *S = G.findExternalSymbolByName(Name: N)) { |
| 694 | G.makeDefined(Sym&: *S, Content&: Anchor, Offset, Size: 0, L: Linkage::Strong, S: Scope::Local, IsLive: true); |
| 695 | return *S; |
| 696 | } |
| 697 | return G.addDefinedSymbol(Content&: Anchor, Offset, Name: N, Size: 0, L: Linkage::Strong, S: Scope::Local, |
| 698 | IsCallable: false, IsLive: true); |
| 699 | } |
| 700 | |
| 701 | static void prepareGPRegion(LinkGraph &G, |
| 702 | ArrayRef<std::string> GPRelSectionNames) { |
| 703 | Section *GOT = G.findSectionByName(Name: GOTSectionName); |
| 704 | if (!GOT) |
| 705 | GOT = &G.createSection(Name: GOTSectionName, |
| 706 | Prot: orc::MemProt::Read | orc::MemProt::Write); |
| 707 | // Keep the reserved GP window as content so it can share the GOT section. |
| 708 | auto &Anchor = G.createMutableContentBlock( |
| 709 | Parent&: *GOT, ContentSize: GPAnchorOffset, Address: orc::ExecutorAddr(), Alignment: G.getPointerSize(), AlignmentOffset: 0); |
| 710 | defineMagic(G, Anchor, Name: GOTSymbolName, Offset: 0); |
| 711 | defineMagic(G, Anchor, Name: GPName, Offset: GPAnchorOffset); |
| 712 | defineMagic(G, Anchor, Name: GPDispName, Offset: GPAnchorOffset); |
| 713 | defineMagic(G, Anchor, Name: LocalGPName, Offset: GPAnchorOffset); |
| 714 | |
| 715 | for (const std::string &Name : GPRelSectionNames) |
| 716 | if (auto *S = G.findSectionByName(Name)) { |
| 717 | SmallVector<Block *> Blocks(S->blocks().begin(), S->blocks().end()); |
| 718 | for (auto *B : Blocks) |
| 719 | G.transferBlock(B&: *B, NewSection&: *GOT); |
| 720 | } |
| 721 | } |
| 722 | |
| 723 | static Error orderGPRegion(LinkGraph &G) { |
| 724 | auto *GOT = G.findSectionByName(Name: GOTSectionName); |
| 725 | if (!GOT) |
| 726 | return Error::success(); |
| 727 | |
| 728 | if (auto *TLSInfo = G.findSectionByName(Name: TLSInfoSectionName)) |
| 729 | G.mergeSections(DstSection&: *GOT, SrcSection&: *TLSInfo); |
| 730 | |
| 731 | auto *GOTBase = G.findDefinedSymbolByName(Name: G.intern(SymbolName: GOTSymbolName)); |
| 732 | assert(GOTBase && &GOTBase->getBlock().getSection() == GOT && |
| 733 | GOTBase->getOffset() == 0 && "invalid MIPS GOT base" ); |
| 734 | |
| 735 | // BasicLayout orders equal-address blocks by size. Give synthesized entries |
| 736 | // the anchor's end address to keep the reserved GP window first. |
| 737 | Block &Anchor = GOTBase->getBlock(); |
| 738 | Anchor.setAddress(orc::ExecutorAddr()); |
| 739 | for (auto *B : GOT->blocks()) |
| 740 | if (B != &Anchor) |
| 741 | B->setAddress(orc::ExecutorAddr(Anchor.getSize())); |
| 742 | |
| 743 | return Error::success(); |
| 744 | } |
| 745 | |
| 746 | template <typename ELFT> |
| 747 | Error validateABIFlags(const object::ELFFile<ELFT> &Obj, MipsABI ABI, |
| 748 | StringRef FileName) { |
| 749 | auto Sections = Obj.sections(); |
| 750 | if (!Sections) |
| 751 | return Sections.takeError(); |
| 752 | const typename ELFT::Shdr *ABIFlagsSec = nullptr; |
| 753 | for (const auto &Sec : *Sections) |
| 754 | if (Sec.sh_type == ELF::SHT_MIPS_ABIFLAGS) { |
| 755 | if (ABIFlagsSec) |
| 756 | return make_error<JITLinkError>(Args: FileName.str() + |
| 757 | ": multiple .MIPS.abiflags sections" ); |
| 758 | ABIFlagsSec = &Sec; |
| 759 | } |
| 760 | if (!ABIFlagsSec) |
| 761 | return Error::success(); |
| 762 | auto Contents = Obj.template getSectionContentsAsArray<char>(*ABIFlagsSec); |
| 763 | if (!Contents) |
| 764 | return Contents.takeError(); |
| 765 | if (Contents->size() != sizeof(object::Elf_Mips_ABIFlags<ELFT>)) |
| 766 | return make_error<JITLinkError>(Args: FileName.str() + |
| 767 | ": invalid .MIPS.abiflags size" ); |
| 768 | const auto &AF = *reinterpret_cast<const object::Elf_Mips_ABIFlags<ELFT> *>( |
| 769 | Contents->data()); |
| 770 | if (AF.version != 0) |
| 771 | return make_error<JITLinkError>(Args: FileName.str() + |
| 772 | ": unsupported .MIPS.abiflags version" ); |
| 773 | if ((ABI == MipsABI::N32 || ABI == MipsABI::N64) && |
| 774 | AF.gpr_size != Mips::AFL_REG_64) |
| 775 | return make_error<JITLinkError>( |
| 776 | Args: FileName.str() + ": N32/N64 requires 64-bit general registers" ); |
| 777 | if (static_cast<uint32_t>(AF.ases) & |
| 778 | (Mips::AFL_ASE_MIPS16 | Mips::AFL_ASE_MICROMIPS)) |
| 779 | return make_error<JITLinkError>( |
| 780 | Args: FileName.str() + |
| 781 | ": MIPS16 and microMIPS ABI flags are unsupported by JITLink" ); |
| 782 | return Error::success(); |
| 783 | } |
| 784 | |
| 785 | template <typename ELFT> |
| 786 | Expected<std::unique_ptr<LinkGraph>> |
| 787 | buildGraph(object::ELFObjectFile<ELFT> &ObjFile, |
| 788 | std::shared_ptr<orc::SymbolStringPool> SSP, MipsABI ABI, Triple TT, |
| 789 | SubtargetFeatures Features) { |
| 790 | auto &Obj = ObjFile.getELFFile(); |
| 791 | if (auto Err = validateABIFlags(Obj, ABI, ObjFile.getFileName())) |
| 792 | return std::move(Err); |
| 793 | ELFLinkGraphBuilder_mips<ELFT> Builder(ObjFile.getFileName(), Obj, |
| 794 | std::move(SSP), std::move(TT), |
| 795 | std::move(Features), ABI); |
| 796 | auto G = Builder.buildGraph(); |
| 797 | if (!G) |
| 798 | return G.takeError(); |
| 799 | |
| 800 | SmallVector<std::string> GPRelSections; |
| 801 | auto Sections = Obj.sections(); |
| 802 | if (!Sections) |
| 803 | return Sections.takeError(); |
| 804 | for (const auto &Sec : *Sections) |
| 805 | if (Sec.sh_flags & ELF::SHF_MIPS_GPREL) { |
| 806 | auto Name = Obj.getSectionName(Sec); |
| 807 | if (!Name) |
| 808 | return Name.takeError(); |
| 809 | GPRelSections.push_back(Name->str()); |
| 810 | } |
| 811 | prepareGPRegion(**G, GPRelSections); |
| 812 | return G; |
| 813 | } |
| 814 | |
| 815 | static Expected<MipsABI> (const object::ELFObjectFileBase &Obj, |
| 816 | uint8_t ELFClass, StringRef FileName) { |
| 817 | uint32_t Flags = Obj.getPlatformFlags(); |
| 818 | if (Flags & (ELF::EF_MIPS_ARCH_ASE_M16 | ELF::EF_MIPS_MICROMIPS)) |
| 819 | return make_error<JITLinkError>( |
| 820 | Args: FileName.str() + |
| 821 | ": MIPS16 and microMIPS objects are unsupported by JITLink" ); |
| 822 | |
| 823 | uint32_t ABIFlag = Flags & ELF::EF_MIPS_ABI; |
| 824 | if (ELFClass == ELF::ELFCLASS64) { |
| 825 | if ((Flags & ELF::EF_MIPS_ABI2) || ABIFlag != 0) |
| 826 | return make_error<JITLinkError>( |
| 827 | Args: FileName.str() + ": inconsistent MIPS N64 ELF class/ABI flags" ); |
| 828 | return MipsABI::N64; |
| 829 | } |
| 830 | if (Flags & ELF::EF_MIPS_ABI2) { |
| 831 | if (ABIFlag != 0) |
| 832 | return make_error<JITLinkError>( |
| 833 | Args: FileName.str() + ": inconsistent MIPS N32 ELF class/ABI flags" ); |
| 834 | return MipsABI::N32; |
| 835 | } |
| 836 | if (ABIFlag != 0 && ABIFlag != ELF::EF_MIPS_ABI_O32) |
| 837 | return make_error<JITLinkError>(Args: FileName.str() + |
| 838 | ": unsupported 32-bit MIPS ABI flags" ); |
| 839 | return MipsABI::O32; |
| 840 | } |
| 841 | |
| 842 | } // namespace |
| 843 | |
| 844 | namespace llvm { |
| 845 | namespace jitlink { |
| 846 | |
| 847 | Expected<std::unique_ptr<LinkGraph>> |
| 848 | createLinkGraphFromELFObject_mips(MemoryBufferRef ObjectBuffer, |
| 849 | std::shared_ptr<orc::SymbolStringPool> SSP) { |
| 850 | StringRef FileName = ObjectBuffer.getBufferIdentifier(); |
| 851 | auto ELFObj = object::ObjectFile::createELFObjectFile(Object: ObjectBuffer); |
| 852 | if (!ELFObj) |
| 853 | return ELFObj.takeError(); |
| 854 | auto &Base = cast<object::ELFObjectFileBase>(Val&: **ELFObj); |
| 855 | assert(Base.getEMachine() == ELF::EM_MIPS && "expected an ELF/MIPS object" ); |
| 856 | |
| 857 | StringRef Buf = ObjectBuffer.getBuffer(); |
| 858 | uint8_t Class = Buf[ELF::EI_CLASS]; |
| 859 | uint8_t Data = Buf[ELF::EI_DATA]; |
| 860 | auto ABI = validateHeader(Obj: Base, ELFClass: Class, FileName); |
| 861 | if (!ABI) |
| 862 | return ABI.takeError(); |
| 863 | auto Features = Base.getFeatures(); |
| 864 | if (!Features) |
| 865 | return Features.takeError(); |
| 866 | |
| 867 | Triple TT = Base.makeTriple(); |
| 868 | if (*ABI == MipsABI::N32) { |
| 869 | TT.setArch(Kind: Data == ELF::ELFDATA2LSB ? Triple::mips64el : Triple::mips64); |
| 870 | TT.setEnvironment(Triple::GNUABIN32); |
| 871 | } |
| 872 | |
| 873 | if (Class == ELF::ELFCLASS32 && Data == ELF::ELFDATA2LSB) |
| 874 | return buildGraph(ObjFile&: cast<object::ELFObjectFile<object::ELF32LE>>(Val&: **ELFObj), |
| 875 | SSP: std::move(SSP), ABI: *ABI, TT, Features: std::move(*Features)); |
| 876 | if (Class == ELF::ELFCLASS32 && Data == ELF::ELFDATA2MSB) |
| 877 | return buildGraph(ObjFile&: cast<object::ELFObjectFile<object::ELF32BE>>(Val&: **ELFObj), |
| 878 | SSP: std::move(SSP), ABI: *ABI, TT, Features: std::move(*Features)); |
| 879 | if (Class == ELF::ELFCLASS64 && Data == ELF::ELFDATA2LSB) |
| 880 | return buildGraph(ObjFile&: cast<object::ELFObjectFile<object::ELF64LE>>(Val&: **ELFObj), |
| 881 | SSP: std::move(SSP), ABI: *ABI, TT, Features: std::move(*Features)); |
| 882 | if (Class == ELF::ELFCLASS64 && Data == ELF::ELFDATA2MSB) |
| 883 | return buildGraph(ObjFile&: cast<object::ELFObjectFile<object::ELF64BE>>(Val&: **ELFObj), |
| 884 | SSP: std::move(SSP), ABI: *ABI, TT, Features: std::move(*Features)); |
| 885 | llvm_unreachable("invalid ELF/MIPS class or byte order" ); |
| 886 | } |
| 887 | |
| 888 | void link_ELF_mips(std::unique_ptr<LinkGraph> G, |
| 889 | std::unique_ptr<JITLinkContext> Ctx) { |
| 890 | PassConfiguration Config; |
| 891 | const Triple &TT = G->getTargetTriple(); |
| 892 | if (Ctx->shouldAddDefaultTargetPasses(TT)) { |
| 893 | Config.PrePrunePasses.push_back(x: DWARFRecordSectionSplitter(".eh_frame" )); |
| 894 | Config.PrePrunePasses.push_back( |
| 895 | x: EHFrameEdgeFixer(".eh_frame" , G->getPointerSize(), Pointer32, Pointer64, |
| 896 | Delta32, Delta64, NegDelta32)); |
| 897 | Config.PrePrunePasses.push_back(x: EHFrameNullTerminator(".eh_frame" )); |
| 898 | if (auto MarkLive = Ctx->getMarkLivePass(TT)) |
| 899 | Config.PrePrunePasses.push_back(x: std::move(MarkLive)); |
| 900 | else |
| 901 | Config.PrePrunePasses.push_back(x: markAllSymbolsLive); |
| 902 | Config.PostPrunePasses.push_back(x: buildTables); |
| 903 | } |
| 904 | if (auto Err = Ctx->modifyPassConfig(G&: *G, Config)) |
| 905 | return Ctx->notifyFailed(Err: std::move(Err)); |
| 906 | if (Ctx->shouldAddDefaultTargetPasses(TT)) |
| 907 | Config.PostPrunePasses.push_back(x: orderGPRegion); |
| 908 | ELFJITLinker_mips::link(Args: std::move(Ctx), Args: std::move(G), Args: std::move(Config)); |
| 909 | } |
| 910 | |
| 911 | } // namespace jitlink |
| 912 | } // namespace llvm |
| 913 | |