[llvm] [BOLT] Move target-specific relocation logic into target handlers (PR #217926)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 22 02:08:03 PDT 2026
https://github.com/maksimra updated https://github.com/llvm/llvm-project/pull/217926
>From 82755fb2b5af3adbf2d6c43cc34640980fd5f481 Mon Sep 17 00:00:00 2001
From: Maksim <rachinskii.mv at phystech.edu>
Date: Thu, 20 Aug 2026 17:10:41 +0300
Subject: [PATCH 1/2] [BOLT] Introduce target-specific relocation handlers
This PR cleans up BOLT's target-specific relocation handling.
Move relocation logic directly into the X86, AArch64, and RISC-V handlers located in their corresponding lib/Target directories.
This removes the remaining target-specific relocation helpers from the generic Relocation.cpp implementation.
This is a behavior-preserving refactoring.
AI tools (codex) were used to assist with implementation.
---
bolt/include/bolt/Core/BinaryContext.h | 8 +
bolt/include/bolt/Core/BinarySection.h | 5 +-
bolt/include/bolt/Core/Relocation.h | 180 ++-
bolt/lib/Core/BinaryContext.cpp | 14 +-
bolt/lib/Core/BinaryEmitter.cpp | 14 +-
bolt/lib/Core/BinaryFunction.cpp | 8 +-
bolt/lib/Core/BinarySection.cpp | 57 +-
bolt/lib/Core/CMakeLists.txt | 3 +
bolt/lib/Core/Relocation.cpp | 1028 +----------------
bolt/lib/Rewrite/LinuxKernelRewriter.cpp | 10 +-
bolt/lib/Rewrite/MachORewriteInstance.cpp | 1 -
bolt/lib/Rewrite/RSeqRewriter.cpp | 2 +-
bolt/lib/Rewrite/RewriteInstance.cpp | 82 +-
.../Target/AArch64/AArch64MCSymbolizer.cpp | 5 +-
.../AArch64/AArch64RelocationHandler.cpp | 448 +++++++
bolt/lib/Target/AArch64/CMakeLists.txt | 3 +
bolt/lib/Target/RISCV/CMakeLists.txt | 3 +
bolt/lib/Target/RISCV/RISCVMCSymbolizer.cpp | 24 +-
.../Target/RISCV/RISCVRelocationHandler.cpp | 348 ++++++
bolt/lib/Target/X86/CMakeLists.txt | 3 +
bolt/lib/Target/X86/X86MCSymbolizer.cpp | 19 +-
bolt/lib/Target/X86/X86RelocationHandler.cpp | 224 ++++
bolt/unittests/Core/BinaryContext.cpp | 19 +-
bolt/unittests/Core/CMakeLists.txt | 1 +
bolt/unittests/Core/MCPlusBuilder.cpp | 1 -
bolt/unittests/Core/MemoryMaps.cpp | 1 -
bolt/unittests/Core/Relocation.cpp | 75 ++
bolt/unittests/Passes/LivenessAnalysis.cpp | 1 -
bolt/unittests/Passes/PointerAuthCFIFixup.cpp | 1 -
bolt/unittests/Profile/DataAggregator.cpp | 1 -
bolt/unittests/Profile/PerfScripts.cpp | 1 -
bolt/unittests/Profile/PerfSpeEvents.cpp | 1 -
32 files changed, 1387 insertions(+), 1204 deletions(-)
create mode 100644 bolt/lib/Target/AArch64/AArch64RelocationHandler.cpp
create mode 100644 bolt/lib/Target/RISCV/RISCVRelocationHandler.cpp
create mode 100644 bolt/lib/Target/X86/X86RelocationHandler.cpp
create mode 100644 bolt/unittests/Core/Relocation.cpp
diff --git a/bolt/include/bolt/Core/BinaryContext.h b/bolt/include/bolt/Core/BinaryContext.h
index bee2b46e78cd1..38aaa128f96a4 100644
--- a/bolt/include/bolt/Core/BinaryContext.h
+++ b/bolt/include/bolt/Core/BinaryContext.h
@@ -730,6 +730,10 @@ class BinaryContext {
std::unique_ptr<Triple> TheTriple;
+private:
+ std::unique_ptr<RelocationHandler> RelocHandler;
+
+public:
std::shared_ptr<orc::SymbolStringPool> SSP;
const Target *TheTarget;
@@ -987,6 +991,10 @@ class BinaryContext {
bool isMachO() const { return TheTriple->isOSBinFormatMachO(); }
+ const RelocationHandler &getRelocationHandler() const {
+ return *RelocHandler;
+ }
+
bool isAArch64() const {
return TheTriple->getArch() == llvm::Triple::aarch64;
}
diff --git a/bolt/include/bolt/Core/BinarySection.h b/bolt/include/bolt/Core/BinarySection.h
index 3e3ad8217ea71..ae907fea091f2 100644
--- a/bolt/include/bolt/Core/BinarySection.h
+++ b/bolt/include/bolt/Core/BinarySection.h
@@ -373,10 +373,7 @@ class BinarySection {
JmpRelocationIndex});
}
- void addDynamicRelocation(const Relocation &Reloc) {
- assert(Reloc.Offset < getSize() && "offset not within section bounds");
- DynamicRelocations.emplace(Reloc);
- }
+ void addDynamicRelocation(const Relocation &Reloc);
/// Add relocation against the original contents of this section.
void addPendingRelocation(const Relocation &Rel) {
diff --git a/bolt/include/bolt/Core/Relocation.h b/bolt/include/bolt/Core/Relocation.h
index 02d18ff97cf98..897bb0758a007 100644
--- a/bolt/include/bolt/Core/Relocation.h
+++ b/bolt/include/bolt/Core/Relocation.h
@@ -17,6 +17,7 @@
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/TargetParser/Triple.h"
+#include <memory>
namespace llvm {
class MCSymbol;
@@ -34,6 +35,79 @@ enum { R_X86_64_converted_reloc_bit = 0x80 };
namespace bolt {
+/// Target-specific relocation operations. One handler is owned by each
+/// BinaryContext, while Relocation remains a lightweight value type.
+class RelocationHandler {
+public:
+ virtual ~RelocationHandler() = default;
+
+ /// Check if \p Type is a supported relocation type.
+ virtual bool isSupported(uint32_t Type) const = 0;
+
+ /// Return size in bytes of the given relocation \p Type.
+ virtual size_t getSizeForType(uint32_t Type) const = 0;
+
+ /// Skip relocations that we don't want to handle in BOLT
+ virtual bool skipRelocationType(uint32_t Type) const = 0;
+
+ /// Adjust value depending on relocation type (make it PC relative or not).
+ virtual uint64_t encodeValue(uint32_t Type, uint64_t Value,
+ uint64_t PC) const = 0;
+
+ /// Return true if there are enough bits to encode the relocation value.
+ virtual bool canEncodeValue(uint32_t Type, uint64_t Value,
+ uint64_t PC) const = 0;
+
+ /// Extract current relocated value from binary contents. This is used for
+ /// RISC architectures where values are encoded in specific bits depending
+ /// on the relocation value. For X86, we limit to sign extending the value
+ /// if necessary.
+ virtual uint64_t extractValue(uint32_t Type, uint64_t Contents,
+ uint64_t PC) const = 0;
+
+ /// Return true if relocation type implies the creation of a GOT entry
+ virtual bool isGOT(uint32_t Type) const = 0;
+
+ /// Return true if relocation type is NONE
+ bool isNone(uint32_t Type) const { return Type == getNone(); }
+
+ /// Return true if relocation type is RELATIVE
+ virtual bool isRelative(uint32_t Type) const = 0;
+
+ /// Return true if relocation type is IRELATIVE
+ virtual bool isIRelative(uint32_t Type) const = 0;
+
+ /// Return true if relocation type is for thread local storage.
+ virtual bool isTLS(uint32_t Type) const = 0;
+
+ /// Return true of relocation type is for referencing a specific instruction
+ /// (as opposed to a function, basic block, etc).
+ virtual bool isInstructionReference(uint32_t Type) const { return false; }
+
+ /// Return code for a NONE relocation
+ virtual uint32_t getNone() const = 0;
+
+ /// Return code for a PC-relative 4-byte relocation
+ virtual uint32_t getPC32() const = 0;
+
+ /// Return code for a PC-relative 8-byte relocation
+ virtual uint32_t getPC64() const = 0;
+
+ /// Return true if relocation type is PC-relative. Return false otherwise.
+ virtual bool isPCRelative(uint32_t Type) const = 0;
+
+ /// Return code for a ABS 8-byte relocation
+ virtual uint32_t getAbs64() const = 0;
+
+ /// Return code for a RELATIVE relocation
+ virtual uint32_t getRelative() const = 0;
+ virtual MCBinaryExpr::Opcode getComposeOpcodeFor(uint32_t Type) const;
+ virtual void printType(raw_ostream &OS, uint32_t Type) const = 0;
+};
+
+std::unique_ptr<RelocationHandler>
+createRelocationHandler(Triple::ArchType Arch);
+
/// Relocation class.
class Relocation {
public:
@@ -44,17 +118,12 @@ class Relocation {
uint32_t JmpRelocationIndex = NoJmpRelocationIndex)
: Offset(Offset), Symbol(Symbol), Addend(Addend), Value(Value),
Type(Type), JmpRelocationIndex(JmpRelocationIndex), Optional(false),
- IsRELR(IsRELR) {
- assert((isRelative() || !isRELR()) &&
- "Only relative relocations can be relr.");
- }
+ IsRELR(IsRELR) {}
Relocation()
: Offset(0), Symbol(0), Addend(0), Value(0), Type(0),
JmpRelocationIndex(NoJmpRelocationIndex), Optional(0), IsRELR(0) {}
- static Triple::ArchType Arch; /// set by BinaryContext ctor.
-
/// The offset of this relocation in the object it is contained in.
uint64_t Offset;
@@ -96,9 +165,6 @@ class Relocation {
return JmpRelocationIndex;
}
- /// Return size in bytes of the given relocation \p Type.
- static size_t getSizeForType(uint32_t Type);
-
void setOptional() { Optional = true; }
bool isOptional() { return Optional; }
@@ -106,91 +172,24 @@ class Relocation {
bool isRELR() const { return IsRELR; }
/// Return size of this relocation.
- size_t getSize() const { return getSizeForType(Type); }
-
- /// Skip relocations that we don't want to handle in BOLT
- static bool skipRelocationType(uint32_t Type);
-
- /// Adjust value depending on relocation type (make it PC relative or not).
- static uint64_t encodeValue(uint32_t Type, uint64_t Value, uint64_t PC);
-
- /// Return true if there are enough bits to encode the relocation value.
- static bool canEncodeValue(uint32_t Type, uint64_t Value, uint64_t PC);
-
- /// Extract current relocated value from binary contents. This is used for
- /// RISC architectures where values are encoded in specific bits depending
- /// on the relocation value. For X86, we limit to sign extending the value
- /// if necessary.
- static uint64_t extractValue(uint32_t Type, uint64_t Contents, uint64_t PC);
-
- /// Return true if relocation type is PC-relative. Return false otherwise.
- static bool isPCRelative(uint32_t Type);
-
- /// Check if \p Type is a supported relocation type.
- static bool isSupported(uint32_t Type);
-
- /// Return true if relocation type implies the creation of a GOT entry
- static bool isGOT(uint32_t Type);
-
- /// Special relocation type that allows the linker to modify the instruction.
- static bool isX86GOTPCRELX(uint32_t Type);
- static bool isX86GOTPC64(uint32_t Type);
-
- /// Return true if relocation type is NONE
- static bool isNone(uint32_t Type);
-
- /// Return true if relocation type is RELATIVE
- static bool isRelative(uint32_t Type);
-
- /// Return true if relocation type is IRELATIVE
- static bool isIRelative(uint32_t Type);
-
- /// Return true if relocation type is for thread local storage.
- static bool isTLS(uint32_t Type);
-
- /// Return true of relocation type is for referencing a specific instruction
- /// (as opposed to a function, basic block, etc).
- static bool isInstructionReference(uint32_t Type);
-
/// Return the relocation type of \p Rel from llvm::object. It checks for
/// overflows as BOLT uses 32 bits for the type.
static uint32_t getType(const object::RelocationRef &Rel);
- /// Return code for a NONE relocation
- static uint32_t getNone();
-
- /// Return code for a PC-relative 4-byte relocation
- static uint32_t getPC32();
-
- /// Return code for a PC-relative 8-byte relocation
- static uint32_t getPC64();
-
- /// Return code for a ABS 8-byte relocation
- static uint32_t getAbs64();
-
- /// Return code for a RELATIVE relocation
- static uint32_t getRelative();
-
- /// Return true if this relocation is PC-relative. Return false otherwise.
- bool isPCRelative() const { return isPCRelative(Type); }
-
- /// Return true if this relocation is R_*_RELATIVE type. Return false
- /// otherwise.
- bool isRelative() const { return isRelative(Type); }
-
- /// Return true if this relocation is R_*_IRELATIVE type. Return false
- /// otherwise.
- bool isIRelative() const { return isIRelative(Type); }
+ size_t getSize(const RelocationHandler &RH) const {
+ return RH.getSizeForType(Type);
+ }
/// Emit relocation at a current \p Streamer' position. The caller is
/// responsible for setting the position correctly.
- size_t emit(MCStreamer *Streamer) const;
+ size_t emit(MCStreamer *Streamer, const RelocationHandler &RH) const;
/// Emit a group of composed relocations. All relocations must have the same
/// offset. If std::distance(Begin, End) == 1, this is equivalent to
/// Begin->emit(Streamer).
template <typename RelocIt>
- static size_t emit(RelocIt Begin, RelocIt End, MCStreamer *Streamer) {
+ static size_t emit(RelocIt Begin, RelocIt End, MCStreamer *Streamer,
+ const RelocationHandler &RH) {
if (Begin == End)
return 0;
@@ -199,23 +198,23 @@ class Relocation {
for (auto RI = Begin; RI != End; ++RI) {
assert(RI->Offset == Begin->Offset &&
"emitting composed relocations with different offsets");
- Value = RI->createExpr(Streamer, Value);
+ Value = RI->createExpr(Streamer, Value, RH);
}
assert(Value && "failed to create relocation value");
- auto Size = std::prev(End)->getSize();
+ auto Size = std::prev(End)->getSize(RH);
Streamer->emitValue(Value, Size);
return Size;
}
/// Print a relocation to \p OS.
- void print(raw_ostream &OS) const;
+ void print(raw_ostream &OS, const RelocationHandler &RH) const;
private:
- const MCExpr *createExpr(MCStreamer *Streamer) const;
const MCExpr *createExpr(MCStreamer *Streamer,
- const MCExpr *RetainedValue) const;
- static MCBinaryExpr::Opcode getComposeOpcodeFor(uint32_t Type);
+ const RelocationHandler &RH) const;
+ const MCExpr *createExpr(MCStreamer *Streamer, const MCExpr *RetainedValue,
+ const RelocationHandler &RH) const;
};
/// Relocation ordering by offset.
@@ -227,11 +226,6 @@ inline bool operator<(const Relocation &A, uint64_t B) { return A.Offset < B; }
inline bool operator<(uint64_t A, const Relocation &B) { return A < B.Offset; }
-inline raw_ostream &operator<<(raw_ostream &OS, const Relocation &Rel) {
- Rel.print(OS);
- return OS;
-}
-
} // namespace bolt
} // namespace llvm
diff --git a/bolt/lib/Core/BinaryContext.cpp b/bolt/lib/Core/BinaryContext.cpp
index ae320ab695af3..d77ecbdf3411b 100644
--- a/bolt/lib/Core/BinaryContext.cpp
+++ b/bolt/lib/Core/BinaryContext.cpp
@@ -165,12 +165,14 @@ BinaryContext::BinaryContext(std::unique_ptr<MCContext> Ctx,
std::unique_ptr<MCDisassembler> DisAsm,
JournalingStreams Logger)
: Ctx(std::move(Ctx)), DwCtx(std::move(DwCtx)),
- TheTriple(std::move(TheTriple)), SSP(std::move(SSP)),
- TheTarget(TheTarget), TripleName(TripleName), MCE(std::move(MCE)),
- MOFI(std::move(MOFI)), AsmInfo(std::move(AsmInfo)), MII(std::move(MII)),
- STI(std::move(STI)), InstPrinter(std::move(InstPrinter)),
- MIA(std::move(MIA)), MIB(std::move(MIB)), MRI(std::move(MRI)),
- DisAsm(std::move(DisAsm)), Logger(Logger), InitialDynoStats(isAArch64()) {
+ TheTriple(std::move(TheTriple)),
+ RelocHandler(createRelocationHandler(this->TheTriple->getArch())),
+ SSP(std::move(SSP)), TheTarget(TheTarget), TripleName(TripleName),
+ MCE(std::move(MCE)), MOFI(std::move(MOFI)), AsmInfo(std::move(AsmInfo)),
+ MII(std::move(MII)), STI(std::move(STI)),
+ InstPrinter(std::move(InstPrinter)), MIA(std::move(MIA)),
+ MIB(std::move(MIB)), MRI(std::move(MRI)), DisAsm(std::move(DisAsm)),
+ Logger(Logger), InitialDynoStats(isAArch64()) {
RegularPageSize = isAArch64() ? RegularPageSizeAArch64 : RegularPageSizeX86;
PageAlign = opts::NoHugePages ? RegularPageSize : HugePageSize;
}
diff --git a/bolt/lib/Core/BinaryEmitter.cpp b/bolt/lib/Core/BinaryEmitter.cpp
index 29dbcab7945ec..b28d44d3eef93 100644
--- a/bolt/lib/Core/BinaryEmitter.cpp
+++ b/bolt/lib/Core/BinaryEmitter.cpp
@@ -581,6 +581,8 @@ void BinaryEmitter::emitConstantIslands(BinaryFunction &BF, bool EmitColdPart,
if (FunctionOffset >= EndOffset)
return;
+ const RelocationHandler &RH = BC.getRelocationHandler();
+
for (auto It = Islands.Relocations.lower_bound(FunctionOffset);
It != Islands.Relocations.end(); ++It) {
if (It->first >= EndOffset)
@@ -593,13 +595,13 @@ void BinaryEmitter::emitConstantIslands(BinaryFunction &BF, bool EmitColdPart,
FunctionOffset = Relocation.Offset;
}
- LLVM_DEBUG(
- dbgs() << "BOLT-DEBUG: emitting constant island relocation"
- << " for " << BF << " at offset 0x"
- << Twine::utohexstr(Relocation.Offset) << " with size "
- << Relocation::getSizeForType(Relocation.Type) << '\n');
+ LLVM_DEBUG(dbgs() << "BOLT-DEBUG: emitting constant island relocation"
+ << " for " << BF << " at offset 0x"
+ << Twine::utohexstr(Relocation.Offset)
+ << " with size " << RH.getSizeForType(Relocation.Type)
+ << '\n');
- FunctionOffset += Relocation.emit(&Streamer);
+ FunctionOffset += Relocation.emit(&Streamer, RH);
}
assert(FunctionOffset <= EndOffset && "overflow error");
diff --git a/bolt/lib/Core/BinaryFunction.cpp b/bolt/lib/Core/BinaryFunction.cpp
index 39c4dd5595e3c..bc38cfdac4a83 100644
--- a/bolt/lib/Core/BinaryFunction.cpp
+++ b/bolt/lib/Core/BinaryFunction.cpp
@@ -703,7 +703,9 @@ void BinaryFunction::printRelocations(raw_ostream &OS, uint64_t Offset,
auto RI = Relocations.lower_bound(Offset);
while (RI != Relocations.end() && RI->first < Offset + Size) {
- OS << Sep << "(R: " << RI->second << ")";
+ OS << Sep << "(R: ";
+ RI->second.print(OS, BC.getRelocationHandler());
+ OS << ")";
Sep = ", ";
++RI;
}
@@ -1827,7 +1829,7 @@ bool BinaryFunction::scanExternalRefs() {
if (ignoreReference(Rel->Symbol))
continue;
- if (Relocation::getSizeForType(Rel->Type) < 4) {
+ if (BC.getRelocationHandler().getSizeForType(Rel->Type) < 4) {
// If the instruction uses a short form, then we might not be able
// to handle the rewrite without relaxation, and hence cannot reliably
// create an external reference relocation.
@@ -2098,7 +2100,7 @@ bool BinaryFunction::validateInternalRefDataRelocations() {
const Relocation *Relocation = BC.getRelocationAt(RelocationAddress);
BC.errs() << " ";
if (Relocation)
- BC.errs() << *Relocation;
+ Relocation->print(BC.errs(), BC.getRelocationHandler());
else
BC.errs() << "<missing relocation>";
BC.errs() << '\n';
diff --git a/bolt/lib/Core/BinarySection.cpp b/bolt/lib/Core/BinarySection.cpp
index a8620ba83ebfb..5fcac5ac2e52b 100644
--- a/bolt/lib/Core/BinarySection.cpp
+++ b/bolt/lib/Core/BinarySection.cpp
@@ -29,6 +29,14 @@ extern cl::opt<bool> PrintRelocations;
uint64_t BinarySection::Count = 0;
+void BinarySection::addDynamicRelocation(const Relocation &Reloc) {
+ assert(Reloc.Offset < getSize() && "offset not within section bounds");
+ assert(
+ (!Reloc.isRELR() || BC.getRelocationHandler().isRelative(Reloc.Type)) &&
+ "Only relative relocations can be relr.");
+ DynamicRelocations.emplace(Reloc);
+}
+
bool BinarySection::isELF() const { return BC.isELF(); }
bool BinarySection::isMachO() const { return BC.isMachO(); }
@@ -60,7 +68,7 @@ BinarySection::hash(const BinaryData &BD,
Hash, hash_value(Contents.substr(Offset, Begin->Offset - Offset)));
if (BinaryData *RelBD = BC.getBinaryDataByName(Rel.Symbol->getName()))
Hash = hash_combine(Hash, hash(*RelBD, Cache));
- Offset = Rel.Offset + Rel.getSize();
+ Offset = Rel.Offset + Rel.getSize(BC.getRelocationHandler());
}
Hash = hash_combine(Hash,
@@ -73,6 +81,7 @@ BinarySection::hash(const BinaryData &BD,
void BinarySection::emitAsData(MCStreamer &Streamer,
const Twine &SectionName) const {
+ const RelocationHandler &RH = BC.getRelocationHandler();
StringRef SectionContents =
isFinalized() ? getOutputContents() : getContents();
MCSectionELF *ELFSection =
@@ -123,17 +132,17 @@ void BinarySection::emitAsData(MCStreamer &Streamer,
#ifndef NDEBUG
for (const auto &Relocation : make_range(ROI, ROE)) {
- LLVM_DEBUG(
- dbgs() << "BOLT-DEBUG: emitting relocation for symbol "
- << (Relocation.Symbol ? Relocation.Symbol->getName()
- : StringRef("<none>"))
- << " at offset 0x" << Twine::utohexstr(Relocation.Offset)
- << " with size "
- << Relocation::getSizeForType(Relocation.Type) << '\n');
+ LLVM_DEBUG(dbgs() << "BOLT-DEBUG: emitting relocation for symbol "
+ << (Relocation.Symbol ? Relocation.Symbol->getName()
+ : StringRef("<none>"))
+ << " at offset 0x"
+ << Twine::utohexstr(Relocation.Offset)
+ << " with size " << RH.getSizeForType(Relocation.Type)
+ << '\n');
}
#endif
- size_t RelocationSize = Relocation::emit(ROI, ROE, &Streamer);
+ size_t RelocationSize = Relocation::emit(ROI, ROE, &Streamer, RH);
SectionOffset += RelocationSize;
}
assert(SectionOffset <= SectionContents.size() && "overflow error");
@@ -160,6 +169,7 @@ void BinarySection::flushPendingRelocations(raw_fd_ostream &OS,
return;
const uint64_t SectionAddress = getAddress();
+ const RelocationHandler &RH = BC.getRelocationHandler();
// We apply relocations to original section contents. For allocatable sections
// this means using their input file offsets, since the output file offset
@@ -185,22 +195,19 @@ void BinarySection::flushPendingRelocations(raw_fd_ostream &OS,
// Safely skip any optional pending relocation that cannot be encoded.
if (Reloc.isOptional() &&
- !Relocation::canEncodeValue(Reloc.Type, Value,
- SectionAddress + Reloc.Offset)) {
+ !RH.canEncodeValue(Reloc.Type, Value, SectionAddress + Reloc.Offset)) {
++SkippedPendingRelocations;
continue;
}
- Value = Relocation::encodeValue(Reloc.Type, Value,
- SectionAddress + Reloc.Offset);
+ Value = RH.encodeValue(Reloc.Type, Value, SectionAddress + Reloc.Offset);
safePWrite(OS, reinterpret_cast<const char *>(&Value),
- Relocation::getSizeForType(Reloc.Type),
- SectionFileOffset + Reloc.Offset);
+ RH.getSizeForType(Reloc.Type), SectionFileOffset + Reloc.Offset);
LLVM_DEBUG(
dbgs() << "BOLT-DEBUG: writing value 0x" << Twine::utohexstr(Value)
- << " of size " << Relocation::getSizeForType(Reloc.Type)
+ << " of size " << RH.getSizeForType(Reloc.Type)
<< " at section offset 0x" << Twine::utohexstr(Reloc.Offset)
<< " address 0x"
<< Twine::utohexstr(SectionAddress + Reloc.Offset)
@@ -236,8 +243,10 @@ void BinarySection::print(raw_ostream &OS) const {
OS << " (tls)";
if (opts::PrintRelocations)
- for (const Relocation &R : relocations())
- OS << "\n " << R;
+ for (const Relocation &R : relocations()) {
+ OS << "\n ";
+ R.print(OS, BC.getRelocationHandler());
+ }
}
BinarySection::RelocationSetType
@@ -258,8 +267,13 @@ BinarySection::reorderRelocations(bool Inplace) const {
uint64_t RelOffset = RelAddr - BD->getAddress();
NewRel.Offset = BD->getOutputOffset() + RelOffset;
assert(NewRel.Offset < getSize());
- LLVM_DEBUG(dbgs() << "BOLT-DEBUG: moving " << Rel << " -> " << NewRel
- << "\n");
+ LLVM_DEBUG({
+ dbgs() << "BOLT-DEBUG: moving ";
+ Rel.print(dbgs(), BC.getRelocationHandler());
+ dbgs() << " -> ";
+ NewRel.print(dbgs(), BC.getRelocationHandler());
+ dbgs() << "\n";
+ });
NewRelocations.emplace(std::move(NewRel));
}
return NewRelocations;
@@ -267,6 +281,7 @@ BinarySection::reorderRelocations(bool Inplace) const {
void BinarySection::reorderContents(const std::vector<BinaryData *> &Order,
bool Inplace) {
+ const RelocationHandler &RH = BC.getRelocationHandler();
IsReordered = true;
Relocations = reorderRelocations(Inplace);
@@ -292,7 +307,7 @@ void BinarySection::reorderContents(const std::vector<BinaryData *> &Order,
// of the reordered segment to force LLVM to recognize and map this
// section.
MCSymbol *ZeroSym = BC.registerNameAtAddress("Zero", 0, 0, 0);
- addRelocation(OS.tell(), ZeroSym, Relocation::getAbs64(), 0xdeadbeef);
+ addRelocation(OS.tell(), ZeroSym, RH.getAbs64(), 0xdeadbeef);
uint64_t Zero = 0;
OS.write(reinterpret_cast<const char *>(&Zero), sizeof(Zero));
diff --git a/bolt/lib/Core/CMakeLists.txt b/bolt/lib/Core/CMakeLists.txt
index 430a1c93a9f0c..0a967b94c86e7 100644
--- a/bolt/lib/Core/CMakeLists.txt
+++ b/bolt/lib/Core/CMakeLists.txt
@@ -37,6 +37,9 @@ add_llvm_library(LLVMBOLTCore
MCPlusBuilder.cpp
ParallelUtilities.cpp
Relocation.cpp
+ ../Target/AArch64/AArch64RelocationHandler.cpp
+ ../Target/RISCV/RISCVRelocationHandler.cpp
+ ../Target/X86/X86RelocationHandler.cpp
NO_EXPORT
DISABLE_LLVM_LINK_LLVM_DYLIB
diff --git a/bolt/lib/Core/Relocation.cpp b/bolt/lib/Core/Relocation.cpp
index b36c2cd8a4c82..ddf5e344b8ddc 100644
--- a/bolt/lib/Core/Relocation.cpp
+++ b/bolt/lib/Core/Relocation.cpp
@@ -15,939 +15,37 @@
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSymbol.h"
-#include "llvm/Object/ELF.h"
#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
using namespace llvm;
using namespace bolt;
-namespace ELFReserved {
-enum {
- R_RISCV_TPREL_I = 49,
- R_RISCV_TPREL_S = 50,
-};
-} // namespace ELFReserved
+namespace llvm::bolt {
+std::unique_ptr<RelocationHandler> createAArch64RelocationHandler();
+std::unique_ptr<RelocationHandler> createRISCVRelocationHandler(bool Is64Bit);
+std::unique_ptr<RelocationHandler> createX86RelocationHandler();
+} // namespace llvm::bolt
-Triple::ArchType Relocation::Arch;
-
-static bool isSupportedX86(uint32_t Type) {
- switch (Type) {
- default:
- return false;
- case ELF::R_X86_64_8:
- case ELF::R_X86_64_16:
- case ELF::R_X86_64_32:
- case ELF::R_X86_64_32S:
- case ELF::R_X86_64_64:
- case ELF::R_X86_64_PC8:
- case ELF::R_X86_64_PC32:
- case ELF::R_X86_64_PC64:
- case ELF::R_X86_64_PLT32:
- case ELF::R_X86_64_GOTPC64:
- case ELF::R_X86_64_GOTPCREL:
- case ELF::R_X86_64_GOTTPOFF:
- case ELF::R_X86_64_TPOFF32:
- case ELF::R_X86_64_GOTPCRELX:
- case ELF::R_X86_64_REX_GOTPCRELX:
- return true;
- }
-}
-
-static bool isSupportedAArch64(uint32_t Type) {
- switch (Type) {
- default:
- return false;
- case ELF::R_AARCH64_CALL26:
- case ELF::R_AARCH64_JUMP26:
- case ELF::R_AARCH64_TSTBR14:
- case ELF::R_AARCH64_CONDBR19:
- case ELF::R_AARCH64_ADR_PREL_LO21:
- case ELF::R_AARCH64_ADR_PREL_PG_HI21:
- case ELF::R_AARCH64_ADR_PREL_PG_HI21_NC:
- case ELF::R_AARCH64_LDST64_ABS_LO12_NC:
- case ELF::R_AARCH64_ADD_ABS_LO12_NC:
- case ELF::R_AARCH64_LDST128_ABS_LO12_NC:
- case ELF::R_AARCH64_LDST32_ABS_LO12_NC:
- case ELF::R_AARCH64_LDST16_ABS_LO12_NC:
- case ELF::R_AARCH64_LDST8_ABS_LO12_NC:
- case ELF::R_AARCH64_ADR_GOT_PAGE:
- case ELF::R_AARCH64_TLSGD_ADR_PAGE21:
- case ELF::R_AARCH64_TLSGD_ADD_LO12_NC:
- case ELF::R_AARCH64_TLSDESC_ADR_PREL21:
- case ELF::R_AARCH64_TLSDESC_ADR_PAGE21:
- case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
- case ELF::R_AARCH64_TLSLE_ADD_TPREL_HI12:
- case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
- case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0:
- case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
- case ELF::R_AARCH64_LD64_GOT_LO12_NC:
- case ELF::R_AARCH64_TLSDESC_LD64_LO12:
- case ELF::R_AARCH64_TLSDESC_ADD_LO12:
- case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
- case ELF::R_AARCH64_PREL16:
- case ELF::R_AARCH64_PREL32:
- case ELF::R_AARCH64_PREL64:
- case ELF::R_AARCH64_ABS16:
- case ELF::R_AARCH64_ABS32:
- case ELF::R_AARCH64_ABS64:
- case ELF::R_AARCH64_MOVW_UABS_G0:
- case ELF::R_AARCH64_MOVW_UABS_G0_NC:
- case ELF::R_AARCH64_MOVW_UABS_G1:
- case ELF::R_AARCH64_MOVW_UABS_G1_NC:
- case ELF::R_AARCH64_MOVW_UABS_G2:
- case ELF::R_AARCH64_MOVW_UABS_G2_NC:
- case ELF::R_AARCH64_MOVW_UABS_G3:
- case ELF::R_AARCH64_PLT32:
- return true;
- }
-}
-
-static bool isSupportedRISCV(uint32_t Type) {
- switch (Type) {
- default:
- return false;
- case ELF::R_RISCV_JAL:
- case ELF::R_RISCV_CALL:
- case ELF::R_RISCV_CALL_PLT:
- case ELF::R_RISCV_BRANCH:
- case ELF::R_RISCV_RELAX:
- case ELF::R_RISCV_GOT_HI20:
- case ELF::R_RISCV_PCREL_HI20:
- case ELF::R_RISCV_PCREL_LO12_I:
- case ELF::R_RISCV_PCREL_LO12_S:
- case ELF::R_RISCV_RVC_JUMP:
- case ELF::R_RISCV_RVC_BRANCH:
- case ELF::R_RISCV_ADD32:
- case ELF::R_RISCV_SUB32:
- case ELF::R_RISCV_HI20:
- case ELF::R_RISCV_LO12_I:
- case ELF::R_RISCV_LO12_S:
- case ELF::R_RISCV_32:
- case ELF::R_RISCV_64:
- case ELF::R_RISCV_TLS_GOT_HI20:
- case ELF::R_RISCV_TLS_GD_HI20:
- case ELF::R_RISCV_TPREL_HI20:
- case ELF::R_RISCV_TPREL_ADD:
- case ELF::R_RISCV_TPREL_LO12_I:
- case ELF::R_RISCV_TPREL_LO12_S:
- case ELFReserved::R_RISCV_TPREL_I:
- case ELFReserved::R_RISCV_TPREL_S:
- return true;
- }
-}
-
-static size_t getSizeForTypeX86(uint32_t Type) {
- switch (Type) {
- default:
- errs() << object::getELFRelocationTypeName(ELF::EM_X86_64, Type) << '\n';
- llvm_unreachable("unsupported relocation type");
- case ELF::R_X86_64_8:
- case ELF::R_X86_64_PC8:
- return 1;
- case ELF::R_X86_64_16:
- return 2;
- case ELF::R_X86_64_PLT32:
- case ELF::R_X86_64_PC32:
- case ELF::R_X86_64_32S:
- case ELF::R_X86_64_32:
- case ELF::R_X86_64_GOTPCREL:
- case ELF::R_X86_64_GOTTPOFF:
- case ELF::R_X86_64_TPOFF32:
- case ELF::R_X86_64_GOTPCRELX:
- case ELF::R_X86_64_REX_GOTPCRELX:
- return 4;
- case ELF::R_X86_64_PC64:
- case ELF::R_X86_64_64:
- case ELF::R_X86_64_GOTPC64:
- return 8;
- }
-}
-
-static size_t getSizeForTypeAArch64(uint32_t Type) {
- switch (Type) {
- default:
- errs() << object::getELFRelocationTypeName(ELF::EM_AARCH64, Type) << '\n';
- llvm_unreachable("unsupported relocation type");
- case ELF::R_AARCH64_ABS16:
- case ELF::R_AARCH64_PREL16:
- return 2;
- case ELF::R_AARCH64_CALL26:
- case ELF::R_AARCH64_JUMP26:
- case ELF::R_AARCH64_TSTBR14:
- case ELF::R_AARCH64_CONDBR19:
- case ELF::R_AARCH64_ADR_PREL_LO21:
- case ELF::R_AARCH64_ADR_PREL_PG_HI21:
- case ELF::R_AARCH64_ADR_PREL_PG_HI21_NC:
- case ELF::R_AARCH64_LDST64_ABS_LO12_NC:
- case ELF::R_AARCH64_ADD_ABS_LO12_NC:
- case ELF::R_AARCH64_LDST128_ABS_LO12_NC:
- case ELF::R_AARCH64_LDST32_ABS_LO12_NC:
- case ELF::R_AARCH64_LDST16_ABS_LO12_NC:
- case ELF::R_AARCH64_LDST8_ABS_LO12_NC:
- case ELF::R_AARCH64_ADR_GOT_PAGE:
- case ELF::R_AARCH64_TLSGD_ADR_PAGE21:
- case ELF::R_AARCH64_TLSGD_ADD_LO12_NC:
- case ELF::R_AARCH64_TLSDESC_ADR_PREL21:
- case ELF::R_AARCH64_TLSDESC_ADR_PAGE21:
- case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
- case ELF::R_AARCH64_TLSLE_ADD_TPREL_HI12:
- case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
- case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0:
- case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
- case ELF::R_AARCH64_LD64_GOT_LO12_NC:
- case ELF::R_AARCH64_TLSDESC_LD64_LO12:
- case ELF::R_AARCH64_TLSDESC_ADD_LO12:
- case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
- case ELF::R_AARCH64_PREL32:
- case ELF::R_AARCH64_MOVW_UABS_G0:
- case ELF::R_AARCH64_MOVW_UABS_G0_NC:
- case ELF::R_AARCH64_MOVW_UABS_G1:
- case ELF::R_AARCH64_MOVW_UABS_G1_NC:
- case ELF::R_AARCH64_MOVW_UABS_G2:
- case ELF::R_AARCH64_MOVW_UABS_G2_NC:
- case ELF::R_AARCH64_MOVW_UABS_G3:
- case ELF::R_AARCH64_ABS32:
- case ELF::R_AARCH64_PLT32:
- return 4;
- case ELF::R_AARCH64_ABS64:
- case ELF::R_AARCH64_PREL64:
- return 8;
- }
-}
-
-static size_t getSizeForTypeRISCV(uint32_t Type) {
- switch (Type) {
- default:
- errs() << object::getELFRelocationTypeName(ELF::EM_RISCV, Type) << '\n';
- llvm_unreachable("unsupported relocation type");
- case ELF::R_RISCV_RVC_JUMP:
- case ELF::R_RISCV_RVC_BRANCH:
- return 2;
- case ELF::R_RISCV_JAL:
- case ELF::R_RISCV_BRANCH:
- case ELF::R_RISCV_PCREL_HI20:
- case ELF::R_RISCV_PCREL_LO12_I:
- case ELF::R_RISCV_PCREL_LO12_S:
- case ELF::R_RISCV_32_PCREL:
- case ELF::R_RISCV_ADD32:
- case ELF::R_RISCV_SUB32:
- case ELF::R_RISCV_HI20:
- case ELF::R_RISCV_LO12_I:
- case ELF::R_RISCV_LO12_S:
- case ELF::R_RISCV_32:
- return 4;
- case ELF::R_RISCV_64:
- case ELF::R_RISCV_CALL:
- case ELF::R_RISCV_CALL_PLT:
- case ELF::R_RISCV_GOT_HI20:
- case ELF::R_RISCV_TLS_GOT_HI20:
- case ELF::R_RISCV_TLS_GD_HI20:
- // See extractValueRISCV for why this is necessary.
- return 8;
- }
-}
-
-static bool skipRelocationTypeX86(uint32_t Type) {
- return Type == ELF::R_X86_64_NONE;
-}
-
-static bool skipRelocationTypeAArch64(uint32_t Type) {
- switch (Type) {
- default:
- return false;
- case ELF::R_AARCH64_NONE:
- case ELF::R_AARCH64_LD_PREL_LO19:
- case ELF::R_AARCH64_TLSDESC_CALL:
- return true;
- }
-}
-
-static bool skipRelocationTypeRISCV(uint32_t Type) {
- switch (Type) {
- default:
- return false;
- case ELF::R_RISCV_NONE:
- case ELF::R_RISCV_RELAX:
- return true;
- }
-}
-
-static uint64_t encodeValueX86(uint32_t Type, uint64_t Value, uint64_t PC) {
- switch (Type) {
- default:
- llvm_unreachable("unsupported relocation");
- case ELF::R_X86_64_64:
- case ELF::R_X86_64_32:
- break;
- case ELF::R_X86_64_PC32:
- Value -= PC;
- break;
- }
- return Value;
-}
-
-static bool canEncodeValueAArch64(uint32_t Type, uint64_t Value, uint64_t PC) {
- switch (Type) {
- default:
- llvm_unreachable("unsupported relocation");
- case ELF::R_AARCH64_CALL26:
- case ELF::R_AARCH64_JUMP26:
- return isInt<28>(Value - PC);
- }
-}
-
-static uint64_t encodeValueAArch64(uint32_t Type, uint64_t Value, uint64_t PC) {
- switch (Type) {
- default:
- llvm_unreachable("unsupported relocation");
- case ELF::R_AARCH64_ABS16:
- case ELF::R_AARCH64_ABS32:
- case ELF::R_AARCH64_ABS64:
- break;
- case ELF::R_AARCH64_PREL16:
- case ELF::R_AARCH64_PREL32:
- case ELF::R_AARCH64_PREL64:
- Value -= PC;
- break;
- case ELF::R_AARCH64_CALL26:
- Value -= PC;
- assert(isInt<28>(Value) && "only PC +/- 128MB is allowed for direct call");
- // Immediate goes in bits 25:0 of BL.
- // OP 1001_01 goes in bits 31:26 of BL.
- Value = ((Value >> 2) & 0x3ffffff) | 0x94000000ULL;
- break;
- case ELF::R_AARCH64_JUMP26:
- Value -= PC;
- assert(isInt<28>(Value) &&
- "only PC +/- 128MB is allowed for direct branch");
- // Immediate goes in bits 25:0 of B.
- // OP 0001_01 goes in bits 31:26 of B.
- Value = ((Value >> 2) & 0x3ffffff) | 0x14000000ULL;
- break;
- }
- return Value;
-}
-
-static uint64_t canEncodeValueRISCV(uint32_t Type, uint64_t Value,
- uint64_t PC) {
- switch (Type) {
- default:
- llvm_unreachable("unsupported relocation");
- case ELF::R_RISCV_32:
- case ELF::R_RISCV_64:
- return true;
- }
-}
-
-static uint64_t encodeValueRISCV(uint32_t Type, uint64_t Value, uint64_t PC) {
- switch (Type) {
- default:
- llvm_unreachable("unsupported relocation");
- case ELF::R_RISCV_32:
- case ELF::R_RISCV_64:
- break;
- }
- return Value;
-}
-
-static uint64_t extractValueX86(uint32_t Type, uint64_t Contents, uint64_t PC) {
- if (Type == ELF::R_X86_64_32S)
- return SignExtend64<32>(Contents);
- if (Relocation::isPCRelative(Type))
- return SignExtend64(Contents, 8 * Relocation::getSizeForType(Type));
- return Contents;
-}
-
-static uint64_t extractValueAArch64(uint32_t Type, uint64_t Contents,
- uint64_t PC) {
- switch (Type) {
- default:
- errs() << object::getELFRelocationTypeName(ELF::EM_AARCH64, Type) << '\n';
- llvm_unreachable("unsupported relocation type");
- case ELF::R_AARCH64_ABS16:
- case ELF::R_AARCH64_ABS32:
- case ELF::R_AARCH64_ABS64:
- return Contents;
- case ELF::R_AARCH64_PREL16:
- return static_cast<int64_t>(PC) + SignExtend64<16>(Contents & 0xffff);
- case ELF::R_AARCH64_PREL32:
- case ELF::R_AARCH64_PLT32:
- return static_cast<int64_t>(PC) + SignExtend64<32>(Contents & 0xffffffff);
- case ELF::R_AARCH64_PREL64:
- return static_cast<int64_t>(PC) + Contents;
- case ELF::R_AARCH64_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_TLSGD_ADR_PAGE21:
- 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_TLSGD_ADD_LO12_NC:
- case ELF::R_AARCH64_TLSDESC_ADD_LO12:
- case ELF::R_AARCH64_ADD_ABS_LO12_NC: {
- // Immediate goes in bits 21:10 of ADD instruction
- Contents &= ~0xffffffffffc003ffU;
- return Contents >> (10 - 0);
- }
- case ELF::R_AARCH64_LDST128_ABS_LO12_NC: {
- // Immediate goes in bits 21:10 of ADD instruction, taken
- // from bits 11:4 of Symbol address
- Contents &= ~0xffffffffffc003ffU;
- return Contents >> (10 - 4);
- }
- case ELF::R_AARCH64_LDST32_ABS_LO12_NC: {
- // Immediate goes in bits 21:10 of ADD instruction, taken
- // from bits 11:2 of Symbol address
- Contents &= ~0xffffffffffc003ffU;
- return Contents >> (10 - 2);
- }
- case ELF::R_AARCH64_LDST16_ABS_LO12_NC: {
- // Immediate goes in bits 21:10 of ADD instruction, taken
- // from bits 11:1 of Symbol address
- Contents &= ~0xffffffffffc003ffU;
- return Contents >> (10 - 1);
- }
- case ELF::R_AARCH64_LDST8_ABS_LO12_NC: {
- // Immediate goes in bits 21:10 of ADD instruction, taken
- // from bits 11:0 of Symbol address
- Contents &= ~0xffffffffffc003ffU;
- return Contents >> (10 - 0);
- }
- case ELF::R_AARCH64_MOVW_UABS_G3:
- case ELF::R_AARCH64_MOVW_UABS_G2_NC:
- case ELF::R_AARCH64_MOVW_UABS_G2:
- case ELF::R_AARCH64_MOVW_UABS_G1_NC:
- case ELF::R_AARCH64_MOVW_UABS_G1:
- case ELF::R_AARCH64_MOVW_UABS_G0_NC:
- case ELF::R_AARCH64_MOVW_UABS_G0:
- // The shift goes in bits 22:21 of MOV* instructions
- uint8_t Shift = (Contents >> 21) & 0x3;
- // Immediate goes in bits 20:5
- Contents = (Contents >> 5) & 0xffff;
- return Contents << (16 * Shift);
- }
-}
-
-static uint64_t extractUImmRISCV(uint32_t Contents) {
- return SignExtend64<32>(Contents & 0xfffff000);
-}
-
-static uint64_t extractIImmRISCV(uint32_t Contents) {
- return SignExtend64<12>(Contents >> 20);
-}
-
-static uint64_t extractSImmRISCV(uint32_t Contents) {
- return SignExtend64<12>(((Contents >> 7) & 0x1f) | ((Contents >> 25) << 5));
-}
-
-static uint64_t extractJImmRISCV(uint32_t Contents) {
- return SignExtend64<21>(
- (((Contents >> 21) & 0x3ff) << 1) | (((Contents >> 20) & 0x1) << 11) |
- (((Contents >> 12) & 0xff) << 12) | (((Contents >> 31) & 0x1) << 20));
-}
-
-static uint64_t extractBImmRISCV(uint32_t Contents) {
- return SignExtend64<13>(
- (((Contents >> 8) & 0xf) << 1) | (((Contents >> 25) & 0x3f) << 5) |
- (((Contents >> 7) & 0x1) << 11) | (((Contents >> 31) & 0x1) << 12));
-}
-
-static uint64_t extractValueRISCV(uint32_t Type, uint64_t Contents,
- uint64_t PC) {
- switch (Type) {
- default:
- errs() << object::getELFRelocationTypeName(ELF::EM_RISCV, Type) << '\n';
- llvm_unreachable("unsupported relocation type");
- case ELF::R_RISCV_JAL:
- return extractJImmRISCV(Contents);
- case ELF::R_RISCV_CALL:
- case ELF::R_RISCV_CALL_PLT:
- // The psABI "Relocations" chapter's "Procedure Calls" section defines
- // R_RISCV_CALL and R_RISCV_CALL_PLT over an AUIPC/JALR pair. Decode both
- // instructions so the addend includes the low 12 bits carried by JALR.
- return extractUImmRISCV(Contents & 0xffffffff) +
- extractIImmRISCV(Contents >> 32);
- case ELF::R_RISCV_BRANCH:
- return extractBImmRISCV(Contents);
- case ELF::R_RISCV_GOT_HI20:
- case ELF::R_RISCV_TLS_GOT_HI20:
- case ELF::R_RISCV_TLS_GD_HI20:
- // We need to know the exact address of the GOT entry so we extract the
- // value from both the AUIPC and L[D|W]. We cannot rely on the symbol in the
- // relocation for this since it simply refers to the object that is stored
- // in the GOT entry, not to the entry itself.
- return extractUImmRISCV(Contents & 0xffffffff) +
- extractIImmRISCV(Contents >> 32);
- case ELF::R_RISCV_PCREL_HI20:
- case ELF::R_RISCV_HI20:
- return extractUImmRISCV(Contents);
- case ELF::R_RISCV_PCREL_LO12_I:
- case ELF::R_RISCV_LO12_I:
- return extractIImmRISCV(Contents);
- case ELF::R_RISCV_PCREL_LO12_S:
- case ELF::R_RISCV_LO12_S:
- return extractSImmRISCV(Contents);
- case ELF::R_RISCV_RVC_JUMP:
- return SignExtend64<11>(Contents >> 2);
- case ELF::R_RISCV_RVC_BRANCH:
- return SignExtend64<8>(((Contents >> 2) & 0x1f) | ((Contents >> 5) & 0xe0));
- case ELF::R_RISCV_ADD32:
- case ELF::R_RISCV_SUB32:
- case ELF::R_RISCV_32:
- case ELF::R_RISCV_64:
- return Contents;
- }
-}
-
-static bool isGOTX86(uint32_t Type) {
- switch (Type) {
- default:
- return false;
- case ELF::R_X86_64_GOT32:
- case ELF::R_X86_64_GOTPCREL:
- case ELF::R_X86_64_GOTTPOFF:
- case ELF::R_X86_64_GOTOFF64:
- case ELF::R_X86_64_GOTPC32:
- case ELF::R_X86_64_GOT64:
- case ELF::R_X86_64_GOTPCREL64:
- case ELF::R_X86_64_GOTPC64:
- case ELF::R_X86_64_GOTPLT64:
- case ELF::R_X86_64_GOTPC32_TLSDESC:
- case ELF::R_X86_64_GOTPCRELX:
- case ELF::R_X86_64_REX_GOTPCRELX:
- return true;
- }
-}
-
-static bool isGOTAArch64(uint32_t Type) {
- switch (Type) {
- default:
- return false;
- case ELF::R_AARCH64_ADR_GOT_PAGE:
- case ELF::R_AARCH64_LD64_GOT_LO12_NC:
- case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
- case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
- case ELF::R_AARCH64_TLSGD_ADR_PAGE21:
- case ELF::R_AARCH64_TLSGD_ADD_LO12_NC:
- 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:
- return true;
- }
-}
-
-static bool isGOTRISCV(uint32_t Type) {
- switch (Type) {
- default:
- return false;
- case ELF::R_RISCV_GOT_HI20:
- case ELF::R_RISCV_TLS_GOT_HI20:
- case ELF::R_RISCV_TLS_GD_HI20:
- return true;
- }
-}
-
-static bool isTLSX86(uint32_t Type) {
- switch (Type) {
- default:
- return false;
- case ELF::R_X86_64_TPOFF32:
- case ELF::R_X86_64_TPOFF64:
- case ELF::R_X86_64_GOTTPOFF:
- return true;
- }
-}
-
-static bool isTLSAArch64(uint32_t Type) {
- switch (Type) {
- default:
- return false;
- case ELF::R_AARCH64_TLSGD_ADR_PAGE21:
- case ELF::R_AARCH64_TLSGD_ADD_LO12_NC:
- case ELF::R_AARCH64_TLSDESC_ADR_PREL21:
- case ELF::R_AARCH64_TLSDESC_ADR_PAGE21:
- case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
- case ELF::R_AARCH64_TLSLE_ADD_TPREL_HI12:
- case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
- case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0:
- case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
- case ELF::R_AARCH64_TLSDESC_LD64_LO12:
- case ELF::R_AARCH64_TLSDESC_ADD_LO12:
- case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
- return true;
- }
-}
-
-static bool isTLSRISCV(uint32_t Type) {
- switch (Type) {
- default:
- return false;
- case ELF::R_RISCV_TLS_GOT_HI20:
- case ELF::R_RISCV_TLS_GD_HI20:
- case ELF::R_RISCV_TPREL_HI20:
- case ELF::R_RISCV_TPREL_ADD:
- case ELF::R_RISCV_TPREL_LO12_I:
- case ELF::R_RISCV_TPREL_LO12_S:
- case ELFReserved::R_RISCV_TPREL_I:
- case ELFReserved::R_RISCV_TPREL_S:
- return true;
- }
-}
-
-static bool isPCRelativeX86(uint32_t Type) {
- switch (Type) {
- default:
- llvm_unreachable("Unknown relocation type");
- case ELF::R_X86_64_64:
- case ELF::R_X86_64_32:
- case ELF::R_X86_64_32S:
- case ELF::R_X86_64_16:
- case ELF::R_X86_64_8:
- case ELF::R_X86_64_TPOFF32:
- return false;
- case ELF::R_X86_64_PC8:
- case ELF::R_X86_64_PC32:
- case ELF::R_X86_64_PC64:
- case ELF::R_X86_64_GOTPCREL:
- case ELF::R_X86_64_PLT32:
- case ELF::R_X86_64_GOTOFF64:
- case ELF::R_X86_64_GOTPC32:
- case ELF::R_X86_64_GOTPC64:
- case ELF::R_X86_64_GOTTPOFF:
- case ELF::R_X86_64_GOTPCRELX:
- case ELF::R_X86_64_REX_GOTPCRELX:
- return true;
- }
-}
-
-static bool isPCRelativeAArch64(uint32_t Type) {
- switch (Type) {
- default:
- llvm_unreachable("Unknown relocation type");
- case ELF::R_AARCH64_ABS16:
- case ELF::R_AARCH64_ABS32:
- case ELF::R_AARCH64_ABS64:
- case ELF::R_AARCH64_LDST64_ABS_LO12_NC:
- case ELF::R_AARCH64_ADD_ABS_LO12_NC:
- case ELF::R_AARCH64_LDST128_ABS_LO12_NC:
- case ELF::R_AARCH64_LDST32_ABS_LO12_NC:
- case ELF::R_AARCH64_LDST16_ABS_LO12_NC:
- case ELF::R_AARCH64_LDST8_ABS_LO12_NC:
- case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
- case ELF::R_AARCH64_TLSGD_ADD_LO12_NC:
- case ELF::R_AARCH64_TLSLE_ADD_TPREL_HI12:
- case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
- case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0:
- case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
- case ELF::R_AARCH64_LD64_GOT_LO12_NC:
- case ELF::R_AARCH64_TLSDESC_LD64_LO12:
- case ELF::R_AARCH64_TLSDESC_ADD_LO12:
- case ELF::R_AARCH64_MOVW_UABS_G0:
- case ELF::R_AARCH64_MOVW_UABS_G0_NC:
- case ELF::R_AARCH64_MOVW_UABS_G1:
- case ELF::R_AARCH64_MOVW_UABS_G1_NC:
- case ELF::R_AARCH64_MOVW_UABS_G2:
- case ELF::R_AARCH64_MOVW_UABS_G2_NC:
- case ELF::R_AARCH64_MOVW_UABS_G3:
- return false;
- case ELF::R_AARCH64_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_TLSGD_ADR_PAGE21:
- case ELF::R_AARCH64_TLSDESC_ADR_PREL21:
- case ELF::R_AARCH64_TLSDESC_ADR_PAGE21:
- case ELF::R_AARCH64_PREL16:
- case ELF::R_AARCH64_PREL32:
- case ELF::R_AARCH64_PREL64:
- case ELF::R_AARCH64_PLT32:
- return true;
- }
-}
-
-static bool isPCRelativeRISCV(uint32_t Type) {
- switch (Type) {
- default:
- llvm_unreachable("Unknown relocation type");
- case ELF::R_RISCV_ADD32:
- case ELF::R_RISCV_SUB32:
- case ELF::R_RISCV_HI20:
- case ELF::R_RISCV_LO12_I:
- case ELF::R_RISCV_LO12_S:
- case ELF::R_RISCV_32:
- case ELF::R_RISCV_64:
- return false;
- case ELF::R_RISCV_JAL:
- case ELF::R_RISCV_CALL:
- case ELF::R_RISCV_CALL_PLT:
- case ELF::R_RISCV_BRANCH:
- case ELF::R_RISCV_GOT_HI20:
- case ELF::R_RISCV_PCREL_HI20:
- case ELF::R_RISCV_PCREL_LO12_I:
- case ELF::R_RISCV_PCREL_LO12_S:
- case ELF::R_RISCV_RVC_JUMP:
- case ELF::R_RISCV_RVC_BRANCH:
- case ELF::R_RISCV_32_PCREL:
- case ELF::R_RISCV_TLS_GOT_HI20:
- case ELF::R_RISCV_TLS_GD_HI20:
- return true;
- }
-}
-
-bool Relocation::isSupported(uint32_t Type) {
- switch (Arch) {
- default:
- return false;
- case Triple::aarch64:
- return isSupportedAArch64(Type);
- case Triple::riscv64:
- case Triple::riscv32:
- return isSupportedRISCV(Type);
- case Triple::x86_64:
- return isSupportedX86(Type);
- }
-}
-
-size_t Relocation::getSizeForType(uint32_t Type) {
- switch (Arch) {
- default:
- llvm_unreachable("Unsupported architecture");
- case Triple::aarch64:
- return getSizeForTypeAArch64(Type);
- case Triple::riscv64:
- case Triple::riscv32:
- return getSizeForTypeRISCV(Type);
- case Triple::x86_64:
- return getSizeForTypeX86(Type);
- }
-}
-
-bool Relocation::skipRelocationType(uint32_t Type) {
- switch (Arch) {
- default:
- llvm_unreachable("Unsupported architecture");
- case Triple::aarch64:
- return skipRelocationTypeAArch64(Type);
- case Triple::riscv64:
- case Triple::riscv32:
- return skipRelocationTypeRISCV(Type);
- case Triple::x86_64:
- return skipRelocationTypeX86(Type);
- }
-}
-
-uint64_t Relocation::encodeValue(uint32_t Type, uint64_t Value, uint64_t PC) {
- switch (Arch) {
- default:
- llvm_unreachable("Unsupported architecture");
- case Triple::aarch64:
- return encodeValueAArch64(Type, Value, PC);
- case Triple::riscv64:
- case Triple::riscv32:
- return encodeValueRISCV(Type, Value, PC);
- case Triple::x86_64:
- return encodeValueX86(Type, Value, PC);
- }
-}
-
-bool Relocation::canEncodeValue(uint32_t Type, uint64_t Value, uint64_t PC) {
- switch (Arch) {
- default:
- llvm_unreachable("Unsupported architecture");
- case Triple::aarch64:
- return canEncodeValueAArch64(Type, Value, PC);
- case Triple::riscv64:
- case Triple::riscv32:
- return canEncodeValueRISCV(Type, Value, PC);
- case Triple::x86_64:
- return true;
- }
-}
-
-uint64_t Relocation::extractValue(uint32_t Type, uint64_t Contents,
- uint64_t PC) {
- switch (Arch) {
- default:
- llvm_unreachable("Unsupported architecture");
- case Triple::aarch64:
- return extractValueAArch64(Type, Contents, PC);
- case Triple::riscv64:
- case Triple::riscv32:
- return extractValueRISCV(Type, Contents, PC);
- case Triple::x86_64:
- return extractValueX86(Type, Contents, PC);
- }
-}
-
-bool Relocation::isGOT(uint32_t Type) {
- switch (Arch) {
- default:
- llvm_unreachable("Unsupported architecture");
- case Triple::aarch64:
- return isGOTAArch64(Type);
- case Triple::riscv64:
- case Triple::riscv32:
- return isGOTRISCV(Type);
- case Triple::x86_64:
- return isGOTX86(Type);
- }
-}
-
-bool Relocation::isX86GOTPCRELX(uint32_t Type) {
- if (Arch != Triple::x86_64)
- return false;
- return Type == ELF::R_X86_64_GOTPCRELX || Type == ELF::R_X86_64_REX_GOTPCRELX;
-}
-
-bool Relocation::isX86GOTPC64(uint32_t Type) {
- if (Arch != Triple::x86_64)
- return false;
- return Type == ELF::R_X86_64_GOTPC64;
-}
-
-bool Relocation::isNone(uint32_t Type) { return Type == getNone(); }
-
-bool Relocation::isRelative(uint32_t Type) {
- switch (Arch) {
- default:
- llvm_unreachable("Unsupported architecture");
- case Triple::aarch64:
- return Type == ELF::R_AARCH64_RELATIVE;
- case Triple::riscv64:
- case Triple::riscv32:
- return Type == ELF::R_RISCV_RELATIVE;
- case Triple::x86_64:
- return Type == ELF::R_X86_64_RELATIVE;
- }
-}
-
-bool Relocation::isIRelative(uint32_t Type) {
- switch (Arch) {
- default:
- llvm_unreachable("Unsupported architecture");
- case Triple::aarch64:
- return Type == ELF::R_AARCH64_IRELATIVE;
- case Triple::riscv64:
- return Type == ELF::R_RISCV_IRELATIVE;
- case Triple::riscv32:
- llvm_unreachable("not implemented");
- case Triple::x86_64:
- return Type == ELF::R_X86_64_IRELATIVE;
- }
-}
-
-bool Relocation::isTLS(uint32_t Type) {
- switch (Arch) {
- default:
- llvm_unreachable("Unsupported architecture");
- case Triple::aarch64:
- return isTLSAArch64(Type);
- case Triple::riscv64:
- case Triple::riscv32:
- return isTLSRISCV(Type);
- case Triple::x86_64:
- return isTLSX86(Type);
- }
-}
-
-bool Relocation::isInstructionReference(uint32_t Type) {
- if (Arch != Triple::riscv64 && Arch != Triple::riscv32)
- return false;
-
- switch (Type) {
- default:
- return false;
- case ELF::R_RISCV_PCREL_LO12_I:
- case ELF::R_RISCV_PCREL_LO12_S:
- return true;
- }
+MCBinaryExpr::Opcode
+RelocationHandler::getComposeOpcodeFor(uint32_t Type) const {
+ llvm_unreachable("composed relocations are unsupported for this target");
}
-uint32_t Relocation::getNone() {
+std::unique_ptr<RelocationHandler>
+llvm::bolt::createRelocationHandler(Triple::ArchType Arch) {
switch (Arch) {
default:
llvm_unreachable("Unsupported architecture");
case Triple::aarch64:
- return ELF::R_AARCH64_NONE;
- case Triple::riscv64:
+ return createAArch64RelocationHandler();
case Triple::riscv32:
- return ELF::R_RISCV_NONE;
- case Triple::x86_64:
- return ELF::R_X86_64_NONE;
- }
-}
-
-uint32_t Relocation::getPC32() {
- switch (Arch) {
- default:
- llvm_unreachable("Unsupported architecture");
- case Triple::aarch64:
- return ELF::R_AARCH64_PREL32;
+ return createRISCVRelocationHandler(false);
case Triple::riscv64:
- case Triple::riscv32:
- return ELF::R_RISCV_32_PCREL;
- case Triple::x86_64:
- return ELF::R_X86_64_PC32;
- }
-}
-
-uint32_t Relocation::getPC64() {
- switch (Arch) {
- default:
- llvm_unreachable("Unsupported architecture");
- case Triple::aarch64:
- return ELF::R_AARCH64_PREL64;
- case Triple::riscv64:
- case Triple::riscv32:
- llvm_unreachable("not implemented");
+ return createRISCVRelocationHandler(true);
case Triple::x86_64:
- return ELF::R_X86_64_PC64;
+ return createX86RelocationHandler();
}
}
@@ -957,57 +55,16 @@ uint32_t Relocation::getType(const object::RelocationRef &Rel) {
return static_cast<uint32_t>(RelType);
}
-bool Relocation::isPCRelative(uint32_t Type) {
- switch (Arch) {
- default:
- llvm_unreachable("Unsupported architecture");
- case Triple::aarch64:
- return isPCRelativeAArch64(Type);
- case Triple::riscv64:
- case Triple::riscv32:
- return isPCRelativeRISCV(Type);
- case Triple::x86_64:
- return isPCRelativeX86(Type);
- }
-}
-
-uint32_t Relocation::getAbs64() {
- switch (Arch) {
- default:
- llvm_unreachable("Unsupported architecture");
- case Triple::aarch64:
- return ELF::R_AARCH64_ABS64;
- case Triple::riscv64:
- case Triple::riscv32:
- return ELF::R_RISCV_64;
- case Triple::x86_64:
- return ELF::R_X86_64_64;
- }
-}
-
-uint32_t Relocation::getRelative() {
- switch (Arch) {
- default:
- llvm_unreachable("Unsupported architecture");
- case Triple::aarch64:
- return ELF::R_AARCH64_RELATIVE;
- case Triple::riscv64:
- return ELF::R_RISCV_RELATIVE;
- case Triple::riscv32:
- llvm_unreachable("not implemented");
- case Triple::x86_64:
- return ELF::R_X86_64_RELATIVE;
- }
-}
-
-size_t Relocation::emit(MCStreamer *Streamer) const {
- const size_t Size = getSizeForType(Type);
- const auto *Value = createExpr(Streamer);
+size_t Relocation::emit(MCStreamer *Streamer,
+ const RelocationHandler &RH) const {
+ const size_t Size = RH.getSizeForType(Type);
+ const auto *Value = createExpr(Streamer, RH);
Streamer->emitValue(Value, Size);
return Size;
}
-const MCExpr *Relocation::createExpr(MCStreamer *Streamer) const {
+const MCExpr *Relocation::createExpr(MCStreamer *Streamer,
+ const RelocationHandler &RH) const {
MCContext &Ctx = Streamer->getContext();
const MCExpr *Value = nullptr;
@@ -1020,7 +77,7 @@ const MCExpr *Relocation::createExpr(MCStreamer *Streamer) const {
Value = MCConstantExpr::create(Addend, Ctx);
}
- if (isPCRelative(Type)) {
+ if (RH.isPCRelative(Type)) {
MCSymbol *TempLabel = Ctx.createNamedTempSymbol();
Streamer->emitLabel(TempLabel);
Value = MCBinaryExpr::createSub(
@@ -1031,47 +88,20 @@ const MCExpr *Relocation::createExpr(MCStreamer *Streamer) const {
}
const MCExpr *Relocation::createExpr(MCStreamer *Streamer,
- const MCExpr *RetainedValue) const {
- const auto *Value = createExpr(Streamer);
+ const MCExpr *RetainedValue,
+ const RelocationHandler &RH) const {
+ const auto *Value = createExpr(Streamer, RH);
if (RetainedValue) {
- Value = MCBinaryExpr::create(getComposeOpcodeFor(Type), RetainedValue,
+ Value = MCBinaryExpr::create(RH.getComposeOpcodeFor(Type), RetainedValue,
Value, Streamer->getContext());
}
return Value;
}
-MCBinaryExpr::Opcode Relocation::getComposeOpcodeFor(uint32_t Type) {
- assert((Arch == Triple::riscv32 || Arch == Triple::riscv64) &&
- "only implemented for RISC-V");
-
- switch (Type) {
- default:
- llvm_unreachable("not implemented");
- case ELF::R_RISCV_ADD32:
- return MCBinaryExpr::Add;
- case ELF::R_RISCV_SUB32:
- return MCBinaryExpr::Sub;
- }
-}
-
-void Relocation::print(raw_ostream &OS) const {
- switch (Arch) {
- default:
- OS << "RType:" << Twine::utohexstr(Type);
- break;
- case Triple::aarch64:
- OS << object::getELFRelocationTypeName(ELF::EM_AARCH64, Type);
- break;
- case Triple::riscv64:
- case Triple::riscv32:
- OS << object::getELFRelocationTypeName(ELF::EM_RISCV, Type);
- break;
- case Triple::x86_64:
- OS << object::getELFRelocationTypeName(ELF::EM_X86_64, Type);
- break;
- }
+void Relocation::print(raw_ostream &OS, const RelocationHandler &RH) const {
+ RH.printType(OS, Type);
OS << ", 0x" << Twine::utohexstr(Offset);
if (Symbol) {
OS << ", " << Symbol->getName();
diff --git a/bolt/lib/Rewrite/LinuxKernelRewriter.cpp b/bolt/lib/Rewrite/LinuxKernelRewriter.cpp
index 0916f6f915758..722015ab499bf 100644
--- a/bolt/lib/Rewrite/LinuxKernelRewriter.cpp
+++ b/bolt/lib/Rewrite/LinuxKernelRewriter.cpp
@@ -480,6 +480,7 @@ void LinuxKernelRewriter::processLKKSymtab(bool IsGPL) {
"__ksymtab[_gpl] section not found in Linux Kernel binary");
const uint64_t SectionSize = SectionOrError->getSize();
const uint64_t SectionAddress = SectionOrError->getAddress();
+ const uint32_t PC32 = BC.getRelocationHandler().getPC32();
assert((SectionSize % 4) == 0 &&
"The size of the __ksymtab[_gpl] section should be a multiple of 4");
@@ -493,8 +494,7 @@ void LinuxKernelRewriter::processLKKSymtab(bool IsGPL) {
if (!BF)
continue;
- BC.addRelocation(EntryAddress, BF->getSymbol(), Relocation::getPC32(), 0,
- *Offset);
+ BC.addRelocation(EntryAddress, BF->getSymbol(), PC32, 0, *Offset);
}
}
@@ -801,6 +801,8 @@ Error LinuxKernelRewriter::rewriteORCTables() {
if (!NumORCEntries)
return Error::success();
+ const uint32_t PC32 = BC.getRelocationHandler().getPC32();
+
// Update ORC sections in-place. As we change the code, the number of ORC
// entries may increase for some functions. However, as we remove terminator
// redundancy (see below), more space is freed up and we should always be able
@@ -831,8 +833,8 @@ Error LinuxKernelRewriter::rewriteORCTables() {
"exceeded the number of allocated ORC entries");
if (Label)
- ORCUnwindIPSection->addRelocation(UnwindIPWriter.getOffset(), Label,
- Relocation::getPC32(), /*Addend*/ 0);
+ ORCUnwindIPSection->addRelocation(UnwindIPWriter.getOffset(), Label, PC32,
+ /*Addend*/ 0);
const int32_t IPValue =
IP - ORCUnwindIPSection->getAddress() - UnwindIPWriter.getOffset();
diff --git a/bolt/lib/Rewrite/MachORewriteInstance.cpp b/bolt/lib/Rewrite/MachORewriteInstance.cpp
index 1aff93dd26edb..6190d28ff2ad8 100644
--- a/bolt/lib/Rewrite/MachORewriteInstance.cpp
+++ b/bolt/lib/Rewrite/MachORewriteInstance.cpp
@@ -71,7 +71,6 @@ MachORewriteInstance::MachORewriteInstance(object::MachOObjectFile *InputFile,
StringRef ToolPath, Error &Err)
: InputFile(InputFile), ToolPath(ToolPath) {
ErrorAsOutParameter EAO(&Err);
- Relocation::Arch = InputFile->makeTriple().getArch();
auto BCOrErr = BinaryContext::createBinaryContext(
InputFile->makeTriple(), std::make_shared<orc::SymbolStringPool>(),
InputFile->getFileName(), nullptr,
diff --git a/bolt/lib/Rewrite/RSeqRewriter.cpp b/bolt/lib/Rewrite/RSeqRewriter.cpp
index 46bce66d13ddf..687ad91012588 100644
--- a/bolt/lib/Rewrite/RSeqRewriter.cpp
+++ b/bolt/lib/Rewrite/RSeqRewriter.cpp
@@ -39,7 +39,7 @@ class RSeqRewriter final : public MetadataRewriter {
BinaryFunction *BF = nullptr;
if (Rel.Symbol)
BF = BC.getFunctionForSymbol(Rel.Symbol);
- else if (Relocation::isRelative(Rel.Type))
+ else if (BC.getRelocationHandler().isRelative(Rel.Type))
BF = BC.getBinaryFunctionContainingAddress(Rel.Addend);
if (!BF) {
diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index d7078907cf514..da6293f331275 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -453,7 +453,6 @@ RewriteInstance::RewriteInstance(ELFObjectFileBase *File, const int Argc,
}
}
- Relocation::Arch = TheTriple.getArch();
auto BCOrErr = BinaryContext::createBinaryContext(
TheTriple, std::make_shared<orc::SymbolStringPool>(), File->getFileName(),
Features.get(), IsPIC,
@@ -534,10 +533,11 @@ static bool shouldDisassemble(const BinaryFunction &BF) {
static void createRISCVIFuncResolverFunctions(BinaryContext &BC) {
assert(BC.isRISCV() && "expected RISC-V target");
+ const RelocationHandler &RH = BC.getRelocationHandler();
for (const BinarySection &Section : BC.allocatableSections()) {
for (const Relocation &Rel : Section.dynamicRelocations()) {
- if (!Rel.isIRelative() || !Rel.Addend ||
+ if (!RH.isIRelative(Rel.Type) || !Rel.Addend ||
BC.getBinaryFunctionAtAddress(Rel.Addend))
continue;
@@ -1444,6 +1444,7 @@ void RewriteInstance::discoverFileObjects() {
}
if (BC->isAArch64()) {
+ const RelocationHandler &RH = BC->getRelocationHandler();
// Check for dynamic relocations that might be contained in
// constant islands.
for (const BinarySection &Section : BC->allocatableSections()) {
@@ -1455,7 +1456,8 @@ void RewriteInstance::discoverFileObjects() {
/*CheckPastEnd*/ false,
/*UseMaxSize*/ true);
if (BF) {
- assert(Rel.isRelative() && "Expected relative relocation for island");
+ assert(RH.isRelative(Rel.Type) &&
+ "Expected relative relocation for island");
BC->logBOLTErrorsAndQuitOnFatal(
BF->markIslandDynamicRelocationAtAddress(RelAddress));
}
@@ -1551,7 +1553,7 @@ Error RewriteInstance::discoverRtInitAddress() {
}
if (const Relocation *Reloc = InitArraySection->getDynamicRelocationAt(0)) {
- if (Reloc->isRelative()) {
+ if (BC->getRelocationHandler().isRelative(Reloc->Type)) {
BC->StartFunctionAddress = Reloc->Addend;
} else {
MCSymbol *Sym = Reloc->Symbol;
@@ -1624,6 +1626,7 @@ Error RewriteInstance::discoverRtFiniAddress() {
}
Error RewriteInstance::updateRtInitReloc() {
+ const RelocationHandler &RH = BC->getRelocationHandler();
if (BC->HasInterpHeader && opts::RuntimeLibInitHook == opts::RLIH_ENTRY_POINT)
return Error::success();
@@ -1649,7 +1652,7 @@ Error RewriteInstance::updateRtInitReloc() {
if (std::optional<Relocation> Reloc =
InitArraySection->takeDynamicRelocationAt(0)) {
- if (Reloc->isRelative()) {
+ if (RH.isRelative(Reloc->Type)) {
if (Reloc->Addend != BC->StartFunctionAddress)
return createStringError(std::errc::not_supported,
"inconsistent .init_array dynamic relocation");
@@ -1669,9 +1672,9 @@ Error RewriteInstance::updateRtInitReloc() {
if (BF->getAddress() + Reloc->Addend != BC->StartFunctionAddress)
return createStringError(std::errc::not_supported,
"inconsistent .init_array dynamic relocation");
- InitArraySection->addDynamicRelocation(Relocation{
- /*Offset*/ 0, /*Symbol*/ nullptr, /*Type*/ Relocation::getAbs64(),
- /*Addend*/ RT->getRuntimeStartAddress(), /*Value*/ 0});
+ InitArraySection->addDynamicRelocation(
+ Relocation{/*Offset*/ 0, /*Symbol*/ nullptr, /*Type*/ RH.getAbs64(),
+ /*Addend*/ RT->getRuntimeStartAddress(), /*Value*/ 0});
}
}
// Update the static relocation by adding a pending relocation which will get
@@ -1679,9 +1682,9 @@ Error RewriteInstance::updateRtInitReloc() {
// flushPendingRelocations will calculate the value to patch as
// "Symbol + Addend". Since we don't have a symbol, just set the addend to the
// desired value.
- InitArraySection->addPendingRelocation(Relocation{
- /*Offset*/ 0, /*Symbol*/ nullptr, /*Type*/ Relocation::getAbs64(),
- /*Addend*/ RT->getRuntimeStartAddress(), /*Value*/ 0});
+ InitArraySection->addPendingRelocation(
+ Relocation{/*Offset*/ 0, /*Symbol*/ nullptr, /*Type*/ RH.getAbs64(),
+ /*Addend*/ RT->getRuntimeStartAddress(), /*Value*/ 0});
BC->outs()
<< "BOLT-INFO: runtime library initialization was hooked via .init_array "
"entry, set to 0x"
@@ -1690,6 +1693,7 @@ Error RewriteInstance::updateRtInitReloc() {
}
Error RewriteInstance::updateRtFiniReloc() {
+ const RelocationHandler &RH = BC->getRelocationHandler();
// Updating DT_FINI is handled by patchELFDynamic.
if (BC->FiniAddress)
return Error::success();
@@ -1725,9 +1729,9 @@ Error RewriteInstance::updateRtFiniReloc() {
// flushPendingRelocations will calculate the value to patch as
// "Symbol + Addend". Since we don't have a symbol, just set the addend to the
// desired value.
- FiniArraySection->addPendingRelocation(Relocation{
- /*Offset*/ 0, /*Symbol*/ nullptr, /*Type*/ Relocation::getAbs64(),
- /*Addend*/ RT->getRuntimeFiniAddress(), /*Value*/ 0});
+ FiniArraySection->addPendingRelocation(
+ Relocation{/*Offset*/ 0, /*Symbol*/ nullptr, /*Type*/ RH.getAbs64(),
+ /*Addend*/ RT->getRuntimeFiniAddress(), /*Value*/ 0});
BC->outs() << "BOLT-INFO: runtime library finalization was hooked via "
".fini_array entry, set to 0x"
<< Twine::utohexstr(RT->getRuntimeFiniAddress()) << "\n";
@@ -1915,7 +1919,7 @@ void RewriteInstance::createPLTBinaryFunction(uint64_t TargetAddress,
MCSymbol *Symbol = Rel->Symbol;
if (!Symbol) {
- if (!Rel->Addend || !Rel->isIRelative())
+ if (!Rel->Addend || !BC->getRelocationHandler().isIRelative(Rel->Type))
return;
// IFUNC trampoline without symbol
@@ -1945,7 +1949,7 @@ void RewriteInstance::createPLTBinaryFunction(uint64_t TargetAddress,
// symbols can alias that resolver, and R_RISCV_CALL_PLT relocations may use
// any of their names. Register every such name for the same IPLT entry so
// getPLTBinaryDataByName() can resolve those call sites.
- if (BC->isRISCV() && Rel->isIRelative()) {
+ if (BC->isRISCV() && BC->getRelocationHandler().isIRelative(Rel->Type)) {
auto ResolverSyms = FileSymRefs.equal_range(Rel->Addend);
for (const SymbolRef &AliasSymbol : llvm::make_second_range(
llvm::make_range(ResolverSyms.first, ResolverSyms.second))) {
@@ -2422,12 +2426,12 @@ void RewriteInstance::relocateEHFrameSection() {
llvm_unreachable("unsupported DWARF encoding type");
case dwarf::DW_EH_PE_sdata4:
case dwarf::DW_EH_PE_udata4:
- RelType = Relocation::getPC32();
+ RelType = BC->getRelocationHandler().getPC32();
Offset -= 4;
break;
case dwarf::DW_EH_PE_sdata8:
case dwarf::DW_EH_PE_udata8:
- RelType = Relocation::getPC64();
+ RelType = BC->getRelocationHandler().getPC64();
Offset -= 8;
break;
}
@@ -2830,7 +2834,8 @@ bool RewriteInstance::analyzeRelocation(
const RelocationRef &Rel, uint32_t &RType, std::string &SymbolName,
bool &IsSectionRelocation, uint64_t &SymbolAddress, int64_t &Addend,
uint64_t &ExtractedValue) const {
- if (!Relocation::isSupported(RType))
+ const RelocationHandler &RH = BC->getRelocationHandler();
+ if (!RH.isSupported(RType))
return false;
auto IsWeakReference = [](const SymbolRef &Symbol) {
@@ -2844,16 +2849,16 @@ bool RewriteInstance::analyzeRelocation(
const bool IsAArch64 = BC->isAArch64();
const bool IsRISCV = BC->isRISCV();
- const size_t RelSize = Relocation::getSizeForType(RType);
+ const size_t RelSize = RH.getSizeForType(RType);
ErrorOr<uint64_t> Value =
BC->getUnsignedValueAtAddress(Rel.getOffset(), RelSize);
assert(Value && "failed to extract relocated value");
- ExtractedValue = Relocation::extractValue(RType, *Value, Rel.getOffset());
+ ExtractedValue = RH.extractValue(RType, *Value, Rel.getOffset());
Addend = getRelocationAddend(InputFile, Rel);
- const bool IsPCRelative = Relocation::isPCRelative(RType);
+ const bool IsPCRelative = RH.isPCRelative(RType);
const uint64_t PCRelOffset = IsPCRelative && !IsAArch64 ? Rel.getOffset() : 0;
bool SkipVerification = false;
auto SymbolIter = Rel.getSymbol();
@@ -2914,7 +2919,7 @@ bool RewriteInstance::analyzeRelocation(
// causing the extracted value mismatch. Similar cases can happen for TLS.
// Pass the relocation information as is to the disassembler and let it decide
// how to use it for the operand symbolization.
- if (Relocation::isGOT(RType) || Relocation::isTLS(RType)) {
+ if (RH.isGOT(RType) || RH.isTLS(RType)) {
SkipVerification = true;
} else if (!SymbolAddress) {
assert(!IsSectionRelocation);
@@ -3055,7 +3060,7 @@ void RewriteInstance::readDynamicRelocations(const SectionRef &Section,
}
const uint32_t RType = Relocation::getType(Rel);
- if (Relocation::isNone(RType))
+ if (BC->getRelocationHandler().isNone(RType))
continue;
StringRef SymbolName = "<none>";
@@ -3087,7 +3092,7 @@ void RewriteInstance::readDynamicRelocations(const SectionRef &Section,
// Check if this relocation targets an address within a function. This
// happens with indirect goto.
const uint64_t ReferencedAddress = SymbolAddress + Addend;
- if (Relocation::isRelative(RType)) {
+ if (BC->getRelocationHandler().isRelative(RType)) {
if (SymbolAddress != 0) {
BC->errs() << "BOLT-ERROR: symbol address non zero for RELATIVE "
"relocation type\n";
@@ -3110,7 +3115,7 @@ void RewriteInstance::readDynamicRelrRelocations(BinarySection &Section) {
<< ":\n";
});
- const uint32_t RType = Relocation::getRelative();
+ const uint32_t RType = BC->getRelocationHandler().getRelative();
const uint8_t PSize = BC->AsmInfo->getCodePointerSize();
const uint64_t MaxDelta = ((CHAR_BIT * DynamicRelrEntrySize) - 1) * PSize;
@@ -3240,6 +3245,7 @@ void RewriteInstance::readRelocations(const SectionRef &Section) {
void RewriteInstance::handleRelocation(const SectionRef &RelocatedSection,
const RelocationRef &Rel) {
+ const RelocationHandler &RH = BC->getRelocationHandler();
const bool IsAArch64 = BC->isAArch64();
const bool IsX86 = BC->isX86();
const bool IsFromCode = RelocatedSection.isText();
@@ -3248,7 +3254,7 @@ void RewriteInstance::handleRelocation(const SectionRef &RelocatedSection,
SmallString<16> TypeName;
Rel.getTypeName(TypeName);
uint32_t RType = Relocation::getType(Rel);
- if (Relocation::skipRelocationType(RType))
+ if (RH.skipRelocationType(RType))
return;
// Adjust the relocation type as the linker might have skewed it.
@@ -3258,14 +3264,14 @@ void RewriteInstance::handleRelocation(const SectionRef &RelocatedSection,
RType &= ~ELF::R_X86_64_converted_reloc_bit;
}
- if (Relocation::isTLS(RType)) {
+ if (RH.isTLS(RType)) {
// No special handling required for TLS relocations on X86.
if (IsX86)
return;
// The non-got related TLS relocations on AArch64 and RISC-V also could be
// skipped.
- if (!Relocation::isGOT(RType))
+ if (!RH.isGOT(RType))
return;
}
@@ -3293,7 +3299,7 @@ void RewriteInstance::handleRelocation(const SectionRef &RelocatedSection,
}
if (!IsFromCode && !IsWritable && (IsX86 || IsAArch64) &&
- Relocation::isPCRelative(RType)) {
+ RH.isPCRelative(RType)) {
BinaryData *BD = BC->getBinaryDataContainingAddress(Rel.getOffset());
if (BD && (BD->nameStartsWith("_ZTV") || // vtable
BD->nameStartsWith("_ZTCN"))) { // construction vtable
@@ -3378,7 +3384,7 @@ void RewriteInstance::handleRelocation(const SectionRef &RelocatedSection,
const bool IsToCode = ReferencedSection && ReferencedSection->isText();
// Special handling of PC-relative relocations.
- if (IsX86 && Relocation::isPCRelative(RType)) {
+ if (IsX86 && RH.isPCRelative(RType)) {
if (!IsFromCode && IsToCode) {
// PC-relative relocations from data to code are tricky since the
// original information is typically lost after linking, even with
@@ -3411,7 +3417,7 @@ void RewriteInstance::handleRelocation(const SectionRef &RelocatedSection,
}
bool ForceRelocation = BC->forceSymbolRelocations(SymbolName);
- if ((BC->isAArch64() || BC->isRISCV()) && Relocation::isGOT(RType))
+ if ((BC->isAArch64() || BC->isRISCV()) && RH.isGOT(RType))
ForceRelocation = true;
if (!ReferencedSection && !ForceRelocation) {
@@ -3457,15 +3463,14 @@ void RewriteInstance::handleRelocation(const SectionRef &RelocatedSection,
// Workaround for a member function pointer de-virtualization bug. We check
// if a non-pc-relative relocation in the code is pointing to (fptr - 1).
- if (IsToCode && ContainingBF && !Relocation::isPCRelative(RType) &&
+ if (IsToCode && ContainingBF && !RH.isPCRelative(RType) &&
(!ReferencedBF || (ReferencedBF->getAddress() != Address))) {
if (const BinaryFunction *RogueBF =
BC->getBinaryFunctionAtAddress(Address + 1)) {
// Do an extra check that the function was referenced previously.
// It's a linear search, but it should rarely happen.
auto CheckReloc = [&](const Relocation &Rel) {
- return Rel.Symbol == RogueBF->getSymbol() &&
- !Relocation::isPCRelative(Rel.Type);
+ return Rel.Symbol == RogueBF->getSymbol() && !RH.isPCRelative(Rel.Type);
};
bool Found = llvm::any_of(
llvm::make_second_range(ContainingBF->Relocations), CheckReloc);
@@ -3497,7 +3502,7 @@ void RewriteInstance::handleRelocation(const SectionRef &RelocatedSection,
// Adjust the point of reference to a code location inside a function.
if (ReferencedBF->containsAddress(Address, /*UseMaxSize = */ true)) {
RefFunctionOffset = Address - ReferencedBF->getAddress();
- if (Relocation::isInstructionReference(RType)) {
+ if (RH.isInstructionReference(RType)) {
// Instruction labels are created while disassembling so we just leave
// the symbol empty for now. Since the extracted value is typically
// unrelated to the referenced symbol (e.g., %pcrel_lo in RISC-V
@@ -6287,6 +6292,7 @@ RewriteInstance::patchELFAllocatableRelaSections(ELFObjectFile<ELFT> *File) {
using Elf_Rela = typename ELFT::Rela;
raw_fd_ostream &OS = Out->os();
const ELFFile<ELFT> &EF = File->getELFFile();
+ const RelocationHandler &RH = BC->getRelocationHandler();
uint64_t RelDynOffset = 0, RelDynEndOffset = 0;
uint64_t RelPltOffset = 0, RelPltEndOffset = 0;
@@ -6363,7 +6369,7 @@ RewriteInstance::patchELFAllocatableRelaSections(ELFObjectFile<ELFT> *File) {
if (Rel.isJmpRelocation())
continue;
- const bool IsRelative = Rel.isRelative();
+ const bool IsRelative = RH.isRelative(Rel.Type);
if (PatchRelative != IsRelative || Rel.isRELR())
continue;
@@ -6385,7 +6391,7 @@ RewriteInstance::patchELFAllocatableRelaSections(ELFObjectFile<ELFT> *File) {
return;
typename ELFObjectFile<ELFT>::Elf_Rela RelA;
- RelA.setSymbolAndType(0, Relocation::getNone(), EF.isMips64EL());
+ RelA.setSymbolAndType(0, RH.getNone(), EF.isMips64EL());
RelA.r_offset = 0;
RelA.r_addend = 0;
while (Offset < EndOffset) {
diff --git a/bolt/lib/Target/AArch64/AArch64MCSymbolizer.cpp b/bolt/lib/Target/AArch64/AArch64MCSymbolizer.cpp
index da469a9a5ab95..0a1f19d639ec3 100644
--- a/bolt/lib/Target/AArch64/AArch64MCSymbolizer.cpp
+++ b/bolt/lib/Target/AArch64/AArch64MCSymbolizer.cpp
@@ -83,6 +83,7 @@ std::optional<Relocation>
AArch64MCSymbolizer::adjustRelocation(const Relocation &Rel,
const MCInst &Inst) const {
BinaryContext &BC = Function.getBinaryContext();
+ const RelocationHandler &RH = BC.getRelocationHandler();
// The linker can convert ADRP+ADD and ADRP+LDR instruction sequences into
// NOP+ADR. After the conversion, the linker might keep the relocations and
@@ -114,7 +115,7 @@ AArch64MCSymbolizer::adjustRelocation(const Relocation &Rel,
}
}
- if (!Relocation::isGOT(Rel.Type))
+ if (!RH.isGOT(Rel.Type))
return Rel;
Relocation AdjustedRel = Rel;
@@ -137,7 +138,7 @@ AArch64MCSymbolizer::adjustRelocation(const Relocation &Rel,
// Note that ADRP relaxation described above cannot happen for TLS relocation.
// Since TLS relocations may not even have a valid symbol (not supported by
// BOLT), we explicitly exclude them from the check.
- if (BC.MIB->isADRP(Inst) && Rel.Addend == 0 && !Relocation::isTLS(Rel.Type)) {
+ if (BC.MIB->isADRP(Inst) && Rel.Addend == 0 && !RH.isTLS(Rel.Type)) {
ErrorOr<uint64_t> SymbolValue = BC.getSymbolValue(*Rel.Symbol);
assert(SymbolValue && "Symbol value should be set");
const uint64_t SymbolPageAddr = *SymbolValue & ~0xfffULL;
diff --git a/bolt/lib/Target/AArch64/AArch64RelocationHandler.cpp b/bolt/lib/Target/AArch64/AArch64RelocationHandler.cpp
new file mode 100644
index 0000000000000..3c04660ea0b1e
--- /dev/null
+++ b/bolt/lib/Target/AArch64/AArch64RelocationHandler.cpp
@@ -0,0 +1,448 @@
+//===- AArch64RelocationHandler.cpp
+//-----------------------------------------------===//
+//
+// 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 AArch64 relocation handler.
+//
+//===----------------------------------------------------------------------===//
+
+#include "bolt/Core/Relocation.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace bolt;
+
+namespace {
+
+class AArch64RelocationHandler final : public RelocationHandler {
+public:
+ bool isSupported(uint32_t Type) const override;
+ size_t getSizeForType(uint32_t Type) const override;
+ bool skipRelocationType(uint32_t Type) const override;
+
+ uint64_t encodeValue(uint32_t Type, uint64_t Value,
+ uint64_t PC) const override;
+ bool canEncodeValue(uint32_t Type, uint64_t Value,
+ uint64_t PC) const override;
+ uint64_t extractValue(uint32_t Type, uint64_t Contents,
+ uint64_t PC) const override;
+
+ bool isGOT(uint32_t Type) const override;
+ bool isRelative(uint32_t Type) const override;
+ bool isIRelative(uint32_t Type) const override;
+ bool isTLS(uint32_t Type) const override;
+ bool isPCRelative(uint32_t Type) const override;
+
+ uint32_t getNone() const override;
+ uint32_t getPC32() const override;
+ uint32_t getPC64() const override;
+ uint32_t getAbs64() const override;
+ uint32_t getRelative() const override;
+
+ void printType(raw_ostream &OS, uint32_t Type) const override;
+};
+
+} // namespace
+
+bool AArch64RelocationHandler::isRelative(uint32_t Type) const {
+ return Type == ELF::R_AARCH64_RELATIVE;
+}
+
+bool AArch64RelocationHandler::isIRelative(uint32_t Type) const {
+ return Type == ELF::R_AARCH64_IRELATIVE;
+}
+
+uint32_t AArch64RelocationHandler::getNone() const {
+ return ELF::R_AARCH64_NONE;
+}
+
+uint32_t AArch64RelocationHandler::getPC32() const {
+ return ELF::R_AARCH64_PREL32;
+}
+
+uint32_t AArch64RelocationHandler::getPC64() const {
+ return ELF::R_AARCH64_PREL64;
+}
+
+uint32_t AArch64RelocationHandler::getAbs64() const {
+ return ELF::R_AARCH64_ABS64;
+}
+
+uint32_t AArch64RelocationHandler::getRelative() const {
+ return ELF::R_AARCH64_RELATIVE;
+}
+
+void AArch64RelocationHandler::printType(raw_ostream &OS, uint32_t Type) const {
+ OS << object::getELFRelocationTypeName(ELF::EM_AARCH64, Type);
+}
+
+bool AArch64RelocationHandler::isSupported(uint32_t Type) const {
+ 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_TLSGD_ADR_PAGE21:
+ case ELF::R_AARCH64_TLSGD_ADD_LO12_NC:
+ case ELF::R_AARCH64_TLSDESC_ADR_PREL21:
+ case ELF::R_AARCH64_TLSDESC_ADR_PAGE21:
+ case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+ case ELF::R_AARCH64_TLSLE_ADD_TPREL_HI12:
+ case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
+ case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0:
+ case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
+ case ELF::R_AARCH64_LD64_GOT_LO12_NC:
+ case ELF::R_AARCH64_TLSDESC_LD64_LO12:
+ case ELF::R_AARCH64_TLSDESC_ADD_LO12:
+ case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+ case ELF::R_AARCH64_PREL16:
+ case ELF::R_AARCH64_PREL32:
+ case ELF::R_AARCH64_PREL64:
+ case ELF::R_AARCH64_ABS16:
+ case ELF::R_AARCH64_ABS32:
+ case ELF::R_AARCH64_ABS64:
+ case ELF::R_AARCH64_MOVW_UABS_G0:
+ case ELF::R_AARCH64_MOVW_UABS_G0_NC:
+ case ELF::R_AARCH64_MOVW_UABS_G1:
+ case ELF::R_AARCH64_MOVW_UABS_G1_NC:
+ case ELF::R_AARCH64_MOVW_UABS_G2:
+ case ELF::R_AARCH64_MOVW_UABS_G2_NC:
+ case ELF::R_AARCH64_MOVW_UABS_G3:
+ case ELF::R_AARCH64_PLT32:
+ return true;
+ }
+}
+
+size_t AArch64RelocationHandler::getSizeForType(uint32_t Type) const {
+ 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_TLSGD_ADR_PAGE21:
+ case ELF::R_AARCH64_TLSGD_ADD_LO12_NC:
+ case ELF::R_AARCH64_TLSDESC_ADR_PREL21:
+ case ELF::R_AARCH64_TLSDESC_ADR_PAGE21:
+ case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+ case ELF::R_AARCH64_TLSLE_ADD_TPREL_HI12:
+ case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
+ case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0:
+ case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
+ case ELF::R_AARCH64_LD64_GOT_LO12_NC:
+ case ELF::R_AARCH64_TLSDESC_LD64_LO12:
+ case ELF::R_AARCH64_TLSDESC_ADD_LO12:
+ case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+ case ELF::R_AARCH64_PREL32:
+ case ELF::R_AARCH64_MOVW_UABS_G0:
+ case ELF::R_AARCH64_MOVW_UABS_G0_NC:
+ case ELF::R_AARCH64_MOVW_UABS_G1:
+ case ELF::R_AARCH64_MOVW_UABS_G1_NC:
+ case ELF::R_AARCH64_MOVW_UABS_G2:
+ case ELF::R_AARCH64_MOVW_UABS_G2_NC:
+ case ELF::R_AARCH64_MOVW_UABS_G3:
+ case ELF::R_AARCH64_ABS32:
+ case ELF::R_AARCH64_PLT32:
+ return 4;
+ case ELF::R_AARCH64_ABS64:
+ case ELF::R_AARCH64_PREL64:
+ return 8;
+ }
+}
+
+bool AArch64RelocationHandler::skipRelocationType(uint32_t Type) const {
+ switch (Type) {
+ default:
+ return false;
+ case ELF::R_AARCH64_NONE:
+ case ELF::R_AARCH64_LD_PREL_LO19:
+ case ELF::R_AARCH64_TLSDESC_CALL:
+ return true;
+ }
+}
+
+bool AArch64RelocationHandler::canEncodeValue(uint32_t Type, uint64_t Value,
+ uint64_t PC) const {
+ switch (Type) {
+ default:
+ llvm_unreachable("unsupported relocation");
+ case ELF::R_AARCH64_CALL26:
+ case ELF::R_AARCH64_JUMP26:
+ return isInt<28>(Value - PC);
+ }
+}
+
+uint64_t AArch64RelocationHandler::encodeValue(uint32_t Type, uint64_t Value,
+ uint64_t PC) const {
+ switch (Type) {
+ default:
+ llvm_unreachable("unsupported relocation");
+ case ELF::R_AARCH64_ABS16:
+ case ELF::R_AARCH64_ABS32:
+ case ELF::R_AARCH64_ABS64:
+ break;
+ case ELF::R_AARCH64_PREL16:
+ case ELF::R_AARCH64_PREL32:
+ case ELF::R_AARCH64_PREL64:
+ Value -= PC;
+ break;
+ case ELF::R_AARCH64_CALL26:
+ Value -= PC;
+ assert(isInt<28>(Value) && "only PC +/- 128MB is allowed for direct call");
+ // Immediate goes in bits 25:0 of BL.
+ // OP 1001_01 goes in bits 31:26 of BL.
+ Value = ((Value >> 2) & 0x3ffffff) | 0x94000000ULL;
+ break;
+ case ELF::R_AARCH64_JUMP26:
+ Value -= PC;
+ assert(isInt<28>(Value) &&
+ "only PC +/- 128MB is allowed for direct branch");
+ // Immediate goes in bits 25:0 of B.
+ // OP 0001_01 goes in bits 31:26 of B.
+ Value = ((Value >> 2) & 0x3ffffff) | 0x14000000ULL;
+ break;
+ }
+ return Value;
+}
+
+uint64_t AArch64RelocationHandler::extractValue(uint32_t Type,
+ uint64_t Contents,
+ uint64_t PC) const {
+ switch (Type) {
+ default:
+ errs() << object::getELFRelocationTypeName(ELF::EM_AARCH64, Type) << '\n';
+ llvm_unreachable("unsupported relocation type");
+ case ELF::R_AARCH64_ABS16:
+ case ELF::R_AARCH64_ABS32:
+ case ELF::R_AARCH64_ABS64:
+ return Contents;
+ case ELF::R_AARCH64_PREL16:
+ return static_cast<int64_t>(PC) + SignExtend64<16>(Contents & 0xffff);
+ case ELF::R_AARCH64_PREL32:
+ case ELF::R_AARCH64_PLT32:
+ return static_cast<int64_t>(PC) + SignExtend64<32>(Contents & 0xffffffff);
+ case ELF::R_AARCH64_PREL64:
+ return static_cast<int64_t>(PC) + Contents;
+ case ELF::R_AARCH64_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_TLSGD_ADR_PAGE21:
+ 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_TLSGD_ADD_LO12_NC:
+ case ELF::R_AARCH64_TLSDESC_ADD_LO12:
+ case ELF::R_AARCH64_ADD_ABS_LO12_NC: {
+ // Immediate goes in bits 21:10 of ADD instruction
+ Contents &= ~0xffffffffffc003ffU;
+ return Contents >> (10 - 0);
+ }
+ case ELF::R_AARCH64_LDST128_ABS_LO12_NC: {
+ // Immediate goes in bits 21:10 of ADD instruction, taken
+ // from bits 11:4 of Symbol address
+ Contents &= ~0xffffffffffc003ffU;
+ return Contents >> (10 - 4);
+ }
+ case ELF::R_AARCH64_LDST32_ABS_LO12_NC: {
+ // Immediate goes in bits 21:10 of ADD instruction, taken
+ // from bits 11:2 of Symbol address
+ Contents &= ~0xffffffffffc003ffU;
+ return Contents >> (10 - 2);
+ }
+ case ELF::R_AARCH64_LDST16_ABS_LO12_NC: {
+ // Immediate goes in bits 21:10 of ADD instruction, taken
+ // from bits 11:1 of Symbol address
+ Contents &= ~0xffffffffffc003ffU;
+ return Contents >> (10 - 1);
+ }
+ case ELF::R_AARCH64_LDST8_ABS_LO12_NC: {
+ // Immediate goes in bits 21:10 of ADD instruction, taken
+ // from bits 11:0 of Symbol address
+ Contents &= ~0xffffffffffc003ffU;
+ return Contents >> (10 - 0);
+ }
+ case ELF::R_AARCH64_MOVW_UABS_G3:
+ case ELF::R_AARCH64_MOVW_UABS_G2_NC:
+ case ELF::R_AARCH64_MOVW_UABS_G2:
+ case ELF::R_AARCH64_MOVW_UABS_G1_NC:
+ case ELF::R_AARCH64_MOVW_UABS_G1:
+ case ELF::R_AARCH64_MOVW_UABS_G0_NC:
+ case ELF::R_AARCH64_MOVW_UABS_G0:
+ // The shift goes in bits 22:21 of MOV* instructions
+ uint8_t Shift = (Contents >> 21) & 0x3;
+ // Immediate goes in bits 20:5
+ Contents = (Contents >> 5) & 0xffff;
+ return Contents << (16 * Shift);
+ }
+}
+
+bool AArch64RelocationHandler::isGOT(uint32_t Type) const {
+ 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_TLSGD_ADR_PAGE21:
+ case ELF::R_AARCH64_TLSGD_ADD_LO12_NC:
+ 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:
+ return true;
+ }
+}
+
+bool AArch64RelocationHandler::isTLS(uint32_t Type) const {
+ switch (Type) {
+ default:
+ return false;
+ case ELF::R_AARCH64_TLSGD_ADR_PAGE21:
+ case ELF::R_AARCH64_TLSGD_ADD_LO12_NC:
+ case ELF::R_AARCH64_TLSDESC_ADR_PREL21:
+ case ELF::R_AARCH64_TLSDESC_ADR_PAGE21:
+ case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+ case ELF::R_AARCH64_TLSLE_ADD_TPREL_HI12:
+ case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
+ case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0:
+ case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
+ case ELF::R_AARCH64_TLSDESC_LD64_LO12:
+ case ELF::R_AARCH64_TLSDESC_ADD_LO12:
+ case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+ return true;
+ }
+}
+
+bool AArch64RelocationHandler::isPCRelative(uint32_t Type) const {
+ 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_TLSGD_ADD_LO12_NC:
+ case ELF::R_AARCH64_TLSLE_ADD_TPREL_HI12:
+ case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
+ case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0:
+ case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
+ case ELF::R_AARCH64_LD64_GOT_LO12_NC:
+ case ELF::R_AARCH64_TLSDESC_LD64_LO12:
+ case ELF::R_AARCH64_TLSDESC_ADD_LO12:
+ case ELF::R_AARCH64_MOVW_UABS_G0:
+ case ELF::R_AARCH64_MOVW_UABS_G0_NC:
+ case ELF::R_AARCH64_MOVW_UABS_G1:
+ case ELF::R_AARCH64_MOVW_UABS_G1_NC:
+ case ELF::R_AARCH64_MOVW_UABS_G2:
+ case ELF::R_AARCH64_MOVW_UABS_G2_NC:
+ case ELF::R_AARCH64_MOVW_UABS_G3:
+ return false;
+ case ELF::R_AARCH64_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_TLSGD_ADR_PAGE21:
+ case ELF::R_AARCH64_TLSDESC_ADR_PREL21:
+ case ELF::R_AARCH64_TLSDESC_ADR_PAGE21:
+ case ELF::R_AARCH64_PREL16:
+ case ELF::R_AARCH64_PREL32:
+ case ELF::R_AARCH64_PREL64:
+ case ELF::R_AARCH64_PLT32:
+ return true;
+ }
+}
+
+namespace llvm::bolt {
+
+std::unique_ptr<RelocationHandler> createAArch64RelocationHandler() {
+ return std::make_unique<AArch64RelocationHandler>();
+}
+
+} // namespace llvm::bolt
diff --git a/bolt/lib/Target/AArch64/CMakeLists.txt b/bolt/lib/Target/AArch64/CMakeLists.txt
index 715efc1e8c5a4..ec33fc1656841 100644
--- a/bolt/lib/Target/AArch64/CMakeLists.txt
+++ b/bolt/lib/Target/AArch64/CMakeLists.txt
@@ -22,6 +22,9 @@ add_llvm_library(LLVMBOLTTargetAArch64
AArch64MCPlusBuilder.cpp
AArch64MCSymbolizer.cpp
+ # AArch64RelocationHandler.cpp is part of LLVMBOLTCore to avoid a circular
+ # dependency between the core relocation factory and LLVMBOLTTargetAArch64.
+ PARTIAL_SOURCES_INTENDED
NO_EXPORT
DISABLE_LLVM_LINK_LLVM_DYLIB
diff --git a/bolt/lib/Target/RISCV/CMakeLists.txt b/bolt/lib/Target/RISCV/CMakeLists.txt
index e7fa950de29df..922edafae5d48 100644
--- a/bolt/lib/Target/RISCV/CMakeLists.txt
+++ b/bolt/lib/Target/RISCV/CMakeLists.txt
@@ -22,6 +22,9 @@ add_llvm_library(LLVMBOLTTargetRISCV
RISCVMCPlusBuilder.cpp
RISCVMCSymbolizer.cpp
+ # RISCVRelocationHandler.cpp is part of LLVMBOLTCore to avoid a circular
+ # dependency between the core relocation factory and LLVMBOLTTargetRISCV.
+ PARTIAL_SOURCES_INTENDED
NO_EXPORT
DISABLE_LLVM_LINK_LLVM_DYLIB
diff --git a/bolt/lib/Target/RISCV/RISCVMCSymbolizer.cpp b/bolt/lib/Target/RISCV/RISCVMCSymbolizer.cpp
index 87a702a8c9464..d2d1fa29cdb66 100644
--- a/bolt/lib/Target/RISCV/RISCVMCSymbolizer.cpp
+++ b/bolt/lib/Target/RISCV/RISCVMCSymbolizer.cpp
@@ -64,6 +64,8 @@ RISCVMCSymbolizer::RISCVMCSymbolizer(BinaryFunction &Function,
bool CreateNewSymbols)
: MCSymbolizer(*Function.getBinaryContext().Ctx, nullptr),
Function(Function), CreateNewSymbols(CreateNewSymbols) {
+ BinaryContext &BC = Function.getBinaryContext();
+ const RelocationHandler &RH = BC.getRelocationHandler();
// Discover instruction references before decoding starts. This lets us
// attach a label while decoding the referenced %pcrel_hi instruction even
// though its %pcrel_lo user is normally decoded later.
@@ -73,7 +75,7 @@ RISCVMCSymbolizer::RISCVMCSymbolizer(BinaryFunction &Function,
if (!Rel)
break;
- if (Relocation::isInstructionReference(Rel->Type)) {
+ if (RH.isInstructionReference(Rel->Type)) {
assert(Rel->Value >= Function.getAddress() &&
Rel->Value < Function.getAddress() + Function.getSize() &&
"RISC-V instruction reference outside of function");
@@ -97,6 +99,7 @@ MCSymbol *RISCVMCSymbolizer::getOrCreateInstructionLabel(
uint64_t RISCVMCSymbolizer::getGOTValue(const Relocation &Rel) const {
BinaryContext &BC = Function.getBinaryContext();
+ const RelocationHandler &RH = BC.getRelocationHandler();
const uint64_t HiAddress = Function.getAddress() + Rel.Offset;
// A GOT high relocation records a combined high/low value. Locate the low
@@ -106,16 +109,14 @@ uint64_t RISCVMCSymbolizer::getGOTValue(const Relocation &Rel) const {
if (It != InstructionReferences.end() && It->second.LowRelocation) {
const Relocation *LoRel = It->second.LowRelocation;
ErrorOr<uint64_t> HiContents = BC.getUnsignedValueAtAddress(HiAddress, 4);
- ErrorOr<uint64_t> LoContents =
- BC.getUnsignedValueAtAddress(Function.getAddress() + LoRel->Offset,
- Relocation::getSizeForType(LoRel->Type));
+ ErrorOr<uint64_t> LoContents = BC.getUnsignedValueAtAddress(
+ Function.getAddress() + LoRel->Offset, RH.getSizeForType(LoRel->Type));
assert(HiContents && LoContents &&
"cannot read RISC-V GOT relocation pair");
- return Relocation::extractValue(ELF::R_RISCV_PCREL_HI20, *HiContents,
- HiAddress) +
- Relocation::extractValue(LoRel->Type, *LoContents,
- Function.getAddress() + LoRel->Offset);
+ return RH.extractValue(ELF::R_RISCV_PCREL_HI20, *HiContents, HiAddress) +
+ RH.extractValue(LoRel->Type, *LoContents,
+ Function.getAddress() + LoRel->Offset);
}
return Rel.Value;
@@ -181,6 +182,7 @@ bool RISCVMCSymbolizer::tryAddingSymbolicOperand(
MCInst &Inst, raw_ostream &CStream, int64_t Value, uint64_t InstAddress,
bool IsBranch, uint64_t ImmOffset, uint64_t ImmSize, uint64_t InstSize) {
BinaryContext &BC = Function.getBinaryContext();
+ const RelocationHandler &RH = BC.getRelocationHandler();
MCContext *Ctx = BC.Ctx.get();
const uint64_t InstOffset = InstAddress - Function.getAddress();
@@ -201,7 +203,7 @@ bool RISCVMCSymbolizer::tryAddingSymbolicOperand(
MCSymbol *Symbol = Rel->Symbol;
uint64_t Addend = Rel->Addend;
- if (Relocation::isInstructionReference(Rel->Type)) {
+ if (RH.isInstructionReference(Rel->Type)) {
if (!CreateNewSymbols)
return false;
auto [It, _] =
@@ -216,8 +218,8 @@ bool RISCVMCSymbolizer::tryAddingSymbolicOperand(
// GOT high relocations name the object stored in the GOT, not the GOT entry
// addressed by AUIPC. Preserve the actual entry address using a zero-based
// symbol, as the RISC-V emitter reuses the input GOT.
- if (Relocation::isGOT(Rel->Type)) {
- assert(Relocation::isPCRelative(Rel->Type) &&
+ if (RH.isGOT(Rel->Type)) {
+ assert(RH.isPCRelative(Rel->Type) &&
"GOT relocation must be PC-relative on RISC-V");
Symbol = BC.registerNameAtAddress("__BOLT_got_zero", 0, 0, 0);
Addend = getGOTValue(*Rel) + InstAddress;
diff --git a/bolt/lib/Target/RISCV/RISCVRelocationHandler.cpp b/bolt/lib/Target/RISCV/RISCVRelocationHandler.cpp
new file mode 100644
index 0000000000000..e778a9d93bbec
--- /dev/null
+++ b/bolt/lib/Target/RISCV/RISCVRelocationHandler.cpp
@@ -0,0 +1,348 @@
+//===- RISCVRelocationHandler.cpp
+//-------------------------------------------------===//
+//
+// 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 RISCV relocation handler.
+//
+//===----------------------------------------------------------------------===//
+
+#include "bolt/Core/Relocation.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace bolt;
+
+namespace ELFReserved {
+enum {
+ R_RISCV_TPREL_I = 49,
+ R_RISCV_TPREL_S = 50,
+};
+} // namespace ELFReserved
+
+namespace {
+
+class RISCVRelocationHandler final : public RelocationHandler {
+ bool Is64Bit;
+
+public:
+ explicit RISCVRelocationHandler(bool Is64Bit) : Is64Bit(Is64Bit) {}
+
+ bool isSupported(uint32_t Type) const override;
+ size_t getSizeForType(uint32_t Type) const override;
+ bool skipRelocationType(uint32_t Type) const override;
+
+ uint64_t encodeValue(uint32_t Type, uint64_t Value,
+ uint64_t PC) const override;
+ bool canEncodeValue(uint32_t Type, uint64_t Value,
+ uint64_t PC) const override;
+ uint64_t extractValue(uint32_t Type, uint64_t Contents,
+ uint64_t PC) const override;
+
+ bool isGOT(uint32_t Type) const override;
+ bool isRelative(uint32_t Type) const override;
+ bool isIRelative(uint32_t Type) const override;
+ bool isTLS(uint32_t Type) const override;
+ bool isInstructionReference(uint32_t Type) const override;
+ bool isPCRelative(uint32_t Type) const override;
+
+ uint32_t getNone() const override;
+ uint32_t getPC32() const override;
+ uint32_t getPC64() const override;
+ uint32_t getAbs64() const override;
+ uint32_t getRelative() const override;
+
+ MCBinaryExpr::Opcode getComposeOpcodeFor(uint32_t Type) const override;
+ void printType(raw_ostream &OS, uint32_t Type) const override;
+};
+
+} // namespace
+
+bool RISCVRelocationHandler::isRelative(uint32_t Type) const {
+ return Type == ELF::R_RISCV_RELATIVE;
+}
+
+bool RISCVRelocationHandler::isIRelative(uint32_t Type) const {
+ if (!Is64Bit)
+ llvm_unreachable("not implemented");
+ return Type == ELF::R_RISCV_IRELATIVE;
+}
+
+bool RISCVRelocationHandler::isInstructionReference(uint32_t Type) const {
+ return Type == ELF::R_RISCV_PCREL_LO12_I || Type == ELF::R_RISCV_PCREL_LO12_S;
+}
+
+uint32_t RISCVRelocationHandler::getNone() const { return ELF::R_RISCV_NONE; }
+
+uint32_t RISCVRelocationHandler::getPC32() const {
+ return ELF::R_RISCV_32_PCREL;
+}
+
+uint32_t RISCVRelocationHandler::getPC64() const {
+ llvm_unreachable("not implemented");
+}
+
+uint32_t RISCVRelocationHandler::getAbs64() const { return ELF::R_RISCV_64; }
+
+uint32_t RISCVRelocationHandler::getRelative() const {
+ if (!Is64Bit)
+ llvm_unreachable("not implemented");
+ return ELF::R_RISCV_RELATIVE;
+}
+
+MCBinaryExpr::Opcode
+RISCVRelocationHandler::getComposeOpcodeFor(uint32_t Type) const {
+ switch (Type) {
+ default:
+ llvm_unreachable("not implemented");
+ case ELF::R_RISCV_ADD32:
+ return MCBinaryExpr::Add;
+ case ELF::R_RISCV_SUB32:
+ return MCBinaryExpr::Sub;
+ }
+}
+
+void RISCVRelocationHandler::printType(raw_ostream &OS, uint32_t Type) const {
+ OS << object::getELFRelocationTypeName(ELF::EM_RISCV, Type);
+}
+
+bool RISCVRelocationHandler::isSupported(uint32_t Type) const {
+ switch (Type) {
+ default:
+ return false;
+ case ELF::R_RISCV_JAL:
+ case ELF::R_RISCV_CALL:
+ case ELF::R_RISCV_CALL_PLT:
+ case ELF::R_RISCV_BRANCH:
+ case ELF::R_RISCV_RELAX:
+ case ELF::R_RISCV_GOT_HI20:
+ case ELF::R_RISCV_PCREL_HI20:
+ case ELF::R_RISCV_PCREL_LO12_I:
+ case ELF::R_RISCV_PCREL_LO12_S:
+ case ELF::R_RISCV_RVC_JUMP:
+ case ELF::R_RISCV_RVC_BRANCH:
+ case ELF::R_RISCV_ADD32:
+ case ELF::R_RISCV_SUB32:
+ case ELF::R_RISCV_HI20:
+ case ELF::R_RISCV_LO12_I:
+ case ELF::R_RISCV_LO12_S:
+ case ELF::R_RISCV_32:
+ case ELF::R_RISCV_64:
+ case ELF::R_RISCV_TLS_GOT_HI20:
+ case ELF::R_RISCV_TLS_GD_HI20:
+ case ELF::R_RISCV_TPREL_HI20:
+ case ELF::R_RISCV_TPREL_ADD:
+ case ELF::R_RISCV_TPREL_LO12_I:
+ case ELF::R_RISCV_TPREL_LO12_S:
+ case ELFReserved::R_RISCV_TPREL_I:
+ case ELFReserved::R_RISCV_TPREL_S:
+ return true;
+ }
+}
+
+size_t RISCVRelocationHandler::getSizeForType(uint32_t Type) const {
+ switch (Type) {
+ default:
+ errs() << object::getELFRelocationTypeName(ELF::EM_RISCV, Type) << '\n';
+ llvm_unreachable("unsupported relocation type");
+ case ELF::R_RISCV_RVC_JUMP:
+ case ELF::R_RISCV_RVC_BRANCH:
+ return 2;
+ case ELF::R_RISCV_JAL:
+ case ELF::R_RISCV_BRANCH:
+ case ELF::R_RISCV_PCREL_HI20:
+ case ELF::R_RISCV_PCREL_LO12_I:
+ case ELF::R_RISCV_PCREL_LO12_S:
+ case ELF::R_RISCV_32_PCREL:
+ case ELF::R_RISCV_ADD32:
+ case ELF::R_RISCV_SUB32:
+ case ELF::R_RISCV_HI20:
+ case ELF::R_RISCV_LO12_I:
+ case ELF::R_RISCV_LO12_S:
+ case ELF::R_RISCV_32:
+ return 4;
+ case ELF::R_RISCV_64:
+ case ELF::R_RISCV_CALL:
+ case ELF::R_RISCV_CALL_PLT:
+ case ELF::R_RISCV_GOT_HI20:
+ case ELF::R_RISCV_TLS_GOT_HI20:
+ case ELF::R_RISCV_TLS_GD_HI20:
+ // See extractValue for why this is necessary.
+ return 8;
+ }
+}
+
+bool RISCVRelocationHandler::skipRelocationType(uint32_t Type) const {
+ switch (Type) {
+ default:
+ return false;
+ case ELF::R_RISCV_NONE:
+ case ELF::R_RISCV_RELAX:
+ return true;
+ }
+}
+
+bool RISCVRelocationHandler::canEncodeValue(uint32_t Type, uint64_t Value,
+ uint64_t PC) const {
+ switch (Type) {
+ default:
+ llvm_unreachable("unsupported relocation");
+ case ELF::R_RISCV_32:
+ case ELF::R_RISCV_64:
+ return true;
+ }
+}
+
+uint64_t RISCVRelocationHandler::encodeValue(uint32_t Type, uint64_t Value,
+ uint64_t PC) const {
+ switch (Type) {
+ default:
+ llvm_unreachable("unsupported relocation");
+ case ELF::R_RISCV_32:
+ case ELF::R_RISCV_64:
+ break;
+ }
+ return Value;
+}
+
+static uint64_t extractUImmRISCV(uint32_t Contents) {
+ return SignExtend64<32>(Contents & 0xfffff000);
+}
+
+static uint64_t extractIImmRISCV(uint32_t Contents) {
+ return SignExtend64<12>(Contents >> 20);
+}
+
+static uint64_t extractSImmRISCV(uint32_t Contents) {
+ return SignExtend64<12>(((Contents >> 7) & 0x1f) | ((Contents >> 25) << 5));
+}
+
+static uint64_t extractJImmRISCV(uint32_t Contents) {
+ return SignExtend64<21>(
+ (((Contents >> 21) & 0x3ff) << 1) | (((Contents >> 20) & 0x1) << 11) |
+ (((Contents >> 12) & 0xff) << 12) | (((Contents >> 31) & 0x1) << 20));
+}
+
+static uint64_t extractBImmRISCV(uint32_t Contents) {
+ return SignExtend64<13>(
+ (((Contents >> 8) & 0xf) << 1) | (((Contents >> 25) & 0x3f) << 5) |
+ (((Contents >> 7) & 0x1) << 11) | (((Contents >> 31) & 0x1) << 12));
+}
+
+uint64_t RISCVRelocationHandler::extractValue(uint32_t Type, uint64_t Contents,
+ uint64_t PC) const {
+ 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:
+ // The psABI "Relocations" chapter's "Procedure Calls" section defines
+ // R_RISCV_CALL and R_RISCV_CALL_PLT over an AUIPC/JALR pair. Decode both
+ // instructions so the addend includes the low 12 bits carried by JALR.
+ return extractUImmRISCV(Contents & 0xffffffff) +
+ extractIImmRISCV(Contents >> 32);
+ case ELF::R_RISCV_BRANCH:
+ return extractBImmRISCV(Contents);
+ case ELF::R_RISCV_GOT_HI20:
+ case ELF::R_RISCV_TLS_GOT_HI20:
+ case ELF::R_RISCV_TLS_GD_HI20:
+ // We need to know the exact address of the GOT entry so we extract the
+ // value from both the AUIPC and L[D|W]. We cannot rely on the symbol in the
+ // relocation for this since it simply refers to the object that is stored
+ // in the GOT entry, not to the entry itself.
+ return extractUImmRISCV(Contents & 0xffffffff) +
+ extractIImmRISCV(Contents >> 32);
+ case ELF::R_RISCV_PCREL_HI20:
+ case ELF::R_RISCV_HI20:
+ return extractUImmRISCV(Contents);
+ case ELF::R_RISCV_PCREL_LO12_I:
+ case ELF::R_RISCV_LO12_I:
+ return extractIImmRISCV(Contents);
+ case ELF::R_RISCV_PCREL_LO12_S:
+ case ELF::R_RISCV_LO12_S:
+ return extractSImmRISCV(Contents);
+ case ELF::R_RISCV_RVC_JUMP:
+ return SignExtend64<11>(Contents >> 2);
+ case ELF::R_RISCV_RVC_BRANCH:
+ return SignExtend64<8>(((Contents >> 2) & 0x1f) | ((Contents >> 5) & 0xe0));
+ case ELF::R_RISCV_ADD32:
+ case ELF::R_RISCV_SUB32:
+ case ELF::R_RISCV_32:
+ case ELF::R_RISCV_64:
+ return Contents;
+ }
+}
+
+bool RISCVRelocationHandler::isGOT(uint32_t Type) const {
+ switch (Type) {
+ default:
+ return false;
+ case ELF::R_RISCV_GOT_HI20:
+ case ELF::R_RISCV_TLS_GOT_HI20:
+ case ELF::R_RISCV_TLS_GD_HI20:
+ return true;
+ }
+}
+
+bool RISCVRelocationHandler::isTLS(uint32_t Type) const {
+ switch (Type) {
+ default:
+ return false;
+ case ELF::R_RISCV_TLS_GOT_HI20:
+ case ELF::R_RISCV_TLS_GD_HI20:
+ case ELF::R_RISCV_TPREL_HI20:
+ case ELF::R_RISCV_TPREL_ADD:
+ case ELF::R_RISCV_TPREL_LO12_I:
+ case ELF::R_RISCV_TPREL_LO12_S:
+ case ELFReserved::R_RISCV_TPREL_I:
+ case ELFReserved::R_RISCV_TPREL_S:
+ return true;
+ }
+}
+
+bool RISCVRelocationHandler::isPCRelative(uint32_t Type) const {
+ switch (Type) {
+ default:
+ llvm_unreachable("Unknown relocation type");
+ case ELF::R_RISCV_ADD32:
+ case ELF::R_RISCV_SUB32:
+ case ELF::R_RISCV_HI20:
+ case ELF::R_RISCV_LO12_I:
+ case ELF::R_RISCV_LO12_S:
+ case ELF::R_RISCV_32:
+ case ELF::R_RISCV_64:
+ return false;
+ case ELF::R_RISCV_JAL:
+ case ELF::R_RISCV_CALL:
+ case ELF::R_RISCV_CALL_PLT:
+ case ELF::R_RISCV_BRANCH:
+ case ELF::R_RISCV_GOT_HI20:
+ case ELF::R_RISCV_PCREL_HI20:
+ case ELF::R_RISCV_PCREL_LO12_I:
+ case ELF::R_RISCV_PCREL_LO12_S:
+ case ELF::R_RISCV_RVC_JUMP:
+ case ELF::R_RISCV_RVC_BRANCH:
+ case ELF::R_RISCV_32_PCREL:
+ case ELF::R_RISCV_TLS_GOT_HI20:
+ case ELF::R_RISCV_TLS_GD_HI20:
+ return true;
+ }
+}
+
+namespace llvm::bolt {
+
+std::unique_ptr<RelocationHandler> createRISCVRelocationHandler(bool Is64Bit) {
+ return std::make_unique<RISCVRelocationHandler>(Is64Bit);
+}
+
+} // namespace llvm::bolt
diff --git a/bolt/lib/Target/X86/CMakeLists.txt b/bolt/lib/Target/X86/CMakeLists.txt
index 0da4713b191aa..bdf8ff317253a 100644
--- a/bolt/lib/Target/X86/CMakeLists.txt
+++ b/bolt/lib/Target/X86/CMakeLists.txt
@@ -21,6 +21,9 @@ add_llvm_library(LLVMBOLTTargetX86
X86MCPlusBuilder.cpp
X86MCSymbolizer.cpp
+ # X86RelocationHandler.cpp is part of LLVMBOLTCore to avoid a circular
+ # dependency between the core relocation factory and LLVMBOLTTargetX86.
+ PARTIAL_SOURCES_INTENDED
NO_EXPORT
DISABLE_LLVM_LINK_LLVM_DYLIB
diff --git a/bolt/lib/Target/X86/X86MCSymbolizer.cpp b/bolt/lib/Target/X86/X86MCSymbolizer.cpp
index 0e0ad9270550c..41e5eb9a495da 100644
--- a/bolt/lib/Target/X86/X86MCSymbolizer.cpp
+++ b/bolt/lib/Target/X86/X86MCSymbolizer.cpp
@@ -12,6 +12,7 @@
#include "bolt/Core/BinaryFunction.h"
#include "bolt/Core/MCPlusBuilder.h"
#include "bolt/Core/Relocation.h"
+#include "llvm/BinaryFormat/ELF.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCRegisterInfo.h"
@@ -20,6 +21,12 @@
namespace llvm {
namespace bolt {
+static bool isGOTPCRELX(uint32_t Type) {
+ return Type == ELF::R_X86_64_GOTPCRELX || Type == ELF::R_X86_64_REX_GOTPCRELX;
+}
+
+static bool isGOTPC64(uint32_t Type) { return Type == ELF::R_X86_64_GOTPC64; }
+
X86MCSymbolizer::~X86MCSymbolizer() {}
bool X86MCSymbolizer::tryAddingSymbolicOperand(
@@ -97,7 +104,7 @@ bool X86MCSymbolizer::tryAddingSymbolicOperand(
const uint64_t InstOffset = InstAddress - Function.getAddress();
const Relocation *Relocation =
Function.getRelocationInRange(InstOffset, InstOffset + InstSize);
- if (Relocation && Relocation::isX86GOTPCRELX(Relocation->Type)) {
+ if (Relocation && isGOTPCRELX(Relocation->Type)) {
// If the operand is PC-relative, convert it without using the relocation
// information. For GOTPCRELX, it is safe to use the absolute address
// instead of extracting the addend from the relocation, as non-standard
@@ -133,7 +140,7 @@ bool X86MCSymbolizer::tryAddingSymbolicOperand(
// GOTPC64 is special because the X86 Assembler doesn't know how to emit
// a PC-relative 8-byte fixup, which is what we need to cover this. The
// only way to do this is to use the symbol name _GLOBAL_OFFSET_TABLE_.
- if (Relocation::isX86GOTPC64(Relocation->Type)) {
+ if (isGOTPC64(Relocation->Type)) {
auto PairOrErr = handleGOTPC64(*Relocation, InstAddress);
if (auto E = PairOrErr.takeError()) {
Function.setSimple(false);
@@ -145,18 +152,20 @@ bool X86MCSymbolizer::tryAddingSymbolicOperand(
return true;
}
+ const bool IsPCRelative =
+ BC.getRelocationHandler().isPCRelative(Relocation->Type);
uint64_t SymbolValue = Relocation->Value - Relocation->Addend;
- if (Relocation->isPCRelative())
+ if (IsPCRelative)
SymbolValue += InstAddress + ImmOffset;
// Process reference to the symbol.
if (CreateNewSymbols)
- BC.handleAddressRef(SymbolValue, Function, Relocation->isPCRelative());
+ BC.handleAddressRef(SymbolValue, Function, IsPCRelative);
uint64_t Addend = Relocation->Addend;
// Real addend for pc-relative targets is adjusted with a delta from
// the relocation placement to the next instruction.
- if (Relocation->isPCRelative())
+ if (IsPCRelative)
Addend += InstOffset + InstSize - Relocation->Offset;
addOperand(Relocation->Symbol, Addend);
diff --git a/bolt/lib/Target/X86/X86RelocationHandler.cpp b/bolt/lib/Target/X86/X86RelocationHandler.cpp
new file mode 100644
index 0000000000000..4895bfd4fd449
--- /dev/null
+++ b/bolt/lib/Target/X86/X86RelocationHandler.cpp
@@ -0,0 +1,224 @@
+//===- X86RelocationHandler.cpp
+//---------------------------------------------------===//
+//
+// 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 X86 relocation handler.
+//
+//===----------------------------------------------------------------------===//
+
+#include "bolt/Core/Relocation.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace bolt;
+
+namespace {
+
+class X86RelocationHandler final : public RelocationHandler {
+public:
+ bool isSupported(uint32_t Type) const override;
+ size_t getSizeForType(uint32_t Type) const override;
+ bool skipRelocationType(uint32_t Type) const override;
+
+ uint64_t encodeValue(uint32_t Type, uint64_t Value,
+ uint64_t PC) const override;
+ bool canEncodeValue(uint32_t Type, uint64_t Value,
+ uint64_t PC) const override;
+ uint64_t extractValue(uint32_t Type, uint64_t Contents,
+ uint64_t PC) const override;
+
+ bool isGOT(uint32_t Type) const override;
+ bool isRelative(uint32_t Type) const override;
+ bool isIRelative(uint32_t Type) const override;
+ bool isTLS(uint32_t Type) const override;
+ bool isPCRelative(uint32_t Type) const override;
+
+ uint32_t getNone() const override;
+ uint32_t getPC32() const override;
+ uint32_t getPC64() const override;
+ uint32_t getAbs64() const override;
+ uint32_t getRelative() const override;
+
+ void printType(raw_ostream &OS, uint32_t Type) const override;
+};
+
+} // namespace
+
+bool X86RelocationHandler::canEncodeValue(uint32_t, uint64_t, uint64_t) const {
+ return true;
+}
+
+bool X86RelocationHandler::isRelative(uint32_t Type) const {
+ return Type == ELF::R_X86_64_RELATIVE;
+}
+
+bool X86RelocationHandler::isIRelative(uint32_t Type) const {
+ return Type == ELF::R_X86_64_IRELATIVE;
+}
+
+uint32_t X86RelocationHandler::getNone() const { return ELF::R_X86_64_NONE; }
+
+uint32_t X86RelocationHandler::getPC32() const { return ELF::R_X86_64_PC32; }
+
+uint32_t X86RelocationHandler::getPC64() const { return ELF::R_X86_64_PC64; }
+
+uint32_t X86RelocationHandler::getAbs64() const { return ELF::R_X86_64_64; }
+
+uint32_t X86RelocationHandler::getRelative() const {
+ return ELF::R_X86_64_RELATIVE;
+}
+
+void X86RelocationHandler::printType(raw_ostream &OS, uint32_t Type) const {
+ OS << object::getELFRelocationTypeName(ELF::EM_X86_64, Type);
+}
+
+bool X86RelocationHandler::isSupported(uint32_t Type) const {
+ switch (Type) {
+ default:
+ return false;
+ case ELF::R_X86_64_8:
+ case ELF::R_X86_64_16:
+ case ELF::R_X86_64_32:
+ case ELF::R_X86_64_32S:
+ case ELF::R_X86_64_64:
+ case ELF::R_X86_64_PC8:
+ case ELF::R_X86_64_PC32:
+ case ELF::R_X86_64_PC64:
+ case ELF::R_X86_64_PLT32:
+ case ELF::R_X86_64_GOTPC64:
+ case ELF::R_X86_64_GOTPCREL:
+ case ELF::R_X86_64_GOTTPOFF:
+ case ELF::R_X86_64_TPOFF32:
+ case ELF::R_X86_64_GOTPCRELX:
+ case ELF::R_X86_64_REX_GOTPCRELX:
+ return true;
+ }
+}
+
+size_t X86RelocationHandler::getSizeForType(uint32_t Type) const {
+ switch (Type) {
+ default:
+ errs() << object::getELFRelocationTypeName(ELF::EM_X86_64, Type) << '\n';
+ llvm_unreachable("unsupported relocation type");
+ case ELF::R_X86_64_8:
+ case ELF::R_X86_64_PC8:
+ return 1;
+ case ELF::R_X86_64_16:
+ return 2;
+ case ELF::R_X86_64_PLT32:
+ case ELF::R_X86_64_PC32:
+ case ELF::R_X86_64_32S:
+ case ELF::R_X86_64_32:
+ case ELF::R_X86_64_GOTPCREL:
+ case ELF::R_X86_64_GOTTPOFF:
+ case ELF::R_X86_64_TPOFF32:
+ case ELF::R_X86_64_GOTPCRELX:
+ case ELF::R_X86_64_REX_GOTPCRELX:
+ return 4;
+ case ELF::R_X86_64_PC64:
+ case ELF::R_X86_64_64:
+ case ELF::R_X86_64_GOTPC64:
+ return 8;
+ }
+}
+
+bool X86RelocationHandler::skipRelocationType(uint32_t Type) const {
+ return Type == ELF::R_X86_64_NONE;
+}
+
+uint64_t X86RelocationHandler::encodeValue(uint32_t Type, uint64_t Value,
+ uint64_t PC) const {
+ switch (Type) {
+ default:
+ llvm_unreachable("unsupported relocation");
+ case ELF::R_X86_64_64:
+ case ELF::R_X86_64_32:
+ break;
+ case ELF::R_X86_64_PC32:
+ Value -= PC;
+ break;
+ }
+ return Value;
+}
+
+uint64_t X86RelocationHandler::extractValue(uint32_t Type, uint64_t Contents,
+ uint64_t PC) const {
+ if (Type == ELF::R_X86_64_32S)
+ return SignExtend64<32>(Contents);
+ if (isPCRelative(Type))
+ return SignExtend64(Contents, 8 * getSizeForType(Type));
+ return Contents;
+}
+
+bool X86RelocationHandler::isGOT(uint32_t Type) const {
+ 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 X86RelocationHandler::isTLS(uint32_t Type) const {
+ 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 X86RelocationHandler::isPCRelative(uint32_t Type) const {
+ switch (Type) {
+ default:
+ llvm_unreachable("Unknown relocation type");
+ case ELF::R_X86_64_64:
+ case ELF::R_X86_64_32:
+ case ELF::R_X86_64_32S:
+ case ELF::R_X86_64_16:
+ case ELF::R_X86_64_8:
+ case ELF::R_X86_64_TPOFF32:
+ return false;
+ case ELF::R_X86_64_PC8:
+ case ELF::R_X86_64_PC32:
+ case ELF::R_X86_64_PC64:
+ case ELF::R_X86_64_GOTPCREL:
+ case ELF::R_X86_64_PLT32:
+ case ELF::R_X86_64_GOTOFF64:
+ case ELF::R_X86_64_GOTPC32:
+ case ELF::R_X86_64_GOTPC64:
+ case ELF::R_X86_64_GOTTPOFF:
+ case ELF::R_X86_64_GOTPCRELX:
+ case ELF::R_X86_64_REX_GOTPCRELX:
+ return true;
+ }
+}
+
+namespace llvm::bolt {
+
+std::unique_ptr<RelocationHandler> createX86RelocationHandler() {
+ return std::make_unique<X86RelocationHandler>();
+}
+
+} // namespace llvm::bolt
diff --git a/bolt/unittests/Core/BinaryContext.cpp b/bolt/unittests/Core/BinaryContext.cpp
index f48eba1b74405..a8c00a3bb24b6 100644
--- a/bolt/unittests/Core/BinaryContext.cpp
+++ b/bolt/unittests/Core/BinaryContext.cpp
@@ -53,7 +53,6 @@ struct BinaryContextTester : public testing::TestWithParam<Triple::ArchType> {
void initializeBOLT() {
const Triple TheTriple = GetParam();
- Relocation::Arch = TheTriple.getArch();
// Minimal test ELFs have no RISC-V attributes. RISC-V needs an empty
// feature set for +relax, while other targets reject a non-null one.
SubtargetFeatures Features;
@@ -68,6 +67,20 @@ struct BinaryContextTester : public testing::TestWithParam<Triple::ArchType> {
std::unique_ptr<ObjectFile> ObjFile;
std::unique_ptr<BinaryContext> BC;
};
+
+TEST(RelocationHandlerTest, ArchitectureStateIsIndependent) {
+ std::unique_ptr<RelocationHandler> X86Handler =
+ createRelocationHandler(Triple::x86_64);
+ std::unique_ptr<RelocationHandler> AArch64Handler =
+ createRelocationHandler(Triple::aarch64);
+
+ EXPECT_EQ(X86Handler->getPC32(), ELF::R_X86_64_PC32);
+ EXPECT_EQ(AArch64Handler->getPC32(), ELF::R_AARCH64_PREL32);
+ EXPECT_TRUE(X86Handler->isSupported(ELF::R_X86_64_PC32));
+ EXPECT_FALSE(X86Handler->isSupported(ELF::R_AARCH64_CALL26));
+ EXPECT_TRUE(AArch64Handler->isSupported(ELF::R_AARCH64_CALL26));
+ EXPECT_FALSE(AArch64Handler->isSupported(ELF::R_X86_64_PC32));
+}
} // namespace
#ifdef X86_AVAILABLE
@@ -93,7 +106,7 @@ TEST_P(BinaryContextTester, FlushPendingRelocCALL26) {
if (GetParam() != Triple::aarch64)
GTEST_SKIP();
- // This test checks that encodeValueAArch64 used by flushPendingRelocations
+ // This test checks that AArch64 encodeValue used by flushPendingRelocations
// returns correctly encoded values for CALL26 relocation for both backward
// and forward branches.
//
@@ -140,7 +153,7 @@ TEST_P(BinaryContextTester, FlushPendingRelocJUMP26) {
if (GetParam() != Triple::aarch64)
GTEST_SKIP();
- // This test checks that encodeValueAArch64 used by flushPendingRelocations
+ // This test checks that AArch64 encodeValue used by flushPendingRelocations
// returns correctly encoded values for R_AARCH64_JUMP26 relocation for both
// backward and forward branches.
//
diff --git a/bolt/unittests/Core/CMakeLists.txt b/bolt/unittests/Core/CMakeLists.txt
index 6b9b73bd16052..477562b2eef1d 100644
--- a/bolt/unittests/Core/CMakeLists.txt
+++ b/bolt/unittests/Core/CMakeLists.txt
@@ -13,6 +13,7 @@ add_bolt_unittest(CoreTests
MCPlusBuilder.cpp
MemoryMaps.cpp
DynoStats.cpp
+ Relocation.cpp
# FIXME CoreTests uses `llvm::detail::TakeError(llvm::Error)`, but linking
# to LLVMTestingSupport introduces a transitive dependency on the
diff --git a/bolt/unittests/Core/MCPlusBuilder.cpp b/bolt/unittests/Core/MCPlusBuilder.cpp
index 6cd25644d378f..606de9fde80f4 100644
--- a/bolt/unittests/Core/MCPlusBuilder.cpp
+++ b/bolt/unittests/Core/MCPlusBuilder.cpp
@@ -82,7 +82,6 @@ struct MCPlusBuilderTester : public testing::TestWithParam<Triple::ArchType> {
void initializeBolt() {
const Triple TheTriple = GetParam();
- Relocation::Arch = TheTriple.getArch();
// Minimal test ELFs have no RISC-V attributes. RISC-V needs an empty
// feature set for +relax, while other targets reject a non-null one.
SubtargetFeatures Features;
diff --git a/bolt/unittests/Core/MemoryMaps.cpp b/bolt/unittests/Core/MemoryMaps.cpp
index 0bbd98c36c06e..c725bb88bb10b 100644
--- a/bolt/unittests/Core/MemoryMaps.cpp
+++ b/bolt/unittests/Core/MemoryMaps.cpp
@@ -62,7 +62,6 @@ struct MemoryMapsTester : public testing::TestWithParam<Triple::ArchType> {
void initializeBOLT() {
const Triple TheTriple = GetParam();
- Relocation::Arch = TheTriple.getArch();
// Minimal test ELFs have no RISC-V attributes. RISC-V needs an empty
// feature set for +relax, while other targets reject a non-null one.
SubtargetFeatures Features;
diff --git a/bolt/unittests/Core/Relocation.cpp b/bolt/unittests/Core/Relocation.cpp
new file mode 100644
index 0000000000000..93695aae8a913
--- /dev/null
+++ b/bolt/unittests/Core/Relocation.cpp
@@ -0,0 +1,75 @@
+//===- bolt/unittest/Core/Relocation.cpp ----------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "bolt/Core/Relocation.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/TargetParser/Triple.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::bolt;
+
+#ifdef AARCH64_AVAILABLE
+
+namespace {
+
+TEST(AArch64RelocationHandlerTest, ClassificationAndSize) {
+ std::unique_ptr<RelocationHandler> Handler =
+ createRelocationHandler(Triple::aarch64);
+
+ EXPECT_TRUE(Handler->isSupported(ELF::R_AARCH64_CALL26));
+ EXPECT_TRUE(Handler->isSupported(ELF::R_AARCH64_PREL32));
+ EXPECT_FALSE(Handler->isSupported(ELF::R_AARCH64_NONE));
+
+ EXPECT_EQ(Handler->getSizeForType(ELF::R_AARCH64_CALL26), 4u);
+ EXPECT_EQ(Handler->getSizeForType(ELF::R_AARCH64_PREL32), 4u);
+ EXPECT_EQ(Handler->getSizeForType(ELF::R_AARCH64_ABS64), 8u);
+
+ EXPECT_TRUE(Handler->isPCRelative(ELF::R_AARCH64_CALL26));
+ EXPECT_TRUE(Handler->isPCRelative(ELF::R_AARCH64_PREL32));
+ EXPECT_FALSE(Handler->isPCRelative(ELF::R_AARCH64_ABS64));
+}
+
+TEST(AArch64RelocationHandlerTest, EncodeAndExtractCall26) {
+ std::unique_ptr<RelocationHandler> Handler =
+ createRelocationHandler(Triple::aarch64);
+ constexpr uint64_t PC = 0x1000;
+ constexpr uint64_t Target = 0x1100;
+
+ const uint64_t Encoded =
+ Handler->encodeValue(ELF::R_AARCH64_CALL26, Target, PC);
+ EXPECT_EQ(Encoded, 0x94000040u);
+ EXPECT_EQ(Handler->extractValue(ELF::R_AARCH64_CALL26, Encoded, PC), Target);
+}
+
+TEST(AArch64RelocationHandlerTest, EncodeAndExtractPrel32) {
+ std::unique_ptr<RelocationHandler> Handler =
+ createRelocationHandler(Triple::aarch64);
+ constexpr uint64_t PC = 0x1000;
+ constexpr uint64_t Target = 0xf00;
+
+ const uint64_t Encoded =
+ Handler->encodeValue(ELF::R_AARCH64_PREL32, Target, PC);
+ EXPECT_EQ(Encoded, static_cast<uint64_t>(-0x100));
+ EXPECT_EQ(Handler->extractValue(ELF::R_AARCH64_PREL32, Encoded, PC), Target);
+}
+
+TEST(AArch64RelocationHandlerTest, Call26EncodingRange) {
+ std::unique_ptr<RelocationHandler> Handler =
+ createRelocationHandler(Triple::aarch64);
+ constexpr uint64_t PC = 0x1000;
+ constexpr uint64_t Range = uint64_t{1} << 27;
+
+ EXPECT_TRUE(
+ Handler->canEncodeValue(ELF::R_AARCH64_CALL26, PC + Range - 4, PC));
+ EXPECT_FALSE(Handler->canEncodeValue(ELF::R_AARCH64_CALL26, PC + Range, PC));
+}
+
+} // namespace
+
+#endif
diff --git a/bolt/unittests/Passes/LivenessAnalysis.cpp b/bolt/unittests/Passes/LivenessAnalysis.cpp
index 7ddf683a855ec..8ef3504a9c45b 100644
--- a/bolt/unittests/Passes/LivenessAnalysis.cpp
+++ b/bolt/unittests/Passes/LivenessAnalysis.cpp
@@ -65,7 +65,6 @@ struct LivenessAnalysisTester
}
void initializeBolt() {
- Relocation::Arch = ObjFile->makeTriple().getArch();
BC = cantFail(BinaryContext::createBinaryContext(
ObjFile->makeTriple(), std::make_shared<orc::SymbolStringPool>(),
ObjFile->getFileName(), nullptr, true, DWARFContext::create(*ObjFile),
diff --git a/bolt/unittests/Passes/PointerAuthCFIFixup.cpp b/bolt/unittests/Passes/PointerAuthCFIFixup.cpp
index 89896d0ce3fdc..33286d2551c34 100644
--- a/bolt/unittests/Passes/PointerAuthCFIFixup.cpp
+++ b/bolt/unittests/Passes/PointerAuthCFIFixup.cpp
@@ -77,7 +77,6 @@ struct PassTester : public testing::TestWithParam<Triple::ArchType> {
ObjFile = cantFail(ObjectFile::createObjectFile(Source));
}
void initializeBolt() {
- Relocation::Arch = ObjFile->makeTriple().getArch();
BC = cantFail(BinaryContext::createBinaryContext(
ObjFile->makeTriple(), std::make_shared<orc::SymbolStringPool>(),
ObjFile->getFileName(), nullptr, true, DWARFContext::create(*ObjFile),
diff --git a/bolt/unittests/Profile/DataAggregator.cpp b/bolt/unittests/Profile/DataAggregator.cpp
index e5e4611a639c9..5d5ad98dc02a2 100644
--- a/bolt/unittests/Profile/DataAggregator.cpp
+++ b/bolt/unittests/Profile/DataAggregator.cpp
@@ -70,7 +70,6 @@ struct PreAggregatedTestHelper : public testing::Test {
MemoryBufferRef Source(StringRef(ElfBuf, sizeof(ElfBuf)), "ELF");
ObjFile = cantFail(ObjectFile::createObjectFile(Source));
- Relocation::Arch = ObjFile->makeTriple().getArch();
BC = cantFail(BinaryContext::createBinaryContext(
ObjFile->makeTriple(), std::make_shared<orc::SymbolStringPool>(),
ObjFile->getFileName(), nullptr, /*IsPIC*/ false,
diff --git a/bolt/unittests/Profile/PerfScripts.cpp b/bolt/unittests/Profile/PerfScripts.cpp
index c430460a08827..a429b494562a8 100644
--- a/bolt/unittests/Profile/PerfScripts.cpp
+++ b/bolt/unittests/Profile/PerfScripts.cpp
@@ -64,7 +64,6 @@ struct PerfScriptTestHelper : public testing::TestWithParam<Triple::ArchType> {
void initializeBOLT() {
const Triple TheTriple = GetParam();
- Relocation::Arch = TheTriple.getArch();
// Minimal test ELFs have no RISC-V attributes. RISC-V needs an empty
// feature set for +relax, while other targets reject a non-null one.
SubtargetFeatures Features;
diff --git a/bolt/unittests/Profile/PerfSpeEvents.cpp b/bolt/unittests/Profile/PerfSpeEvents.cpp
index 556b49619386b..5f3ecb4618858 100644
--- a/bolt/unittests/Profile/PerfSpeEvents.cpp
+++ b/bolt/unittests/Profile/PerfSpeEvents.cpp
@@ -61,7 +61,6 @@ struct PerfSpeEventsTestHelper : public testing::Test {
}
void initializeBOLT() {
- Relocation::Arch = ObjFile->makeTriple().getArch();
BC = cantFail(BinaryContext::createBinaryContext(
ObjFile->makeTriple(), std::make_shared<orc::SymbolStringPool>(),
ObjFile->getFileName(), nullptr, /*IsPIC*/ false,
>From 4cb799227ee9b809d41eb8c344809b0e0d80f1d0 Mon Sep 17 00:00:00 2001
From: Maksim <rachinskii.mv at phystech.edu>
Date: Sun, 20 Sep 2026 23:42:22 +0300
Subject: [PATCH 2/2] [BOLT] Review feedback
---
bolt/include/bolt/Core/BinaryContext.h | 15 ++--
bolt/include/bolt/Core/Relocation.h | 7 +-
bolt/include/bolt/Rewrite/RewriteInstance.h | 3 +
.../Target/AArch64/AArch64RelocationHandler.h | 24 ++++++
.../Target/RISCV/RISCVRelocationHandler.h | 24 ++++++
.../bolt/Target/X86/X86RelocationHandler.h | 24 ++++++
bolt/lib/Core/BinaryContext.cpp | 14 ++--
bolt/lib/Core/CMakeLists.txt | 3 -
bolt/lib/Core/Relocation.cpp | 22 -----
bolt/lib/Rewrite/MachORewriteInstance.cpp | 2 +
bolt/lib/Rewrite/RewriteInstance.cpp | 40 ++++++++-
.../AArch64/AArch64RelocationHandler.cpp | 4 +-
bolt/lib/Target/AArch64/CMakeLists.txt | 4 +-
bolt/lib/Target/RISCV/CMakeLists.txt | 4 +-
.../Target/RISCV/RISCVRelocationHandler.cpp | 4 +-
bolt/lib/Target/X86/CMakeLists.txt | 4 +-
bolt/lib/Target/X86/X86RelocationHandler.cpp | 4 +-
bolt/unittests/Core/BinaryContext.cpp | 47 ++++++++++-
bolt/unittests/Core/Relocation.cpp | 82 +++++++++++++++++--
19 files changed, 256 insertions(+), 75 deletions(-)
create mode 100644 bolt/include/bolt/Target/AArch64/AArch64RelocationHandler.h
create mode 100644 bolt/include/bolt/Target/RISCV/RISCVRelocationHandler.h
create mode 100644 bolt/include/bolt/Target/X86/X86RelocationHandler.h
diff --git a/bolt/include/bolt/Core/BinaryContext.h b/bolt/include/bolt/Core/BinaryContext.h
index 38aaa128f96a4..94f7a58fdeb8e 100644
--- a/bolt/include/bolt/Core/BinaryContext.h
+++ b/bolt/include/bolt/Core/BinaryContext.h
@@ -320,6 +320,13 @@ class BinaryContext {
MIB = std::move(TargetBuilder);
}
+ /// Set up target-specific relocation handling.
+ void initializeRelocationHandler(std::unique_ptr<RelocationHandler> Handler) {
+ assert(Handler && "expected a relocation handler");
+ assert(!RelocHandler && "relocation handler is already initialized");
+ RelocHandler = std::move(Handler);
+ }
+
/// Return function fragments to skip.
const std::unordered_set<BinaryFunction *> &getFragmentsToSkip() {
return FragmentsToSkip;
@@ -729,11 +736,6 @@ class BinaryContext {
std::unique_ptr<DWARFContext> DwCtx;
std::unique_ptr<Triple> TheTriple;
-
-private:
- std::unique_ptr<RelocationHandler> RelocHandler;
-
-public:
std::shared_ptr<orc::SymbolStringPool> SSP;
const Target *TheTarget;
@@ -756,6 +758,8 @@ class BinaryContext {
std::unique_ptr<MCPlusBuilder> MIB;
+ std::unique_ptr<RelocationHandler> RelocHandler;
+
std::unique_ptr<const MCRegisterInfo> MRI;
std::unique_ptr<MCDisassembler> DisAsm;
@@ -992,6 +996,7 @@ class BinaryContext {
bool isMachO() const { return TheTriple->isOSBinFormatMachO(); }
const RelocationHandler &getRelocationHandler() const {
+ assert(RelocHandler && "relocation handler is not initialized");
return *RelocHandler;
}
diff --git a/bolt/include/bolt/Core/Relocation.h b/bolt/include/bolt/Core/Relocation.h
index 897bb0758a007..19448bed8d485 100644
--- a/bolt/include/bolt/Core/Relocation.h
+++ b/bolt/include/bolt/Core/Relocation.h
@@ -16,8 +16,6 @@
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCStreamer.h"
-#include "llvm/TargetParser/Triple.h"
-#include <memory>
namespace llvm {
class MCSymbol;
@@ -105,9 +103,6 @@ class RelocationHandler {
virtual void printType(raw_ostream &OS, uint32_t Type) const = 0;
};
-std::unique_ptr<RelocationHandler>
-createRelocationHandler(Triple::ArchType Arch);
-
/// Relocation class.
class Relocation {
public:
@@ -171,11 +166,11 @@ class Relocation {
bool isRELR() const { return IsRELR; }
- /// Return size of this relocation.
/// Return the relocation type of \p Rel from llvm::object. It checks for
/// overflows as BOLT uses 32 bits for the type.
static uint32_t getType(const object::RelocationRef &Rel);
+ /// Return size of this relocation.
size_t getSize(const RelocationHandler &RH) const {
return RH.getSizeForType(Type);
}
diff --git a/bolt/include/bolt/Rewrite/RewriteInstance.h b/bolt/include/bolt/Rewrite/RewriteInstance.h
index 4a253f579c6c2..551c0341b9946 100644
--- a/bolt/include/bolt/Rewrite/RewriteInstance.h
+++ b/bolt/include/bolt/Rewrite/RewriteInstance.h
@@ -657,6 +657,9 @@ MCPlusBuilder *createMCPlusBuilder(const Triple::ArchType Arch,
const MCRegisterInfo *RegInfo,
const MCSubtargetInfo *STI);
+std::unique_ptr<RelocationHandler>
+createRelocationHandler(Triple::ArchType Arch);
+
} // namespace bolt
} // namespace llvm
diff --git a/bolt/include/bolt/Target/AArch64/AArch64RelocationHandler.h b/bolt/include/bolt/Target/AArch64/AArch64RelocationHandler.h
new file mode 100644
index 0000000000000..8ad33e5e74d41
--- /dev/null
+++ b/bolt/include/bolt/Target/AArch64/AArch64RelocationHandler.h
@@ -0,0 +1,24 @@
+//===- AArch64RelocationHandler.h ------------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef BOLT_TARGET_AARCH64_AARCH64RELOCATIONHANDLER_H
+#define BOLT_TARGET_AARCH64_AARCH64RELOCATIONHANDLER_H
+
+#include <memory>
+
+namespace llvm {
+namespace bolt {
+
+class RelocationHandler;
+
+std::unique_ptr<RelocationHandler> createAArch64RelocationHandler();
+
+} // namespace bolt
+} // namespace llvm
+
+#endif
diff --git a/bolt/include/bolt/Target/RISCV/RISCVRelocationHandler.h b/bolt/include/bolt/Target/RISCV/RISCVRelocationHandler.h
new file mode 100644
index 0000000000000..0e68f6f09bc93
--- /dev/null
+++ b/bolt/include/bolt/Target/RISCV/RISCVRelocationHandler.h
@@ -0,0 +1,24 @@
+//===- RISCVRelocationHandler.h --------------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef BOLT_TARGET_RISCV_RISCVRELOCATIONHANDLER_H
+#define BOLT_TARGET_RISCV_RISCVRELOCATIONHANDLER_H
+
+#include <memory>
+
+namespace llvm {
+namespace bolt {
+
+class RelocationHandler;
+
+std::unique_ptr<RelocationHandler> createRISCVRelocationHandler(bool Is64Bit);
+
+} // namespace bolt
+} // namespace llvm
+
+#endif
diff --git a/bolt/include/bolt/Target/X86/X86RelocationHandler.h b/bolt/include/bolt/Target/X86/X86RelocationHandler.h
new file mode 100644
index 0000000000000..bf0d2b886fb07
--- /dev/null
+++ b/bolt/include/bolt/Target/X86/X86RelocationHandler.h
@@ -0,0 +1,24 @@
+//===- X86RelocationHandler.h ----------------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef BOLT_TARGET_X86_X86RELOCATIONHANDLER_H
+#define BOLT_TARGET_X86_X86RELOCATIONHANDLER_H
+
+#include <memory>
+
+namespace llvm {
+namespace bolt {
+
+class RelocationHandler;
+
+std::unique_ptr<RelocationHandler> createX86RelocationHandler();
+
+} // namespace bolt
+} // namespace llvm
+
+#endif
diff --git a/bolt/lib/Core/BinaryContext.cpp b/bolt/lib/Core/BinaryContext.cpp
index d77ecbdf3411b..ae320ab695af3 100644
--- a/bolt/lib/Core/BinaryContext.cpp
+++ b/bolt/lib/Core/BinaryContext.cpp
@@ -165,14 +165,12 @@ BinaryContext::BinaryContext(std::unique_ptr<MCContext> Ctx,
std::unique_ptr<MCDisassembler> DisAsm,
JournalingStreams Logger)
: Ctx(std::move(Ctx)), DwCtx(std::move(DwCtx)),
- TheTriple(std::move(TheTriple)),
- RelocHandler(createRelocationHandler(this->TheTriple->getArch())),
- SSP(std::move(SSP)), TheTarget(TheTarget), TripleName(TripleName),
- MCE(std::move(MCE)), MOFI(std::move(MOFI)), AsmInfo(std::move(AsmInfo)),
- MII(std::move(MII)), STI(std::move(STI)),
- InstPrinter(std::move(InstPrinter)), MIA(std::move(MIA)),
- MIB(std::move(MIB)), MRI(std::move(MRI)), DisAsm(std::move(DisAsm)),
- Logger(Logger), InitialDynoStats(isAArch64()) {
+ TheTriple(std::move(TheTriple)), SSP(std::move(SSP)),
+ TheTarget(TheTarget), TripleName(TripleName), MCE(std::move(MCE)),
+ MOFI(std::move(MOFI)), AsmInfo(std::move(AsmInfo)), MII(std::move(MII)),
+ STI(std::move(STI)), InstPrinter(std::move(InstPrinter)),
+ MIA(std::move(MIA)), MIB(std::move(MIB)), MRI(std::move(MRI)),
+ DisAsm(std::move(DisAsm)), Logger(Logger), InitialDynoStats(isAArch64()) {
RegularPageSize = isAArch64() ? RegularPageSizeAArch64 : RegularPageSizeX86;
PageAlign = opts::NoHugePages ? RegularPageSize : HugePageSize;
}
diff --git a/bolt/lib/Core/CMakeLists.txt b/bolt/lib/Core/CMakeLists.txt
index 0a967b94c86e7..430a1c93a9f0c 100644
--- a/bolt/lib/Core/CMakeLists.txt
+++ b/bolt/lib/Core/CMakeLists.txt
@@ -37,9 +37,6 @@ add_llvm_library(LLVMBOLTCore
MCPlusBuilder.cpp
ParallelUtilities.cpp
Relocation.cpp
- ../Target/AArch64/AArch64RelocationHandler.cpp
- ../Target/RISCV/RISCVRelocationHandler.cpp
- ../Target/X86/X86RelocationHandler.cpp
NO_EXPORT
DISABLE_LLVM_LINK_LLVM_DYLIB
diff --git a/bolt/lib/Core/Relocation.cpp b/bolt/lib/Core/Relocation.cpp
index ddf5e344b8ddc..f4722a7e96368 100644
--- a/bolt/lib/Core/Relocation.cpp
+++ b/bolt/lib/Core/Relocation.cpp
@@ -22,33 +22,11 @@
using namespace llvm;
using namespace bolt;
-namespace llvm::bolt {
-std::unique_ptr<RelocationHandler> createAArch64RelocationHandler();
-std::unique_ptr<RelocationHandler> createRISCVRelocationHandler(bool Is64Bit);
-std::unique_ptr<RelocationHandler> createX86RelocationHandler();
-} // namespace llvm::bolt
-
MCBinaryExpr::Opcode
RelocationHandler::getComposeOpcodeFor(uint32_t Type) const {
llvm_unreachable("composed relocations are unsupported for this target");
}
-std::unique_ptr<RelocationHandler>
-llvm::bolt::createRelocationHandler(Triple::ArchType Arch) {
- switch (Arch) {
- default:
- llvm_unreachable("Unsupported architecture");
- case Triple::aarch64:
- return createAArch64RelocationHandler();
- case Triple::riscv32:
- return createRISCVRelocationHandler(false);
- case Triple::riscv64:
- return createRISCVRelocationHandler(true);
- case Triple::x86_64:
- return createX86RelocationHandler();
- }
-}
-
uint32_t Relocation::getType(const object::RelocationRef &Rel) {
uint64_t RelType = Rel.getType();
assert(isUInt<32>(RelType) && "BOLT relocation types are 32 bits");
diff --git a/bolt/lib/Rewrite/MachORewriteInstance.cpp b/bolt/lib/Rewrite/MachORewriteInstance.cpp
index 6190d28ff2ad8..72597681ad530 100644
--- a/bolt/lib/Rewrite/MachORewriteInstance.cpp
+++ b/bolt/lib/Rewrite/MachORewriteInstance.cpp
@@ -81,6 +81,8 @@ MachORewriteInstance::MachORewriteInstance(object::MachOObjectFile *InputFile,
return;
}
BC = std::move(BCOrErr.get());
+ BC->initializeRelocationHandler(
+ createRelocationHandler(BC->TheTriple->getArch()));
BC->initializeTarget(std::unique_ptr<MCPlusBuilder>(
createMCPlusBuilder(BC->TheTriple->getArch(), BC->MIA.get(),
BC->MII.get(), BC->MRI.get(), BC->STI.get())));
diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index da6293f331275..afa87ac99e80f 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -34,6 +34,15 @@
#include "bolt/Rewrite/MetadataRewriters.h"
#include "bolt/RuntimeLibs/HugifyRuntimeLibrary.h"
#include "bolt/RuntimeLibs/InstrumentationRuntimeLibrary.h"
+#ifdef AARCH64_AVAILABLE
+#include "bolt/Target/AArch64/AArch64RelocationHandler.h"
+#endif
+#ifdef RISCV_AVAILABLE
+#include "bolt/Target/RISCV/RISCVRelocationHandler.h"
+#endif
+#ifdef X86_AVAILABLE
+#include "bolt/Target/X86/X86RelocationHandler.h"
+#endif
#include "bolt/Utils/CommandLineOpts.h"
#include "bolt/Utils/Utils.h"
#include "llvm/ADT/AddressRanges.h"
@@ -361,10 +370,9 @@ namespace bolt {
extern const char *BoltRevision;
-// Weird location for createMCPlusBuilder, but this is here to avoid a
-// cyclic dependency of libCore (its natural place) and libTarget. libRewrite
-// can depend on libTarget, but not libCore. Since libRewrite is the only
-// user of this function, we define it here.
+// Weird location for the target factories, but this is here to avoid a cyclic
+// dependency of libCore (their natural place) and libTarget. libRewrite can
+// depend on libTarget, but libCore cannot.
MCPlusBuilder *createMCPlusBuilder(const Triple::ArchType Arch,
const MCInstrAnalysis *Analysis,
const MCInstrInfo *Info,
@@ -388,6 +396,28 @@ MCPlusBuilder *createMCPlusBuilder(const Triple::ArchType Arch,
llvm_unreachable("architecture unsupported by MCPlusBuilder");
}
+std::unique_ptr<RelocationHandler>
+createRelocationHandler(Triple::ArchType Arch) {
+#ifdef X86_AVAILABLE
+ if (Arch == Triple::x86_64)
+ return createX86RelocationHandler();
+#endif
+
+#ifdef AARCH64_AVAILABLE
+ if (Arch == Triple::aarch64)
+ return createAArch64RelocationHandler();
+#endif
+
+#ifdef RISCV_AVAILABLE
+ if (Arch == Triple::riscv32)
+ return createRISCVRelocationHandler(false);
+ if (Arch == Triple::riscv64)
+ return createRISCVRelocationHandler(true);
+#endif
+
+ llvm_unreachable("architecture unsupported by RelocationHandler");
+}
+
} // namespace bolt
} // namespace llvm
@@ -466,6 +496,8 @@ RewriteInstance::RewriteInstance(ELFObjectFileBase *File, const int Argc,
return;
}
BC = std::move(BCOrErr.get());
+ BC->initializeRelocationHandler(
+ createRelocationHandler(BC->TheTriple->getArch()));
BC->initializeTarget(std::unique_ptr<MCPlusBuilder>(
createMCPlusBuilder(BC->TheTriple->getArch(), BC->MIA.get(),
BC->MII.get(), BC->MRI.get(), BC->STI.get())));
diff --git a/bolt/lib/Target/AArch64/AArch64RelocationHandler.cpp b/bolt/lib/Target/AArch64/AArch64RelocationHandler.cpp
index 3c04660ea0b1e..61afb79cd8967 100644
--- a/bolt/lib/Target/AArch64/AArch64RelocationHandler.cpp
+++ b/bolt/lib/Target/AArch64/AArch64RelocationHandler.cpp
@@ -1,5 +1,4 @@
-//===- AArch64RelocationHandler.cpp
-//-----------------------------------------------===//
+//===- AArch64RelocationHandler.cpp - AArch64 relocation handling -------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -11,6 +10,7 @@
//
//===----------------------------------------------------------------------===//
+#include "bolt/Target/AArch64/AArch64RelocationHandler.h"
#include "bolt/Core/Relocation.h"
#include "llvm/Object/ELF.h"
#include "llvm/Support/ErrorHandling.h"
diff --git a/bolt/lib/Target/AArch64/CMakeLists.txt b/bolt/lib/Target/AArch64/CMakeLists.txt
index ec33fc1656841..b56d382b581d4 100644
--- a/bolt/lib/Target/AArch64/CMakeLists.txt
+++ b/bolt/lib/Target/AArch64/CMakeLists.txt
@@ -21,10 +21,8 @@ endif()
add_llvm_library(LLVMBOLTTargetAArch64
AArch64MCPlusBuilder.cpp
AArch64MCSymbolizer.cpp
+ AArch64RelocationHandler.cpp
- # AArch64RelocationHandler.cpp is part of LLVMBOLTCore to avoid a circular
- # dependency between the core relocation factory and LLVMBOLTTargetAArch64.
- PARTIAL_SOURCES_INTENDED
NO_EXPORT
DISABLE_LLVM_LINK_LLVM_DYLIB
diff --git a/bolt/lib/Target/RISCV/CMakeLists.txt b/bolt/lib/Target/RISCV/CMakeLists.txt
index 922edafae5d48..76dbe2bc2789c 100644
--- a/bolt/lib/Target/RISCV/CMakeLists.txt
+++ b/bolt/lib/Target/RISCV/CMakeLists.txt
@@ -21,10 +21,8 @@ endif()
add_llvm_library(LLVMBOLTTargetRISCV
RISCVMCPlusBuilder.cpp
RISCVMCSymbolizer.cpp
+ RISCVRelocationHandler.cpp
- # RISCVRelocationHandler.cpp is part of LLVMBOLTCore to avoid a circular
- # dependency between the core relocation factory and LLVMBOLTTargetRISCV.
- PARTIAL_SOURCES_INTENDED
NO_EXPORT
DISABLE_LLVM_LINK_LLVM_DYLIB
diff --git a/bolt/lib/Target/RISCV/RISCVRelocationHandler.cpp b/bolt/lib/Target/RISCV/RISCVRelocationHandler.cpp
index e778a9d93bbec..f7f7cb51e9176 100644
--- a/bolt/lib/Target/RISCV/RISCVRelocationHandler.cpp
+++ b/bolt/lib/Target/RISCV/RISCVRelocationHandler.cpp
@@ -1,5 +1,4 @@
-//===- RISCVRelocationHandler.cpp
-//-------------------------------------------------===//
+//===- RISCVRelocationHandler.cpp - RISC-V relocation handling -----------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -11,6 +10,7 @@
//
//===----------------------------------------------------------------------===//
+#include "bolt/Target/RISCV/RISCVRelocationHandler.h"
#include "bolt/Core/Relocation.h"
#include "llvm/Object/ELF.h"
#include "llvm/Support/ErrorHandling.h"
diff --git a/bolt/lib/Target/X86/CMakeLists.txt b/bolt/lib/Target/X86/CMakeLists.txt
index bdf8ff317253a..f08d6b25ff87a 100644
--- a/bolt/lib/Target/X86/CMakeLists.txt
+++ b/bolt/lib/Target/X86/CMakeLists.txt
@@ -20,10 +20,8 @@ endif()
add_llvm_library(LLVMBOLTTargetX86
X86MCPlusBuilder.cpp
X86MCSymbolizer.cpp
+ X86RelocationHandler.cpp
- # X86RelocationHandler.cpp is part of LLVMBOLTCore to avoid a circular
- # dependency between the core relocation factory and LLVMBOLTTargetX86.
- PARTIAL_SOURCES_INTENDED
NO_EXPORT
DISABLE_LLVM_LINK_LLVM_DYLIB
diff --git a/bolt/lib/Target/X86/X86RelocationHandler.cpp b/bolt/lib/Target/X86/X86RelocationHandler.cpp
index 4895bfd4fd449..3c1eaf69e0294 100644
--- a/bolt/lib/Target/X86/X86RelocationHandler.cpp
+++ b/bolt/lib/Target/X86/X86RelocationHandler.cpp
@@ -1,5 +1,4 @@
-//===- X86RelocationHandler.cpp
-//---------------------------------------------------===//
+//===- X86RelocationHandler.cpp - X86 relocation handling ---------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -11,6 +10,7 @@
//
//===----------------------------------------------------------------------===//
+#include "bolt/Target/X86/X86RelocationHandler.h"
#include "bolt/Core/Relocation.h"
#include "llvm/Object/ELF.h"
#include "llvm/Support/ErrorHandling.h"
diff --git a/bolt/unittests/Core/BinaryContext.cpp b/bolt/unittests/Core/BinaryContext.cpp
index a8c00a3bb24b6..2c6745563144f 100644
--- a/bolt/unittests/Core/BinaryContext.cpp
+++ b/bolt/unittests/Core/BinaryContext.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "bolt/Core/BinaryContext.h"
+#include "bolt/Rewrite/RewriteInstance.h"
#include "bolt/Utils/CommandLineOpts.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
@@ -61,6 +62,8 @@ struct BinaryContextTester : public testing::TestWithParam<Triple::ArchType> {
ObjFile->getFileName(), TheTriple.isRISCV() ? &Features : nullptr, true,
DWARFContext::create(*ObjFile), {llvm::outs(), llvm::errs()}));
ASSERT_FALSE(!BC);
+ BC->initializeRelocationHandler(
+ createRelocationHandler(TheTriple.getArch()));
}
char ElfBuf[sizeof(typename ELF64LE::Ehdr)] = {};
@@ -68,19 +71,57 @@ struct BinaryContextTester : public testing::TestWithParam<Triple::ArchType> {
std::unique_ptr<BinaryContext> BC;
};
+TEST_P(BinaryContextTester, InitializesRelocationHandler) {
+ const RelocationHandler &Handler = BC->getRelocationHandler();
+
+ switch (GetParam()) {
+ case Triple::x86_64:
+ EXPECT_EQ(Handler.getPC32(), ELF::R_X86_64_PC32);
+ break;
+ case Triple::aarch64:
+ EXPECT_EQ(Handler.getPC32(), ELF::R_AARCH64_PREL32);
+ break;
+ case Triple::riscv64:
+ EXPECT_EQ(Handler.getPC32(), ELF::R_RISCV_32_PCREL);
+ break;
+ default:
+ FAIL() << "unsupported test architecture";
+ }
+}
+
TEST(RelocationHandlerTest, ArchitectureStateIsIndependent) {
+#ifdef X86_AVAILABLE
std::unique_ptr<RelocationHandler> X86Handler =
createRelocationHandler(Triple::x86_64);
+#endif
+
+#ifdef AARCH64_AVAILABLE
std::unique_ptr<RelocationHandler> AArch64Handler =
createRelocationHandler(Triple::aarch64);
+#endif
+
+#ifdef RISCV_AVAILABLE
+ std::unique_ptr<RelocationHandler> RISCVHandler =
+ createRelocationHandler(Triple::riscv64);
+#endif
+#ifdef X86_AVAILABLE
EXPECT_EQ(X86Handler->getPC32(), ELF::R_X86_64_PC32);
- EXPECT_EQ(AArch64Handler->getPC32(), ELF::R_AARCH64_PREL32);
EXPECT_TRUE(X86Handler->isSupported(ELF::R_X86_64_PC32));
- EXPECT_FALSE(X86Handler->isSupported(ELF::R_AARCH64_CALL26));
+#endif
+
+#ifdef AARCH64_AVAILABLE
+ EXPECT_EQ(AArch64Handler->getPC32(), ELF::R_AARCH64_PREL32);
EXPECT_TRUE(AArch64Handler->isSupported(ELF::R_AARCH64_CALL26));
- EXPECT_FALSE(AArch64Handler->isSupported(ELF::R_X86_64_PC32));
+#endif
+
+#ifdef RISCV_AVAILABLE
+ EXPECT_EQ(RISCVHandler->getPC32(), ELF::R_RISCV_32_PCREL);
+ EXPECT_EQ(RISCVHandler->getRelative(), ELF::R_RISCV_RELATIVE);
+ EXPECT_TRUE(RISCVHandler->isIRelative(ELF::R_RISCV_IRELATIVE));
+#endif
}
+
} // namespace
#ifdef X86_AVAILABLE
diff --git a/bolt/unittests/Core/Relocation.cpp b/bolt/unittests/Core/Relocation.cpp
index 93695aae8a913..5765c490a369e 100644
--- a/bolt/unittests/Core/Relocation.cpp
+++ b/bolt/unittests/Core/Relocation.cpp
@@ -7,8 +7,16 @@
//===----------------------------------------------------------------------===//
#include "bolt/Core/Relocation.h"
+#ifdef AARCH64_AVAILABLE
+#include "bolt/Target/AArch64/AArch64RelocationHandler.h"
+#endif
+#ifdef RISCV_AVAILABLE
+#include "bolt/Target/RISCV/RISCVRelocationHandler.h"
+#endif
+#ifdef X86_AVAILABLE
+#include "bolt/Target/X86/X86RelocationHandler.h"
+#endif
#include "llvm/BinaryFormat/ELF.h"
-#include "llvm/TargetParser/Triple.h"
#include "gtest/gtest.h"
using namespace llvm;
@@ -19,8 +27,7 @@ using namespace llvm::bolt;
namespace {
TEST(AArch64RelocationHandlerTest, ClassificationAndSize) {
- std::unique_ptr<RelocationHandler> Handler =
- createRelocationHandler(Triple::aarch64);
+ std::unique_ptr<RelocationHandler> Handler = createAArch64RelocationHandler();
EXPECT_TRUE(Handler->isSupported(ELF::R_AARCH64_CALL26));
EXPECT_TRUE(Handler->isSupported(ELF::R_AARCH64_PREL32));
@@ -36,8 +43,7 @@ TEST(AArch64RelocationHandlerTest, ClassificationAndSize) {
}
TEST(AArch64RelocationHandlerTest, EncodeAndExtractCall26) {
- std::unique_ptr<RelocationHandler> Handler =
- createRelocationHandler(Triple::aarch64);
+ std::unique_ptr<RelocationHandler> Handler = createAArch64RelocationHandler();
constexpr uint64_t PC = 0x1000;
constexpr uint64_t Target = 0x1100;
@@ -48,8 +54,7 @@ TEST(AArch64RelocationHandlerTest, EncodeAndExtractCall26) {
}
TEST(AArch64RelocationHandlerTest, EncodeAndExtractPrel32) {
- std::unique_ptr<RelocationHandler> Handler =
- createRelocationHandler(Triple::aarch64);
+ std::unique_ptr<RelocationHandler> Handler = createAArch64RelocationHandler();
constexpr uint64_t PC = 0x1000;
constexpr uint64_t Target = 0xf00;
@@ -60,8 +65,7 @@ TEST(AArch64RelocationHandlerTest, EncodeAndExtractPrel32) {
}
TEST(AArch64RelocationHandlerTest, Call26EncodingRange) {
- std::unique_ptr<RelocationHandler> Handler =
- createRelocationHandler(Triple::aarch64);
+ std::unique_ptr<RelocationHandler> Handler = createAArch64RelocationHandler();
constexpr uint64_t PC = 0x1000;
constexpr uint64_t Range = uint64_t{1} << 27;
@@ -73,3 +77,63 @@ TEST(AArch64RelocationHandlerTest, Call26EncodingRange) {
} // namespace
#endif
+
+#ifdef X86_AVAILABLE
+
+namespace {
+
+TEST(X86RelocationHandlerTest, ClassificationAndEncoding) {
+ std::unique_ptr<RelocationHandler> Handler = createX86RelocationHandler();
+ constexpr uint64_t PC = 0x1000;
+ constexpr uint64_t Target = 0xf00;
+
+ EXPECT_TRUE(Handler->isSupported(ELF::R_X86_64_PC32));
+ EXPECT_EQ(Handler->getSizeForType(ELF::R_X86_64_PC32), 4u);
+ EXPECT_TRUE(Handler->isPCRelative(ELF::R_X86_64_PC32));
+
+ const uint64_t Encoded = Handler->encodeValue(ELF::R_X86_64_PC32, Target, PC);
+ EXPECT_EQ(Encoded, static_cast<uint64_t>(-0x100));
+ EXPECT_EQ(Handler->extractValue(ELF::R_X86_64_PC32, Encoded, PC),
+ static_cast<uint64_t>(-0x100));
+}
+
+} // namespace
+
+#endif
+
+#ifdef RISCV_AVAILABLE
+
+namespace {
+
+TEST(RISCVRelocationHandlerTest, ClassificationAndEncoding) {
+ std::unique_ptr<RelocationHandler> Handler =
+ createRISCVRelocationHandler(true);
+ constexpr uint64_t Value = 0x12345678;
+
+ EXPECT_TRUE(Handler->isSupported(ELF::R_RISCV_CALL));
+ EXPECT_EQ(Handler->getSizeForType(ELF::R_RISCV_CALL), 8u);
+ EXPECT_TRUE(Handler->isPCRelative(ELF::R_RISCV_CALL));
+ EXPECT_TRUE(Handler->isInstructionReference(ELF::R_RISCV_PCREL_LO12_I));
+
+ const uint64_t Encoded = Handler->encodeValue(ELF::R_RISCV_32, Value, 0);
+ EXPECT_EQ(Encoded, Value);
+ EXPECT_EQ(Handler->extractValue(ELF::R_RISCV_32, Encoded, 0), Value);
+}
+
+TEST(RISCVRelocationHandlerTest, Preserves32And64BitBehavior) {
+ std::unique_ptr<RelocationHandler> RISCV32Handler =
+ createRISCVRelocationHandler(false);
+ std::unique_ptr<RelocationHandler> RISCV64Handler =
+ createRISCVRelocationHandler(true);
+
+ EXPECT_TRUE(
+ RISCV32Handler->isInstructionReference(ELF::R_RISCV_PCREL_LO12_S));
+ EXPECT_TRUE(
+ RISCV64Handler->isInstructionReference(ELF::R_RISCV_PCREL_LO12_S));
+ EXPECT_EQ(RISCV64Handler->getRelative(), ELF::R_RISCV_RELATIVE);
+ EXPECT_TRUE(RISCV64Handler->isIRelative(ELF::R_RISCV_IRELATIVE));
+}
+
+} // namespace
+
+#endif
More information about the llvm-commits
mailing list