mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-26 19:16:05 +00:00

Some refactoring. * Make the arrays themselves const -- not just the strings being pointed to. * Move each relocation array to the case using it. * Add a suitable assert, to make sure there's no out-of-bounds indexing.
1118 lines
32 KiB
C++
1118 lines
32 KiB
C++
//===- 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_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_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<int64_t>(PC) + SignExtend64<16>(Contents & 0xffff);
|
|
case ELF::R_AARCH64_PREL32:
|
|
return static_cast<int64_t>(PC) + SignExtend64<32>(Contents & 0xffffffff);
|
|
case ELF::R_AARCH64_PREL64:
|
|
return static_cast<int64_t>(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<int64_t>(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<int64_t>(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<int64_t>(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<int64_t>(PC) + SignExtend64<21>(Contents);
|
|
|
|
// ADRP instruction
|
|
Contents = static_cast<int64_t>(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_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_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);
|
|
}
|