2017-11-14 20:05:11 -08:00
|
|
|
//===--- Relocation.cpp - Interface for object file relocations ----------===//
|
|
|
|
|
//
|
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
|
//
|
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
|
//
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
//
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
|
|
#include "Relocation.h"
|
|
|
|
|
#include "llvm/MC/MCContext.h"
|
|
|
|
|
#include "llvm/MC/MCStreamer.h"
|
|
|
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
|
using namespace bolt;
|
|
|
|
|
|
|
|
|
|
Triple::ArchType Relocation::Arch;
|
|
|
|
|
|
|
|
|
|
bool Relocation::isSupported(uint64_t Type) {
|
|
|
|
|
switch (Type) {
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
case ELF::R_X86_64_8:
|
|
|
|
|
case ELF::R_X86_64_16:
|
|
|
|
|
case ELF::R_X86_64_32:
|
|
|
|
|
case ELF::R_X86_64_32S:
|
|
|
|
|
case ELF::R_X86_64_64:
|
|
|
|
|
case ELF::R_X86_64_PC8:
|
|
|
|
|
case ELF::R_X86_64_PC32:
|
|
|
|
|
case ELF::R_X86_64_PC64:
|
|
|
|
|
case ELF::R_X86_64_PLT32:
|
|
|
|
|
case ELF::R_X86_64_GOTPCREL:
|
|
|
|
|
case ELF::R_X86_64_GOTTPOFF:
|
|
|
|
|
case ELF::R_X86_64_TPOFF32:
|
|
|
|
|
case ELF::R_X86_64_GOTPCRELX:
|
|
|
|
|
case ELF::R_X86_64_REX_GOTPCRELX:
|
|
|
|
|
case ELF::R_AARCH64_CALL26:
|
|
|
|
|
case ELF::R_AARCH64_ADR_PREL_PG_HI21:
|
|
|
|
|
case ELF::R_AARCH64_LDST64_ABS_LO12_NC:
|
|
|
|
|
case ELF::R_AARCH64_ADD_ABS_LO12_NC:
|
|
|
|
|
case ELF::R_AARCH64_LDST128_ABS_LO12_NC:
|
|
|
|
|
case ELF::R_AARCH64_LDST32_ABS_LO12_NC:
|
|
|
|
|
case ELF::R_AARCH64_LDST16_ABS_LO12_NC:
|
|
|
|
|
case ELF::R_AARCH64_LDST8_ABS_LO12_NC:
|
|
|
|
|
case ELF::R_AARCH64_ADR_GOT_PAGE:
|
|
|
|
|
case ELF::R_AARCH64_TLSDESC_ADR_PAGE21:
|
|
|
|
|
case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
|
|
|
|
|
case ELF::R_AARCH64_TLSLE_ADD_TPREL_HI12:
|
|
|
|
|
case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
|
|
|
|
|
case ELF::R_AARCH64_LD64_GOT_LO12_NC:
|
|
|
|
|
case ELF::R_AARCH64_TLSDESC_LD64_LO12:
|
|
|
|
|
case ELF::R_AARCH64_TLSDESC_ADD_LO12:
|
|
|
|
|
case ELF::R_AARCH64_TLSDESC_CALL:
|
|
|
|
|
case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
|
|
|
|
|
case ELF::R_AARCH64_JUMP26:
|
|
|
|
|
case ELF::R_AARCH64_PREL32:
|
|
|
|
|
case ELF::R_AARCH64_ABS64:
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t Relocation::getSizeForType(uint64_t Type) {
|
|
|
|
|
switch (Type) {
|
|
|
|
|
default:
|
|
|
|
|
llvm_unreachable("unsupported relocation type");
|
|
|
|
|
case ELF::R_X86_64_8:
|
|
|
|
|
case ELF::R_X86_64_PC8:
|
|
|
|
|
return 1;
|
|
|
|
|
case ELF::R_X86_64_16:
|
|
|
|
|
return 2;
|
|
|
|
|
case ELF::R_X86_64_PLT32:
|
|
|
|
|
case ELF::R_X86_64_PC32:
|
|
|
|
|
case ELF::R_X86_64_32S:
|
|
|
|
|
case ELF::R_X86_64_32:
|
|
|
|
|
case ELF::R_X86_64_GOTPCREL:
|
|
|
|
|
case ELF::R_X86_64_GOTTPOFF:
|
|
|
|
|
case ELF::R_X86_64_TPOFF32:
|
|
|
|
|
case ELF::R_X86_64_GOTPCRELX:
|
|
|
|
|
case ELF::R_X86_64_REX_GOTPCRELX:
|
|
|
|
|
case ELF::R_AARCH64_CALL26:
|
|
|
|
|
case ELF::R_AARCH64_ADR_PREL_PG_HI21:
|
|
|
|
|
case ELF::R_AARCH64_LDST64_ABS_LO12_NC:
|
|
|
|
|
case ELF::R_AARCH64_ADD_ABS_LO12_NC:
|
|
|
|
|
case ELF::R_AARCH64_LDST128_ABS_LO12_NC:
|
|
|
|
|
case ELF::R_AARCH64_LDST32_ABS_LO12_NC:
|
|
|
|
|
case ELF::R_AARCH64_LDST16_ABS_LO12_NC:
|
|
|
|
|
case ELF::R_AARCH64_LDST8_ABS_LO12_NC:
|
|
|
|
|
case ELF::R_AARCH64_ADR_GOT_PAGE:
|
|
|
|
|
case ELF::R_AARCH64_TLSDESC_ADR_PAGE21:
|
|
|
|
|
case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
|
|
|
|
|
case ELF::R_AARCH64_TLSLE_ADD_TPREL_HI12:
|
|
|
|
|
case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
|
|
|
|
|
case ELF::R_AARCH64_LD64_GOT_LO12_NC:
|
|
|
|
|
case ELF::R_AARCH64_TLSDESC_LD64_LO12:
|
|
|
|
|
case ELF::R_AARCH64_TLSDESC_ADD_LO12:
|
|
|
|
|
case ELF::R_AARCH64_TLSDESC_CALL:
|
|
|
|
|
case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
|
|
|
|
|
case ELF::R_AARCH64_JUMP26:
|
|
|
|
|
case ELF::R_AARCH64_PREL32:
|
|
|
|
|
return 4;
|
|
|
|
|
case ELF::R_X86_64_PC64:
|
|
|
|
|
case ELF::R_X86_64_64:
|
|
|
|
|
case ELF::R_AARCH64_ABS64:
|
|
|
|
|
return 8;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint64_t Relocation::extractValue(uint64_t Type, uint64_t Contents,
|
|
|
|
|
uint64_t PC) {
|
|
|
|
|
switch (Type) {
|
|
|
|
|
default:
|
|
|
|
|
return Contents;
|
2020-10-05 12:41:03 -07:00
|
|
|
case ELF::R_X86_64_32S:
|
|
|
|
|
return SignExtend64<32>(Contents & 0xffffffff);
|
2017-11-14 20:05:11 -08:00
|
|
|
case ELF::R_AARCH64_PREL32:
|
|
|
|
|
return static_cast<int64_t>(PC) + SignExtend64<32>(Contents & 0xffffffff);
|
|
|
|
|
case ELF::R_AARCH64_TLSDESC_CALL:
|
|
|
|
|
case ELF::R_AARCH64_JUMP26:
|
|
|
|
|
case ELF::R_AARCH64_CALL26:
|
|
|
|
|
// Immediate goes in bits 25:0 of B and BL.
|
|
|
|
|
Contents &= ~0xfffffffffc000000ULL;
|
|
|
|
|
return static_cast<int64_t>(PC) + SignExtend64<28>(Contents << 2);
|
|
|
|
|
case ELF::R_AARCH64_ADR_GOT_PAGE:
|
|
|
|
|
case ELF::R_AARCH64_TLSDESC_ADR_PAGE21:
|
|
|
|
|
case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
|
|
|
|
|
case ELF::R_AARCH64_ADR_PREL_PG_HI21: {
|
|
|
|
|
// Bits 32:12 of Symbol address goes in bits 30:29 + 23:5 of ADRP
|
|
|
|
|
// instruction
|
|
|
|
|
Contents &= ~0xffffffff9f00001fUll;
|
|
|
|
|
auto LowBits = (Contents >> 29) & 0x3;
|
|
|
|
|
auto HighBits = (Contents >> 5) & 0x7ffff;
|
|
|
|
|
Contents = LowBits | (HighBits << 2);
|
|
|
|
|
Contents = static_cast<int64_t>(PC) + SignExtend64<32>(Contents << 12);
|
|
|
|
|
Contents &= ~0xfffUll;
|
|
|
|
|
return Contents;
|
|
|
|
|
}
|
|
|
|
|
case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
|
|
|
|
|
case ELF::R_AARCH64_TLSDESC_LD64_LO12:
|
|
|
|
|
case ELF::R_AARCH64_LD64_GOT_LO12_NC:
|
|
|
|
|
case ELF::R_AARCH64_LDST64_ABS_LO12_NC: {
|
|
|
|
|
// Immediate goes in bits 21:10 of LD/ST instruction, taken
|
|
|
|
|
// from bits 11:3 of Symbol address
|
|
|
|
|
Contents &= ~0xffffffffffc003ffU;
|
|
|
|
|
return Contents >> (10 - 3);
|
|
|
|
|
}
|
|
|
|
|
case ELF::R_AARCH64_TLSLE_ADD_TPREL_HI12:
|
|
|
|
|
case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
|
|
|
|
|
case ELF::R_AARCH64_TLSDESC_ADD_LO12:
|
|
|
|
|
case ELF::R_AARCH64_ADD_ABS_LO12_NC: {
|
|
|
|
|
// Immediate goes in bits 21:10 of ADD instruction
|
|
|
|
|
Contents &= ~0xffffffffffc003ffU;
|
|
|
|
|
return Contents >> (10 - 0);
|
|
|
|
|
}
|
|
|
|
|
case ELF::R_AARCH64_LDST128_ABS_LO12_NC: {
|
|
|
|
|
// Immediate goes in bits 21:10 of ADD instruction, taken
|
|
|
|
|
// from bits 11:4 of Symbol address
|
|
|
|
|
Contents &= ~0xffffffffffc003ffU;
|
|
|
|
|
return Contents >> (10 - 4);
|
|
|
|
|
}
|
|
|
|
|
case ELF::R_AARCH64_LDST32_ABS_LO12_NC: {
|
|
|
|
|
// Immediate goes in bits 21:10 of ADD instruction, taken
|
|
|
|
|
// from bits 11:2 of Symbol address
|
|
|
|
|
Contents &= ~0xffffffffffc003ffU;
|
|
|
|
|
return Contents >> (10 - 2);
|
|
|
|
|
}
|
|
|
|
|
case ELF::R_AARCH64_LDST16_ABS_LO12_NC: {
|
|
|
|
|
// Immediate goes in bits 21:10 of ADD instruction, taken
|
|
|
|
|
// from bits 11:1 of Symbol address
|
|
|
|
|
Contents &= ~0xffffffffffc003ffU;
|
|
|
|
|
return Contents >> (10 - 1);
|
|
|
|
|
}
|
|
|
|
|
case ELF::R_AARCH64_LDST8_ABS_LO12_NC: {
|
|
|
|
|
// Immediate goes in bits 21:10 of ADD instruction, taken
|
|
|
|
|
// from bits 11:0 of Symbol address
|
|
|
|
|
Contents &= ~0xffffffffffc003ffU;
|
|
|
|
|
return Contents >> (10 - 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Relocation::isGOT(uint64_t Type) {
|
|
|
|
|
switch (Type) {
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
case ELF::R_X86_64_GOT32:
|
|
|
|
|
case ELF::R_X86_64_GOTPCREL:
|
|
|
|
|
case ELF::R_X86_64_GOTTPOFF:
|
|
|
|
|
case ELF::R_X86_64_GOTOFF64:
|
|
|
|
|
case ELF::R_X86_64_GOTPC32:
|
|
|
|
|
case ELF::R_X86_64_GOT64:
|
|
|
|
|
case ELF::R_X86_64_GOTPCREL64:
|
|
|
|
|
case ELF::R_X86_64_GOTPC64:
|
|
|
|
|
case ELF::R_X86_64_GOTPLT64:
|
|
|
|
|
case ELF::R_X86_64_GOTPC32_TLSDESC:
|
|
|
|
|
case ELF::R_X86_64_GOTPCRELX:
|
|
|
|
|
case ELF::R_X86_64_REX_GOTPCRELX:
|
|
|
|
|
case ELF::R_AARCH64_ADR_GOT_PAGE:
|
|
|
|
|
case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
|
|
|
|
|
case ELF::R_AARCH64_LD64_GOT_LO12_NC:
|
|
|
|
|
case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
|
|
|
|
|
case ELF::R_AARCH64_TLSLE_ADD_TPREL_HI12:
|
|
|
|
|
case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
|
|
|
|
|
case ELF::R_AARCH64_TLSDESC_ADR_PAGE21:
|
|
|
|
|
case ELF::R_AARCH64_TLSDESC_LD64_LO12:
|
|
|
|
|
case ELF::R_AARCH64_TLSDESC_ADD_LO12:
|
|
|
|
|
case ELF::R_AARCH64_TLSDESC_CALL:
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Relocation::isTLS(uint64_t Type) {
|
|
|
|
|
switch (Type) {
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
case ELF::R_X86_64_TPOFF32:
|
|
|
|
|
case ELF::R_X86_64_TPOFF64:
|
|
|
|
|
case ELF::R_X86_64_GOTTPOFF:
|
|
|
|
|
case ELF::R_AARCH64_TLSDESC_ADR_PAGE21:
|
|
|
|
|
case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
|
|
|
|
|
case ELF::R_AARCH64_TLSLE_ADD_TPREL_HI12:
|
|
|
|
|
case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
|
|
|
|
|
case ELF::R_AARCH64_TLSDESC_LD64_LO12:
|
|
|
|
|
case ELF::R_AARCH64_TLSDESC_ADD_LO12:
|
|
|
|
|
case ELF::R_AARCH64_TLSDESC_CALL:
|
|
|
|
|
case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Relocation::isPCRelative(uint64_t Type) {
|
|
|
|
|
switch (Type) {
|
|
|
|
|
default:
|
|
|
|
|
llvm_unreachable("Unknown relocation type");
|
|
|
|
|
|
|
|
|
|
case ELF::R_X86_64_64:
|
|
|
|
|
case ELF::R_X86_64_32:
|
|
|
|
|
case ELF::R_X86_64_32S:
|
|
|
|
|
case ELF::R_X86_64_16:
|
|
|
|
|
case ELF::R_X86_64_8:
|
|
|
|
|
case ELF::R_X86_64_TPOFF32:
|
|
|
|
|
case ELF::R_AARCH64_ABS64:
|
|
|
|
|
case ELF::R_AARCH64_LDST64_ABS_LO12_NC:
|
|
|
|
|
case ELF::R_AARCH64_ADD_ABS_LO12_NC:
|
|
|
|
|
case ELF::R_AARCH64_LDST128_ABS_LO12_NC:
|
|
|
|
|
case ELF::R_AARCH64_LDST32_ABS_LO12_NC:
|
|
|
|
|
case ELF::R_AARCH64_LDST16_ABS_LO12_NC:
|
|
|
|
|
case ELF::R_AARCH64_LDST8_ABS_LO12_NC:
|
|
|
|
|
case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
|
|
|
|
|
case ELF::R_AARCH64_TLSLE_ADD_TPREL_HI12:
|
|
|
|
|
case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
|
|
|
|
|
case ELF::R_AARCH64_LD64_GOT_LO12_NC:
|
|
|
|
|
case ELF::R_AARCH64_TLSDESC_LD64_LO12:
|
|
|
|
|
case ELF::R_AARCH64_TLSDESC_ADD_LO12:
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
case ELF::R_X86_64_PC8:
|
|
|
|
|
case ELF::R_X86_64_PC32:
|
2018-07-24 14:30:16 -07:00
|
|
|
case ELF::R_X86_64_PC64:
|
2017-11-14 20:05:11 -08:00
|
|
|
case ELF::R_X86_64_GOTPCREL:
|
|
|
|
|
case ELF::R_X86_64_PLT32:
|
|
|
|
|
case ELF::R_X86_64_GOTTPOFF:
|
|
|
|
|
case ELF::R_X86_64_GOTPCRELX:
|
|
|
|
|
case ELF::R_X86_64_REX_GOTPCRELX:
|
|
|
|
|
case ELF::R_AARCH64_TLSDESC_CALL:
|
|
|
|
|
case ELF::R_AARCH64_CALL26:
|
|
|
|
|
case ELF::R_AARCH64_ADR_PREL_PG_HI21:
|
|
|
|
|
case ELF::R_AARCH64_ADR_GOT_PAGE:
|
|
|
|
|
case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
|
|
|
|
|
case ELF::R_AARCH64_TLSDESC_ADR_PAGE21:
|
|
|
|
|
case ELF::R_AARCH64_JUMP26:
|
|
|
|
|
case ELF::R_AARCH64_PREL32:
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t Relocation::emit(MCStreamer *Streamer) const {
|
|
|
|
|
const auto Size = getSizeForType(Type);
|
|
|
|
|
auto &Ctx = Streamer->getContext();
|
|
|
|
|
if (isPCRelative(Type)) {
|
|
|
|
|
auto *TempLabel = Ctx.createTempSymbol();
|
|
|
|
|
Streamer->EmitLabel(TempLabel);
|
2020-04-16 00:02:35 -07:00
|
|
|
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);
|
2017-11-14 20:05:11 -08:00
|
|
|
}
|
2020-04-16 00:02:35 -07:00
|
|
|
Value = MCBinaryExpr::createSub(Value,
|
|
|
|
|
MCSymbolRefExpr::create(TempLabel, Ctx),
|
|
|
|
|
Ctx);
|
2017-11-14 20:05:11 -08:00
|
|
|
Streamer->EmitValue(Value, Size);
|
2020-04-16 00:02:35 -07:00
|
|
|
|
|
|
|
|
return Size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Symbol && Addend) {
|
2017-11-14 20:05:11 -08:00
|
|
|
auto Value = MCBinaryExpr::createAdd(MCSymbolRefExpr::create(Symbol, Ctx),
|
|
|
|
|
MCConstantExpr::create(Addend, Ctx),
|
|
|
|
|
Ctx);
|
|
|
|
|
Streamer->EmitValue(Value, Size);
|
2020-04-16 00:02:35 -07:00
|
|
|
} else if (Symbol) {
|
2017-11-14 20:05:11 -08:00
|
|
|
Streamer->EmitSymbolValue(Symbol, Size);
|
2020-04-16 00:02:35 -07:00
|
|
|
} else {
|
|
|
|
|
Streamer->EmitIntValue(Addend, Size);
|
2017-11-14 20:05:11 -08:00
|
|
|
}
|
2020-04-16 00:02:35 -07:00
|
|
|
|
2017-11-14 20:05:11 -08:00
|
|
|
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);
|
|
|
|
|
}
|