Files
clang-p2996/bolt/lib/Core/Relocation.cpp
Vladislav Khmelevsky 6e26ffa064 [BOLT][AARCH64] Skip R_AARCH64_LD_PREL_LO19 relocation
Supress failed to analyze relocations warning for R_AARCH64_LD_PREL_LO19
relocation. This relocation is mostly used to get value stored in CI and
we don't process it since we are caluclating target address using the
instruction value in evaluateMemOperandTarget().

Differential Revision: https://reviews.llvm.org/D127413
2022-06-13 15:40:06 +03:00

687 lines
20 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;
Triple::ArchType Relocation::Arch;
namespace {
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_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;
}
}
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;
}
}
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:
return 8;
}
}
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;
}
}
bool skipRelocationTypeX86(uint64_t Type) { return Type == ELF::R_X86_64_NONE; }
bool skipRelocationTypeAArch64(uint64_t Type) {
return Type == ELF::R_AARCH64_NONE || Type == ELF::R_AARCH64_LD_PREL_LO19;
}
bool skipRelocationProcessX86(uint64_t Type, uint64_t Contents) {
return false;
}
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 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 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 proccess 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;
}
uint64_t adjustValueX86(uint64_t Type, uint64_t Value, uint64_t PC) {
switch (Type) {
default:
llvm_unreachable("not supported relocation");
case ELF::R_X86_64_32:
break;
case ELF::R_X86_64_PC32:
Value -= PC;
break;
}
return Value;
}
uint64_t adjustValueAArch64(uint64_t Type, uint64_t Value, uint64_t PC) {
switch (Type) {
default:
llvm_unreachable("not supported relocation");
case ELF::R_AARCH64_ABS32:
break;
case ELF::R_AARCH64_PREL16:
case ELF::R_AARCH64_PREL32:
case ELF::R_AARCH64_PREL64:
Value -= PC;
break;
}
return Value;
}
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;
}
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 goest 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);
}
}
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;
}
}
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;
}
}
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;
}
}
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;
}
}
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_GOTTPOFF:
case ELF::R_X86_64_GOTPCRELX:
case ELF::R_X86_64_REX_GOTPCRELX:
return true;
}
}
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;
}
}
} // end anonymous namespace
bool Relocation::isSupported(uint64_t Type) {
if (Arch == Triple::aarch64)
return isSupportedAArch64(Type);
return isSupportedX86(Type);
}
size_t Relocation::getSizeForType(uint64_t Type) {
if (Arch == Triple::aarch64)
return getSizeForTypeAArch64(Type);
return getSizeForTypeX86(Type);
}
bool Relocation::skipRelocationType(uint64_t Type) {
if (Arch == Triple::aarch64)
return skipRelocationTypeAArch64(Type);
return skipRelocationTypeX86(Type);
}
bool Relocation::skipRelocationProcess(uint64_t Type, uint64_t Contents) {
if (Arch == Triple::aarch64)
return skipRelocationProcessAArch64(Type, Contents);
return skipRelocationProcessX86(Type, Contents);
}
uint64_t Relocation::adjustValue(uint64_t Type, uint64_t Value,
uint64_t PC) {
if (Arch == Triple::aarch64)
return adjustValueAArch64(Type, Value, PC);
return adjustValueX86(Type, Value, PC);
}
uint64_t Relocation::extractValue(uint64_t Type, uint64_t Contents,
uint64_t PC) {
if (Arch == Triple::aarch64)
return extractValueAArch64(Type, Contents, PC);
return extractValueX86(Type, Contents, PC);
}
bool Relocation::isGOT(uint64_t Type) {
if (Arch == Triple::aarch64)
return isGOTAArch64(Type);
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::isNone(uint64_t Type) { return Type == getNone(); }
bool Relocation::isRelative(uint64_t Type) {
if (Arch == Triple::aarch64)
return Type == ELF::R_AARCH64_RELATIVE;
return Type == ELF::R_X86_64_RELATIVE;
}
bool Relocation::isIRelative(uint64_t Type) {
if (Arch == Triple::aarch64)
return Type == ELF::R_AARCH64_IRELATIVE;
return Type == ELF::R_X86_64_IRELATIVE;
}
bool Relocation::isTLS(uint64_t Type) {
if (Arch == Triple::aarch64)
return isTLSAArch64(Type);
return isTLSX86(Type);
}
uint64_t Relocation::getNone() {
if (Arch == Triple::aarch64)
return ELF::R_AARCH64_NONE;
return ELF::R_X86_64_NONE;
}
uint64_t Relocation::getPC32() {
if (Arch == Triple::aarch64)
return ELF::R_AARCH64_PREL32;
return ELF::R_X86_64_PC32;
}
uint64_t Relocation::getPC64() {
if (Arch == Triple::aarch64)
return ELF::R_AARCH64_PREL64;
return ELF::R_X86_64_PC64;
}
bool Relocation::isPCRelative(uint64_t Type) {
if (Arch == Triple::aarch64)
return isPCRelativeAArch64(Type);
return isPCRelativeX86(Type);
}
size_t Relocation::emit(MCStreamer *Streamer) const {
const size_t Size = getSizeForType(Type);
MCContext &Ctx = Streamer->getContext();
if (isPCRelative(Type)) {
MCSymbol *TempLabel = Ctx.createNamedTempSymbol();
Streamer->emitLabel(TempLabel);
const MCExpr *Value = nullptr;
if (Symbol) {
Value = MCSymbolRefExpr::create(Symbol, Ctx);
if (Addend) {
Value = MCBinaryExpr::createAdd(
Value, MCConstantExpr::create(Addend, Ctx), Ctx);
}
} else {
Value = MCConstantExpr::create(Addend, Ctx);
}
Value = MCBinaryExpr::createSub(
Value, MCSymbolRefExpr::create(TempLabel, Ctx), Ctx);
Streamer->emitValue(Value, Size);
return Size;
}
if (Symbol && Addend) {
auto Value =
MCBinaryExpr::createAdd(MCSymbolRefExpr::create(Symbol, Ctx),
MCConstantExpr::create(Addend, Ctx), Ctx);
Streamer->emitValue(Value, Size);
} else if (Symbol) {
Streamer->emitSymbolValue(Symbol, Size);
} else {
Streamer->emitIntValue(Addend, Size);
}
return Size;
}
#define ELF_RELOC(name, value) #name,
void Relocation::print(raw_ostream &OS) const {
static const char *X86RelocNames[] = {
#include "llvm/BinaryFormat/ELFRelocs/x86_64.def"
};
static const char *AArch64RelocNames[] = {
#include "llvm/BinaryFormat/ELFRelocs/AArch64.def"
};
if (Arch == Triple::aarch64)
OS << AArch64RelocNames[Type];
else
OS << X86RelocNames[Type];
OS << ", 0x" << Twine::utohexstr(Offset);
if (Symbol) {
OS << ", " << Symbol->getName();
}
if (int64_t(Addend) < 0)
OS << ", -0x" << Twine::utohexstr(-int64_t(Addend));
else
OS << ", 0x" << Twine::utohexstr(Addend);
OS << ", 0x" << Twine::utohexstr(Value);
}