-
Notifications
You must be signed in to change notification settings - Fork 15.3k
[wip][LLD] Support RISCV vendor-specific relocations. #168497
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
4e2e28e
ec1a0a5
2b9e004
a8f3a11
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -14,6 +14,7 @@ | |||||
| //===----------------------------------------------------------------------===// | ||||||
|
|
||||||
| #include "SyntheticSections.h" | ||||||
| #include "Arch/RISCVInternalRelocations.h" | ||||||
| #include "Config.h" | ||||||
| #include "DWARF.h" | ||||||
| #include "EhFrame.h" | ||||||
|
|
@@ -1703,6 +1704,18 @@ void DynamicReloc::finalize(Ctx &ctx, SymbolTableBaseSection *symt) { | |||||
| isFinal = true; // Catch errors | ||||||
| } | ||||||
|
|
||||||
| size_t RelocationBaseSection::getSize() const { | ||||||
| size_t size = relocs.size() * entsize; | ||||||
| if (ctx.arg.emachine == EM_RISCV) { | ||||||
| for (const auto &reloc : relocs) { | ||||||
| if (reloc.type.v & INTERNAL_RISCV_VENDOR_MASK) { | ||||||
| size += entsize; | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| return size; | ||||||
| } | ||||||
|
|
||||||
| void RelocationBaseSection::computeRels() { | ||||||
| SymbolTableBaseSection *symTab = getPartition(ctx).dynSymTab.get(); | ||||||
| parallelForEach(relocs, [&ctx = ctx, symTab](DynamicReloc &rel) { | ||||||
|
|
@@ -1725,6 +1738,47 @@ void RelocationBaseSection::computeRels() { | |||||
| return std::tie(a.r_sym, a.r_offset) < std::tie(b.r_sym, b.r_offset); | ||||||
| }); | ||||||
| } | ||||||
| // Insert R_RISCV_VENDOR relocations very late, so that it doesn't interfere | ||||||
| // with relocation sorting above. | ||||||
| if (ctx.arg.emachine == EM_RISCV) { | ||||||
resistor marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
| SmallVector<DynamicReloc, 0> processedRelocs; | ||||||
| processedRelocs.reserve(relocs.size()); | ||||||
| for (auto reloc : relocs) { | ||||||
| auto vendorString = getRISCVVendorString(reloc.type); | ||||||
| if (vendorString) { | ||||||
| // Symbol *vendorSym = ctx.symtab->find(*vendorString); | ||||||
| auto *vendorSym = ctx.symtab->find(*vendorString); | ||||||
| if (!vendorSym || !vendorSym->isDefined()) { | ||||||
| vendorSym = ctx.symtab->addSymbol(Defined{ctx, nullptr, *vendorString, | ||||||
| STB_GLOBAL, STV_HIDDEN, | ||||||
| STT_NOTYPE, 0, 0, nullptr}); | ||||||
| symTab->addSymbol(vendorSym); | ||||||
| } | ||||||
| vendorSym->isUsedInRegularObj = true; | ||||||
| vendorSym->isExported = true; | ||||||
| processedRelocs.push_back({llvm::ELF::R_RISCV_VENDOR, reloc.inputSec, | ||||||
| reloc.offsetInSec, true, *vendorSym, 0, | ||||||
| R_ABS}); | ||||||
| processedRelocs.back().finalize(ctx, symTab); | ||||||
| } | ||||||
|
|
||||||
| reloc.type.v &= ~INTERNAL_RISCV_VENDOR_MASK; | ||||||
| processedRelocs.push_back(reloc); | ||||||
| } | ||||||
|
|
||||||
| relocs = std::move(processedRelocs); | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| void RelocationBaseSection::maybeAddRISCVendorRelocation( | ||||||
| const DynamicReloc &reloc, SmallVector<DynamicReloc, 0> &outRelocs) { | ||||||
| auto riscvVendorString = getRISCVVendorString(reloc.type); | ||||||
| if (ctx.arg.emachine == llvm::ELF::EM_RISCV && riscvVendorString) { | ||||||
| Symbol &vendorSym = *ctx.symtab->addSymbol(Defined{ | ||||||
| ctx, ctx.internalFile, *riscvVendorString, llvm::ELF::STB_GLOBAL, | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
I think we've said these need to be local, but maybe that's not right for dynamic relocs.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I thought I recalled that dynamic relocations could only point to global symbols, but I'm failing to find that requirement in the ELF spec.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oracle docs seem to agree with you:
From: https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-79797.html#stlac I will go back to the ABI about this. We made them local to echo mapping symbols, but evidently that doesn't work for vendor-specific dynamic relocations.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks. Can you share the ABI discussion link once you bring it there? |
||||||
| llvm::ELF::STV_HIDDEN, llvm::ELF::STT_NOTYPE, 0, 0, nullptr}); | ||||||
| vendorSym.isUsedInRegularObj = true; | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| template <class ELFT> | ||||||
|
|
||||||
Uh oh!
There was an error while loading. Please reload this page.