2021-12-21 10:21:41 -08:00
|
|
|
//===- bolt/Core/Relocation.cpp - Object file relocations -----------------===//
|
2017-11-14 20:05:11 -08:00
|
|
|
//
|
2021-03-15 18:04:18 -07:00
|
|
|
// 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
|
2017-11-14 20:05:11 -08:00
|
|
|
//
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
//
|
2021-12-21 10:21:41 -08:00
|
|
|
// This file implements the Relocation class.
|
|
|
|
|
//
|
2017-11-14 20:05:11 -08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
2021-10-08 11:47:10 -07:00
|
|
|
#include "bolt/Core/Relocation.h"
|
2017-11-14 20:05:11 -08:00
|
|
|
#include "llvm/MC/MCContext.h"
|
2022-02-09 08:26:30 -05:00
|
|
|
#include "llvm/MC/MCExpr.h"
|
2017-11-14 20:05:11 -08:00
|
|
|
#include "llvm/MC/MCStreamer.h"
|
2022-02-09 08:26:30 -05:00
|
|
|
#include "llvm/MC/MCSymbol.h"
|
2021-11-29 13:20:03 -08:00
|
|
|
#include "llvm/Object/ELF.h"
|
2025-03-14 18:15:59 +00:00
|
|
|
#include "llvm/Object/ObjectFile.h"
|
2017-11-14 20:05:11 -08:00
|
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
|
using namespace bolt;
|
|
|
|
|
|
2023-10-05 08:53:51 +00:00
|
|
|
namespace ELFReserved {
|
|
|
|
|
enum {
|
|
|
|
|
R_RISCV_TPREL_I = 49,
|
|
|
|
|
R_RISCV_TPREL_S = 50,
|
|
|
|
|
};
|
|
|
|
|
} // namespace ELFReserved
|
|
|
|
|
|
2017-11-14 20:05:11 -08:00
|
|
|
Triple::ArchType Relocation::Arch;
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
static bool isSupportedX86(uint32_t Type) {
|
2017-11-14 20:05:11 -08:00
|
|
|
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:
|
2023-08-17 18:14:53 -07:00
|
|
|
case ELF::R_X86_64_GOTPC64:
|
2017-11-14 20:05:11 -08:00
|
|
|
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:
|
2020-10-07 15:40:51 -07:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
static bool isSupportedAArch64(uint32_t Type) {
|
2020-10-07 15:40:51 -07:00
|
|
|
switch (Type) {
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
2017-11-14 20:05:11 -08:00
|
|
|
case ELF::R_AARCH64_CALL26:
|
2021-10-03 13:41:41 +03:00
|
|
|
case ELF::R_AARCH64_JUMP26:
|
|
|
|
|
case ELF::R_AARCH64_TSTBR14:
|
|
|
|
|
case ELF::R_AARCH64_CONDBR19:
|
2021-08-20 03:07:01 +03:00
|
|
|
case ELF::R_AARCH64_ADR_PREL_LO21:
|
2017-11-14 20:05:11 -08:00
|
|
|
case ELF::R_AARCH64_ADR_PREL_PG_HI21:
|
2021-08-20 03:07:01 +03:00
|
|
|
case ELF::R_AARCH64_ADR_PREL_PG_HI21_NC:
|
2017-11-14 20:05:11 -08:00
|
|
|
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:
|
2021-08-20 03:07:01 +03:00
|
|
|
case ELF::R_AARCH64_TLSDESC_ADR_PREL21:
|
2017-11-14 20:05:11 -08:00
|
|
|
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:
|
2024-12-20 15:54:36 +03:00
|
|
|
case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0:
|
|
|
|
|
case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
|
2017-11-14 20:05:11 -08:00
|
|
|
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:
|
2022-04-21 13:52:00 +03:00
|
|
|
case ELF::R_AARCH64_PREL16:
|
2017-11-14 20:05:11 -08:00
|
|
|
case ELF::R_AARCH64_PREL32:
|
2022-04-21 13:52:00 +03:00
|
|
|
case ELF::R_AARCH64_PREL64:
|
2021-10-19 16:46:20 +03:00
|
|
|
case ELF::R_AARCH64_ABS16:
|
|
|
|
|
case ELF::R_AARCH64_ABS32:
|
2017-11-14 20:05:11 -08:00
|
|
|
case ELF::R_AARCH64_ABS64:
|
2021-09-23 00:52:36 +03:00
|
|
|
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:
|
2025-04-14 10:24:47 -07:00
|
|
|
case ELF::R_AARCH64_PLT32:
|
2017-11-14 20:05:11 -08:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
static bool isSupportedRISCV(uint32_t Type) {
|
2023-06-16 11:49:19 +02:00
|
|
|
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:
|
2023-09-09 08:22:37 +00:00
|
|
|
case ELF::R_RISCV_PCREL_LO12_S:
|
2023-06-16 11:49:19 +02:00
|
|
|
case ELF::R_RISCV_RVC_JUMP:
|
|
|
|
|
case ELF::R_RISCV_RVC_BRANCH:
|
2023-06-22 09:32:32 +02:00
|
|
|
case ELF::R_RISCV_ADD32:
|
|
|
|
|
case ELF::R_RISCV_SUB32:
|
2023-09-26 15:54:11 +00:00
|
|
|
case ELF::R_RISCV_HI20:
|
|
|
|
|
case ELF::R_RISCV_LO12_I:
|
|
|
|
|
case ELF::R_RISCV_LO12_S:
|
2023-09-27 14:33:59 +00:00
|
|
|
case ELF::R_RISCV_64:
|
2023-10-05 08:53:51 +00:00
|
|
|
case ELF::R_RISCV_TLS_GOT_HI20:
|
2025-04-17 14:01:00 +08:00
|
|
|
case ELF::R_RISCV_TLS_GD_HI20:
|
2023-10-05 08:53:51 +00:00
|
|
|
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:
|
2023-06-16 11:49:19 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
static size_t getSizeForTypeX86(uint32_t Type) {
|
2017-11-14 20:05:11 -08:00
|
|
|
switch (Type) {
|
|
|
|
|
default:
|
2021-11-29 13:20:03 -08:00
|
|
|
errs() << object::getELFRelocationTypeName(ELF::EM_X86_64, Type) << '\n';
|
2017-11-14 20:05:11 -08:00
|
|
|
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:
|
2020-10-07 15:40:51 -07:00
|
|
|
return 4;
|
|
|
|
|
case ELF::R_X86_64_PC64:
|
|
|
|
|
case ELF::R_X86_64_64:
|
2023-08-17 18:14:53 -07:00
|
|
|
case ELF::R_X86_64_GOTPC64:
|
2020-10-07 15:40:51 -07:00
|
|
|
return 8;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
static size_t getSizeForTypeAArch64(uint32_t Type) {
|
2020-10-07 15:40:51 -07:00
|
|
|
switch (Type) {
|
|
|
|
|
default:
|
2021-11-29 13:20:03 -08:00
|
|
|
errs() << object::getELFRelocationTypeName(ELF::EM_AARCH64, Type) << '\n';
|
2020-10-07 15:40:51 -07:00
|
|
|
llvm_unreachable("unsupported relocation type");
|
2021-10-19 16:46:20 +03:00
|
|
|
case ELF::R_AARCH64_ABS16:
|
2022-04-21 13:52:00 +03:00
|
|
|
case ELF::R_AARCH64_PREL16:
|
2021-10-19 16:46:20 +03:00
|
|
|
return 2;
|
2017-11-14 20:05:11 -08:00
|
|
|
case ELF::R_AARCH64_CALL26:
|
2021-10-03 13:41:41 +03:00
|
|
|
case ELF::R_AARCH64_JUMP26:
|
|
|
|
|
case ELF::R_AARCH64_TSTBR14:
|
|
|
|
|
case ELF::R_AARCH64_CONDBR19:
|
2021-08-20 03:07:01 +03:00
|
|
|
case ELF::R_AARCH64_ADR_PREL_LO21:
|
2017-11-14 20:05:11 -08:00
|
|
|
case ELF::R_AARCH64_ADR_PREL_PG_HI21:
|
2021-08-20 03:07:01 +03:00
|
|
|
case ELF::R_AARCH64_ADR_PREL_PG_HI21_NC:
|
2017-11-14 20:05:11 -08:00
|
|
|
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:
|
2021-08-20 03:07:01 +03:00
|
|
|
case ELF::R_AARCH64_TLSDESC_ADR_PREL21:
|
2017-11-14 20:05:11 -08:00
|
|
|
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:
|
2024-12-20 15:54:36 +03:00
|
|
|
case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0:
|
|
|
|
|
case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
|
2017-11-14 20:05:11 -08:00
|
|
|
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:
|
2021-09-23 00:52:36 +03:00
|
|
|
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:
|
2021-10-19 16:46:20 +03:00
|
|
|
case ELF::R_AARCH64_ABS32:
|
2025-04-14 10:24:47 -07:00
|
|
|
case ELF::R_AARCH64_PLT32:
|
2017-11-14 20:05:11 -08:00
|
|
|
return 4;
|
|
|
|
|
case ELF::R_AARCH64_ABS64:
|
2022-04-21 13:52:00 +03:00
|
|
|
case ELF::R_AARCH64_PREL64:
|
2017-11-14 20:05:11 -08:00
|
|
|
return 8;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
static size_t getSizeForTypeRISCV(uint32_t Type) {
|
2023-06-16 11:49:19 +02:00
|
|
|
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:
|
2023-09-09 08:22:37 +00:00
|
|
|
case ELF::R_RISCV_PCREL_LO12_S:
|
2023-06-16 11:49:19 +02:00
|
|
|
case ELF::R_RISCV_32_PCREL:
|
|
|
|
|
case ELF::R_RISCV_CALL:
|
|
|
|
|
case ELF::R_RISCV_CALL_PLT:
|
2023-06-22 09:32:32 +02:00
|
|
|
case ELF::R_RISCV_ADD32:
|
|
|
|
|
case ELF::R_RISCV_SUB32:
|
2023-09-26 15:54:11 +00:00
|
|
|
case ELF::R_RISCV_HI20:
|
|
|
|
|
case ELF::R_RISCV_LO12_I:
|
|
|
|
|
case ELF::R_RISCV_LO12_S:
|
2023-06-16 11:49:19 +02:00
|
|
|
return 4;
|
2023-09-27 14:33:59 +00:00
|
|
|
case ELF::R_RISCV_64:
|
2023-06-16 11:49:19 +02:00
|
|
|
case ELF::R_RISCV_GOT_HI20:
|
2023-10-05 08:53:51 +00:00
|
|
|
case ELF::R_RISCV_TLS_GOT_HI20:
|
2025-04-17 14:01:00 +08:00
|
|
|
case ELF::R_RISCV_TLS_GD_HI20:
|
2023-06-16 11:49:19 +02:00
|
|
|
// See extractValueRISCV for why this is necessary.
|
|
|
|
|
return 8;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
static bool skipRelocationTypeX86(uint32_t Type) {
|
2023-02-06 17:38:20 -08:00
|
|
|
return Type == ELF::R_X86_64_NONE;
|
|
|
|
|
}
|
2022-06-09 19:00:24 +03:00
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
static bool skipRelocationTypeAArch64(uint32_t Type) {
|
2022-06-09 19:00:24 +03:00
|
|
|
return Type == ELF::R_AARCH64_NONE || Type == ELF::R_AARCH64_LD_PREL_LO19;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
static bool skipRelocationTypeRISCV(uint32_t Type) {
|
2023-06-16 11:49:19 +02:00
|
|
|
switch (Type) {
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
case ELF::R_RISCV_NONE:
|
|
|
|
|
case ELF::R_RISCV_RELAX:
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
static uint64_t encodeValueX86(uint32_t Type, uint64_t Value, uint64_t PC) {
|
2021-12-08 16:53:38 +03:00
|
|
|
switch (Type) {
|
|
|
|
|
default:
|
2023-05-10 17:56:43 -07:00
|
|
|
llvm_unreachable("unsupported relocation");
|
|
|
|
|
case ELF::R_X86_64_64:
|
2021-12-08 16:53:38 +03:00
|
|
|
case ELF::R_X86_64_32:
|
|
|
|
|
break;
|
|
|
|
|
case ELF::R_X86_64_PC32:
|
|
|
|
|
Value -= PC;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return Value;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-04 17:31:14 +01:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
static uint64_t encodeValueAArch64(uint32_t Type, uint64_t Value, uint64_t PC) {
|
2021-12-08 16:53:38 +03:00
|
|
|
switch (Type) {
|
|
|
|
|
default:
|
2023-05-10 17:56:43 -07:00
|
|
|
llvm_unreachable("unsupported relocation");
|
2023-11-08 11:01:10 +00:00
|
|
|
case ELF::R_AARCH64_ABS16:
|
2021-12-08 16:53:38 +03:00
|
|
|
case ELF::R_AARCH64_ABS32:
|
2023-11-08 11:01:10 +00:00
|
|
|
case ELF::R_AARCH64_ABS64:
|
2021-12-08 16:53:38 +03:00
|
|
|
break;
|
2022-04-21 13:52:00 +03:00
|
|
|
case ELF::R_AARCH64_PREL16:
|
2021-12-08 16:53:38 +03:00
|
|
|
case ELF::R_AARCH64_PREL32:
|
2022-04-21 13:52:00 +03:00
|
|
|
case ELF::R_AARCH64_PREL64:
|
2021-12-08 16:53:38 +03:00
|
|
|
Value -= PC;
|
|
|
|
|
break;
|
2023-08-23 00:50:31 +08:00
|
|
|
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.
|
2023-09-18 19:52:23 +08:00
|
|
|
Value = ((Value >> 2) & 0x3ffffff) | 0x94000000ULL;
|
2023-08-23 00:50:31 +08:00
|
|
|
break;
|
2024-03-04 17:11:47 +08:00
|
|
|
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;
|
2021-12-08 16:53:38 +03:00
|
|
|
}
|
|
|
|
|
return Value;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-04 17:31:14 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
static uint64_t encodeValueRISCV(uint32_t Type, uint64_t Value, uint64_t PC) {
|
2023-09-27 14:33:59 +00:00
|
|
|
switch (Type) {
|
|
|
|
|
default:
|
|
|
|
|
llvm_unreachable("unsupported relocation");
|
|
|
|
|
case ELF::R_RISCV_64:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return Value;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
static uint64_t extractValueX86(uint32_t Type, uint64_t Contents, uint64_t PC) {
|
2020-10-07 15:40:51 -07:00
|
|
|
if (Type == ELF::R_X86_64_32S)
|
2022-02-23 22:54:42 -08:00
|
|
|
return SignExtend64<32>(Contents);
|
|
|
|
|
if (Relocation::isPCRelative(Type))
|
|
|
|
|
return SignExtend64(Contents, 8 * Relocation::getSizeForType(Type));
|
2020-10-07 15:40:51 -07:00
|
|
|
return Contents;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
static uint64_t extractValueAArch64(uint32_t Type, uint64_t Contents,
|
2023-02-06 17:38:20 -08:00
|
|
|
uint64_t PC) {
|
2017-11-14 20:05:11 -08:00
|
|
|
switch (Type) {
|
|
|
|
|
default:
|
2021-11-29 13:20:03 -08:00
|
|
|
errs() << object::getELFRelocationTypeName(ELF::EM_AARCH64, Type) << '\n';
|
2020-10-07 15:40:51 -07:00
|
|
|
llvm_unreachable("unsupported relocation type");
|
2021-10-19 16:46:20 +03:00
|
|
|
case ELF::R_AARCH64_ABS16:
|
|
|
|
|
case ELF::R_AARCH64_ABS32:
|
2020-10-07 15:40:51 -07:00
|
|
|
case ELF::R_AARCH64_ABS64:
|
2017-11-14 20:05:11 -08:00
|
|
|
return Contents;
|
2022-04-21 13:52:00 +03:00
|
|
|
case ELF::R_AARCH64_PREL16:
|
|
|
|
|
return static_cast<int64_t>(PC) + SignExtend64<16>(Contents & 0xffff);
|
2017-11-14 20:05:11 -08:00
|
|
|
case ELF::R_AARCH64_PREL32:
|
2025-04-14 10:24:47 -07:00
|
|
|
case ELF::R_AARCH64_PLT32:
|
2017-11-14 20:05:11 -08:00
|
|
|
return static_cast<int64_t>(PC) + SignExtend64<32>(Contents & 0xffffffff);
|
2022-04-21 13:52:00 +03:00
|
|
|
case ELF::R_AARCH64_PREL64:
|
|
|
|
|
return static_cast<int64_t>(PC) + Contents;
|
2017-11-14 20:05:11 -08:00
|
|
|
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);
|
2021-10-03 13:41:41 +03:00
|
|
|
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);
|
2017-11-14 20:05:11 -08:00
|
|
|
case ELF::R_AARCH64_ADR_GOT_PAGE:
|
2021-08-20 03:07:01 +03:00
|
|
|
case ELF::R_AARCH64_TLSDESC_ADR_PREL21:
|
2017-11-14 20:05:11 -08:00
|
|
|
case ELF::R_AARCH64_TLSDESC_ADR_PAGE21:
|
|
|
|
|
case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
|
2021-08-20 03:07:01 +03:00
|
|
|
case ELF::R_AARCH64_ADR_PREL_LO21:
|
|
|
|
|
case ELF::R_AARCH64_ADR_PREL_PG_HI21:
|
|
|
|
|
case ELF::R_AARCH64_ADR_PREL_PG_HI21_NC: {
|
2017-11-14 20:05:11 -08:00
|
|
|
// Bits 32:12 of Symbol address goes in bits 30:29 + 23:5 of ADRP
|
2021-08-20 03:07:01 +03:00
|
|
|
// and ADR instructions
|
|
|
|
|
bool IsAdr = !!(((Contents >> 31) & 0x1) == 0);
|
2017-11-14 20:05:11 -08:00
|
|
|
Contents &= ~0xffffffff9f00001fUll;
|
2021-04-08 00:19:26 -07:00
|
|
|
uint64_t LowBits = (Contents >> 29) & 0x3;
|
|
|
|
|
uint64_t HighBits = (Contents >> 5) & 0x7ffff;
|
2017-11-14 20:05:11 -08:00
|
|
|
Contents = LowBits | (HighBits << 2);
|
2021-08-20 03:07:01 +03:00
|
|
|
if (IsAdr)
|
|
|
|
|
return static_cast<int64_t>(PC) + SignExtend64<21>(Contents);
|
|
|
|
|
|
|
|
|
|
// ADRP instruction
|
2021-08-11 22:21:37 +03:00
|
|
|
Contents = static_cast<int64_t>(PC) + SignExtend64<33>(Contents << 12);
|
2017-11-14 20:05:11 -08:00
|
|
|
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);
|
|
|
|
|
}
|
2021-09-23 00:52:36 +03:00
|
|
|
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:
|
2023-11-09 13:29:46 -06:00
|
|
|
// The shift goes in bits 22:21 of MOV* instructions
|
2021-09-23 00:52:36 +03:00
|
|
|
uint8_t Shift = (Contents >> 21) & 0x3;
|
|
|
|
|
// Immediate goes in bits 20:5
|
|
|
|
|
Contents = (Contents >> 5) & 0xffff;
|
|
|
|
|
return Contents << (16 * Shift);
|
2017-11-14 20:05:11 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-16 11:49:19 +02:00
|
|
|
static uint64_t extractUImmRISCV(uint32_t Contents) {
|
|
|
|
|
return SignExtend64<32>(Contents & 0xfffff000);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static uint64_t extractIImmRISCV(uint32_t Contents) {
|
|
|
|
|
return SignExtend64<12>(Contents >> 20);
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-09 08:22:37 +00:00
|
|
|
static uint64_t extractSImmRISCV(uint32_t Contents) {
|
|
|
|
|
return SignExtend64<12>(((Contents >> 7) & 0x1f) | ((Contents >> 25) << 5));
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-16 11:49:19 +02:00
|
|
|
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));
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
static uint64_t extractValueRISCV(uint32_t Type, uint64_t Contents,
|
2023-06-16 11:49:19 +02:00
|
|
|
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:
|
2023-10-05 08:53:51 +00:00
|
|
|
case ELF::R_RISCV_TLS_GOT_HI20:
|
2025-04-17 14:01:00 +08:00
|
|
|
case ELF::R_RISCV_TLS_GD_HI20:
|
2023-06-16 11:49:19 +02:00
|
|
|
// 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:
|
2023-09-26 15:54:11 +00:00
|
|
|
case ELF::R_RISCV_HI20:
|
2023-06-16 11:49:19 +02:00
|
|
|
return extractUImmRISCV(Contents);
|
|
|
|
|
case ELF::R_RISCV_PCREL_LO12_I:
|
2023-09-26 15:54:11 +00:00
|
|
|
case ELF::R_RISCV_LO12_I:
|
2023-06-16 11:49:19 +02:00
|
|
|
return extractIImmRISCV(Contents);
|
2023-09-09 08:22:37 +00:00
|
|
|
case ELF::R_RISCV_PCREL_LO12_S:
|
2023-09-26 15:54:11 +00:00
|
|
|
case ELF::R_RISCV_LO12_S:
|
2023-09-09 08:22:37 +00:00
|
|
|
return extractSImmRISCV(Contents);
|
2023-06-16 11:49:19 +02:00
|
|
|
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));
|
2023-06-22 09:32:32 +02:00
|
|
|
case ELF::R_RISCV_ADD32:
|
|
|
|
|
case ELF::R_RISCV_SUB32:
|
2023-09-27 14:33:59 +00:00
|
|
|
case ELF::R_RISCV_64:
|
2023-06-22 09:32:32 +02:00
|
|
|
return Contents;
|
2023-06-16 11:49:19 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
static bool isGOTX86(uint32_t Type) {
|
2017-11-14 20:05:11 -08:00
|
|
|
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:
|
2020-10-07 15:40:51 -07:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
static bool isGOTAArch64(uint32_t Type) {
|
2020-10-07 15:40:51 -07:00
|
|
|
switch (Type) {
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
2017-11-14 20:05:11 -08:00
|
|
|
case ELF::R_AARCH64_ADR_GOT_PAGE:
|
|
|
|
|
case ELF::R_AARCH64_LD64_GOT_LO12_NC:
|
2021-09-02 21:04:33 +03:00
|
|
|
case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
|
2017-11-14 20:05:11 -08:00
|
|
|
case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
|
2021-08-20 03:07:01 +03:00
|
|
|
case ELF::R_AARCH64_TLSDESC_ADR_PREL21:
|
2017-11-14 20:05:11 -08:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
static bool isGOTRISCV(uint32_t Type) {
|
2023-06-16 11:49:19 +02:00
|
|
|
switch (Type) {
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
case ELF::R_RISCV_GOT_HI20:
|
2023-10-05 08:53:51 +00:00
|
|
|
case ELF::R_RISCV_TLS_GOT_HI20:
|
2023-06-16 11:49:19 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
static bool isTLSX86(uint32_t Type) {
|
2017-11-14 20:05:11 -08:00
|
|
|
switch (Type) {
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
case ELF::R_X86_64_TPOFF32:
|
|
|
|
|
case ELF::R_X86_64_TPOFF64:
|
|
|
|
|
case ELF::R_X86_64_GOTTPOFF:
|
2020-10-07 15:40:51 -07:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
static bool isTLSAArch64(uint32_t Type) {
|
2020-10-07 15:40:51 -07:00
|
|
|
switch (Type) {
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
2021-08-20 03:07:01 +03:00
|
|
|
case ELF::R_AARCH64_TLSDESC_ADR_PREL21:
|
2017-11-14 20:05:11 -08:00
|
|
|
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:
|
2024-12-20 15:54:36 +03:00
|
|
|
case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0:
|
|
|
|
|
case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
|
2017-11-14 20:05:11 -08:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
static bool isTLSRISCV(uint32_t Type) {
|
2023-06-16 11:49:19 +02:00
|
|
|
switch (Type) {
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
2023-10-05 08:53:51 +00:00
|
|
|
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;
|
2023-06-16 11:49:19 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
static bool isPCRelativeX86(uint32_t Type) {
|
2017-11-14 20:05:11 -08:00
|
|
|
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:
|
2020-10-07 15:40:51 -07:00
|
|
|
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:
|
2022-02-23 22:54:42 -08:00
|
|
|
case ELF::R_X86_64_GOTOFF64:
|
|
|
|
|
case ELF::R_X86_64_GOTPC32:
|
2023-08-17 18:14:53 -07:00
|
|
|
case ELF::R_X86_64_GOTPC64:
|
2020-10-07 15:40:51 -07:00
|
|
|
case ELF::R_X86_64_GOTTPOFF:
|
|
|
|
|
case ELF::R_X86_64_GOTPCRELX:
|
|
|
|
|
case ELF::R_X86_64_REX_GOTPCRELX:
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
static bool isPCRelativeAArch64(uint32_t Type) {
|
2020-10-07 15:40:51 -07:00
|
|
|
switch (Type) {
|
|
|
|
|
default:
|
|
|
|
|
llvm_unreachable("Unknown relocation type");
|
2021-10-19 16:46:20 +03:00
|
|
|
case ELF::R_AARCH64_ABS16:
|
|
|
|
|
case ELF::R_AARCH64_ABS32:
|
2017-11-14 20:05:11 -08:00
|
|
|
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:
|
2024-12-20 15:54:36 +03:00
|
|
|
case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0:
|
|
|
|
|
case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
|
2017-11-14 20:05:11 -08:00
|
|
|
case ELF::R_AARCH64_LD64_GOT_LO12_NC:
|
|
|
|
|
case ELF::R_AARCH64_TLSDESC_LD64_LO12:
|
|
|
|
|
case ELF::R_AARCH64_TLSDESC_ADD_LO12:
|
2021-09-23 00:52:36 +03:00
|
|
|
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:
|
2017-11-14 20:05:11 -08:00
|
|
|
return false;
|
|
|
|
|
case ELF::R_AARCH64_TLSDESC_CALL:
|
|
|
|
|
case ELF::R_AARCH64_CALL26:
|
2021-10-03 13:41:41 +03:00
|
|
|
case ELF::R_AARCH64_JUMP26:
|
|
|
|
|
case ELF::R_AARCH64_TSTBR14:
|
|
|
|
|
case ELF::R_AARCH64_CONDBR19:
|
2021-08-20 03:07:01 +03:00
|
|
|
case ELF::R_AARCH64_ADR_PREL_LO21:
|
2017-11-14 20:05:11 -08:00
|
|
|
case ELF::R_AARCH64_ADR_PREL_PG_HI21:
|
2021-08-20 03:07:01 +03:00
|
|
|
case ELF::R_AARCH64_ADR_PREL_PG_HI21_NC:
|
2017-11-14 20:05:11 -08:00
|
|
|
case ELF::R_AARCH64_ADR_GOT_PAGE:
|
|
|
|
|
case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
|
2021-08-20 03:07:01 +03:00
|
|
|
case ELF::R_AARCH64_TLSDESC_ADR_PREL21:
|
2017-11-14 20:05:11 -08:00
|
|
|
case ELF::R_AARCH64_TLSDESC_ADR_PAGE21:
|
2022-04-21 13:52:00 +03:00
|
|
|
case ELF::R_AARCH64_PREL16:
|
2017-11-14 20:05:11 -08:00
|
|
|
case ELF::R_AARCH64_PREL32:
|
2022-04-21 13:52:00 +03:00
|
|
|
case ELF::R_AARCH64_PREL64:
|
2025-04-14 10:24:47 -07:00
|
|
|
case ELF::R_AARCH64_PLT32:
|
2017-11-14 20:05:11 -08:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
static bool isPCRelativeRISCV(uint32_t Type) {
|
2023-06-16 11:49:19 +02:00
|
|
|
switch (Type) {
|
|
|
|
|
default:
|
|
|
|
|
llvm_unreachable("Unknown relocation type");
|
2023-06-22 09:32:32 +02:00
|
|
|
case ELF::R_RISCV_ADD32:
|
|
|
|
|
case ELF::R_RISCV_SUB32:
|
2023-09-26 15:54:11 +00:00
|
|
|
case ELF::R_RISCV_HI20:
|
|
|
|
|
case ELF::R_RISCV_LO12_I:
|
|
|
|
|
case ELF::R_RISCV_LO12_S:
|
2023-09-27 14:33:59 +00:00
|
|
|
case ELF::R_RISCV_64:
|
2023-06-22 09:32:32 +02:00
|
|
|
return false;
|
2023-06-16 11:49:19 +02:00
|
|
|
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:
|
2023-09-09 08:22:37 +00:00
|
|
|
case ELF::R_RISCV_PCREL_LO12_S:
|
2023-06-16 11:49:19 +02:00
|
|
|
case ELF::R_RISCV_RVC_JUMP:
|
|
|
|
|
case ELF::R_RISCV_RVC_BRANCH:
|
|
|
|
|
case ELF::R_RISCV_32_PCREL:
|
2023-10-05 08:53:51 +00:00
|
|
|
case ELF::R_RISCV_TLS_GOT_HI20:
|
2025-04-17 14:01:00 +08:00
|
|
|
case ELF::R_RISCV_TLS_GD_HI20:
|
2023-06-16 11:49:19 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
bool Relocation::isSupported(uint32_t Type) {
|
2024-04-08 09:01:28 -04:00
|
|
|
switch (Arch) {
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
case Triple::aarch64:
|
2020-10-07 15:40:51 -07:00
|
|
|
return isSupportedAArch64(Type);
|
2024-04-08 09:01:28 -04:00
|
|
|
case Triple::riscv64:
|
2023-06-16 11:49:19 +02:00
|
|
|
return isSupportedRISCV(Type);
|
2024-04-08 09:01:28 -04:00
|
|
|
case Triple::x86_64:
|
|
|
|
|
return isSupportedX86(Type);
|
|
|
|
|
}
|
2020-10-07 15:40:51 -07:00
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
size_t Relocation::getSizeForType(uint32_t Type) {
|
2024-04-08 09:01:28 -04:00
|
|
|
switch (Arch) {
|
|
|
|
|
default:
|
|
|
|
|
llvm_unreachable("Unsupported architecture");
|
|
|
|
|
case Triple::aarch64:
|
2020-10-07 15:40:51 -07:00
|
|
|
return getSizeForTypeAArch64(Type);
|
2024-04-08 09:01:28 -04:00
|
|
|
case Triple::riscv64:
|
2023-06-16 11:49:19 +02:00
|
|
|
return getSizeForTypeRISCV(Type);
|
2024-04-08 09:01:28 -04:00
|
|
|
case Triple::x86_64:
|
|
|
|
|
return getSizeForTypeX86(Type);
|
|
|
|
|
}
|
2020-10-07 15:40:51 -07:00
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
bool Relocation::skipRelocationType(uint32_t Type) {
|
2024-04-08 09:01:28 -04:00
|
|
|
switch (Arch) {
|
|
|
|
|
default:
|
|
|
|
|
llvm_unreachable("Unsupported architecture");
|
|
|
|
|
case Triple::aarch64:
|
2022-06-09 19:00:24 +03:00
|
|
|
return skipRelocationTypeAArch64(Type);
|
2024-04-08 09:01:28 -04:00
|
|
|
case Triple::riscv64:
|
2023-06-16 11:49:19 +02:00
|
|
|
return skipRelocationTypeRISCV(Type);
|
2024-04-08 09:01:28 -04:00
|
|
|
case Triple::x86_64:
|
|
|
|
|
return skipRelocationTypeX86(Type);
|
|
|
|
|
}
|
2022-06-09 19:00:24 +03:00
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
uint64_t Relocation::encodeValue(uint32_t Type, uint64_t Value, uint64_t PC) {
|
2024-04-08 09:01:28 -04:00
|
|
|
switch (Arch) {
|
|
|
|
|
default:
|
|
|
|
|
llvm_unreachable("Unsupported architecture");
|
|
|
|
|
case Triple::aarch64:
|
2023-05-10 17:56:43 -07:00
|
|
|
return encodeValueAArch64(Type, Value, PC);
|
2024-04-08 09:01:28 -04:00
|
|
|
case Triple::riscv64:
|
2023-09-27 14:33:59 +00:00
|
|
|
return encodeValueRISCV(Type, Value, PC);
|
2024-04-08 09:01:28 -04:00
|
|
|
case Triple::x86_64:
|
|
|
|
|
return encodeValueX86(Type, Value, PC);
|
|
|
|
|
}
|
2021-12-08 16:53:38 +03:00
|
|
|
}
|
|
|
|
|
|
2025-04-04 17:31:14 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
uint64_t Relocation::extractValue(uint32_t Type, uint64_t Contents,
|
2020-10-07 15:40:51 -07:00
|
|
|
uint64_t PC) {
|
2024-04-08 09:01:28 -04:00
|
|
|
switch (Arch) {
|
|
|
|
|
default:
|
|
|
|
|
llvm_unreachable("Unsupported architecture");
|
|
|
|
|
case Triple::aarch64:
|
2020-10-07 15:40:51 -07:00
|
|
|
return extractValueAArch64(Type, Contents, PC);
|
2024-04-08 09:01:28 -04:00
|
|
|
case Triple::riscv64:
|
2023-06-16 11:49:19 +02:00
|
|
|
return extractValueRISCV(Type, Contents, PC);
|
2024-04-08 09:01:28 -04:00
|
|
|
case Triple::x86_64:
|
|
|
|
|
return extractValueX86(Type, Contents, PC);
|
|
|
|
|
}
|
2020-10-07 15:40:51 -07:00
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
bool Relocation::isGOT(uint32_t Type) {
|
2024-04-08 09:01:28 -04:00
|
|
|
switch (Arch) {
|
|
|
|
|
default:
|
|
|
|
|
llvm_unreachable("Unsupported architecture");
|
|
|
|
|
case Triple::aarch64:
|
2020-10-07 15:40:51 -07:00
|
|
|
return isGOTAArch64(Type);
|
2024-04-08 09:01:28 -04:00
|
|
|
case Triple::riscv64:
|
2023-06-16 11:49:19 +02:00
|
|
|
return isGOTRISCV(Type);
|
2024-04-08 09:01:28 -04:00
|
|
|
case Triple::x86_64:
|
|
|
|
|
return isGOTX86(Type);
|
|
|
|
|
}
|
2020-10-07 15:40:51 -07:00
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
bool Relocation::isX86GOTPCRELX(uint32_t Type) {
|
2022-05-26 12:05:52 -07:00
|
|
|
if (Arch != Triple::x86_64)
|
|
|
|
|
return false;
|
|
|
|
|
return Type == ELF::R_X86_64_GOTPCRELX || Type == ELF::R_X86_64_REX_GOTPCRELX;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
bool Relocation::isX86GOTPC64(uint32_t Type) {
|
2023-08-17 18:14:53 -07:00
|
|
|
if (Arch != Triple::x86_64)
|
|
|
|
|
return false;
|
|
|
|
|
return Type == ELF::R_X86_64_GOTPC64;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
bool Relocation::isNone(uint32_t Type) { return Type == getNone(); }
|
2021-02-17 15:36:58 -08:00
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
bool Relocation::isRelative(uint32_t Type) {
|
2024-04-08 09:01:28 -04:00
|
|
|
switch (Arch) {
|
|
|
|
|
default:
|
|
|
|
|
llvm_unreachable("Unsupported architecture");
|
|
|
|
|
case Triple::aarch64:
|
2021-06-02 00:03:56 +03:00
|
|
|
return Type == ELF::R_AARCH64_RELATIVE;
|
2024-04-08 09:01:28 -04:00
|
|
|
case Triple::riscv64:
|
2023-06-16 11:49:19 +02:00
|
|
|
return Type == ELF::R_RISCV_RELATIVE;
|
2024-04-08 09:01:28 -04:00
|
|
|
case Triple::x86_64:
|
|
|
|
|
return Type == ELF::R_X86_64_RELATIVE;
|
|
|
|
|
}
|
2021-06-02 00:03:56 +03:00
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
bool Relocation::isIRelative(uint32_t Type) {
|
2024-04-08 09:01:28 -04:00
|
|
|
switch (Arch) {
|
|
|
|
|
default:
|
|
|
|
|
llvm_unreachable("Unsupported architecture");
|
|
|
|
|
case Triple::aarch64:
|
2021-06-02 00:03:56 +03:00
|
|
|
return Type == ELF::R_AARCH64_IRELATIVE;
|
2024-04-08 09:01:28 -04:00
|
|
|
case Triple::riscv64:
|
2023-06-16 11:49:19 +02:00
|
|
|
llvm_unreachable("not implemented");
|
2024-04-08 09:01:28 -04:00
|
|
|
case Triple::x86_64:
|
|
|
|
|
return Type == ELF::R_X86_64_IRELATIVE;
|
|
|
|
|
}
|
2021-06-02 00:03:56 +03:00
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
bool Relocation::isTLS(uint32_t Type) {
|
2024-04-08 09:01:28 -04:00
|
|
|
switch (Arch) {
|
|
|
|
|
default:
|
|
|
|
|
llvm_unreachable("Unsupported architecture");
|
|
|
|
|
case Triple::aarch64:
|
2020-10-07 15:40:51 -07:00
|
|
|
return isTLSAArch64(Type);
|
2024-04-08 09:01:28 -04:00
|
|
|
case Triple::riscv64:
|
2023-06-16 11:49:19 +02:00
|
|
|
return isTLSRISCV(Type);
|
2024-04-08 09:01:28 -04:00
|
|
|
case Triple::x86_64:
|
|
|
|
|
return isTLSX86(Type);
|
|
|
|
|
}
|
2020-10-07 15:40:51 -07:00
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
bool Relocation::isInstructionReference(uint32_t Type) {
|
[BOLT] Improve handling of relocations targeting specific instructions (#66395)
On RISC-V, there are certain relocations that target a specific
instruction instead of a more abstract location like a function or basic
block. Take the following example that loads a value from symbol `foo`:
```
nop
1: auipc t0, %pcrel_hi(foo)
ld t0, %pcrel_lo(1b)(t0)
```
This results in two relocation:
- auipc: `R_RISCV_PCREL_HI20` referencing `foo`;
- ld: `R_RISCV_PCREL_LO12_I` referencing to local label `1` which points
to the auipc instruction.
It is of utmost importance that the `R_RISCV_PCREL_LO12_I` keeps
referring to the auipc instruction; if not, the program will fail to
assemble. However, BOLT currently does not guarantee this.
BOLT currently assumes that all local symbols are jump targets and
always starts a new basic block at symbol locations. The example above
results in a CFG the looks like this:
```
.BB0:
nop
.BB1:
auipc t0, %pcrel_hi(foo)
ld t0, %pcrel_lo(.BB1)(t0)
```
While this currently works (i.e., the `R_RISCV_PCREL_LO12_I` relocation
points to the correct instruction), it has two downsides:
- Too many basic blocks are created (the example above is logically only
one yet two are created);
- If instructions are inserted in `.BB1` (e.g., by instrumentation),
things will break since the label will not point to the auipc anymore.
This patch proposes to fix this issue by teaching BOLT to track labels
that should always point to a specific instruction. This is implemented
as follows:
- Add a new annotation type (`kLabel`) that allows us to annotate
instructions with an `MCSymbol *`;
- Whenever we encounter a relocation type that is used to refer to a
specific instruction (`Relocation::isInstructionReference`), we
register it without a symbol;
- During disassembly, whenever we encounter an instruction with such a
relocation, create a symbol for its target and store it in an offset
to symbol map (to ensure multiple relocations referencing the same
instruction use the same label);
- After disassembly, iterate this map to attach labels to instructions
via the new annotation type;
- During emission, emit these labels right before the instruction.
I believe the use of annotations works quite well for this use case as
it allows us to reliably track instruction labels. If we were to store
them as offsets in basic blocks, it would be error prone to keep them
updated whenever instructions are inserted or removed.
I have chosen to add labels as first-class annotations (as opposed to a
generic one) because the documentation of `MCAnnotation` suggests that
generic annotations are to be used for optional metadata that can be
discarded without affecting correctness. As this is not the case for
labels, a first-class annotation seemed more appropriate.
2023-10-06 06:46:16 +00:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
uint32_t Relocation::getNone() {
|
2024-04-08 09:01:28 -04:00
|
|
|
switch (Arch) {
|
|
|
|
|
default:
|
|
|
|
|
llvm_unreachable("Unsupported architecture");
|
|
|
|
|
case Triple::aarch64:
|
2022-07-11 09:49:41 -07:00
|
|
|
return ELF::R_AARCH64_NONE;
|
2024-04-08 09:01:28 -04:00
|
|
|
case Triple::riscv64:
|
2023-06-16 11:49:19 +02:00
|
|
|
return ELF::R_RISCV_NONE;
|
2024-04-08 09:01:28 -04:00
|
|
|
case Triple::x86_64:
|
|
|
|
|
return ELF::R_X86_64_NONE;
|
|
|
|
|
}
|
2020-10-07 15:40:51 -07:00
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
uint32_t Relocation::getPC32() {
|
2024-04-08 09:01:28 -04:00
|
|
|
switch (Arch) {
|
|
|
|
|
default:
|
|
|
|
|
llvm_unreachable("Unsupported architecture");
|
|
|
|
|
case Triple::aarch64:
|
2020-10-07 15:40:51 -07:00
|
|
|
return ELF::R_AARCH64_PREL32;
|
2024-04-08 09:01:28 -04:00
|
|
|
case Triple::riscv64:
|
2023-06-16 11:49:19 +02:00
|
|
|
return ELF::R_RISCV_32_PCREL;
|
2024-04-08 09:01:28 -04:00
|
|
|
case Triple::x86_64:
|
|
|
|
|
return ELF::R_X86_64_PC32;
|
|
|
|
|
}
|
2020-10-07 15:40:51 -07:00
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
uint32_t Relocation::getPC64() {
|
2024-04-08 09:01:28 -04:00
|
|
|
switch (Arch) {
|
|
|
|
|
default:
|
|
|
|
|
llvm_unreachable("Unsupported architecture");
|
|
|
|
|
case Triple::aarch64:
|
2020-10-07 15:40:51 -07:00
|
|
|
return ELF::R_AARCH64_PREL64;
|
2024-04-08 09:01:28 -04:00
|
|
|
case Triple::riscv64:
|
2023-06-16 11:49:19 +02:00
|
|
|
llvm_unreachable("not implemented");
|
2024-04-08 09:01:28 -04:00
|
|
|
case Triple::x86_64:
|
|
|
|
|
return ELF::R_X86_64_PC64;
|
|
|
|
|
}
|
2020-10-07 15:40:51 -07:00
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
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) {
|
2024-04-08 09:01:28 -04:00
|
|
|
switch (Arch) {
|
|
|
|
|
default:
|
|
|
|
|
llvm_unreachable("Unsupported architecture");
|
|
|
|
|
case Triple::aarch64:
|
2022-07-11 09:49:41 -07:00
|
|
|
return isPCRelativeAArch64(Type);
|
2024-04-08 09:01:28 -04:00
|
|
|
case Triple::riscv64:
|
2023-06-16 11:49:19 +02:00
|
|
|
return isPCRelativeRISCV(Type);
|
2024-04-08 09:01:28 -04:00
|
|
|
case Triple::x86_64:
|
|
|
|
|
return isPCRelativeX86(Type);
|
|
|
|
|
}
|
2022-07-11 09:49:41 -07:00
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
uint32_t Relocation::getAbs64() {
|
2024-04-08 09:01:28 -04:00
|
|
|
switch (Arch) {
|
|
|
|
|
default:
|
|
|
|
|
llvm_unreachable("Unsupported architecture");
|
|
|
|
|
case Triple::aarch64:
|
2023-02-15 17:18:37 +04:00
|
|
|
return ELF::R_AARCH64_ABS64;
|
2024-04-08 09:01:28 -04:00
|
|
|
case Triple::riscv64:
|
2023-09-27 14:33:59 +00:00
|
|
|
return ELF::R_RISCV_64;
|
2024-04-08 09:01:28 -04:00
|
|
|
case Triple::x86_64:
|
|
|
|
|
return ELF::R_X86_64_64;
|
|
|
|
|
}
|
2023-02-15 17:18:37 +04:00
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
uint32_t Relocation::getRelative() {
|
2024-04-08 09:01:28 -04:00
|
|
|
switch (Arch) {
|
|
|
|
|
default:
|
|
|
|
|
llvm_unreachable("Unsupported architecture");
|
|
|
|
|
case Triple::aarch64:
|
2023-03-15 00:08:11 +04:00
|
|
|
return ELF::R_AARCH64_RELATIVE;
|
2024-04-08 09:01:28 -04:00
|
|
|
case Triple::riscv64:
|
|
|
|
|
llvm_unreachable("not implemented");
|
|
|
|
|
case Triple::x86_64:
|
|
|
|
|
return ELF::R_X86_64_RELATIVE;
|
|
|
|
|
}
|
2023-03-15 00:08:11 +04:00
|
|
|
}
|
|
|
|
|
|
2017-11-14 20:05:11 -08:00
|
|
|
size_t Relocation::emit(MCStreamer *Streamer) const {
|
2021-04-08 00:19:26 -07:00
|
|
|
const size_t Size = getSizeForType(Type);
|
[BOLT] Implement composed relocations
BOLT currently assumes (and asserts) that no two relocations can share
the same offset. Although this is true in most cases, ELF has a feature
called (not sure if this is an official term) composed relocations [1]
where multiple relocations at the same offset are combined to produce a
single value.
For example, to support label subtraction (a - b) on RISC-V, two
relocations are emitted at the same offset:
- R_RISCV_ADD32 a + 0
- R_RISCV_SUB32 b + 0
which, when combined, will produce the value of (a - b).
To support this in BOLT, first, RelocationSetType in BinarySection is
changed to be a multiset in order to allow it to store multiple
relocations at the same offset.
Next, Relocation::emit() is changed to receive an iterator pair of
relocations. In most cases, these will point to a single relocation in
which case its behavior is unaltered by this patch. For composed
relocations, they should point to all relocations at the same offset and
the following happens:
- A new method Relocation::createExpr() is called for every relocation.
This method is essentially the same as the original emit() except that
it returns the MCExpr without emitting it.
- The MCExprs of relocations i and i+1 are combined using the opcode
returned by the new method Relocation::getComposeOpcodeFor().
- After combining all MCExprs, the last one is emitted.
Note that in the current patch, getComposeOpcodeFor() simply calls
llvm_unreachable() since none of the current targets use composed
relocations. This will change once the RISC-V target lands.
Finally, BinarySection::emitAsData() is updated to group relocations by
offset and emit them all at once.
Note that this means composed relocations are only supported in data
sections. Since this is the only place they seem to be used in RISC-V, I
believe it's reasonable to only support them there for now to avoid
further code complexity.
[1]: https://www.sco.com/developers/gabi/latest/ch4.reloc.html
Reviewed By: rafauler
Differential Revision: https://reviews.llvm.org/D146546
2023-06-19 16:51:43 +02:00
|
|
|
const auto *Value = createExpr(Streamer);
|
|
|
|
|
Streamer->emitValue(Value, Size);
|
|
|
|
|
return Size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const MCExpr *Relocation::createExpr(MCStreamer *Streamer) const {
|
2021-04-08 00:19:26 -07:00
|
|
|
MCContext &Ctx = Streamer->getContext();
|
[BOLT] Implement composed relocations
BOLT currently assumes (and asserts) that no two relocations can share
the same offset. Although this is true in most cases, ELF has a feature
called (not sure if this is an official term) composed relocations [1]
where multiple relocations at the same offset are combined to produce a
single value.
For example, to support label subtraction (a - b) on RISC-V, two
relocations are emitted at the same offset:
- R_RISCV_ADD32 a + 0
- R_RISCV_SUB32 b + 0
which, when combined, will produce the value of (a - b).
To support this in BOLT, first, RelocationSetType in BinarySection is
changed to be a multiset in order to allow it to store multiple
relocations at the same offset.
Next, Relocation::emit() is changed to receive an iterator pair of
relocations. In most cases, these will point to a single relocation in
which case its behavior is unaltered by this patch. For composed
relocations, they should point to all relocations at the same offset and
the following happens:
- A new method Relocation::createExpr() is called for every relocation.
This method is essentially the same as the original emit() except that
it returns the MCExpr without emitting it.
- The MCExprs of relocations i and i+1 are combined using the opcode
returned by the new method Relocation::getComposeOpcodeFor().
- After combining all MCExprs, the last one is emitted.
Note that in the current patch, getComposeOpcodeFor() simply calls
llvm_unreachable() since none of the current targets use composed
relocations. This will change once the RISC-V target lands.
Finally, BinarySection::emitAsData() is updated to group relocations by
offset and emit them all at once.
Note that this means composed relocations are only supported in data
sections. Since this is the only place they seem to be used in RISC-V, I
believe it's reasonable to only support them there for now to avoid
further code complexity.
[1]: https://www.sco.com/developers/gabi/latest/ch4.reloc.html
Reviewed By: rafauler
Differential Revision: https://reviews.llvm.org/D146546
2023-06-19 16:51:43 +02:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-14 20:05:11 -08:00
|
|
|
if (isPCRelative(Type)) {
|
2021-04-08 00:19:26 -07:00
|
|
|
MCSymbol *TempLabel = Ctx.createNamedTempSymbol();
|
2020-12-01 16:29:39 -08:00
|
|
|
Streamer->emitLabel(TempLabel);
|
2021-12-14 16:52:51 -08:00
|
|
|
Value = MCBinaryExpr::createSub(
|
|
|
|
|
Value, MCSymbolRefExpr::create(TempLabel, Ctx), Ctx);
|
2020-04-16 00:02:35 -07:00
|
|
|
}
|
|
|
|
|
|
[BOLT] Implement composed relocations
BOLT currently assumes (and asserts) that no two relocations can share
the same offset. Although this is true in most cases, ELF has a feature
called (not sure if this is an official term) composed relocations [1]
where multiple relocations at the same offset are combined to produce a
single value.
For example, to support label subtraction (a - b) on RISC-V, two
relocations are emitted at the same offset:
- R_RISCV_ADD32 a + 0
- R_RISCV_SUB32 b + 0
which, when combined, will produce the value of (a - b).
To support this in BOLT, first, RelocationSetType in BinarySection is
changed to be a multiset in order to allow it to store multiple
relocations at the same offset.
Next, Relocation::emit() is changed to receive an iterator pair of
relocations. In most cases, these will point to a single relocation in
which case its behavior is unaltered by this patch. For composed
relocations, they should point to all relocations at the same offset and
the following happens:
- A new method Relocation::createExpr() is called for every relocation.
This method is essentially the same as the original emit() except that
it returns the MCExpr without emitting it.
- The MCExprs of relocations i and i+1 are combined using the opcode
returned by the new method Relocation::getComposeOpcodeFor().
- After combining all MCExprs, the last one is emitted.
Note that in the current patch, getComposeOpcodeFor() simply calls
llvm_unreachable() since none of the current targets use composed
relocations. This will change once the RISC-V target lands.
Finally, BinarySection::emitAsData() is updated to group relocations by
offset and emit them all at once.
Note that this means composed relocations are only supported in data
sections. Since this is the only place they seem to be used in RISC-V, I
believe it's reasonable to only support them there for now to avoid
further code complexity.
[1]: https://www.sco.com/developers/gabi/latest/ch4.reloc.html
Reviewed By: rafauler
Differential Revision: https://reviews.llvm.org/D146546
2023-06-19 16:51:43 +02:00
|
|
|
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());
|
2017-11-14 20:05:11 -08:00
|
|
|
}
|
2020-04-16 00:02:35 -07:00
|
|
|
|
[BOLT] Implement composed relocations
BOLT currently assumes (and asserts) that no two relocations can share
the same offset. Although this is true in most cases, ELF has a feature
called (not sure if this is an official term) composed relocations [1]
where multiple relocations at the same offset are combined to produce a
single value.
For example, to support label subtraction (a - b) on RISC-V, two
relocations are emitted at the same offset:
- R_RISCV_ADD32 a + 0
- R_RISCV_SUB32 b + 0
which, when combined, will produce the value of (a - b).
To support this in BOLT, first, RelocationSetType in BinarySection is
changed to be a multiset in order to allow it to store multiple
relocations at the same offset.
Next, Relocation::emit() is changed to receive an iterator pair of
relocations. In most cases, these will point to a single relocation in
which case its behavior is unaltered by this patch. For composed
relocations, they should point to all relocations at the same offset and
the following happens:
- A new method Relocation::createExpr() is called for every relocation.
This method is essentially the same as the original emit() except that
it returns the MCExpr without emitting it.
- The MCExprs of relocations i and i+1 are combined using the opcode
returned by the new method Relocation::getComposeOpcodeFor().
- After combining all MCExprs, the last one is emitted.
Note that in the current patch, getComposeOpcodeFor() simply calls
llvm_unreachable() since none of the current targets use composed
relocations. This will change once the RISC-V target lands.
Finally, BinarySection::emitAsData() is updated to group relocations by
offset and emit them all at once.
Note that this means composed relocations are only supported in data
sections. Since this is the only place they seem to be used in RISC-V, I
believe it's reasonable to only support them there for now to avoid
further code complexity.
[1]: https://www.sco.com/developers/gabi/latest/ch4.reloc.html
Reviewed By: rafauler
Differential Revision: https://reviews.llvm.org/D146546
2023-06-19 16:51:43 +02:00
|
|
|
return Value;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-14 18:15:59 +00:00
|
|
|
MCBinaryExpr::Opcode Relocation::getComposeOpcodeFor(uint32_t Type) {
|
2023-06-22 09:32:32 +02:00
|
|
|
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;
|
|
|
|
|
}
|
2017-11-14 20:05:11 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Relocation::print(raw_ostream &OS) const {
|
2024-04-08 09:01:28 -04:00
|
|
|
switch (Arch) {
|
|
|
|
|
default:
|
|
|
|
|
OS << "RType:" << Twine::utohexstr(Type);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Triple::aarch64:
|
2024-04-15 09:46:58 -04:00
|
|
|
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());
|
2017-11-14 20:05:11 -08:00
|
|
|
OS << AArch64RelocNames[Type];
|
2024-04-08 09:01:28 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Triple::riscv64:
|
2023-06-16 11:49:19 +02:00
|
|
|
// 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"
|
2024-04-15 09:46:58 -04:00
|
|
|
#undef ELF_RELOC
|
2023-06-16 11:49:19 +02:00
|
|
|
}
|
2024-04-08 09:01:28 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Triple::x86_64:
|
2024-04-15 09:46:58 -04:00
|
|
|
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());
|
2017-11-14 20:05:11 -08:00
|
|
|
OS << X86RelocNames[Type];
|
2024-04-08 09:01:28 -04:00
|
|
|
break;
|
|
|
|
|
}
|
2017-11-14 20:05:11 -08:00
|
|
|
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);
|
|
|
|
|
}
|