//===- bolt/Core/Relocation.cpp - Object file relocations -----------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file implements the Relocation class. // //===----------------------------------------------------------------------===// #include "bolt/Core/Relocation.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Object/ELF.h" using namespace llvm; using namespace bolt; namespace ELFReserved { enum { R_RISCV_TPREL_I = 49, R_RISCV_TPREL_S = 50, }; } // namespace ELFReserved Triple::ArchType Relocation::Arch; static bool isSupportedX86(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_GOTPC64: 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: return true; } } static bool isSupportedAArch64(uint64_t Type) { switch (Type) { default: return false; case ELF::R_AARCH64_CALL26: case ELF::R_AARCH64_JUMP26: case ELF::R_AARCH64_TSTBR14: case ELF::R_AARCH64_CONDBR19: case ELF::R_AARCH64_ADR_PREL_LO21: case ELF::R_AARCH64_ADR_PREL_PG_HI21: case ELF::R_AARCH64_ADR_PREL_PG_HI21_NC: 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_PREL21: 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_TLSLE_MOVW_TPREL_G0: case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0_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_PREL16: case ELF::R_AARCH64_PREL32: case ELF::R_AARCH64_PREL64: case ELF::R_AARCH64_ABS16: case ELF::R_AARCH64_ABS32: case ELF::R_AARCH64_ABS64: case ELF::R_AARCH64_MOVW_UABS_G0: case ELF::R_AARCH64_MOVW_UABS_G0_NC: case ELF::R_AARCH64_MOVW_UABS_G1: case ELF::R_AARCH64_MOVW_UABS_G1_NC: case ELF::R_AARCH64_MOVW_UABS_G2: case ELF::R_AARCH64_MOVW_UABS_G2_NC: case ELF::R_AARCH64_MOVW_UABS_G3: return true; } } static bool isSupportedRISCV(uint64_t Type) { switch (Type) { default: return false; case ELF::R_RISCV_JAL: case ELF::R_RISCV_CALL: case ELF::R_RISCV_CALL_PLT: case ELF::R_RISCV_BRANCH: case ELF::R_RISCV_RELAX: case ELF::R_RISCV_GOT_HI20: case ELF::R_RISCV_PCREL_HI20: case ELF::R_RISCV_PCREL_LO12_I: case ELF::R_RISCV_PCREL_LO12_S: case ELF::R_RISCV_RVC_JUMP: case ELF::R_RISCV_RVC_BRANCH: case ELF::R_RISCV_ADD32: case ELF::R_RISCV_SUB32: case ELF::R_RISCV_HI20: case ELF::R_RISCV_LO12_I: case ELF::R_RISCV_LO12_S: case ELF::R_RISCV_64: case ELF::R_RISCV_TLS_GOT_HI20: case ELF::R_RISCV_TPREL_HI20: case ELF::R_RISCV_TPREL_ADD: case ELF::R_RISCV_TPREL_LO12_I: case ELF::R_RISCV_TPREL_LO12_S: case ELFReserved::R_RISCV_TPREL_I: case ELFReserved::R_RISCV_TPREL_S: return true; } } static size_t getSizeForTypeX86(uint64_t Type) { switch (Type) { default: errs() << object::getELFRelocationTypeName(ELF::EM_X86_64, Type) << '\n'; 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: return 4; case ELF::R_X86_64_PC64: case ELF::R_X86_64_64: case ELF::R_X86_64_GOTPC64: return 8; } } static size_t getSizeForTypeAArch64(uint64_t Type) { switch (Type) { default: errs() << object::getELFRelocationTypeName(ELF::EM_AARCH64, Type) << '\n'; llvm_unreachable("unsupported relocation type"); case ELF::R_AARCH64_ABS16: case ELF::R_AARCH64_PREL16: return 2; case ELF::R_AARCH64_CALL26: case ELF::R_AARCH64_JUMP26: case ELF::R_AARCH64_TSTBR14: case ELF::R_AARCH64_CONDBR19: case ELF::R_AARCH64_ADR_PREL_LO21: case ELF::R_AARCH64_ADR_PREL_PG_HI21: case ELF::R_AARCH64_ADR_PREL_PG_HI21_NC: 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_PREL21: 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_TLSLE_MOVW_TPREL_G0: case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0_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_PREL32: case ELF::R_AARCH64_MOVW_UABS_G0: case ELF::R_AARCH64_MOVW_UABS_G0_NC: case ELF::R_AARCH64_MOVW_UABS_G1: case ELF::R_AARCH64_MOVW_UABS_G1_NC: case ELF::R_AARCH64_MOVW_UABS_G2: case ELF::R_AARCH64_MOVW_UABS_G2_NC: case ELF::R_AARCH64_MOVW_UABS_G3: case ELF::R_AARCH64_ABS32: return 4; case ELF::R_AARCH64_ABS64: case ELF::R_AARCH64_PREL64: return 8; } } static size_t getSizeForTypeRISCV(uint64_t Type) { switch (Type) { default: errs() << object::getELFRelocationTypeName(ELF::EM_RISCV, Type) << '\n'; llvm_unreachable("unsupported relocation type"); case ELF::R_RISCV_RVC_JUMP: case ELF::R_RISCV_RVC_BRANCH: return 2; case ELF::R_RISCV_JAL: case ELF::R_RISCV_BRANCH: case ELF::R_RISCV_PCREL_HI20: case ELF::R_RISCV_PCREL_LO12_I: case ELF::R_RISCV_PCREL_LO12_S: case ELF::R_RISCV_32_PCREL: case ELF::R_RISCV_CALL: case ELF::R_RISCV_CALL_PLT: case ELF::R_RISCV_ADD32: case ELF::R_RISCV_SUB32: case ELF::R_RISCV_HI20: case ELF::R_RISCV_LO12_I: case ELF::R_RISCV_LO12_S: return 4; case ELF::R_RISCV_64: case ELF::R_RISCV_GOT_HI20: case ELF::R_RISCV_TLS_GOT_HI20: // See extractValueRISCV for why this is necessary. return 8; } } static bool skipRelocationTypeX86(uint64_t Type) { return Type == ELF::R_X86_64_NONE; } static bool skipRelocationTypeAArch64(uint64_t Type) { return Type == ELF::R_AARCH64_NONE || Type == ELF::R_AARCH64_LD_PREL_LO19; } static bool skipRelocationTypeRISCV(uint64_t Type) { switch (Type) { default: return false; case ELF::R_RISCV_NONE: case ELF::R_RISCV_RELAX: return true; } } static bool skipRelocationProcessX86(uint64_t &Type, uint64_t Contents) { return false; } static bool skipRelocationProcessAArch64(uint64_t &Type, uint64_t Contents) { auto IsMov = [](uint64_t Contents) -> bool { // The bits 28-23 are 0b100101 return (Contents & 0x1f800000) == 0x12800000; }; auto IsB = [](uint64_t Contents) -> bool { // The bits 31-26 are 0b000101 return (Contents & 0xfc000000) == 0x14000000; }; auto IsAdr = [](uint64_t Contents) -> bool { // The bits 31-24 are 0b0xx10000 return (Contents & 0x9f000000) == 0x10000000; }; auto IsAddImm = [](uint64_t Contents) -> bool { // The bits 30-23 are 0b00100010 return (Contents & 0x7F800000) == 0x11000000; }; auto IsNop = [](uint64_t Contents) -> bool { return Contents == 0xd503201f; }; // The linker might eliminate the instruction and replace it with NOP, ignore if (IsNop(Contents)) return true; // The linker might relax ADRP+LDR instruction sequence for loading symbol // address from GOT table to ADRP+ADD sequence that would point to the // binary-local symbol. Change relocation type in order to process it right. if (Type == ELF::R_AARCH64_LD64_GOT_LO12_NC && IsAddImm(Contents)) { Type = ELF::R_AARCH64_ADD_ABS_LO12_NC; return false; } // The linker might perform TLS relocations relaxations, such as // changed TLS access model (e.g. changed global dynamic model // to initial exec), thus changing the instructions. The static // relocations might be invalid at this point and we might no // need to process these relocations anymore. // More information could be found by searching // elfNN_aarch64_tls_relax in bfd switch (Type) { default: break; case ELF::R_AARCH64_TLSDESC_LD64_LO12: case ELF::R_AARCH64_TLSDESC_ADR_PAGE21: case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: { if (IsMov(Contents)) return true; } } // The linker might replace load/store instruction with jump and // veneer due to errata 843419 // https://documentation-service.arm.com/static/5fa29fddb209f547eebd361d // Thus load/store relocations for these instructions must be ignored // NOTE: We only process GOT and TLS relocations this way since the // addend used in load/store instructions won't change after bolt // (it is important since the instruction in veneer won't have relocation) switch (Type) { default: break; case ELF::R_AARCH64_LD64_GOT_LO12_NC: case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: case ELF::R_AARCH64_TLSDESC_LD64_LO12: { if (IsB(Contents)) return true; } } // The linker might relax ADRP+ADD or ADRP+LDR sequences to the ADR+NOP switch (Type) { default: break; case ELF::R_AARCH64_ADR_PREL_PG_HI21: case ELF::R_AARCH64_ADD_ABS_LO12_NC: case ELF::R_AARCH64_ADR_GOT_PAGE: case ELF::R_AARCH64_LD64_GOT_LO12_NC: if (IsAdr(Contents)) return true; } return false; } static bool skipRelocationProcessRISCV(uint64_t &Type, uint64_t Contents) { return false; } static uint64_t encodeValueX86(uint64_t Type, uint64_t Value, uint64_t PC) { switch (Type) { default: llvm_unreachable("unsupported relocation"); case ELF::R_X86_64_64: case ELF::R_X86_64_32: break; case ELF::R_X86_64_PC32: Value -= PC; break; } return Value; } static uint64_t encodeValueAArch64(uint64_t Type, uint64_t Value, uint64_t PC) { switch (Type) { default: llvm_unreachable("unsupported relocation"); case ELF::R_AARCH64_ABS16: case ELF::R_AARCH64_ABS32: case ELF::R_AARCH64_ABS64: break; case ELF::R_AARCH64_PREL16: case ELF::R_AARCH64_PREL32: case ELF::R_AARCH64_PREL64: Value -= PC; break; case ELF::R_AARCH64_CALL26: Value -= PC; assert(isInt<28>(Value) && "only PC +/- 128MB is allowed for direct call"); // Immediate goes in bits 25:0 of BL. // OP 1001_01 goes in bits 31:26 of BL. Value = ((Value >> 2) & 0x3ffffff) | 0x94000000ULL; break; case ELF::R_AARCH64_JUMP26: Value -= PC; assert(isInt<28>(Value) && "only PC +/- 128MB is allowed for direct branch"); // Immediate goes in bits 25:0 of B. // OP 0001_01 goes in bits 31:26 of B. Value = ((Value >> 2) & 0x3ffffff) | 0x14000000ULL; break; } return Value; } static uint64_t encodeValueRISCV(uint64_t Type, uint64_t Value, uint64_t PC) { switch (Type) { default: llvm_unreachable("unsupported relocation"); case ELF::R_RISCV_64: break; } return Value; } static uint64_t extractValueX86(uint64_t Type, uint64_t Contents, uint64_t PC) { if (Type == ELF::R_X86_64_32S) return SignExtend64<32>(Contents); if (Relocation::isPCRelative(Type)) return SignExtend64(Contents, 8 * Relocation::getSizeForType(Type)); return Contents; } static uint64_t extractValueAArch64(uint64_t Type, uint64_t Contents, uint64_t PC) { switch (Type) { default: errs() << object::getELFRelocationTypeName(ELF::EM_AARCH64, Type) << '\n'; llvm_unreachable("unsupported relocation type"); case ELF::R_AARCH64_ABS16: case ELF::R_AARCH64_ABS32: case ELF::R_AARCH64_ABS64: return Contents; case ELF::R_AARCH64_PREL16: return static_cast(PC) + SignExtend64<16>(Contents & 0xffff); case ELF::R_AARCH64_PREL32: return static_cast(PC) + SignExtend64<32>(Contents & 0xffffffff); case ELF::R_AARCH64_PREL64: return static_cast(PC) + Contents; 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_TSTBR14: // Immediate:15:2 goes in bits 18:5 of TBZ, TBNZ Contents &= ~0xfffffffffff8001fULL; return static_cast(PC) + SignExtend64<16>(Contents >> 3); case ELF::R_AARCH64_CONDBR19: // Immediate:20:2 goes in bits 23:5 of Bcc, CBZ, CBNZ Contents &= ~0xffffffffff00001fULL; return static_cast(PC) + SignExtend64<21>(Contents >> 3); case ELF::R_AARCH64_ADR_GOT_PAGE: case ELF::R_AARCH64_TLSDESC_ADR_PREL21: case ELF::R_AARCH64_TLSDESC_ADR_PAGE21: case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: case ELF::R_AARCH64_ADR_PREL_LO21: case ELF::R_AARCH64_ADR_PREL_PG_HI21: case ELF::R_AARCH64_ADR_PREL_PG_HI21_NC: { // Bits 32:12 of Symbol address goes in bits 30:29 + 23:5 of ADRP // and ADR instructions bool IsAdr = !!(((Contents >> 31) & 0x1) == 0); Contents &= ~0xffffffff9f00001fUll; uint64_t LowBits = (Contents >> 29) & 0x3; uint64_t HighBits = (Contents >> 5) & 0x7ffff; Contents = LowBits | (HighBits << 2); if (IsAdr) return static_cast(PC) + SignExtend64<21>(Contents); // ADRP instruction Contents = static_cast(PC) + SignExtend64<33>(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); } case ELF::R_AARCH64_MOVW_UABS_G3: case ELF::R_AARCH64_MOVW_UABS_G2_NC: case ELF::R_AARCH64_MOVW_UABS_G2: case ELF::R_AARCH64_MOVW_UABS_G1_NC: case ELF::R_AARCH64_MOVW_UABS_G1: case ELF::R_AARCH64_MOVW_UABS_G0_NC: case ELF::R_AARCH64_MOVW_UABS_G0: // The shift goes in bits 22:21 of MOV* instructions uint8_t Shift = (Contents >> 21) & 0x3; // Immediate goes in bits 20:5 Contents = (Contents >> 5) & 0xffff; return Contents << (16 * Shift); } } static uint64_t extractUImmRISCV(uint32_t Contents) { return SignExtend64<32>(Contents & 0xfffff000); } static uint64_t extractIImmRISCV(uint32_t Contents) { return SignExtend64<12>(Contents >> 20); } static uint64_t extractSImmRISCV(uint32_t Contents) { return SignExtend64<12>(((Contents >> 7) & 0x1f) | ((Contents >> 25) << 5)); } static uint64_t extractJImmRISCV(uint32_t Contents) { return SignExtend64<21>( (((Contents >> 21) & 0x3ff) << 1) | (((Contents >> 20) & 0x1) << 11) | (((Contents >> 12) & 0xff) << 12) | (((Contents >> 31) & 0x1) << 20)); } static uint64_t extractBImmRISCV(uint32_t Contents) { return SignExtend64<13>( (((Contents >> 8) & 0xf) << 1) | (((Contents >> 25) & 0x3f) << 5) | (((Contents >> 7) & 0x1) << 11) | (((Contents >> 31) & 0x1) << 12)); } static uint64_t extractValueRISCV(uint64_t Type, uint64_t Contents, uint64_t PC) { switch (Type) { default: errs() << object::getELFRelocationTypeName(ELF::EM_RISCV, Type) << '\n'; llvm_unreachable("unsupported relocation type"); case ELF::R_RISCV_JAL: return extractJImmRISCV(Contents); case ELF::R_RISCV_CALL: case ELF::R_RISCV_CALL_PLT: return extractUImmRISCV(Contents); case ELF::R_RISCV_BRANCH: return extractBImmRISCV(Contents); case ELF::R_RISCV_GOT_HI20: case ELF::R_RISCV_TLS_GOT_HI20: // We need to know the exact address of the GOT entry so we extract the // value from both the AUIPC and L[D|W]. We cannot rely on the symbol in the // relocation for this since it simply refers to the object that is stored // in the GOT entry, not to the entry itself. return extractUImmRISCV(Contents & 0xffffffff) + extractIImmRISCV(Contents >> 32); case ELF::R_RISCV_PCREL_HI20: case ELF::R_RISCV_HI20: return extractUImmRISCV(Contents); case ELF::R_RISCV_PCREL_LO12_I: case ELF::R_RISCV_LO12_I: return extractIImmRISCV(Contents); case ELF::R_RISCV_PCREL_LO12_S: case ELF::R_RISCV_LO12_S: return extractSImmRISCV(Contents); case ELF::R_RISCV_RVC_JUMP: return SignExtend64<11>(Contents >> 2); case ELF::R_RISCV_RVC_BRANCH: return SignExtend64<8>(((Contents >> 2) & 0x1f) | ((Contents >> 5) & 0xe0)); case ELF::R_RISCV_ADD32: case ELF::R_RISCV_SUB32: case ELF::R_RISCV_64: return Contents; } } static bool isGOTX86(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: return true; } } static bool isGOTAArch64(uint64_t Type) { switch (Type) { default: return false; case ELF::R_AARCH64_ADR_GOT_PAGE: case ELF::R_AARCH64_LD64_GOT_LO12_NC: case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: case ELF::R_AARCH64_TLSDESC_ADR_PREL21: 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; } } static bool isGOTRISCV(uint64_t Type) { switch (Type) { default: return false; case ELF::R_RISCV_GOT_HI20: case ELF::R_RISCV_TLS_GOT_HI20: return true; } } static bool isTLSX86(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: return true; } } static bool isTLSAArch64(uint64_t Type) { switch (Type) { default: return false; case ELF::R_AARCH64_TLSDESC_ADR_PREL21: 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_TLSLE_MOVW_TPREL_G0: case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0_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; } } static bool isTLSRISCV(uint64_t Type) { switch (Type) { default: return false; case ELF::R_RISCV_TLS_GOT_HI20: case ELF::R_RISCV_TPREL_HI20: case ELF::R_RISCV_TPREL_ADD: case ELF::R_RISCV_TPREL_LO12_I: case ELF::R_RISCV_TPREL_LO12_S: case ELFReserved::R_RISCV_TPREL_I: case ELFReserved::R_RISCV_TPREL_S: return true; } } static bool isPCRelativeX86(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: 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_GOTOFF64: case ELF::R_X86_64_GOTPC32: case ELF::R_X86_64_GOTPC64: case ELF::R_X86_64_GOTTPOFF: case ELF::R_X86_64_GOTPCRELX: case ELF::R_X86_64_REX_GOTPCRELX: return true; } } static bool isPCRelativeAArch64(uint64_t Type) { switch (Type) { default: llvm_unreachable("Unknown relocation type"); case ELF::R_AARCH64_ABS16: case ELF::R_AARCH64_ABS32: 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_TLSLE_MOVW_TPREL_G0: case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0_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_MOVW_UABS_G0: case ELF::R_AARCH64_MOVW_UABS_G0_NC: case ELF::R_AARCH64_MOVW_UABS_G1: case ELF::R_AARCH64_MOVW_UABS_G1_NC: case ELF::R_AARCH64_MOVW_UABS_G2: case ELF::R_AARCH64_MOVW_UABS_G2_NC: case ELF::R_AARCH64_MOVW_UABS_G3: return false; case ELF::R_AARCH64_TLSDESC_CALL: case ELF::R_AARCH64_CALL26: case ELF::R_AARCH64_JUMP26: case ELF::R_AARCH64_TSTBR14: case ELF::R_AARCH64_CONDBR19: case ELF::R_AARCH64_ADR_PREL_LO21: case ELF::R_AARCH64_ADR_PREL_PG_HI21: case ELF::R_AARCH64_ADR_PREL_PG_HI21_NC: case ELF::R_AARCH64_ADR_GOT_PAGE: case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: case ELF::R_AARCH64_TLSDESC_ADR_PREL21: case ELF::R_AARCH64_TLSDESC_ADR_PAGE21: case ELF::R_AARCH64_PREL16: case ELF::R_AARCH64_PREL32: case ELF::R_AARCH64_PREL64: return true; } } static bool isPCRelativeRISCV(uint64_t Type) { switch (Type) { default: llvm_unreachable("Unknown relocation type"); case ELF::R_RISCV_ADD32: case ELF::R_RISCV_SUB32: case ELF::R_RISCV_HI20: case ELF::R_RISCV_LO12_I: case ELF::R_RISCV_LO12_S: case ELF::R_RISCV_64: return false; case ELF::R_RISCV_JAL: case ELF::R_RISCV_CALL: case ELF::R_RISCV_CALL_PLT: case ELF::R_RISCV_BRANCH: case ELF::R_RISCV_GOT_HI20: case ELF::R_RISCV_PCREL_HI20: case ELF::R_RISCV_PCREL_LO12_I: case ELF::R_RISCV_PCREL_LO12_S: case ELF::R_RISCV_RVC_JUMP: case ELF::R_RISCV_RVC_BRANCH: case ELF::R_RISCV_32_PCREL: case ELF::R_RISCV_TLS_GOT_HI20: return true; } } bool Relocation::isSupported(uint64_t Type) { switch (Arch) { default: return false; case Triple::aarch64: return isSupportedAArch64(Type); case Triple::riscv64: return isSupportedRISCV(Type); case Triple::x86_64: return isSupportedX86(Type); } } size_t Relocation::getSizeForType(uint64_t Type) { switch (Arch) { default: llvm_unreachable("Unsupported architecture"); case Triple::aarch64: return getSizeForTypeAArch64(Type); case Triple::riscv64: return getSizeForTypeRISCV(Type); case Triple::x86_64: return getSizeForTypeX86(Type); } } bool Relocation::skipRelocationType(uint64_t Type) { switch (Arch) { default: llvm_unreachable("Unsupported architecture"); case Triple::aarch64: return skipRelocationTypeAArch64(Type); case Triple::riscv64: return skipRelocationTypeRISCV(Type); case Triple::x86_64: return skipRelocationTypeX86(Type); } } bool Relocation::skipRelocationProcess(uint64_t &Type, uint64_t Contents) { switch (Arch) { default: llvm_unreachable("Unsupported architecture"); case Triple::aarch64: return skipRelocationProcessAArch64(Type, Contents); case Triple::riscv64: return skipRelocationProcessRISCV(Type, Contents); case Triple::x86_64: return skipRelocationProcessX86(Type, Contents); } } uint64_t Relocation::encodeValue(uint64_t Type, uint64_t Value, uint64_t PC) { switch (Arch) { default: llvm_unreachable("Unsupported architecture"); case Triple::aarch64: return encodeValueAArch64(Type, Value, PC); case Triple::riscv64: return encodeValueRISCV(Type, Value, PC); case Triple::x86_64: return encodeValueX86(Type, Value, PC); } } uint64_t Relocation::extractValue(uint64_t Type, uint64_t Contents, uint64_t PC) { switch (Arch) { default: llvm_unreachable("Unsupported architecture"); case Triple::aarch64: return extractValueAArch64(Type, Contents, PC); case Triple::riscv64: return extractValueRISCV(Type, Contents, PC); case Triple::x86_64: return extractValueX86(Type, Contents, PC); } } bool Relocation::isGOT(uint64_t Type) { switch (Arch) { default: llvm_unreachable("Unsupported architecture"); case Triple::aarch64: return isGOTAArch64(Type); case Triple::riscv64: return isGOTRISCV(Type); case Triple::x86_64: return isGOTX86(Type); } } bool Relocation::isX86GOTPCRELX(uint64_t Type) { if (Arch != Triple::x86_64) return false; return Type == ELF::R_X86_64_GOTPCRELX || Type == ELF::R_X86_64_REX_GOTPCRELX; } bool Relocation::isX86GOTPC64(uint64_t Type) { if (Arch != Triple::x86_64) return false; return Type == ELF::R_X86_64_GOTPC64; } bool Relocation::isNone(uint64_t Type) { return Type == getNone(); } bool Relocation::isRelative(uint64_t Type) { switch (Arch) { default: llvm_unreachable("Unsupported architecture"); case Triple::aarch64: return Type == ELF::R_AARCH64_RELATIVE; case Triple::riscv64: return Type == ELF::R_RISCV_RELATIVE; case Triple::x86_64: return Type == ELF::R_X86_64_RELATIVE; } } bool Relocation::isIRelative(uint64_t Type) { switch (Arch) { default: llvm_unreachable("Unsupported architecture"); case Triple::aarch64: return Type == ELF::R_AARCH64_IRELATIVE; case Triple::riscv64: llvm_unreachable("not implemented"); case Triple::x86_64: return Type == ELF::R_X86_64_IRELATIVE; } } bool Relocation::isTLS(uint64_t Type) { switch (Arch) { default: llvm_unreachable("Unsupported architecture"); case Triple::aarch64: return isTLSAArch64(Type); case Triple::riscv64: return isTLSRISCV(Type); case Triple::x86_64: return isTLSX86(Type); } } bool Relocation::isInstructionReference(uint64_t Type) { if (Arch != Triple::riscv64) return false; switch (Type) { default: return false; case ELF::R_RISCV_PCREL_LO12_I: case ELF::R_RISCV_PCREL_LO12_S: return true; } } uint64_t Relocation::getNone() { switch (Arch) { default: llvm_unreachable("Unsupported architecture"); case Triple::aarch64: return ELF::R_AARCH64_NONE; case Triple::riscv64: return ELF::R_RISCV_NONE; case Triple::x86_64: return ELF::R_X86_64_NONE; } } uint64_t Relocation::getPC32() { switch (Arch) { default: llvm_unreachable("Unsupported architecture"); case Triple::aarch64: return ELF::R_AARCH64_PREL32; case Triple::riscv64: return ELF::R_RISCV_32_PCREL; case Triple::x86_64: return ELF::R_X86_64_PC32; } } uint64_t Relocation::getPC64() { switch (Arch) { default: llvm_unreachable("Unsupported architecture"); case Triple::aarch64: return ELF::R_AARCH64_PREL64; case Triple::riscv64: llvm_unreachable("not implemented"); case Triple::x86_64: return ELF::R_X86_64_PC64; } } bool Relocation::isPCRelative(uint64_t Type) { switch (Arch) { default: llvm_unreachable("Unsupported architecture"); case Triple::aarch64: return isPCRelativeAArch64(Type); case Triple::riscv64: return isPCRelativeRISCV(Type); case Triple::x86_64: return isPCRelativeX86(Type); } } uint64_t Relocation::getAbs64() { switch (Arch) { default: llvm_unreachable("Unsupported architecture"); case Triple::aarch64: return ELF::R_AARCH64_ABS64; case Triple::riscv64: return ELF::R_RISCV_64; case Triple::x86_64: return ELF::R_X86_64_64; } } uint64_t Relocation::getRelative() { switch (Arch) { default: llvm_unreachable("Unsupported architecture"); case Triple::aarch64: return ELF::R_AARCH64_RELATIVE; case Triple::riscv64: llvm_unreachable("not implemented"); case Triple::x86_64: return ELF::R_X86_64_RELATIVE; } } size_t Relocation::emit(MCStreamer *Streamer) const { const size_t Size = getSizeForType(Type); const auto *Value = createExpr(Streamer); Streamer->emitValue(Value, Size); return Size; } const MCExpr *Relocation::createExpr(MCStreamer *Streamer) const { MCContext &Ctx = Streamer->getContext(); const MCExpr *Value = nullptr; if (Symbol && Addend) { Value = MCBinaryExpr::createAdd(MCSymbolRefExpr::create(Symbol, Ctx), MCConstantExpr::create(Addend, Ctx), Ctx); } else if (Symbol) { Value = MCSymbolRefExpr::create(Symbol, Ctx); } else { Value = MCConstantExpr::create(Addend, Ctx); } if (isPCRelative(Type)) { MCSymbol *TempLabel = Ctx.createNamedTempSymbol(); Streamer->emitLabel(TempLabel); Value = MCBinaryExpr::createSub( Value, MCSymbolRefExpr::create(TempLabel, Ctx), Ctx); } return Value; } const MCExpr *Relocation::createExpr(MCStreamer *Streamer, const MCExpr *RetainedValue) const { const auto *Value = createExpr(Streamer); if (RetainedValue) { Value = MCBinaryExpr::create(getComposeOpcodeFor(Type), RetainedValue, Value, Streamer->getContext()); } return Value; } MCBinaryExpr::Opcode Relocation::getComposeOpcodeFor(uint64_t Type) { assert(Arch == Triple::riscv64 && "only implemented for RISC-V"); switch (Type) { default: llvm_unreachable("not implemented"); case ELF::R_RISCV_ADD32: return MCBinaryExpr::Add; case ELF::R_RISCV_SUB32: return MCBinaryExpr::Sub; } } void Relocation::print(raw_ostream &OS) const { switch (Arch) { default: OS << "RType:" << Twine::utohexstr(Type); break; case Triple::aarch64: static const char *const AArch64RelocNames[] = { #define ELF_RELOC(name, value) #name, #include "llvm/BinaryFormat/ELFRelocs/AArch64.def" #undef ELF_RELOC }; assert(Type < ArrayRef(AArch64RelocNames).size()); OS << AArch64RelocNames[Type]; break; case Triple::riscv64: // RISC-V relocations are not sequentially numbered so we cannot use an // array switch (Type) { default: llvm_unreachable("illegal RISC-V relocation"); #define ELF_RELOC(name, value) \ case value: \ OS << #name; \ break; #include "llvm/BinaryFormat/ELFRelocs/RISCV.def" #undef ELF_RELOC } break; case Triple::x86_64: static const char *const X86RelocNames[] = { #define ELF_RELOC(name, value) #name, #include "llvm/BinaryFormat/ELFRelocs/x86_64.def" #undef ELF_RELOC }; assert(Type < ArrayRef(X86RelocNames).size()); OS << X86RelocNames[Type]; break; } 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); }