//===--- Relocation.cpp - Interface for object file relocations ----------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // //===----------------------------------------------------------------------===// #include "Relocation.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCStreamer.h" using namespace llvm; using namespace bolt; Triple::ArchType Relocation::Arch; bool Relocation::isSupported(uint64_t Type) { switch (Type) { default: return false; case ELF::R_X86_64_8: case ELF::R_X86_64_16: case ELF::R_X86_64_32: case ELF::R_X86_64_32S: case ELF::R_X86_64_64: case ELF::R_X86_64_PC8: case ELF::R_X86_64_PC32: case ELF::R_X86_64_PC64: case ELF::R_X86_64_PLT32: case ELF::R_X86_64_GOTPCREL: case ELF::R_X86_64_GOTTPOFF: case ELF::R_X86_64_TPOFF32: case ELF::R_X86_64_GOTPCRELX: case ELF::R_X86_64_REX_GOTPCRELX: case ELF::R_AARCH64_CALL26: case ELF::R_AARCH64_ADR_PREL_PG_HI21: case ELF::R_AARCH64_LDST64_ABS_LO12_NC: case ELF::R_AARCH64_ADD_ABS_LO12_NC: case ELF::R_AARCH64_LDST128_ABS_LO12_NC: case ELF::R_AARCH64_LDST32_ABS_LO12_NC: case ELF::R_AARCH64_LDST16_ABS_LO12_NC: case ELF::R_AARCH64_LDST8_ABS_LO12_NC: case ELF::R_AARCH64_ADR_GOT_PAGE: case ELF::R_AARCH64_TLSDESC_ADR_PAGE21: case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: case ELF::R_AARCH64_TLSLE_ADD_TPREL_HI12: case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: case ELF::R_AARCH64_LD64_GOT_LO12_NC: case ELF::R_AARCH64_TLSDESC_LD64_LO12: case ELF::R_AARCH64_TLSDESC_ADD_LO12: case ELF::R_AARCH64_TLSDESC_CALL: case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: case ELF::R_AARCH64_JUMP26: case ELF::R_AARCH64_PREL32: case ELF::R_AARCH64_ABS64: return true; } } size_t Relocation::getSizeForType(uint64_t Type) { switch (Type) { default: llvm_unreachable("unsupported relocation type"); case ELF::R_X86_64_8: case ELF::R_X86_64_PC8: return 1; case ELF::R_X86_64_16: return 2; case ELF::R_X86_64_PLT32: case ELF::R_X86_64_PC32: case ELF::R_X86_64_32S: case ELF::R_X86_64_32: case ELF::R_X86_64_GOTPCREL: case ELF::R_X86_64_GOTTPOFF: case ELF::R_X86_64_TPOFF32: case ELF::R_X86_64_GOTPCRELX: case ELF::R_X86_64_REX_GOTPCRELX: case ELF::R_AARCH64_CALL26: case ELF::R_AARCH64_ADR_PREL_PG_HI21: case ELF::R_AARCH64_LDST64_ABS_LO12_NC: case ELF::R_AARCH64_ADD_ABS_LO12_NC: case ELF::R_AARCH64_LDST128_ABS_LO12_NC: case ELF::R_AARCH64_LDST32_ABS_LO12_NC: case ELF::R_AARCH64_LDST16_ABS_LO12_NC: case ELF::R_AARCH64_LDST8_ABS_LO12_NC: case ELF::R_AARCH64_ADR_GOT_PAGE: case ELF::R_AARCH64_TLSDESC_ADR_PAGE21: case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: case ELF::R_AARCH64_TLSLE_ADD_TPREL_HI12: case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: case ELF::R_AARCH64_LD64_GOT_LO12_NC: case ELF::R_AARCH64_TLSDESC_LD64_LO12: case ELF::R_AARCH64_TLSDESC_ADD_LO12: case ELF::R_AARCH64_TLSDESC_CALL: case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: case ELF::R_AARCH64_JUMP26: case ELF::R_AARCH64_PREL32: return 4; case ELF::R_X86_64_PC64: case ELF::R_X86_64_64: case ELF::R_AARCH64_ABS64: return 8; } } uint64_t Relocation::extractValue(uint64_t Type, uint64_t Contents, uint64_t PC) { switch (Type) { default: return Contents; case ELF::R_X86_64_32S: return SignExtend64<32>(Contents & 0xffffffff); case ELF::R_AARCH64_PREL32: return static_cast(PC) + SignExtend64<32>(Contents & 0xffffffff); case ELF::R_AARCH64_TLSDESC_CALL: case ELF::R_AARCH64_JUMP26: case ELF::R_AARCH64_CALL26: // Immediate goes in bits 25:0 of B and BL. Contents &= ~0xfffffffffc000000ULL; return static_cast(PC) + SignExtend64<28>(Contents << 2); case ELF::R_AARCH64_ADR_GOT_PAGE: case ELF::R_AARCH64_TLSDESC_ADR_PAGE21: case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: case ELF::R_AARCH64_ADR_PREL_PG_HI21: { // Bits 32:12 of Symbol address goes in bits 30:29 + 23:5 of ADRP // instruction Contents &= ~0xffffffff9f00001fUll; auto LowBits = (Contents >> 29) & 0x3; auto HighBits = (Contents >> 5) & 0x7ffff; Contents = LowBits | (HighBits << 2); Contents = static_cast(PC) + SignExtend64<32>(Contents << 12); Contents &= ~0xfffUll; return Contents; } case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: case ELF::R_AARCH64_TLSDESC_LD64_LO12: case ELF::R_AARCH64_LD64_GOT_LO12_NC: case ELF::R_AARCH64_LDST64_ABS_LO12_NC: { // Immediate goes in bits 21:10 of LD/ST instruction, taken // from bits 11:3 of Symbol address Contents &= ~0xffffffffffc003ffU; return Contents >> (10 - 3); } case ELF::R_AARCH64_TLSLE_ADD_TPREL_HI12: case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: case ELF::R_AARCH64_TLSDESC_ADD_LO12: case ELF::R_AARCH64_ADD_ABS_LO12_NC: { // Immediate goes in bits 21:10 of ADD instruction Contents &= ~0xffffffffffc003ffU; return Contents >> (10 - 0); } case ELF::R_AARCH64_LDST128_ABS_LO12_NC: { // Immediate goes in bits 21:10 of ADD instruction, taken // from bits 11:4 of Symbol address Contents &= ~0xffffffffffc003ffU; return Contents >> (10 - 4); } case ELF::R_AARCH64_LDST32_ABS_LO12_NC: { // Immediate goes in bits 21:10 of ADD instruction, taken // from bits 11:2 of Symbol address Contents &= ~0xffffffffffc003ffU; return Contents >> (10 - 2); } case ELF::R_AARCH64_LDST16_ABS_LO12_NC: { // Immediate goes in bits 21:10 of ADD instruction, taken // from bits 11:1 of Symbol address Contents &= ~0xffffffffffc003ffU; return Contents >> (10 - 1); } case ELF::R_AARCH64_LDST8_ABS_LO12_NC: { // Immediate goes in bits 21:10 of ADD instruction, taken // from bits 11:0 of Symbol address Contents &= ~0xffffffffffc003ffU; return Contents >> (10 - 0); } } } bool Relocation::isGOT(uint64_t Type) { switch (Type) { default: return false; case ELF::R_X86_64_GOT32: case ELF::R_X86_64_GOTPCREL: case ELF::R_X86_64_GOTTPOFF: case ELF::R_X86_64_GOTOFF64: case ELF::R_X86_64_GOTPC32: case ELF::R_X86_64_GOT64: case ELF::R_X86_64_GOTPCREL64: case ELF::R_X86_64_GOTPC64: case ELF::R_X86_64_GOTPLT64: case ELF::R_X86_64_GOTPC32_TLSDESC: case ELF::R_X86_64_GOTPCRELX: case ELF::R_X86_64_REX_GOTPCRELX: case ELF::R_AARCH64_ADR_GOT_PAGE: case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: case ELF::R_AARCH64_LD64_GOT_LO12_NC: case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: case ELF::R_AARCH64_TLSLE_ADD_TPREL_HI12: case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: case ELF::R_AARCH64_TLSDESC_ADR_PAGE21: case ELF::R_AARCH64_TLSDESC_LD64_LO12: case ELF::R_AARCH64_TLSDESC_ADD_LO12: case ELF::R_AARCH64_TLSDESC_CALL: return true; } } bool Relocation::isTLS(uint64_t Type) { switch (Type) { default: return false; case ELF::R_X86_64_TPOFF32: case ELF::R_X86_64_TPOFF64: case ELF::R_X86_64_GOTTPOFF: case ELF::R_AARCH64_TLSDESC_ADR_PAGE21: case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: case ELF::R_AARCH64_TLSLE_ADD_TPREL_HI12: case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: case ELF::R_AARCH64_TLSDESC_LD64_LO12: case ELF::R_AARCH64_TLSDESC_ADD_LO12: case ELF::R_AARCH64_TLSDESC_CALL: case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: return true; } } bool Relocation::isPCRelative(uint64_t Type) { switch (Type) { default: llvm_unreachable("Unknown relocation type"); case ELF::R_X86_64_64: case ELF::R_X86_64_32: case ELF::R_X86_64_32S: case ELF::R_X86_64_16: case ELF::R_X86_64_8: case ELF::R_X86_64_TPOFF32: case ELF::R_AARCH64_ABS64: case ELF::R_AARCH64_LDST64_ABS_LO12_NC: case ELF::R_AARCH64_ADD_ABS_LO12_NC: case ELF::R_AARCH64_LDST128_ABS_LO12_NC: case ELF::R_AARCH64_LDST32_ABS_LO12_NC: case ELF::R_AARCH64_LDST16_ABS_LO12_NC: case ELF::R_AARCH64_LDST8_ABS_LO12_NC: case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: case ELF::R_AARCH64_TLSLE_ADD_TPREL_HI12: case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: case ELF::R_AARCH64_LD64_GOT_LO12_NC: case ELF::R_AARCH64_TLSDESC_LD64_LO12: case ELF::R_AARCH64_TLSDESC_ADD_LO12: return false; case ELF::R_X86_64_PC8: case ELF::R_X86_64_PC32: case ELF::R_X86_64_PC64: case ELF::R_X86_64_GOTPCREL: case ELF::R_X86_64_PLT32: case ELF::R_X86_64_GOTTPOFF: case ELF::R_X86_64_GOTPCRELX: case ELF::R_X86_64_REX_GOTPCRELX: case ELF::R_AARCH64_TLSDESC_CALL: case ELF::R_AARCH64_CALL26: case ELF::R_AARCH64_ADR_PREL_PG_HI21: case ELF::R_AARCH64_ADR_GOT_PAGE: case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: case ELF::R_AARCH64_TLSDESC_ADR_PAGE21: case ELF::R_AARCH64_JUMP26: case ELF::R_AARCH64_PREL32: return true; } } size_t Relocation::emit(MCStreamer *Streamer) const { const auto Size = getSizeForType(Type); auto &Ctx = Streamer->getContext(); if (isPCRelative(Type)) { auto *TempLabel = Ctx.createTempSymbol(); Streamer->EmitLabel(TempLabel); const MCExpr *Value{nullptr}; if (Symbol) { Value = MCSymbolRefExpr::create(Symbol, Ctx); if (Addend) { Value = MCBinaryExpr::createAdd(Value, MCConstantExpr::create(Addend, Ctx), Ctx); } } else { Value = MCConstantExpr::create(Addend, Ctx); } Value = MCBinaryExpr::createSub(Value, MCSymbolRefExpr::create(TempLabel, Ctx), Ctx); Streamer->EmitValue(Value, Size); return Size; } if (Symbol && Addend) { auto Value = MCBinaryExpr::createAdd(MCSymbolRefExpr::create(Symbol, Ctx), MCConstantExpr::create(Addend, Ctx), Ctx); Streamer->EmitValue(Value, Size); } else if (Symbol) { Streamer->EmitSymbolValue(Symbol, Size); } else { Streamer->EmitIntValue(Addend, Size); } return Size; } #define ELF_RELOC(name, value) #name, void Relocation::print(raw_ostream &OS) const { static const char *X86RelocNames[] = { #include "llvm/BinaryFormat/ELFRelocs/x86_64.def" }; static const char *AArch64RelocNames[] = { #include "llvm/BinaryFormat/ELFRelocs/AArch64.def" }; if (Arch == Triple::aarch64) OS << AArch64RelocNames[Type]; else OS << X86RelocNames[Type]; OS << ", 0x" << Twine::utohexstr(Offset); if (Symbol) { OS << ", " << Symbol->getName(); } if (int64_t(Addend) < 0) OS << ", -0x" << Twine::utohexstr(-int64_t(Addend)); else OS << ", 0x" << Twine::utohexstr(Addend); OS << ", 0x" << Twine::utohexstr(Value); }