From f873029386dd415cd9caa78f600a593d9570c9ae Mon Sep 17 00:00:00 2001 From: Job Noorman Date: Fri, 16 Jun 2023 11:49:19 +0200 Subject: [PATCH] [BOLT] Add minimal RISC-V 64-bit support Just enough features are implemented to process a simple "hello world" executable and produce something that still runs (including libc calls). This was mainly a matter of implementing support for various relocations. Currently, the following are handled: - R_RISCV_JAL - R_RISCV_CALL - R_RISCV_CALL_PLT - R_RISCV_BRANCH - R_RISCV_RVC_BRANCH - R_RISCV_RVC_JUMP - R_RISCV_GOT_HI20 - R_RISCV_PCREL_HI20 - R_RISCV_PCREL_LO12_I - R_RISCV_RELAX - R_RISCV_NONE Executables linked with linker relaxation will probably fail to be processed. BOLT relocates .text to a high address while leaving .plt at its original (low) address. This causes PC-relative PLT calls that were relaxed to a JAL to not fit their offset in an I-immediate anymore. This is something that will be addressed in a later patch. Changes to the BOLT core are relatively minor. Two things were tricky to implement and needed slightly larger changes. I'll explain those below. The R_RISCV_CALL(_PLT) relocation is put on the first instruction of a AUIPC/JALR pair, the second does not get any relocation (unlike other PCREL pairs). This causes issues with the combinations of the way BOLT processes binaries and the RISC-V MC-layer handles relocations: - BOLT reassembles instructions one by one and since the JALR doesn't have a relocation, it simply gets copied without modification; - Even though the MC-layer handles R_RISCV_CALL properly (adjusts both the AUIPC and the JALR), it assumes the immediates of both instructions are 0 (to be able to or-in a new value). This will most likely not be the case for the JALR that got copied over. To handle this difficulty without resorting to RISC-V-specific hacks in the BOLT core, a new binary pass was added that searches for AUIPC/JALR pairs and zeroes-out the immediate of the JALR. A second difficulty was supporting ABS symbols. As far as I can tell, ABS symbols were not handled at all, causing __global_pointer$ to break. RewriteInstance::analyzeRelocation was updated to handle these generically. Tests are provided for all supported relocations. Note that in order to test the correct handling of PLT entries, an ELF file produced by GCC had to be used. While I tried to strip the YAML representation, it's still quite large. Any suggestions on how to improve this would be appreciated. Reviewed By: rafauler Differential Revision: https://reviews.llvm.org/D145687 --- bolt/CMakeLists.txt | 2 +- bolt/CODE_OWNERS.TXT | 4 + bolt/include/bolt/Core/BinaryContext.h | 2 + bolt/include/bolt/Core/MCPlusBuilder.h | 10 + bolt/include/bolt/Passes/FixRISCVCallsPass.h | 38 + bolt/include/bolt/Rewrite/RewriteInstance.h | 9 + bolt/lib/Core/BinaryContext.cpp | 5 + bolt/lib/Core/BinaryFunction.cpp | 4 +- bolt/lib/Core/Relocation.cpp | 182 +++- bolt/lib/Passes/CMakeLists.txt | 1 + bolt/lib/Passes/FixRISCVCallsPass.cpp | 48 ++ bolt/lib/Rewrite/BinaryPassManager.cpp | 11 + bolt/lib/Rewrite/RewriteInstance.cpp | 79 +- bolt/lib/Target/RISCV/CMakeLists.txt | 21 + bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp | 328 ++++++++ bolt/test/RISCV/Inputs/plt-gnu-ld.yaml | 830 +++++++++++++++++++ bolt/test/RISCV/lit.local.cfg | 7 + bolt/test/RISCV/plt-gnu-ld.test | 9 + bolt/test/RISCV/reloc-abs.s | 26 + bolt/test/RISCV/reloc-branch.s | 16 + bolt/test/RISCV/reloc-call.s | 21 + bolt/test/RISCV/reloc-got.s | 24 + bolt/test/RISCV/reloc-jal.s | 20 + bolt/test/RISCV/reloc-pcrel.s | 22 + bolt/test/RISCV/reloc-rvc-branch.s | 16 + bolt/test/RISCV/reloc-rvc-jump.s | 16 + 26 files changed, 1740 insertions(+), 11 deletions(-) create mode 100644 bolt/include/bolt/Passes/FixRISCVCallsPass.h create mode 100644 bolt/lib/Passes/FixRISCVCallsPass.cpp create mode 100644 bolt/lib/Target/RISCV/CMakeLists.txt create mode 100644 bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp create mode 100644 bolt/test/RISCV/Inputs/plt-gnu-ld.yaml create mode 100644 bolt/test/RISCV/lit.local.cfg create mode 100644 bolt/test/RISCV/plt-gnu-ld.test create mode 100644 bolt/test/RISCV/reloc-abs.s create mode 100644 bolt/test/RISCV/reloc-branch.s create mode 100644 bolt/test/RISCV/reloc-call.s create mode 100644 bolt/test/RISCV/reloc-got.s create mode 100644 bolt/test/RISCV/reloc-jal.s create mode 100644 bolt/test/RISCV/reloc-pcrel.s create mode 100644 bolt/test/RISCV/reloc-rvc-branch.s create mode 100644 bolt/test/RISCV/reloc-rvc-jump.s diff --git a/bolt/CMakeLists.txt b/bolt/CMakeLists.txt index 2e702d40668b4..4ff90c1f7b3a0 100644 --- a/bolt/CMakeLists.txt +++ b/bolt/CMakeLists.txt @@ -9,7 +9,7 @@ list(INSERT CMAKE_MODULE_PATH 0 "${BOLT_SOURCE_DIR}/cmake/modules") # Determine default set of targets to build -- the intersection of # those BOLT supports and those LLVM is targeting. -set(BOLT_TARGETS_TO_BUILD_all "AArch64;X86") +set(BOLT_TARGETS_TO_BUILD_all "AArch64;X86;RISCV") set(BOLT_TARGETS_TO_BUILD_default) foreach (tgt ${BOLT_TARGETS_TO_BUILD_all}) if (tgt IN_LIST LLVM_TARGETS_TO_BUILD) diff --git a/bolt/CODE_OWNERS.TXT b/bolt/CODE_OWNERS.TXT index 00c92e8105c35..39439bb1b3fe0 100644 --- a/bolt/CODE_OWNERS.TXT +++ b/bolt/CODE_OWNERS.TXT @@ -20,3 +20,7 @@ D: DWARF support N: Vladislav Khmelevsky E: och95@yandex.ru D: AArch64 backend + +N: Job Noorman +E: jnoorman@igalia.com +D: RISC-V backend diff --git a/bolt/include/bolt/Core/BinaryContext.h b/bolt/include/bolt/Core/BinaryContext.h index d1a0662e73505..9daa2eb28becf 100644 --- a/bolt/include/bolt/Core/BinaryContext.h +++ b/bolt/include/bolt/Core/BinaryContext.h @@ -722,6 +722,8 @@ class BinaryContext { TheTriple->getArch() == llvm::Triple::x86_64; } + bool isRISCV() const { return TheTriple->getArch() == llvm::Triple::riscv64; } + // AArch64-specific functions to check if symbol is used to delimit // code/data in .text. Code is marked by $x, data by $d. MarkerSymType getMarkerType(const SymbolRef &Symbol) const; diff --git a/bolt/include/bolt/Core/MCPlusBuilder.h b/bolt/include/bolt/Core/MCPlusBuilder.h index 2d6ea6bc2382b..db3f7e7f14f7a 100644 --- a/bolt/include/bolt/Core/MCPlusBuilder.h +++ b/bolt/include/bolt/Core/MCPlusBuilder.h @@ -633,6 +633,12 @@ class MCPlusBuilder { return false; } + /// Returns true if First/Second is a AUIPC/JALR call pair. + virtual bool isRISCVCall(const MCInst &First, const MCInst &Second) const { + llvm_unreachable("not implemented"); + return false; + } + /// If non-zero, this is used to fill the executable space with instructions /// that will trap. Defaults to 0. virtual unsigned getTrapFillValue() const { return 0; } @@ -2032,6 +2038,10 @@ MCPlusBuilder *createAArch64MCPlusBuilder(const MCInstrAnalysis *, const MCInstrInfo *, const MCRegisterInfo *); +MCPlusBuilder *createRISCVMCPlusBuilder(const MCInstrAnalysis *, + const MCInstrInfo *, + const MCRegisterInfo *); + } // namespace bolt } // namespace llvm diff --git a/bolt/include/bolt/Passes/FixRISCVCallsPass.h b/bolt/include/bolt/Passes/FixRISCVCallsPass.h new file mode 100644 index 0000000000000..8e4473f612952 --- /dev/null +++ b/bolt/include/bolt/Passes/FixRISCVCallsPass.h @@ -0,0 +1,38 @@ +//===- bolt/Passes/FixRISCVCallsPass.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 +// +//===----------------------------------------------------------------------===// +// +// This file declares the FixRISCVCallsPass class, which sets the JALR immediate +// to 0 for AUIPC/JALR pairs with a R_RISCV_CALL(_PLT) relocation. This is +// necessary since MC expects it to be zero in order to or-in fixups. +//===----------------------------------------------------------------------===// + +#ifndef BOLT_PASSES_FIXRISCVCALLSPASS_H +#define BOLT_PASSES_FIXRISCVCALLSPASS_H + +#include "bolt/Passes/BinaryPasses.h" + +namespace llvm { +namespace bolt { + +class FixRISCVCallsPass : public BinaryFunctionPass { + void runOnFunction(BinaryFunction &Function); + +public: + explicit FixRISCVCallsPass(const cl::opt &PrintPass) + : BinaryFunctionPass(PrintPass) {} + + const char *getName() const override { return "fix-riscv-calls"; } + + /// Pass entry point + void runOnFunctions(BinaryContext &BC) override; +}; + +} // namespace bolt +} // namespace llvm + +#endif diff --git a/bolt/include/bolt/Rewrite/RewriteInstance.h b/bolt/include/bolt/Rewrite/RewriteInstance.h index 8ebc9eb8e194c..da6475c737381 100644 --- a/bolt/include/bolt/Rewrite/RewriteInstance.h +++ b/bolt/include/bolt/Rewrite/RewriteInstance.h @@ -279,6 +279,9 @@ class RewriteInstance { /// is the expected .plt \p Section entry function size. void disassemblePLTSectionX86(BinarySection &Section, uint64_t EntrySize); + /// Disassemble riscv-specific .plt \p Section auxiliary function + void disassemblePLTSectionRISCV(BinarySection &Section); + /// ELF-specific part. TODO: refactor into new class. #define ELF_FUNCTION(TYPE, FUNC) \ template TYPE FUNC(object::ELFObjectFile *Obj); \ @@ -536,6 +539,9 @@ class RewriteInstance { const PLTSectionInfo AArch64_PLTSections[3] = { {".plt"}, {".iplt"}, {nullptr}}; + /// RISCV PLT sections. + const PLTSectionInfo RISCV_PLTSections[3] = {{".plt"}, {nullptr}}; + /// Return PLT information for a section with \p SectionName or nullptr /// if the section is not PLT. const PLTSectionInfo *getPLTSectionInfo(StringRef SectionName) { @@ -549,6 +555,9 @@ class RewriteInstance { case Triple::aarch64: PLTSI = AArch64_PLTSections; break; + case Triple::riscv64: + PLTSI = RISCV_PLTSections; + break; } for (; PLTSI && PLTSI->Name; ++PLTSI) if (SectionName == PLTSI->Name) diff --git a/bolt/lib/Core/BinaryContext.cpp b/bolt/lib/Core/BinaryContext.cpp index db44d56a40ed4..2d2b35ee2bd9c 100644 --- a/bolt/lib/Core/BinaryContext.cpp +++ b/bolt/lib/Core/BinaryContext.cpp @@ -128,6 +128,11 @@ BinaryContext::createBinaryContext(const ObjectFile *File, bool IsPIC, ArchName = "aarch64"; FeaturesStr = "+all"; break; + case llvm::Triple::riscv64: + ArchName = "riscv64"; + // RV64GC + FeaturesStr = "+m,+a,+f,+d,+zicsr,+zifencei,+c"; + break; default: return createStringError(std::errc::not_supported, "BOLT-ERROR: Unrecognized machine in ELF file"); diff --git a/bolt/lib/Core/BinaryFunction.cpp b/bolt/lib/Core/BinaryFunction.cpp index 12ded3d71566b..dac32c42cc33e 100644 --- a/bolt/lib/Core/BinaryFunction.cpp +++ b/bolt/lib/Core/BinaryFunction.cpp @@ -1323,7 +1323,7 @@ bool BinaryFunction::disassemble() { if (BC.isAArch64()) handleAArch64IndirectCall(Instruction, Offset); } - } else if (BC.isAArch64()) { + } else if (BC.isAArch64() || BC.isRISCV()) { // Check if there's a relocation associated with this instruction. bool UsedReloc = false; for (auto Itr = Relocations.lower_bound(Offset), @@ -1343,7 +1343,7 @@ bool BinaryFunction::disassemble() { UsedReloc = true; } - if (MIB->hasPCRelOperand(Instruction) && !UsedReloc) + if (!BC.isRISCV() && MIB->hasPCRelOperand(Instruction) && !UsedReloc) handlePCRelOperand(Instruction, AbsoluteInstrAddr, Size); } diff --git a/bolt/lib/Core/Relocation.cpp b/bolt/lib/Core/Relocation.cpp index d3e7fccc23100..0901a1465193c 100644 --- a/bolt/lib/Core/Relocation.cpp +++ b/bolt/lib/Core/Relocation.cpp @@ -89,6 +89,24 @@ static bool isSupportedAArch64(uint64_t Type) { } } +static bool isSupportedRISCV(uint64_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_RVC_JUMP: + case ELF::R_RISCV_RVC_BRANCH: + return true; + } +} + static size_t getSizeForTypeX86(uint64_t Type) { switch (Type) { default: @@ -163,6 +181,28 @@ static size_t getSizeForTypeAArch64(uint64_t Type) { } } +static size_t getSizeForTypeRISCV(uint64_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_32_PCREL: + case ELF::R_RISCV_CALL: + case ELF::R_RISCV_CALL_PLT: + return 4; + case ELF::R_RISCV_GOT_HI20: + // See extractValueRISCV for why this is necessary. + return 8; + } +} + static bool skipRelocationTypeX86(uint64_t Type) { return Type == ELF::R_X86_64_NONE; } @@ -171,6 +211,16 @@ static bool skipRelocationTypeAArch64(uint64_t Type) { return Type == ELF::R_AARCH64_NONE || Type == ELF::R_AARCH64_LD_PREL_LO19; } +static bool skipRelocationTypeRISCV(uint64_t Type) { + switch (Type) { + default: + return false; + case ELF::R_RISCV_NONE: + case ELF::R_RISCV_RELAX: + return true; + } +} + static bool skipRelocationProcessX86(uint64_t &Type, uint64_t Contents) { return false; } @@ -262,6 +312,10 @@ static bool skipRelocationProcessAArch64(uint64_t &Type, uint64_t Contents) { return false; } +static bool skipRelocationProcessRISCV(uint64_t &Type, uint64_t Contents) { + return false; +} + static uint64_t encodeValueX86(uint64_t Type, uint64_t Value, uint64_t PC) { switch (Type) { default: @@ -407,6 +461,57 @@ static uint64_t extractValueAArch64(uint64_t Type, uint64_t Contents, } } +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 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(uint64_t Type, uint64_t Contents, + uint64_t PC) { + switch (Type) { + default: + errs() << object::getELFRelocationTypeName(ELF::EM_RISCV, Type) << '\n'; + llvm_unreachable("unsupported relocation type"); + case ELF::R_RISCV_JAL: + return extractJImmRISCV(Contents); + case ELF::R_RISCV_CALL: + case ELF::R_RISCV_CALL_PLT: + return extractUImmRISCV(Contents); + case ELF::R_RISCV_BRANCH: + return extractBImmRISCV(Contents); + case ELF::R_RISCV_GOT_HI20: + // 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: + return extractUImmRISCV(Contents); + case ELF::R_RISCV_PCREL_LO12_I: + return extractIImmRISCV(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)); + } +} + static bool isGOTX86(uint64_t Type) { switch (Type) { default: @@ -444,6 +549,15 @@ static bool isGOTAArch64(uint64_t Type) { } } +static bool isGOTRISCV(uint64_t Type) { + switch (Type) { + default: + return false; + case ELF::R_RISCV_GOT_HI20: + return true; + } +} + static bool isTLSX86(uint64_t Type) { switch (Type) { default: @@ -472,6 +586,13 @@ static bool isTLSAArch64(uint64_t Type) { } } +static bool isTLSRISCV(uint64_t Type) { + switch (Type) { + default: + return false; + } +} + static bool isPCRelativeX86(uint64_t Type) { switch (Type) { default: @@ -543,33 +664,61 @@ static bool isPCRelativeAArch64(uint64_t Type) { } } +static bool isPCRelativeRISCV(uint64_t Type) { + switch (Type) { + default: + llvm_unreachable("Unknown relocation type"); + 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_RVC_JUMP: + case ELF::R_RISCV_RVC_BRANCH: + case ELF::R_RISCV_32_PCREL: + return true; + } +} + bool Relocation::isSupported(uint64_t Type) { if (Arch == Triple::aarch64) return isSupportedAArch64(Type); + if (Arch == Triple::riscv64) + return isSupportedRISCV(Type); return isSupportedX86(Type); } size_t Relocation::getSizeForType(uint64_t Type) { if (Arch == Triple::aarch64) return getSizeForTypeAArch64(Type); + if (Arch == Triple::riscv64) + return getSizeForTypeRISCV(Type); return getSizeForTypeX86(Type); } bool Relocation::skipRelocationType(uint64_t Type) { if (Arch == Triple::aarch64) return skipRelocationTypeAArch64(Type); + if (Arch == Triple::riscv64) + return skipRelocationTypeRISCV(Type); return skipRelocationTypeX86(Type); } bool Relocation::skipRelocationProcess(uint64_t &Type, uint64_t Contents) { if (Arch == Triple::aarch64) return skipRelocationProcessAArch64(Type, Contents); + if (Arch == Triple::riscv64) + skipRelocationProcessRISCV(Type, Contents); return skipRelocationProcessX86(Type, Contents); } uint64_t Relocation::encodeValue(uint64_t Type, uint64_t Value, uint64_t PC) { if (Arch == Triple::aarch64) return encodeValueAArch64(Type, Value, PC); + if (Arch == Triple::riscv64) + llvm_unreachable("not implemented"); return encodeValueX86(Type, Value, PC); } @@ -577,12 +726,16 @@ uint64_t Relocation::extractValue(uint64_t Type, uint64_t Contents, uint64_t PC) { if (Arch == Triple::aarch64) return extractValueAArch64(Type, Contents, PC); + if (Arch == Triple::riscv64) + return extractValueRISCV(Type, Contents, PC); return extractValueX86(Type, Contents, PC); } bool Relocation::isGOT(uint64_t Type) { if (Arch == Triple::aarch64) return isGOTAArch64(Type); + if (Arch == Triple::riscv64) + return isGOTRISCV(Type); return isGOTX86(Type); } @@ -597,42 +750,56 @@ bool Relocation::isNone(uint64_t Type) { return Type == getNone(); } bool Relocation::isRelative(uint64_t Type) { if (Arch == Triple::aarch64) return Type == ELF::R_AARCH64_RELATIVE; + if (Arch == Triple::riscv64) + return Type == ELF::R_RISCV_RELATIVE; return Type == ELF::R_X86_64_RELATIVE; } bool Relocation::isIRelative(uint64_t Type) { if (Arch == Triple::aarch64) return Type == ELF::R_AARCH64_IRELATIVE; + if (Arch == Triple::riscv64) + llvm_unreachable("not implemented"); return Type == ELF::R_X86_64_IRELATIVE; } bool Relocation::isTLS(uint64_t Type) { if (Arch == Triple::aarch64) return isTLSAArch64(Type); + if (Arch == Triple::riscv64) + return isTLSRISCV(Type); return isTLSX86(Type); } uint64_t Relocation::getNone() { if (Arch == Triple::aarch64) return ELF::R_AARCH64_NONE; + if (Arch == Triple::riscv64) + return ELF::R_RISCV_NONE; return ELF::R_X86_64_NONE; } uint64_t Relocation::getPC32() { if (Arch == Triple::aarch64) return ELF::R_AARCH64_PREL32; + if (Arch == Triple::riscv64) + return ELF::R_RISCV_32_PCREL; return ELF::R_X86_64_PC32; } uint64_t Relocation::getPC64() { if (Arch == Triple::aarch64) return ELF::R_AARCH64_PREL64; + if (Arch == Triple::riscv64) + llvm_unreachable("not implemented"); return ELF::R_X86_64_PC64; } bool Relocation::isPCRelative(uint64_t Type) { if (Arch == Triple::aarch64) return isPCRelativeAArch64(Type); + if (Arch == Triple::riscv64) + return isPCRelativeRISCV(Type); return isPCRelativeX86(Type); } @@ -696,7 +863,20 @@ void Relocation::print(raw_ostream &OS) const { }; if (Arch == Triple::aarch64) OS << AArch64RelocNames[Type]; - else + else if (Arch == Triple::riscv64) { + // RISC-V relocations are not sequentially numbered so we cannot use an + // array + switch (Type) { + default: + llvm_unreachable("illegal RISC-V relocation"); +#undef ELF_RELOC +#define ELF_RELOC(name, value) \ + case value: \ + OS << #name; \ + break; +#include "llvm/BinaryFormat/ELFRelocs/RISCV.def" + } + } else OS << X86RelocNames[Type]; OS << ", 0x" << Twine::utohexstr(Offset); if (Symbol) { diff --git a/bolt/lib/Passes/CMakeLists.txt b/bolt/lib/Passes/CMakeLists.txt index 9bc0779d7df23..b8bbe59a64480 100644 --- a/bolt/lib/Passes/CMakeLists.txt +++ b/bolt/lib/Passes/CMakeLists.txt @@ -14,6 +14,7 @@ add_llvm_library(LLVMBOLTPasses FrameAnalysis.cpp FrameOptimizer.cpp FixRelaxationPass.cpp + FixRISCVCallsPass.cpp HFSort.cpp HFSortPlus.cpp Hugify.cpp diff --git a/bolt/lib/Passes/FixRISCVCallsPass.cpp b/bolt/lib/Passes/FixRISCVCallsPass.cpp new file mode 100644 index 0000000000000..5da28e749a5fe --- /dev/null +++ b/bolt/lib/Passes/FixRISCVCallsPass.cpp @@ -0,0 +1,48 @@ +#include "bolt/Passes/FixRISCVCallsPass.h" +#include "bolt/Core/ParallelUtilities.h" + +#include + +using namespace llvm; + +namespace llvm { +namespace bolt { + +void FixRISCVCallsPass::runOnFunction(BinaryFunction &BF) { + auto &BC = BF.getBinaryContext(); + + for (auto &BB : BF) { + for (auto II = BB.begin(), IE = BB.end(); II != IE; ++II) { + auto NextII = std::next(II); + + if (NextII == IE) + break; + + if (!BC.MIB->isRISCVCall(*II, *NextII)) + continue; + + auto L = BC.scopeLock(); + + // The MC layer handles R_RISCV_CALL_PLT but assumes that the immediate + // in the JALR is zero (fixups are or'ed into instructions). Note that + // NextII is guaranteed to point to a JALR by isRISCVCall. + NextII->getOperand(2).setImm(0); + } + } +} + +void FixRISCVCallsPass::runOnFunctions(BinaryContext &BC) { + if (!BC.isRISCV() || !BC.HasRelocations) + return; + + ParallelUtilities::WorkFuncTy WorkFun = [&](BinaryFunction &BF) { + runOnFunction(BF); + }; + + ParallelUtilities::runOnEachFunction( + BC, ParallelUtilities::SchedulingPolicy::SP_INST_LINEAR, WorkFun, nullptr, + "FixRISCVCalls"); +} + +} // namespace bolt +} // namespace llvm diff --git a/bolt/lib/Rewrite/BinaryPassManager.cpp b/bolt/lib/Rewrite/BinaryPassManager.cpp index dd00d62bfa712..517984d990fc5 100644 --- a/bolt/lib/Rewrite/BinaryPassManager.cpp +++ b/bolt/lib/Rewrite/BinaryPassManager.cpp @@ -12,6 +12,7 @@ #include "bolt/Passes/AllocCombiner.h" #include "bolt/Passes/AsmDump.h" #include "bolt/Passes/CMOVConversion.h" +#include "bolt/Passes/FixRISCVCallsPass.h" #include "bolt/Passes/FixRelaxationPass.h" #include "bolt/Passes/FrameOptimizer.h" #include "bolt/Passes/Hugify.h" @@ -185,6 +186,11 @@ static cl::opt cl::desc("print functions after fix relaxations pass"), cl::cat(BoltOptCategory)); +static cl::opt + PrintFixRISCVCalls("print-fix-riscv-calls", + cl::desc("print functions after fix RISCV calls pass"), + cl::cat(BoltOptCategory)); + static cl::opt PrintVeneerElimination( "print-veneer-elimination", cl::desc("print functions after veneer elimination pass"), @@ -328,6 +334,11 @@ void BinaryFunctionPassManager::runAllPasses(BinaryContext &BC) { std::make_unique(PrintVeneerElimination)); } + if (BC.isRISCV()) { + Manager.registerPass( + std::make_unique(PrintFixRISCVCalls)); + } + // Here we manage dependencies/order manually, since passes are run in the // order they're registered. diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp index 5dfe93035d83f..659b295b47acb 100644 --- a/bolt/lib/Rewrite/RewriteInstance.cpp +++ b/bolt/lib/Rewrite/RewriteInstance.cpp @@ -300,6 +300,11 @@ MCPlusBuilder *createMCPlusBuilder(const Triple::ArchType Arch, return createAArch64MCPlusBuilder(Analysis, Info, RegInfo); #endif +#ifdef RISCV_AVAILABLE + if (Arch == Triple::riscv64) + return createRISCVMCPlusBuilder(Analysis, Info, RegInfo); +#endif + llvm_unreachable("architecture unsupported by MCPlusBuilder"); } @@ -1042,7 +1047,9 @@ void RewriteInstance::discoverFileObjects() { section_iterator Section = cantFail(Symbol.getSection(), "cannot get symbol section"); if (Section == InputFile->section_end()) { - // Could be an absolute symbol. Could record for pretty printing. + // Could be an absolute symbol. Used on RISC-V for __global_pointer$ so we + // need to record it to handle relocations against it. For other instances + // of absolute symbols, we record for pretty printing. LLVM_DEBUG(if (opts::Verbosity > 1) { dbgs() << "BOLT-INFO: absolute sym " << UniqueName << "\n"; }); @@ -1464,6 +1471,50 @@ void RewriteInstance::disassemblePLTSectionAArch64(BinarySection &Section) { } } +void RewriteInstance::disassemblePLTSectionRISCV(BinarySection &Section) { + const uint64_t SectionAddress = Section.getAddress(); + const uint64_t SectionSize = Section.getSize(); + StringRef PLTContents = Section.getContents(); + ArrayRef PLTData( + reinterpret_cast(PLTContents.data()), SectionSize); + + auto disassembleInstruction = [&](uint64_t InstrOffset, MCInst &Instruction, + uint64_t &InstrSize) { + const uint64_t InstrAddr = SectionAddress + InstrOffset; + if (!BC->DisAsm->getInstruction(Instruction, InstrSize, + PLTData.slice(InstrOffset), InstrAddr, + nulls())) { + errs() << "BOLT-ERROR: unable to disassemble instruction in PLT section " + << Section.getName() << " at offset 0x" + << Twine::utohexstr(InstrOffset) << '\n'; + exit(1); + } + }; + + // Skip the first special entry since no relocation points to it. + uint64_t InstrOffset = 32; + + while (InstrOffset < SectionSize) { + InstructionListType Instructions; + MCInst Instruction; + const uint64_t EntryOffset = InstrOffset; + const uint64_t EntrySize = 16; + uint64_t InstrSize; + + while (InstrOffset < EntryOffset + EntrySize) { + disassembleInstruction(InstrOffset, Instruction, InstrSize); + Instructions.emplace_back(Instruction); + InstrOffset += InstrSize; + } + + const uint64_t EntryAddress = SectionAddress + EntryOffset; + const uint64_t TargetAddress = BC->MIB->analyzePLTEntry( + Instruction, Instructions.begin(), Instructions.end(), EntryAddress); + + createPLTBinaryFunction(TargetAddress, EntryAddress, EntrySize); + } +} + void RewriteInstance::disassemblePLTSectionX86(BinarySection &Section, uint64_t EntrySize) { const uint64_t SectionAddress = Section.getAddress(); @@ -1523,6 +1574,8 @@ void RewriteInstance::disassemblePLT() { auto analyzeOnePLTSection = [&](BinarySection &Section, uint64_t EntrySize) { if (BC->isAArch64()) return disassemblePLTSectionAArch64(Section); + if (BC->isRISCV()) + return disassemblePLTSectionRISCV(Section); return disassemblePLTSectionX86(Section, EntrySize); }; @@ -1990,7 +2043,7 @@ bool RewriteInstance::analyzeRelocation( // Section symbols are marked as ST_Debug. IsSectionRelocation = (cantFail(Symbol.getType()) == SymbolRef::ST_Debug); // Check for PLT entry registered with symbol name - if (!SymbolAddress && IsAArch64) { + if (!SymbolAddress && (IsAArch64 || BC->isRISCV())) { const BinaryData *BD = BC->getPLTBinaryDataByName(SymbolName); SymbolAddress = BD ? BD->getAddress() : 0; } @@ -2053,7 +2106,7 @@ bool RewriteInstance::analyzeRelocation( if (SkipVerification) return true; - if (IsAArch64) + if (IsAArch64 || BC->isRISCV()) return true; if (SymbolName == "__hot_start" || SymbolName == "__hot_end") @@ -2107,7 +2160,11 @@ void RewriteInstance::processDynamicRelocations() { if (!DynamicRelSectionOrErr) report_error("unable to find section corresponding to DT_RELA", DynamicRelSectionOrErr.getError()); - if (DynamicRelSectionOrErr->getSize() != DynamicRelocationsSize) + auto DynamicRelSectionSize = DynamicRelSectionOrErr->getSize(); + // On RISC-V DT_RELASZ seems to include both .rela.dyn and .rela.plt + if (DynamicRelocationsSize == DynamicRelSectionSize + PLTRelocationsSize) + DynamicRelocationsSize = DynamicRelSectionSize; + if (DynamicRelSectionSize != DynamicRelocationsSize) report_error("section size mismatch for DT_RELASZ", errc::executable_format_error); readDynamicRelocations(DynamicRelSectionOrErr->getSectionRef(), @@ -2598,6 +2655,14 @@ void RewriteInstance::handleRelocation(const SectionRef &RelocatedSection, Expected SectionName = Section->getName(); if (SectionName && !SectionName->empty()) ReferencedSection = BC->getUniqueSectionByName(*SectionName); + } else if (ReferencedSymbol && + (cantFail(Symbol.getFlags()) & SymbolRef::SF_Absolute)) { + // This might be a relocation for an ABS symbols like __global_pointer$ on + // RISC-V + ContainingBF->addRelocation(Rel.getOffset(), ReferencedSymbol, + Rel.getType(), 0, + cantFail(Symbol.getValue())); + return; } } @@ -2607,7 +2672,7 @@ void RewriteInstance::handleRelocation(const SectionRef &RelocatedSection, const bool IsToCode = ReferencedSection && ReferencedSection->isText(); // Special handling of PC-relative relocations. - if (!IsAArch64 && Relocation::isPCRelative(RType)) { + if (!IsAArch64 && !BC->isRISCV() && Relocation::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 @@ -2640,7 +2705,7 @@ void RewriteInstance::handleRelocation(const SectionRef &RelocatedSection, } bool ForceRelocation = BC->forceSymbolRelocations(SymbolName); - if (BC->isAArch64() && Relocation::isGOT(RType)) + if ((BC->isAArch64() || BC->isRISCV()) && Relocation::isGOT(RType)) ForceRelocation = true; if (!ReferencedSection && !ForceRelocation) { @@ -2788,7 +2853,7 @@ void RewriteInstance::handleRelocation(const SectionRef &RelocatedSection, // These are mostly local data symbols but undefined symbols // in relocation sections can get through here too, from .plt. assert( - (IsAArch64 || IsSectionRelocation || + (IsAArch64 || BC->isRISCV() || IsSectionRelocation || BC->getSectionNameForAddress(SymbolAddress)->startswith(".plt")) && "known symbols should not resolve to anonymous locals"); diff --git a/bolt/lib/Target/RISCV/CMakeLists.txt b/bolt/lib/Target/RISCV/CMakeLists.txt new file mode 100644 index 0000000000000..7f95576063200 --- /dev/null +++ b/bolt/lib/Target/RISCV/CMakeLists.txt @@ -0,0 +1,21 @@ +set(LLVM_LINK_COMPONENTS + MC + Support + RISCVDesc + ) + +add_llvm_library(LLVMBOLTTargetRISCV + RISCVMCPlusBuilder.cpp + + DISABLE_LLVM_LINK_LLVM_DYLIB + + DEPENDS + RISCVCommonTableGen + ) + +target_link_libraries(LLVMBOLTTargetRISCV PRIVATE LLVMBOLTCore) + +include_directories( + ${LLVM_MAIN_SRC_DIR}/lib/Target/RISCV + ${LLVM_BINARY_DIR}/lib/Target/RISCV + ) diff --git a/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp b/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp new file mode 100644 index 0000000000000..993dc8b3d74e7 --- /dev/null +++ b/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp @@ -0,0 +1,328 @@ +//===- bolt/Target/RISCV/RISCVMCPlusBuilder.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 provides RISCV-specific MCPlus builder. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/RISCVMCExpr.h" +#include "MCTargetDesc/RISCVMCTargetDesc.h" +#include "bolt/Core/MCPlusBuilder.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/MC/MCInst.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" + +#define DEBUG_TYPE "mcplus" + +using namespace llvm; +using namespace bolt; + +namespace { + +class RISCVMCPlusBuilder : public MCPlusBuilder { +public: + using MCPlusBuilder::MCPlusBuilder; + + bool shouldRecordCodeRelocation(uint64_t RelType) const override { + switch (RelType) { + 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_RVC_BRANCH: + case ELF::R_RISCV_RVC_JUMP: + case ELF::R_RISCV_GOT_HI20: + case ELF::R_RISCV_PCREL_HI20: + case ELF::R_RISCV_PCREL_LO12_I: + return true; + default: + llvm_unreachable("Unexpected RISCV relocation type in code"); + } + } + + bool isNop(const MCInst &Inst) const { + return Inst.getOpcode() == RISCV::ADDI && + Inst.getOperand(0).getReg() == RISCV::X0 && + Inst.getOperand(1).getReg() == RISCV::X0 && + Inst.getOperand(2).getImm() == 0; + } + + bool isCNop(const MCInst &Inst) const { + return Inst.getOpcode() == RISCV::C_NOP; + } + + bool isNoop(const MCInst &Inst) const override { + return isNop(Inst) || isCNop(Inst); + } + + bool hasPCRelOperand(const MCInst &Inst) const override { + switch (Inst.getOpcode()) { + default: + return false; + case RISCV::JAL: + case RISCV::AUIPC: + return true; + } + } + + bool replaceBranchTarget(MCInst &Inst, const MCSymbol *TBB, + MCContext *Ctx) const override { + assert((isCall(Inst) || isBranch(Inst)) && !isIndirectBranch(Inst) && + "Invalid instruction"); + + unsigned SymOpIndex; + + switch (Inst.getOpcode()) { + default: + llvm_unreachable("not implemented"); + case RISCV::C_J: + SymOpIndex = 0; + break; + case RISCV::JAL: + case RISCV::C_BEQZ: + case RISCV::C_BNEZ: + SymOpIndex = 1; + break; + case RISCV::BEQ: + case RISCV::BGE: + SymOpIndex = 2; + break; + } + + Inst.getOperand(SymOpIndex) = MCOperand::createExpr( + MCSymbolRefExpr::create(TBB, MCSymbolRefExpr::VK_None, *Ctx)); + return true; + } + + IndirectBranchType analyzeIndirectBranch( + MCInst &Instruction, InstructionIterator Begin, InstructionIterator End, + const unsigned PtrSize, MCInst *&MemLocInstr, unsigned &BaseRegNum, + unsigned &IndexRegNum, int64_t &DispValue, const MCExpr *&DispExpr, + MCInst *&PCRelBaseOut) const override { + MemLocInstr = nullptr; + BaseRegNum = 0; + IndexRegNum = 0; + DispValue = 0; + DispExpr = nullptr; + PCRelBaseOut = nullptr; + return IndirectBranchType::UNKNOWN; + } + + bool convertJmpToTailCall(MCInst &Inst) override { + if (isTailCall(Inst)) + return false; + + switch (Inst.getOpcode()) { + default: + llvm_unreachable("unsupported tail call opcode"); + case RISCV::JAL: + case RISCV::JALR: + case RISCV::C_J: + case RISCV::C_JR: + break; + } + + setTailCall(Inst); + return true; + } + + bool analyzeBranch(InstructionIterator Begin, InstructionIterator End, + const MCSymbol *&TBB, const MCSymbol *&FBB, + MCInst *&CondBranch, + MCInst *&UncondBranch) const override { + auto I = End; + + while (I != Begin) { + --I; + + // Ignore nops and CFIs + if (isPseudo(*I) || isNoop(*I)) + continue; + + // Stop when we find the first non-terminator + if (!isTerminator(*I) || isTailCall(*I) || !isBranch(*I)) + break; + + // Handle unconditional branches. + if (isUnconditionalBranch(*I)) { + // If any code was seen after this unconditional branch, we've seen + // unreachable code. Ignore them. + CondBranch = nullptr; + UncondBranch = &*I; + const MCSymbol *Sym = getTargetSymbol(*I); + assert(Sym != nullptr && + "Couldn't extract BB symbol from jump operand"); + TBB = Sym; + continue; + } + + // Handle conditional branches and ignore indirect branches + if (isIndirectBranch(*I)) + return false; + + if (CondBranch == nullptr) { + const MCSymbol *TargetBB = getTargetSymbol(*I); + if (TargetBB == nullptr) { + // Unrecognized branch target + return false; + } + FBB = TBB; + TBB = TargetBB; + CondBranch = &*I; + continue; + } + + llvm_unreachable("multiple conditional branches in one BB"); + } + + return true; + } + + const MCSymbol *getTargetSymbol(const MCInst &Inst, + unsigned OpNum = 0) const override { + const MCOperand &Op = Inst.getOperand(OpNum); + if (!Op.isExpr()) + return nullptr; + + return MCPlusBuilder::getTargetSymbol(Op.getExpr()); + } + + bool lowerTailCall(MCInst &Inst) override { + removeAnnotation(Inst, MCPlus::MCAnnotation::kTailCall); + if (getConditionalTailCall(Inst)) + unsetConditionalTailCall(Inst); + return true; + } + + uint64_t analyzePLTEntry(MCInst &Instruction, InstructionIterator Begin, + InstructionIterator End, + uint64_t BeginPC) const override { + auto I = Begin; + + assert(I != End); + auto &AUIPC = *I++; + assert(AUIPC.getOpcode() == RISCV::AUIPC); + assert(AUIPC.getOperand(0).getReg() == RISCV::X28); + + assert(I != End); + auto &LD = *I++; + assert(LD.getOpcode() == RISCV::LD); + assert(LD.getOperand(0).getReg() == RISCV::X28); + assert(LD.getOperand(1).getReg() == RISCV::X28); + + assert(I != End); + auto &JALR = *I++; + (void)JALR; + assert(JALR.getOpcode() == RISCV::JALR); + assert(JALR.getOperand(0).getReg() == RISCV::X6); + assert(JALR.getOperand(1).getReg() == RISCV::X28); + + assert(I != End); + auto &NOP = *I++; + (void)NOP; + assert(isNoop(NOP)); + + assert(I == End); + + auto AUIPCOffset = AUIPC.getOperand(1).getImm() << 12; + auto LDOffset = LD.getOperand(2).getImm(); + return BeginPC + AUIPCOffset + LDOffset; + } + + bool replaceImmWithSymbolRef(MCInst &Inst, const MCSymbol *Symbol, + int64_t Addend, MCContext *Ctx, int64_t &Value, + uint64_t RelType) const override { + unsigned ImmOpNo = -1U; + + for (unsigned Index = 0; Index < MCPlus::getNumPrimeOperands(Inst); + ++Index) { + if (Inst.getOperand(Index).isImm()) { + ImmOpNo = Index; + break; + } + } + + if (ImmOpNo == -1U) + return false; + + Value = Inst.getOperand(ImmOpNo).getImm(); + setOperandToSymbolRef(Inst, ImmOpNo, Symbol, Addend, Ctx, RelType); + return true; + } + + const MCExpr *getTargetExprFor(MCInst &Inst, const MCExpr *Expr, + MCContext &Ctx, + uint64_t RelType) const override { + switch (RelType) { + default: + return Expr; + case ELF::R_RISCV_GOT_HI20: + // The GOT is reused so no need to create GOT relocations + case ELF::R_RISCV_PCREL_HI20: + return RISCVMCExpr::create(Expr, RISCVMCExpr::VK_RISCV_PCREL_HI, Ctx); + case ELF::R_RISCV_PCREL_LO12_I: + return RISCVMCExpr::create(Expr, RISCVMCExpr::VK_RISCV_PCREL_LO, Ctx); + case ELF::R_RISCV_CALL: + return RISCVMCExpr::create(Expr, RISCVMCExpr::VK_RISCV_CALL, Ctx); + case ELF::R_RISCV_CALL_PLT: + return RISCVMCExpr::create(Expr, RISCVMCExpr::VK_RISCV_CALL_PLT, Ctx); + } + } + + bool evaluateMemOperandTarget(const MCInst &Inst, uint64_t &Target, + uint64_t Address, + uint64_t Size) const override { + return false; + } + + bool isCallAuipc(const MCInst &Inst) const { + if (Inst.getOpcode() != RISCV::AUIPC) + return false; + + const auto &ImmOp = Inst.getOperand(1); + if (!ImmOp.isExpr()) + return false; + + const auto *ImmExpr = ImmOp.getExpr(); + if (!isa(ImmExpr)) + return false; + + switch (cast(ImmExpr)->getKind()) { + default: + return false; + case RISCVMCExpr::VK_RISCV_CALL: + case RISCVMCExpr::VK_RISCV_CALL_PLT: + return true; + } + } + + bool isRISCVCall(const MCInst &First, const MCInst &Second) const override { + if (!isCallAuipc(First)) + return false; + + assert(Second.getOpcode() == RISCV::JALR); + return true; + } +}; + +} // end anonymous namespace + +namespace llvm { +namespace bolt { + +MCPlusBuilder *createRISCVMCPlusBuilder(const MCInstrAnalysis *Analysis, + const MCInstrInfo *Info, + const MCRegisterInfo *RegInfo) { + return new RISCVMCPlusBuilder(Analysis, Info, RegInfo); +} + +} // namespace bolt +} // namespace llvm diff --git a/bolt/test/RISCV/Inputs/plt-gnu-ld.yaml b/bolt/test/RISCV/Inputs/plt-gnu-ld.yaml new file mode 100644 index 0000000000000..c03f308b1173d --- /dev/null +++ b/bolt/test/RISCV/Inputs/plt-gnu-ld.yaml @@ -0,0 +1,830 @@ +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_RISCV + Flags: [ EF_RISCV_RVC, EF_RISCV_FLOAT_ABI_DOUBLE ] + Entry: 0x5B0 +ProgramHeaders: + - Type: PT_PHDR + Flags: [ PF_R ] + VAddr: 0x40 + Align: 0x8 + - Type: PT_INTERP + Flags: [ PF_R ] + FirstSec: .interp + LastSec: .interp + VAddr: 0x270 + - Type: 0x70000003 + Flags: [ PF_R ] + FirstSec: .riscv.attributes + LastSec: .riscv.attributes + - Type: PT_LOAD + Flags: [ PF_X, PF_R ] + FirstSec: .interp + LastSec: .eh_frame + Align: 0x1000 + Offset: 0x0 + - Type: PT_LOAD + Flags: [ PF_W, PF_R ] + FirstSec: .preinit_array + LastSec: .bss + VAddr: 0x1E08 + Align: 0x1000 + - Type: PT_DYNAMIC + Flags: [ PF_W, PF_R ] + FirstSec: .dynamic + LastSec: .dynamic + VAddr: 0x1E20 + Align: 0x8 + - Type: PT_GNU_EH_FRAME + Flags: [ PF_R ] + FirstSec: .eh_frame_hdr + LastSec: .eh_frame_hdr + VAddr: 0x6AC + Align: 0x4 + - Type: PT_GNU_STACK + Flags: [ PF_W, PF_R ] + Align: 0x10 + - Type: PT_GNU_RELRO + Flags: [ PF_R ] + FirstSec: .preinit_array + LastSec: .dynamic + VAddr: 0x1E08 +Sections: + - Name: .interp + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + Address: 0x270 + AddressAlign: 0x1 + Content: 2F6C69622F6C642D6C696E75782D726973637636342D6C703634642E736F2E3100 + - Name: .dynsym + Type: SHT_DYNSYM + Flags: [ SHF_ALLOC ] + Address: 0x300 + Link: .dynstr + AddressAlign: 0x8 + - Name: .dynstr + Type: SHT_STRTAB + Flags: [ SHF_ALLOC ] + Address: 0x3C0 + AddressAlign: 0x1 + - Name: .rela.dyn + Type: SHT_RELA + Flags: [ SHF_ALLOC ] + Address: 0x480 + Link: .dynsym + AddressAlign: 0x8 + Relocations: + - Offset: 0x1E08 + Type: R_RISCV_RELATIVE + Addend: 1498 + - Offset: 0x1E10 + Type: R_RISCV_RELATIVE + Addend: 1650 + - Offset: 0x1E18 + Type: R_RISCV_RELATIVE + Addend: 1588 + - Offset: 0x2000 + Type: R_RISCV_RELATIVE + Addend: 8192 + - Offset: 0x2038 + Type: R_RISCV_RELATIVE + Addend: 1658 + - Offset: 0x2030 + Symbol: _ITM_deregisterTMCloneTable + Type: R_RISCV_64 + - Offset: 0x2040 + Symbol: __cxa_finalize + Type: R_RISCV_64 + - Offset: 0x2048 + Symbol: _ITM_registerTMCloneTable + Type: R_RISCV_64 + - Name: .rela.plt + Type: SHT_RELA + Flags: [ SHF_ALLOC, SHF_INFO_LINK ] + Address: 0x540 + Link: .dynsym + AddressAlign: 0x8 + Info: .got + Relocations: + - Offset: 0x2018 + Symbol: __libc_start_main + Type: R_RISCV_JUMP_SLOT + - Offset: 0x2020 + Symbol: puts + Type: R_RISCV_JUMP_SLOT + - Name: .plt + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x570 + AddressAlign: 0x10 + EntSize: 0x10 + Content: 972300003303C34103BE83A9130343FD938283A91353130083B2820067000E00172E0000033E8EA867030E0013000000172E0000033E0EA867030E0013000000 + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x5B0 + AddressAlign: 0x4 + Content: 97000000E780A002AA87172500000335E5A782653000137101FF814601470A8897000000E78000FC029097210000938161228280000017250000130525A2972700009387A7A16388A7009727000083B767A391C38287828017250000130505A0972500009385859F898D93D73540FD91BE95858599C59727000083B727A291C382878280411122E017240000130484A18347040006E495E39727000083B7879F91C7172500000335E59A829797000000E780A0F885472300F400A26002644101828017030000670063F9411106E422E00008170500001305650297000000E78060F181473E85A260026441018280 + - Name: .rodata + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + Address: 0x6A0 + AddressAlign: 0x8 + Content: '0100020000000000686900' + - Name: .eh_frame_hdr + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + Address: 0x6AC + AddressAlign: 0x4 + Content: 011B033B100000000100000004FFFFFF28000000 + - Name: .eh_frame + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + Address: 0x6C0 + AddressAlign: 0x8 + Content: 1000000000000000037A5200017C01011B0D02001000000018000000D4FEFFFF2A0000000007010000000000 + - Name: .preinit_array + Type: SHT_PREINIT_ARRAY + Flags: [ SHF_WRITE, SHF_ALLOC ] + Address: 0x1E08 + AddressAlign: 0x1 + EntSize: 0x8 + Offset: 0xE08 + Content: '0000000000000000' + - Name: .init_array + Type: SHT_INIT_ARRAY + Flags: [ SHF_WRITE, SHF_ALLOC ] + Address: 0x1E10 + AddressAlign: 0x8 + EntSize: 0x8 + Content: '0000000000000000' + - Name: .fini_array + Type: SHT_FINI_ARRAY + Flags: [ SHF_WRITE, SHF_ALLOC ] + Address: 0x1E18 + AddressAlign: 0x8 + EntSize: 0x8 + Content: '0000000000000000' + - Name: .dynamic + Type: SHT_DYNAMIC + Flags: [ SHF_WRITE, SHF_ALLOC ] + Address: 0x1E20 + Link: .dynstr + AddressAlign: 0x8 + Entries: + - Tag: DT_NEEDED + Value: 0x27 + - Tag: DT_PREINIT_ARRAY + Value: 0x1E08 + - Tag: DT_PREINIT_ARRAYSZ + Value: 0x8 + - Tag: DT_INIT_ARRAY + Value: 0x1E10 + - Tag: DT_INIT_ARRAYSZ + Value: 0x8 + - Tag: DT_FINI_ARRAY + Value: 0x1E18 + - Tag: DT_FINI_ARRAYSZ + Value: 0x8 + - Tag: DT_GNU_HASH + Value: 0x2D8 + - Tag: DT_STRTAB + Value: 0x3C0 + - Tag: DT_SYMTAB + Value: 0x300 + - Tag: DT_STRSZ + Value: 0x7D + - Tag: DT_SYMENT + Value: 0x18 + - Tag: DT_DEBUG + Value: 0x0 + - Tag: DT_PLTGOT + Value: 0x2008 + - Tag: DT_PLTRELSZ + Value: 0x30 + - Tag: DT_PLTREL + Value: 0x7 + - Tag: DT_JMPREL + Value: 0x540 + - Tag: DT_RELA + Value: 0x480 + - Tag: DT_RELASZ + Value: 0xF0 + - Tag: DT_RELAENT + Value: 0x18 + - Tag: DT_FLAGS_1 + Value: 0x8000000 + - Tag: DT_VERNEED + Value: 0x450 + - Tag: DT_VERNEEDNUM + Value: 0x1 + - Tag: DT_VERSYM + Value: 0x43E + - Tag: DT_RELACOUNT + Value: 0x5 + - Tag: DT_NULL + Value: 0x0 + - Tag: DT_NULL + Value: 0x0 + - Tag: DT_NULL + Value: 0x0 + - Tag: DT_NULL + Value: 0x0 + - Tag: DT_NULL + Value: 0x0 + - Name: .data + Type: SHT_PROGBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + Address: 0x2000 + AddressAlign: 0x8 + Content: '0000000000000000' + - Name: .tm_clone_table + Type: SHT_PROGBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + Address: 0x2008 + AddressAlign: 0x8 + - Name: .got + Type: SHT_PROGBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + Address: 0x2008 + AddressAlign: 0x8 + EntSize: 0x8 + Content: FFFFFFFFFFFFFFFF000000000000000070050000000000007005000000000000201E0000000000000000000000000000000000000000000000000000000000000000000000000000 + - Name: .bss + Type: SHT_NOBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + Address: 0x2050 + AddressAlign: 0x1 + Size: 0x8 + - Name: .riscv.attributes + Type: SHT_RISCV_ATTRIBUTES + AddressAlign: 0x1 + Content: 4149000000726973637600013F00000004100572763634693270315F6D3270305F613270315F663270325F643270325F633270305F7A696373723270305F7A6966656E63656932703000 + - Name: .rela.text + Type: SHT_RELA + Flags: [ SHF_INFO_LINK ] + Link: .symtab + AddressAlign: 0x8 + Info: .text + Relocations: + - Offset: 0x5B0 + Type: R_RISCV_NONE + Addend: 2 + - Offset: 0x5B0 + Symbol: load_gp + Type: R_RISCV_CALL + - Offset: 0x5B0 + Type: R_RISCV_RELAX + - Offset: 0x5BA + Symbol: main + Type: R_RISCV_GOT_HI20 + - Offset: 0x5BE + Symbol: '.L0 ' + Type: R_RISCV_PCREL_LO12_I + - Offset: 0x5BE + Type: R_RISCV_RELAX + - Offset: 0x5D0 + Symbol: '__libc_start_main@GLIBC_2.34' + Type: R_RISCV_CALL_PLT + - Offset: 0x5D0 + Type: R_RISCV_RELAX + - Offset: 0x5DA + Symbol: '__global_pointer$' + Type: R_RISCV_PCREL_HI20 + - Offset: 0x5DE + Symbol: '.L0 (1)' + Type: R_RISCV_PCREL_LO12_I + - Offset: 0x5E6 + Symbol: __TMC_LIST__ + Type: R_RISCV_PCREL_HI20 + - Offset: 0x5E6 + Type: R_RISCV_RELAX + - Offset: 0x5EA + Symbol: '.L0 (4)' + Type: R_RISCV_PCREL_LO12_I + - Offset: 0x5EA + Type: R_RISCV_RELAX + - Offset: 0x5EE + Symbol: __TMC_END__ + Type: R_RISCV_PCREL_HI20 + - Offset: 0x5EE + Type: R_RISCV_RELAX + - Offset: 0x5F2 + Symbol: '.L0 (5)' + Type: R_RISCV_PCREL_LO12_I + - Offset: 0x5F2 + Type: R_RISCV_RELAX + - Offset: 0x5F6 + Symbol: .L1 + Type: R_RISCV_BRANCH + - Offset: 0x5FA + Symbol: _ITM_deregisterTMCloneTable + Type: R_RISCV_GOT_HI20 + - Offset: 0x5FE + Symbol: '.L0 (6)' + Type: R_RISCV_PCREL_LO12_I + - Offset: 0x5FE + Type: R_RISCV_RELAX + - Offset: 0x602 + Symbol: .L1 + Type: R_RISCV_RVC_BRANCH + - Offset: 0x608 + Symbol: __TMC_LIST__ + Type: R_RISCV_PCREL_HI20 + - Offset: 0x608 + Type: R_RISCV_RELAX + - Offset: 0x60C + Symbol: '.L0 (7)' + Type: R_RISCV_PCREL_LO12_I + - Offset: 0x60C + Type: R_RISCV_RELAX + - Offset: 0x610 + Symbol: __TMC_END__ + Type: R_RISCV_PCREL_HI20 + - Offset: 0x610 + Type: R_RISCV_RELAX + - Offset: 0x614 + Symbol: '.L0 (8)' + Type: R_RISCV_PCREL_LO12_I + - Offset: 0x614 + Type: R_RISCV_RELAX + - Offset: 0x624 + Symbol: .L7 + Type: R_RISCV_RVC_BRANCH + - Offset: 0x626 + Symbol: _ITM_registerTMCloneTable + Type: R_RISCV_GOT_HI20 + - Offset: 0x62A + Symbol: '.L0 (9)' + Type: R_RISCV_PCREL_LO12_I + - Offset: 0x62A + Type: R_RISCV_RELAX + - Offset: 0x62E + Symbol: .L7 + Type: R_RISCV_RVC_BRANCH + - Offset: 0x638 + Symbol: completed.0 + Type: R_RISCV_PCREL_HI20 + - Offset: 0x638 + Type: R_RISCV_RELAX + - Offset: 0x63C + Symbol: '.L0 (10)' + Type: R_RISCV_PCREL_LO12_I + - Offset: 0x63C + Type: R_RISCV_RELAX + - Offset: 0x646 + Symbol: .L15 + Type: R_RISCV_RVC_BRANCH + - Offset: 0x648 + Symbol: '__cxa_finalize@GLIBC_2.27' + Type: R_RISCV_GOT_HI20 + - Offset: 0x64C + Symbol: '.L0 (11)' + Type: R_RISCV_PCREL_LO12_I + - Offset: 0x64C + Type: R_RISCV_RELAX + - Offset: 0x650 + Symbol: .L17 + Type: R_RISCV_RVC_BRANCH + - Offset: 0x652 + Symbol: __dso_handle + Type: R_RISCV_PCREL_HI20 + - Offset: 0x652 + Type: R_RISCV_RELAX + - Offset: 0x656 + Symbol: '.L0 (12)' + Type: R_RISCV_PCREL_LO12_I + - Offset: 0x656 + Type: R_RISCV_RELAX + - Offset: 0x65C + Symbol: deregister_tm_clones + Type: R_RISCV_CALL + - Offset: 0x65C + Type: R_RISCV_RELAX + - Offset: 0x672 + Symbol: register_tm_clones + Type: R_RISCV_CALL + - Offset: 0x672 + Type: R_RISCV_RELAX + - Offset: 0x682 + Symbol: .LC0 + Type: R_RISCV_PCREL_HI20 + - Offset: 0x682 + Type: R_RISCV_RELAX + - Offset: 0x686 + Symbol: '.L0 (13)' + Type: R_RISCV_PCREL_LO12_I + - Offset: 0x686 + Type: R_RISCV_RELAX + - Offset: 0x68A + Symbol: 'puts@GLIBC_2.27' + Type: R_RISCV_CALL_PLT + - Offset: 0x68A + Type: R_RISCV_RELAX + - Name: .rela.eh_frame + Type: SHT_RELA + Flags: [ SHF_INFO_LINK ] + Link: .symtab + AddressAlign: 0x8 + Info: .eh_frame + Relocations: + - Offset: 0x6DC + Symbol: '.L0 (2)' + Type: R_RISCV_32_PCREL + - Offset: 0x6E0 + Symbol: '.L0 (3)' + Type: R_RISCV_ADD32 + - Offset: 0x6E0 + Symbol: '.L0 (2)' + Type: R_RISCV_SUB32 + - Name: .rela.preinit_array + Type: SHT_RELA + Flags: [ SHF_INFO_LINK ] + Link: .symtab + AddressAlign: 0x8 + Info: .preinit_array + Relocations: + - Offset: 0x1E08 + Symbol: load_gp + Type: R_RISCV_64 + - Name: .rela.init_array + Type: SHT_RELA + Flags: [ SHF_INFO_LINK ] + Link: .symtab + AddressAlign: 0x8 + Info: .init_array + Relocations: + - Offset: 0x1E10 + Symbol: frame_dummy + Type: R_RISCV_64 + - Name: .rela.fini_array + Type: SHT_RELA + Flags: [ SHF_INFO_LINK ] + Link: .symtab + AddressAlign: 0x8 + Info: .fini_array + Relocations: + - Offset: 0x1E18 + Symbol: __do_global_dtors_aux + Type: R_RISCV_64 + - Name: .rela.data + Type: SHT_RELA + Flags: [ SHF_INFO_LINK ] + Link: .symtab + AddressAlign: 0x8 + Info: .data + Relocations: + - Offset: 0x2000 + Symbol: __dso_handle + Type: R_RISCV_64 + - Type: SectionHeaderTable + Sections: + - Name: .interp + - Name: .dynsym + - Name: .dynstr + - Name: .rela.dyn + - Name: .rela.plt + - Name: .plt + - Name: .text + - Name: .rela.text + - Name: .rodata + - Name: .eh_frame_hdr + - Name: .eh_frame + - Name: .rela.eh_frame + - Name: .preinit_array + - Name: .rela.preinit_array + - Name: .init_array + - Name: .rela.init_array + - Name: .fini_array + - Name: .rela.fini_array + - Name: .dynamic + - Name: .data + - Name: .rela.data + - Name: .tm_clone_table + - Name: .got + - Name: .bss + - Name: .riscv.attributes + - Name: .symtab + - Name: .strtab + - Name: .shstrtab +Symbols: + - Name: .interp + Type: STT_SECTION + Section: .interp + Value: 0x270 + - Name: .dynsym + Type: STT_SECTION + Section: .dynsym + Value: 0x300 + - Name: .dynstr + Type: STT_SECTION + Section: .dynstr + Value: 0x3C0 + - Name: .rela.dyn + Type: STT_SECTION + Section: .rela.dyn + Value: 0x480 + - Name: .rela.plt + Type: STT_SECTION + Section: .rela.plt + Value: 0x540 + - Name: .plt + Type: STT_SECTION + Section: .plt + Value: 0x570 + - Name: .text + Type: STT_SECTION + Section: .text + Value: 0x5B0 + - Name: .rodata + Type: STT_SECTION + Section: .rodata + Value: 0x6A0 + - Name: .eh_frame_hdr + Type: STT_SECTION + Section: .eh_frame_hdr + Value: 0x6AC + - Name: .eh_frame + Type: STT_SECTION + Section: .eh_frame + Value: 0x6C0 + - Name: .preinit_array + Type: STT_SECTION + Section: .preinit_array + Value: 0x1E08 + - Name: .init_array + Type: STT_SECTION + Section: .init_array + Value: 0x1E10 + - Name: .fini_array + Type: STT_SECTION + Section: .fini_array + Value: 0x1E18 + - Name: .dynamic + Type: STT_SECTION + Section: .dynamic + Value: 0x1E20 + - Name: .data + Type: STT_SECTION + Section: .data + Value: 0x2000 + - Name: .tm_clone_table + Type: STT_SECTION + Section: .tm_clone_table + Value: 0x2008 + - Name: .got + Type: STT_SECTION + Section: .got + Value: 0x2008 + - Name: .bss + Type: STT_SECTION + Section: .bss + Value: 0x2050 + - Name: .riscv.attributes + Type: STT_SECTION + Section: .riscv.attributes + - Name: start.os + Type: STT_FILE + Index: SHN_ABS + - Name: '$x' + Section: .text + Value: 0x5B0 + - Name: load_gp + Section: .text + Value: 0x5DA + - Name: init.c + Type: STT_FILE + Index: SHN_ABS + - Name: '.L0 ' + Section: .text + Value: 0x5BA + - Name: '.L0 (1)' + Section: .text + Value: 0x5DA + - Name: '.L0 (2)' + Section: .text + Value: 0x5B0 + - Name: '.L0 (3)' + Section: .text + Value: 0x5DA + - Name: crtstuff.c + Type: STT_FILE + Index: SHN_ABS + - Name: __TMC_LIST__ + Type: STT_OBJECT + Section: .tm_clone_table + Value: 0x2008 + - Name: deregister_tm_clones + Type: STT_FUNC + Section: .text + Value: 0x5E6 + - Name: '$x (1)' + Section: .text + Value: 0x5E6 + - Name: register_tm_clones + Type: STT_FUNC + Section: .text + Value: 0x608 + - Name: __do_global_dtors_aux + Type: STT_FUNC + Section: .text + Value: 0x634 + - Name: completed.0 + Type: STT_OBJECT + Section: .bss + Value: 0x2050 + Size: 0x1 + - Name: __do_global_dtors_aux_fini_array_entry + Type: STT_OBJECT + Section: .fini_array + Value: 0x1E18 + - Name: frame_dummy + Type: STT_FUNC + Section: .text + Value: 0x672 + - Name: __frame_dummy_init_array_entry + Type: STT_OBJECT + Section: .init_array + Value: 0x1E10 + - Name: '.L0 (4)' + Section: .text + Value: 0x5E6 + - Name: '.L0 (5)' + Section: .text + Value: 0x5EE + - Name: .L1 + Section: .text + Value: 0x606 + - Name: '.L0 (6)' + Section: .text + Value: 0x5FA + - Name: '.L0 (7)' + Section: .text + Value: 0x608 + - Name: '.L0 (8)' + Section: .text + Value: 0x610 + - Name: .L7 + Section: .text + Value: 0x632 + - Name: '.L0 (9)' + Section: .text + Value: 0x626 + - Name: '.L0 (10)' + Section: .text + Value: 0x638 + - Name: .L15 + Section: .text + Value: 0x66A + - Name: '.L0 (11)' + Section: .text + Value: 0x648 + - Name: .L17 + Section: .text + Value: 0x65C + - Name: '.L0 (12)' + Section: .text + Value: 0x652 + - Name: test.c + Type: STT_FILE + Index: SHN_ABS + - Name: '$x (2)' + Section: .text + Value: 0x67A + - Name: .LC0 + Section: .rodata + Value: 0x6A8 + - Name: '.L0 (13)' + Section: .text + Value: 0x682 + - Name: 'crtstuff.c (1)' + Type: STT_FILE + Index: SHN_ABS + - Name: __FRAME_END__ + Type: STT_OBJECT + Section: .eh_frame + Value: 0x6E8 + - Type: STT_FILE + Index: SHN_ABS + - Name: _PROCEDURE_LINKAGE_TABLE_ + Type: STT_OBJECT + Index: SHN_ABS + Value: 0x570 + - Name: _DYNAMIC + Type: STT_OBJECT + Index: SHN_ABS + Value: 0x1E20 + - Name: __GNU_EH_FRAME_HDR + Section: .eh_frame_hdr + Value: 0x6AC + - Name: _GLOBAL_OFFSET_TABLE_ + Type: STT_OBJECT + Index: SHN_ABS + Value: 0x2028 + - Name: '__libc_start_main@GLIBC_2.34' + Type: STT_FUNC + Binding: STB_GLOBAL + - Name: _ITM_deregisterTMCloneTable + Binding: STB_WEAK + - Name: data_start + Section: .data + Binding: STB_WEAK + Value: 0x2000 + - Name: __BSS_END__ + Section: .bss + Binding: STB_GLOBAL + Value: 0x2058 + - Name: _edata + Section: .got + Binding: STB_GLOBAL + Value: 0x2050 + - Name: __SDATA_BEGIN__ + Section: .got + Binding: STB_GLOBAL + Value: 0x2050 + - Name: __DATA_BEGIN__ + Section: .data + Binding: STB_GLOBAL + Value: 0x2000 + - Name: __data_start + Section: .data + Binding: STB_GLOBAL + Value: 0x2000 + - Name: __dso_handle + Type: STT_OBJECT + Section: .data + Binding: STB_GLOBAL + Value: 0x2000 + Other: [ STV_HIDDEN ] + - Name: _IO_stdin_used + Type: STT_OBJECT + Section: .rodata + Binding: STB_GLOBAL + Value: 0x6A0 + Size: 0x4 + - Name: _end + Section: .bss + Binding: STB_GLOBAL + Value: 0x2058 + - Name: _start + Type: STT_FUNC + Section: .text + Binding: STB_GLOBAL + Value: 0x5B0 + Size: 0x2A + - Name: '__global_pointer$' + Index: SHN_ABS + Binding: STB_GLOBAL + Value: 0x2800 + - Name: 'puts@GLIBC_2.27' + Type: STT_FUNC + Binding: STB_GLOBAL + - Name: __bss_start + Section: .bss + Binding: STB_GLOBAL + Value: 0x2050 + - Name: main + Type: STT_FUNC + Section: .text + Binding: STB_GLOBAL + Value: 0x67A + Size: 0x24 + - Name: '__cxa_finalize@GLIBC_2.27' + Type: STT_FUNC + Binding: STB_WEAK + - Name: __TMC_END__ + Type: STT_OBJECT + Section: .tm_clone_table + Binding: STB_GLOBAL + Value: 0x2008 + Other: [ STV_HIDDEN ] + - Name: _ITM_registerTMCloneTable + Binding: STB_WEAK +DynamicSymbols: + - Name: .text + Type: STT_SECTION + Section: .text + Value: 0x5B0 + - Name: __libc_start_main + Type: STT_FUNC + Binding: STB_GLOBAL + - Name: _ITM_deregisterTMCloneTable + Binding: STB_WEAK + - Name: puts + Type: STT_FUNC + Binding: STB_GLOBAL + - Name: __cxa_finalize + Type: STT_FUNC + Binding: STB_WEAK + - Name: _ITM_registerTMCloneTable + Binding: STB_WEAK + - Name: main + Type: STT_FUNC + Section: .text + Binding: STB_GLOBAL + Value: 0x67A + Size: 0x24 +... diff --git a/bolt/test/RISCV/lit.local.cfg b/bolt/test/RISCV/lit.local.cfg new file mode 100644 index 0000000000000..a1ebbfc45bca7 --- /dev/null +++ b/bolt/test/RISCV/lit.local.cfg @@ -0,0 +1,7 @@ +if 'RISCV' not in config.root.targets: + config.unsupported = True + +flags = '--target=riscv64 -nostdlib -ffreestanding -Wl,--no-relax,--emit-relocs' + +config.substitutions.insert(0, ('%cflags', f'%cflags {flags}')) +config.substitutions.insert(0, ('%cxxflags', f'%cxxflags {flags}')) diff --git a/bolt/test/RISCV/plt-gnu-ld.test b/bolt/test/RISCV/plt-gnu-ld.test new file mode 100644 index 0000000000000..f87f51dda8959 --- /dev/null +++ b/bolt/test/RISCV/plt-gnu-ld.test @@ -0,0 +1,9 @@ +// This test checks that the PLT symbols are properly recognized +// by the BOLT tool. + +// RUN: yaml2obj %p/Inputs/plt-gnu-ld.yaml &> %t.exe +// RUN: llvm-bolt %t.exe -o %t.bolt.exe --print-cfg --print-only=main \ +// RUN: | FileCheck %s + +// CHECK: Binary Function "main" after building cfg { +// CHECK: auipc ra, puts@PLT diff --git a/bolt/test/RISCV/reloc-abs.s b/bolt/test/RISCV/reloc-abs.s new file mode 100644 index 0000000000000..3e4b8b1395e1f --- /dev/null +++ b/bolt/test/RISCV/reloc-abs.s @@ -0,0 +1,26 @@ +// RUN: %clang %cflags -Wl,--defsym='__global_pointer$'=0x2800 -o %t %s +// RUN: llvm-bolt --print-cfg --print-only=_start -o /dev/null %t \ +// RUN: | FileCheck %s + + .data + .globl d + .p2align 3 +d: + .dword 0 + + .text + .globl _start + .p2align 1 +// CHECK: Binary Function "_start" after building cfg { +_start: + nop + .option push + .option norelax +1: +// CHECK: .Ltmp0 +// CHECK: auipc gp, %pcrel_hi(__global_pointer$) +// CHECK-NEXT: addi gp, gp, %pcrel_lo(.Ltmp0) + auipc gp, %pcrel_hi(__global_pointer$) + addi gp, gp, %pcrel_lo(1b) + .option pop + .size _start, .-_start diff --git a/bolt/test/RISCV/reloc-branch.s b/bolt/test/RISCV/reloc-branch.s new file mode 100644 index 0000000000000..43991149af8c8 --- /dev/null +++ b/bolt/test/RISCV/reloc-branch.s @@ -0,0 +1,16 @@ +// RUN: %clang %cflags -o %t %s +// RUN: llvm-bolt --print-cfg --print-only=_start -o /dev/null %t \ +// RUN: | FileCheck %s + + .text + .globl _start + .p2align 1 +// CHECK: Binary Function "_start" after building cfg { +_start: +// CHECK: beq zero, zero, .Ltmp0 + beq zero, zero, 1f + nop +// CHECK: .Ltmp0 +1: + ret + .size _start, .-_start diff --git a/bolt/test/RISCV/reloc-call.s b/bolt/test/RISCV/reloc-call.s new file mode 100644 index 0000000000000..17b952b44ff3b --- /dev/null +++ b/bolt/test/RISCV/reloc-call.s @@ -0,0 +1,21 @@ +// RUN: %clang %cflags -o %t %s +// RUN: llvm-bolt --print-fix-riscv-calls --print-only=_start -o /dev/null %t \ +// RUN: | FileCheck %s + + .text + + .global f + .p2align 1 +f: + ret + .size f, .-f + +// CHECK: Binary Function "_start" after fix-riscv-calls { + .globl _start + .p2align 1 +_start: +// CHECK: auipc ra, f +// CHECK-NEXT: jalr ra + call f + ret + .size _start, .-_start diff --git a/bolt/test/RISCV/reloc-got.s b/bolt/test/RISCV/reloc-got.s new file mode 100644 index 0000000000000..b6cd61be723bf --- /dev/null +++ b/bolt/test/RISCV/reloc-got.s @@ -0,0 +1,24 @@ +// RUN: %clang %cflags -o %t %s +// RUN: llvm-bolt --print-cfg --print-only=_start -o /dev/null %t \ +// RUN: | FileCheck %s + + .data + .globl d + .p2align 3 +d: + .dword 0 + + .text + .globl _start + .p2align 1 +// CHECK: Binary Function "_start" after building cfg { +_start: + nop // Here to not make the _start and .Ltmp0 symbols coincide +// CHECK: .Ltmp0 +// CHECK: auipc t0, %pcrel_hi(__BOLT_got_zero+{{[0-9]+}}) +// CHECK-NEXT: ld t0, %pcrel_lo(.Ltmp0)(t0) +1: + auipc t0, %got_pcrel_hi(d) + ld t0, %pcrel_lo(1b)(t0) + ret + .size _start, .-_start diff --git a/bolt/test/RISCV/reloc-jal.s b/bolt/test/RISCV/reloc-jal.s new file mode 100644 index 0000000000000..427e8f230d89a --- /dev/null +++ b/bolt/test/RISCV/reloc-jal.s @@ -0,0 +1,20 @@ +// RUN: %clang %cflags -o %t %s +// RUN: llvm-bolt --print-cfg --print-only=_start -o /dev/null %t \ +// RUN: | FileCheck %s + + .text + + .global f + .p2align 1 +f: + ret + .size f, .-f + +// CHECK: Binary Function "_start" after building cfg { + .globl _start + .p2align 1 +_start: +// CHECK: jal ra, f + jal ra, f + ret + .size _start, .-_start diff --git a/bolt/test/RISCV/reloc-pcrel.s b/bolt/test/RISCV/reloc-pcrel.s new file mode 100644 index 0000000000000..2d5a349d03e78 --- /dev/null +++ b/bolt/test/RISCV/reloc-pcrel.s @@ -0,0 +1,22 @@ +// RUN: %clang %cflags -o %t %s +// RUN: llvm-bolt --print-cfg --print-only=_start -o /dev/null %t \ +// RUN: | FileCheck %s + + .data + .globl d + .p2align 3 +d: + .dword 0 + + .text + .globl _start + .p2align 1 +// CHECK: Binary Function "_start" after building cfg { +_start: + nop // Here to not make the _start and .Ltmp0 symbols coincide +// CHECK: .Ltmp0 +// CHECK: auipc t0, %pcrel_hi(d) +// CHECK-NEXT: ld t0, %pcrel_lo(.Ltmp0)(t0) + ld t0, d + ret + .size _start, .-_start diff --git a/bolt/test/RISCV/reloc-rvc-branch.s b/bolt/test/RISCV/reloc-rvc-branch.s new file mode 100644 index 0000000000000..34221c167d865 --- /dev/null +++ b/bolt/test/RISCV/reloc-rvc-branch.s @@ -0,0 +1,16 @@ +// RUN: %clang %cflags -o %t %s +// RUN: llvm-bolt --print-cfg --print-only=_start -o /dev/null %t \ +// RUN: | FileCheck %s + + .text + .globl _start + .p2align 1 +// CHECK: Binary Function "_start" after building cfg { +_start: +// CHECK: beqz a0, .Ltmp0 + c.beqz a0, 1f + nop +// CHECK: .Ltmp0 +1: + ret + .size _start, .-_start diff --git a/bolt/test/RISCV/reloc-rvc-jump.s b/bolt/test/RISCV/reloc-rvc-jump.s new file mode 100644 index 0000000000000..21b10bab09c7c --- /dev/null +++ b/bolt/test/RISCV/reloc-rvc-jump.s @@ -0,0 +1,16 @@ +// RUN: %clang %cflags -o %t %s +// RUN: llvm-bolt --print-cfg --print-only=_start -o /dev/null %t \ +// RUN: | FileCheck %s + + .text + .globl _start + .p2align 1 +// CHECK: Binary Function "_start" after building cfg { +_start: +// CHECK: j .Ltmp0 + c.j 1f + nop +// CHECK: .Ltmp0 +1: + ret + .size _start, .-_start