aboutsummaryrefslogtreecommitdiff
path: root/lld/ELF/Arch
diff options
context:
space:
mode:
Diffstat (limited to 'lld/ELF/Arch')
-rw-r--r--lld/ELF/Arch/AArch64.cpp7
-rw-r--r--lld/ELF/Arch/RISCV.cpp49
-rw-r--r--lld/ELF/Arch/RISCVInternalRelocations.h113
3 files changed, 159 insertions, 10 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/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