diff options
Diffstat (limited to 'lld/ELF/Arch')
| -rw-r--r-- | lld/ELF/Arch/AArch64.cpp | 7 | ||||
| -rw-r--r-- | lld/ELF/Arch/ARM.cpp | 2 | ||||
| -rw-r--r-- | lld/ELF/Arch/RISCV.cpp | 49 | ||||
| -rw-r--r-- | lld/ELF/Arch/RISCVInternalRelocations.h | 113 |
4 files changed, 160 insertions, 11 deletions
diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp index 2a97df4..4613539 100644 --- a/lld/ELF/Arch/AArch64.cpp +++ b/lld/ELF/Arch/AArch64.cpp @@ -114,6 +114,7 @@ AArch64::AArch64(Ctx &ctx) : TargetInfo(ctx) { copyRel = R_AARCH64_COPY; relativeRel = R_AARCH64_RELATIVE; iRelativeRel = R_AARCH64_IRELATIVE; + iRelSymbolicRel = R_AARCH64_FUNCINIT64; gotRel = R_AARCH64_GLOB_DAT; pltRel = R_AARCH64_JUMP_SLOT; symbolicRel = R_AARCH64_ABS64; @@ -137,6 +138,7 @@ RelExpr AArch64::getRelExpr(RelType type, const Symbol &s, case R_AARCH64_ABS16: case R_AARCH64_ABS32: case R_AARCH64_ABS64: + case R_AARCH64_FUNCINIT64: case R_AARCH64_ADD_ABS_LO12_NC: case R_AARCH64_LDST128_ABS_LO12_NC: case R_AARCH64_LDST16_ABS_LO12_NC: @@ -267,7 +269,8 @@ bool AArch64::usesOnlyLowPageBits(RelType type) const { } RelType AArch64::getDynRel(RelType type) const { - if (type == R_AARCH64_ABS64 || type == R_AARCH64_AUTH_ABS64) + if (type == R_AARCH64_ABS64 || type == R_AARCH64_AUTH_ABS64 || + type == R_AARCH64_FUNCINIT64) return type; return R_AARCH64_NONE; } @@ -762,7 +765,7 @@ void AArch64::relaxTlsGdToIe(uint8_t *loc, const Relocation &rel, relocateNoSym(loc, R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC, val); break; default: - llvm_unreachable("unsupported relocation for TLS GD to LE relaxation"); + llvm_unreachable("unsupported relocation for TLS GD to IE relaxation"); } } diff --git a/lld/ELF/Arch/ARM.cpp b/lld/ELF/Arch/ARM.cpp index 91a673f..6c4290f 100644 --- a/lld/ELF/Arch/ARM.cpp +++ b/lld/ELF/Arch/ARM.cpp @@ -472,7 +472,7 @@ bool ARM::inBranchRange(RelType type, uint64_t src, uint64_t dst) const { // Bit 0 == 1 denotes Thumb state, it is not part of the range. dst &= ~0x1; - int64_t offset = dst - src; + int64_t offset = llvm::SignExtend64<32>(dst - src); switch (type) { case R_ARM_PC24: case R_ARM_PLT32: diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp index 5ed89e4..7ec75b0 100644 --- a/lld/ELF/Arch/RISCV.cpp +++ b/lld/ELF/Arch/RISCV.cpp @@ -8,6 +8,7 @@ #include "InputFiles.h" #include "OutputSections.h" +#include "RISCVInternalRelocations.h" #include "RelocScan.h" #include "Symbols.h" #include "SyntheticSections.h" @@ -345,8 +346,15 @@ RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s, case R_RISCV_SUB_ULEB128: return RE_RISCV_LEB128; default: - Err(ctx) << getErrorLoc(ctx, loc) << "unknown relocation (" << type.v - << ") against symbol " << &s; + if (type.v & INTERNAL_RISCV_VENDOR_MASK) { + Err(ctx) << getErrorLoc(ctx, loc) + << "unsupported vendor-specific relocation " << type + << " against symbol " << &s; + return R_NONE; + } + Err(ctx) << getErrorLoc(ctx, loc) << "unknown relocation (" + << (type.v & ~INTERNAL_RISCV_VENDOR_MASK) << ") against symbol " + << &s; return R_NONE; } } @@ -859,7 +867,7 @@ static bool relax(Ctx &ctx, int pass, InputSection &sec) { std::fill_n(aux.relocTypes.get(), relocs.size(), R_RISCV_NONE); aux.writes.clear(); - for (auto [i, r] : llvm::enumerate(relocs)) { + for (auto [i, r] : llvm::enumerate(riscv_vendor_relocs(relocs))) { const uint64_t loc = secAddr + r.offset - delta; uint32_t &cur = aux.relocDeltas[i], remove = 0; switch (r.type) { @@ -1503,12 +1511,19 @@ void RISCV::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) { rvVendor = sym.getName(); continue; } else if (!rvVendor.empty()) { - Err(ctx) << getErrorLoc(ctx, loc) - << "unknown vendor-specific relocation (" << type.v - << ") in namespace '" << rvVendor << "' against symbol '" << &sym - << "'"; + uint32_t VendorFlag = getRISCVVendorRelMarker(rvVendor); + if (!VendorFlag) { + Err(ctx) << getErrorLoc(ctx, loc) + << "unknown vendor-specific relocation (" << type.v + << ") in namespace '" << rvVendor << "' against symbol '" + << &sym << "'"; + rvVendor = ""; + continue; + } + rvVendor = ""; - continue; + assert((type.v < 256) && "Out of range relocation detected!"); + type.v |= VendorFlag; } rs.scan<ELFT, RelTy>(it, type, rs.getAddend<ELFT>(*it, type)); @@ -1533,3 +1548,21 @@ template <class ELFT> void RISCV::scanSection1(InputSectionBase &sec) { void RISCV::scanSection(InputSectionBase &sec) { invokeELFT(scanSection1, sec); } + +namespace lld::elf { +uint32_t getRISCVVendorRelMarker(StringRef rvVendor) { + return StringSwitch<uint32_t>(rvVendor) + .Case("QUALCOMM", INTERNAL_RISCV_VENDOR_QUALCOMM) + .Case("ANDES", INTERNAL_RISCV_VENDOR_ANDES) + .Default(0); +} + +std::optional<StringRef> getRISCVVendorString(RelType ty) { + if ((ty.v & INTERNAL_RISCV_VENDOR_MASK) == INTERNAL_RISCV_VENDOR_QUALCOMM) + return "QUALCOMM"; + if ((ty.v & INTERNAL_RISCV_VENDOR_MASK) == INTERNAL_RISCV_VENDOR_ANDES) + return "ANDES"; + return std::nullopt; +} + +} // namespace lld::elf diff --git a/lld/ELF/Arch/RISCVInternalRelocations.h b/lld/ELF/Arch/RISCVInternalRelocations.h new file mode 100644 index 0000000..35e2f53 --- /dev/null +++ b/lld/ELF/Arch/RISCVInternalRelocations.h @@ -0,0 +1,113 @@ +//===----------------------------------------------------------------------===// +// +// 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 LLD_ELF_ARCH_RISCVINTERNALRELOCATIONS_H +#define LLD_ELF_ARCH_RISCVINTERNALRELOCATIONS_H + +#include "Relocations.h" +#include "Symbols.h" + +namespace lld::elf { + +// Bit 8 of RelType is used to indicate linker-internal relocations that are +// not vendor-specific. +// These are internal relocation numbers for GP/X0 relaxation. They aren't part +// of the psABI spec. +constexpr uint32_t INTERNAL_R_RISCV_GPREL_I = 256; +constexpr uint32_t INTERNAL_R_RISCV_GPREL_S = 257; +constexpr uint32_t INTERNAL_R_RISCV_X0REL_I = 258; +constexpr uint32_t INTERNAL_R_RISCV_X0REL_S = 259; + +// Bits 9 -> 31 of RelType are used to indicate vendor-specific relocations. +constexpr uint32_t INTERNAL_RISCV_VENDOR_MASK = 0xFFFFFFFF << 9; +constexpr uint32_t INTERNAL_RISCV_VENDOR_QUALCOMM = 1 << 9; +constexpr uint32_t INTERNAL_RISCV_VENDOR_ANDES = 2 << 9; + +constexpr uint32_t INTERNAL_RISCV_QC_ABS20_U = + INTERNAL_RISCV_VENDOR_QUALCOMM | llvm::ELF::R_RISCV_QC_ABS20_U; +constexpr uint32_t INTERNAL_RISCV_QC_E_BRANCH = + INTERNAL_RISCV_VENDOR_QUALCOMM | llvm::ELF::R_RISCV_QC_E_BRANCH; +constexpr uint32_t INTERNAL_RISCV_QC_E_32 = + INTERNAL_RISCV_VENDOR_QUALCOMM | llvm::ELF::R_RISCV_QC_E_32; +constexpr uint32_t INTERNAL_RISCV_QC_E_CALL_PLT = + INTERNAL_RISCV_VENDOR_QUALCOMM | llvm::ELF::R_RISCV_QC_E_CALL_PLT; + +constexpr uint32_t INTERNAL_RISCV_NDS_BRANCH_10 = + INTERNAL_RISCV_VENDOR_ANDES | llvm::ELF::R_RISCV_NDS_BRANCH_10; + +uint32_t getRISCVVendorRelMarker(llvm::StringRef rvVendor); +std::optional<llvm::StringRef> getRISCVVendorString(RelType ty); + +class vendor_reloc_iterator { +public: + using iterator_category = std::forward_iterator_tag; + using value_type = Relocation; + using difference_type = std::ptrdiff_t; + using pointer = Relocation *; + using reference = Relocation; // returned by value + + vendor_reloc_iterator(MutableArrayRef<Relocation>::iterator i, + MutableArrayRef<Relocation>::iterator e) + : it(i), end(e) {} + + // Dereference + Relocation operator*() const { + Relocation r = *it; + r.type.v |= rvVendorFlag; + return r; + } + + struct vendor_reloc_proxy { + Relocation r; + const Relocation *operator->() const { return &r; } + }; + + vendor_reloc_proxy operator->() const { + return vendor_reloc_proxy{this->operator*()}; + } + + vendor_reloc_iterator &operator++() { + ++it; + if (it != end && it->type == llvm::ELF::R_RISCV_VENDOR) { + rvVendorFlag = getRISCVVendorRelMarker(it->sym->getName()); + ++it; + } else { + rvVendorFlag = 0; + } + return *this; + } + + vendor_reloc_iterator operator++(int) { + vendor_reloc_iterator tmp(*this); + ++(*this); + return tmp; + } + + bool operator==(const vendor_reloc_iterator &other) const { + return it == other.it; + } + bool operator!=(const vendor_reloc_iterator &other) const { + return it != other.it; + } + + Relocation *getUnderlyingRelocation() const { return &*it; } + +private: + MutableArrayRef<Relocation>::iterator it; + MutableArrayRef<Relocation>::iterator end; + uint32_t rvVendorFlag = 0; +}; + +inline auto riscv_vendor_relocs(MutableArrayRef<Relocation> arr) { + return llvm::make_range(vendor_reloc_iterator(arr.begin(), arr.end()), + vendor_reloc_iterator(arr.end(), arr.end())); +} + +} // namespace lld::elf + +#endif |
