
This patch adds code generation for RISCV64 instrumentation.The work involved includes the following three points: a) Implements support for instrumenting direct function call and jump on RISC-V which relies on , Atomic instructions (used to increment counters) are only available on RISC-V when the A extension is used. b) Implements support for instrumenting direct function inderect call by implementing the createInstrumentedIndCallHandlerEntryBB and createInstrumentedIndCallHandlerExitBB interfaces. In this process, we need to accurately record the target address and IndCallID to ensure the correct recording of the indirect call counters. c)Implemented the RISCV64 Bolt runtime library, implemented some system call interfaces through embedded assembly. Get the difference between runtime addrress of .text section andstatic address in section header table, which in turn can be used to search for indirect call description. However, the community code currently has problems with relocation in some scenarios, but this has nothing to do with instrumentation. We may continue to submit patches to fix the related bugs.
1066 lines
30 KiB
C++
1066 lines
30 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"
|
|
#include "llvm/Object/ObjectFile.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(uint32_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(uint32_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:
|
|
case ELF::R_AARCH64_PLT32:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
static bool isSupportedRISCV(uint32_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_TLS_GD_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(uint32_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(uint32_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:
|
|
case ELF::R_AARCH64_PLT32:
|
|
return 4;
|
|
case ELF::R_AARCH64_ABS64:
|
|
case ELF::R_AARCH64_PREL64:
|
|
return 8;
|
|
}
|
|
}
|
|
|
|
static size_t getSizeForTypeRISCV(uint32_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:
|
|
case ELF::R_RISCV_TLS_GD_HI20:
|
|
// See extractValueRISCV for why this is necessary.
|
|
return 8;
|
|
}
|
|
}
|
|
|
|
static bool skipRelocationTypeX86(uint32_t Type) {
|
|
return Type == ELF::R_X86_64_NONE;
|
|
}
|
|
|
|
static bool skipRelocationTypeAArch64(uint32_t Type) {
|
|
return Type == ELF::R_AARCH64_NONE || Type == ELF::R_AARCH64_LD_PREL_LO19;
|
|
}
|
|
|
|
static bool skipRelocationTypeRISCV(uint32_t Type) {
|
|
switch (Type) {
|
|
default:
|
|
return false;
|
|
case ELF::R_RISCV_NONE:
|
|
case ELF::R_RISCV_RELAX:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
static uint64_t encodeValueX86(uint32_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 bool canEncodeValueAArch64(uint32_t Type, uint64_t Value, uint64_t PC) {
|
|
switch (Type) {
|
|
default:
|
|
llvm_unreachable("unsupported relocation");
|
|
case ELF::R_AARCH64_CALL26:
|
|
case ELF::R_AARCH64_JUMP26:
|
|
return isInt<28>(Value - PC);
|
|
}
|
|
}
|
|
|
|
static uint64_t encodeValueAArch64(uint32_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 canEncodeValueRISCV(uint32_t Type, uint64_t Value,
|
|
uint64_t PC) {
|
|
switch (Type) {
|
|
default:
|
|
llvm_unreachable("unsupported relocation");
|
|
case ELF::R_RISCV_64:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
static uint64_t encodeValueRISCV(uint32_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(uint32_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(uint32_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:
|
|
case ELF::R_AARCH64_PLT32:
|
|
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(uint32_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:
|
|
case ELF::R_RISCV_TLS_GD_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(uint32_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(uint32_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(uint32_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(uint32_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(uint32_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(uint32_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(uint32_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(uint32_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:
|
|
case ELF::R_AARCH64_PLT32:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
static bool isPCRelativeRISCV(uint32_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:
|
|
case ELF::R_RISCV_TLS_GD_HI20:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool Relocation::isSupported(uint32_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(uint32_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(uint32_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);
|
|
}
|
|
}
|
|
|
|
uint64_t Relocation::encodeValue(uint32_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);
|
|
}
|
|
}
|
|
|
|
bool Relocation::canEncodeValue(uint32_t Type, uint64_t Value, uint64_t PC) {
|
|
switch (Arch) {
|
|
default:
|
|
llvm_unreachable("Unsupported architecture");
|
|
case Triple::aarch64:
|
|
return canEncodeValueAArch64(Type, Value, PC);
|
|
case Triple::riscv64:
|
|
return canEncodeValueRISCV(Type, Value, PC);
|
|
case Triple::x86_64:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
uint64_t Relocation::extractValue(uint32_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(uint32_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(uint32_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(uint32_t Type) {
|
|
if (Arch != Triple::x86_64)
|
|
return false;
|
|
return Type == ELF::R_X86_64_GOTPC64;
|
|
}
|
|
|
|
bool Relocation::isNone(uint32_t Type) { return Type == getNone(); }
|
|
|
|
bool Relocation::isRelative(uint32_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(uint32_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(uint32_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(uint32_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;
|
|
}
|
|
}
|
|
|
|
uint32_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;
|
|
}
|
|
}
|
|
|
|
uint32_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;
|
|
}
|
|
}
|
|
|
|
uint32_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;
|
|
}
|
|
}
|
|
|
|
uint32_t Relocation::getType(const object::RelocationRef &Rel) {
|
|
uint64_t RelType = Rel.getType();
|
|
assert(isUInt<32>(RelType) && "BOLT relocation types are 32 bits");
|
|
return static_cast<uint32_t>(RelType);
|
|
}
|
|
|
|
bool Relocation::isPCRelative(uint32_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);
|
|
}
|
|
}
|
|
|
|
uint32_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;
|
|
}
|
|
}
|
|
|
|
uint32_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(uint32_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);
|
|
}
|