| //===--- BinarySection.cpp - Interface for object file section -----------===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "BinarySection.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: |
| llvm_unreachable("unsupported relocation type"); |
| case ELF::R_AARCH64_ABS64: |
| return Contents; |
| case ELF::R_AARCH64_PREL32: |
| return static_cast<int64_t>(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<int64_t>(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<int64_t>(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_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); |
| auto Value = |
| MCBinaryExpr::createSub(MCSymbolRefExpr::create(Symbol, Ctx), |
| MCSymbolRefExpr::create(TempLabel, Ctx), |
| Ctx); |
| if (Addend) { |
| Value = MCBinaryExpr::createAdd(Value, |
| MCConstantExpr::create(Addend, Ctx), |
| Ctx); |
| } |
| Streamer->EmitValue(Value, Size); |
| } else if (Addend) { |
| auto Value = MCBinaryExpr::createAdd(MCSymbolRefExpr::create(Symbol, Ctx), |
| MCConstantExpr::create(Addend, Ctx), |
| Ctx); |
| Streamer->EmitValue(Value, Size); |
| } else { |
| Streamer->EmitSymbolValue(Symbol, 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); |
| } |