diff options
Diffstat (limited to 'lld/ELF')
| -rw-r--r-- | lld/ELF/Arch/AArch64.cpp | 7 | ||||
| -rw-r--r-- | lld/ELF/Arch/RISCV.cpp | 49 | ||||
| -rw-r--r-- | lld/ELF/Arch/RISCVInternalRelocations.h | 113 | ||||
| -rw-r--r-- | lld/ELF/Driver.cpp | 18 | ||||
| -rw-r--r-- | lld/ELF/InputFiles.cpp | 5 | ||||
| -rw-r--r-- | lld/ELF/Options.td | 2 | ||||
| -rw-r--r-- | lld/ELF/Relocations.cpp | 30 | ||||
| -rw-r--r-- | lld/ELF/ScriptParser.cpp | 7 | ||||
| -rw-r--r-- | lld/ELF/Symbols.h | 6 | ||||
| -rw-r--r-- | lld/ELF/SyntheticSections.cpp | 170 | ||||
| -rw-r--r-- | lld/ELF/SyntheticSections.h | 43 | ||||
| -rw-r--r-- | lld/ELF/Target.cpp | 9 | ||||
| -rw-r--r-- | lld/ELF/Target.h | 1 |
13 files changed, 299 insertions, 161 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 diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index e52d3a0..8647752 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -156,23 +156,23 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(Ctx &ctx, std::pair<ELFKind, uint16_t> ret = StringSwitch<std::pair<ELFKind, uint16_t>>(s) - .Cases("aarch64elf", "aarch64linux", {ELF64LEKind, EM_AARCH64}) - .Cases("aarch64elfb", "aarch64linuxb", {ELF64BEKind, EM_AARCH64}) - .Cases("armelf", "armelf_linux_eabi", {ELF32LEKind, EM_ARM}) - .Cases("armelfb", "armelfb_linux_eabi", {ELF32BEKind, EM_ARM}) + .Cases({"aarch64elf", "aarch64linux"}, {ELF64LEKind, EM_AARCH64}) + .Cases({"aarch64elfb", "aarch64linuxb"}, {ELF64BEKind, EM_AARCH64}) + .Cases({"armelf", "armelf_linux_eabi"}, {ELF32LEKind, EM_ARM}) + .Cases({"armelfb", "armelfb_linux_eabi"}, {ELF32BEKind, EM_ARM}) .Case("elf32_x86_64", {ELF32LEKind, EM_X86_64}) - .Cases("elf32btsmip", "elf32btsmipn32", {ELF32BEKind, EM_MIPS}) - .Cases("elf32ltsmip", "elf32ltsmipn32", {ELF32LEKind, EM_MIPS}) + .Cases({"elf32btsmip", "elf32btsmipn32"}, {ELF32BEKind, EM_MIPS}) + .Cases({"elf32ltsmip", "elf32ltsmipn32"}, {ELF32LEKind, EM_MIPS}) .Case("elf32lriscv", {ELF32LEKind, EM_RISCV}) - .Cases("elf32ppc", "elf32ppclinux", {ELF32BEKind, EM_PPC}) - .Cases("elf32lppc", "elf32lppclinux", {ELF32LEKind, EM_PPC}) + .Cases({"elf32ppc", "elf32ppclinux"}, {ELF32BEKind, EM_PPC}) + .Cases({"elf32lppc", "elf32lppclinux"}, {ELF32LEKind, EM_PPC}) .Case("elf32loongarch", {ELF32LEKind, EM_LOONGARCH}) .Case("elf64btsmip", {ELF64BEKind, EM_MIPS}) .Case("elf64ltsmip", {ELF64LEKind, EM_MIPS}) .Case("elf64lriscv", {ELF64LEKind, EM_RISCV}) .Case("elf64ppc", {ELF64BEKind, EM_PPC64}) .Case("elf64lppc", {ELF64LEKind, EM_PPC64}) - .Cases("elf_amd64", "elf_x86_64", {ELF64LEKind, EM_X86_64}) + .Cases({"elf_amd64", "elf_x86_64"}, {ELF64LEKind, EM_X86_64}) .Case("elf_i386", {ELF32LEKind, EM_386}) .Case("elf_iamcu", {ELF32LEKind, EM_IAMCU}) .Case("elf64_sparc", {ELF64BEKind, EM_SPARCV9}) diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index a5921fe..240a6d0 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -1676,8 +1676,9 @@ template <class ELFT> void SharedFile::parse() { const uint16_t ver = versyms[i], idx = ver & ~VERSYM_HIDDEN; if (sym.isUndefined()) { - // For unversioned undefined symbols, VER_NDX_GLOBAL makes more sense but - // as of binutils 2.34, GNU ld produces VER_NDX_LOCAL. + // Index 0 (VER_NDX_LOCAL) is used for unversioned undefined symbols. + // GNU ld versions between 2.35 and 2.45 also generate VER_NDX_GLOBAL + // for this case (https://sourceware.org/PR33577). if (ver != VER_NDX_LOCAL && ver != VER_NDX_GLOBAL) { if (idx >= verneeds.size()) { ErrAlways(ctx) << "corrupt input file: version need index " << idx diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td index 75184de..c2111e5 100644 --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -154,7 +154,7 @@ def bp_startup_sort: JJ<"bp-startup-sort=">, MetaVarName<"[none,function]">, // Auxiliary options related to balanced partition defm bp_compression_sort_startup_functions: BB<"bp-compression-sort-startup-functions", - "When --irpgo-profile is pecified, prioritize function similarity for compression in addition to startup time", "">; + "When --irpgo-profile is specified, prioritize function similarity for compression in addition to startup time", "">; def verbose_bp_section_orderer: FF<"verbose-bp-section-orderer">, HelpText<"Print information on balanced partitioning">; diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index d21376f..59aa430 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -849,8 +849,8 @@ bool RelocScan::isStaticLinkTimeConstant(RelExpr e, RelType type, // only the low bits are used. if (e == R_GOT || e == R_PLT) return ctx.target->usesOnlyLowPageBits(type) || !ctx.arg.isPic; - // R_AARCH64_AUTH_ABS64 requires a dynamic relocation. - if (e == RE_AARCH64_AUTH) + // R_AARCH64_AUTH_ABS64 and iRelSymbolicRel require a dynamic relocation. + if (e == RE_AARCH64_AUTH || type == ctx.target->iRelSymbolicRel) return false; // The behavior of an undefined weak reference is implementation defined. @@ -1023,6 +1023,23 @@ void RelocScan::process(RelExpr expr, RelType type, uint64_t offset, } return; } + if (LLVM_UNLIKELY(type == ctx.target->iRelSymbolicRel)) { + if (sym.isPreemptible) { + auto diag = Err(ctx); + diag << "relocation " << type + << " cannot be used against preemptible symbol '" << &sym << "'"; + printLocation(diag, *sec, sym, offset); + } else if (isIfunc) { + auto diag = Err(ctx); + diag << "relocation " << type + << " cannot be used against ifunc symbol '" << &sym << "'"; + printLocation(diag, *sec, sym, offset); + } else { + part.relaDyn->addReloc({ctx.target->iRelativeRel, sec, offset, false, + sym, addend, R_ABS}); + return; + } + } part.relaDyn->addSymbolReloc(rel, *sec, offset, sym, addend, type); // MIPS ABI turns using of GOT and dynamic relocations inside out. @@ -1278,7 +1295,7 @@ unsigned RelocScan::handleTlsRelocation(RelExpr expr, RelType type, // label, so TLSDESC=>IE will be categorized as R_RELAX_TLS_GD_TO_LE. We fix // the categorization in RISCV::relocateAllosec-> if (sym.isPreemptible) { - sym.setFlags(NEEDS_TLSGD_TO_IE); + sym.setFlags(NEEDS_TLSIE); sec->addReloc({ctx.target->adjustTlsExpr(type, R_RELAX_TLS_GD_TO_IE), type, offset, addend, &sym}); } else { @@ -1618,18 +1635,13 @@ void elf::postScanRelocations(Ctx &ctx) { else got->addConstant({R_ABS, ctx.target->tlsOffsetRel, offsetOff, 0, &sym}); } - if (flags & NEEDS_TLSGD_TO_IE) { - got->addEntry(sym); - ctx.mainPart->relaDyn->addSymbolReloc(ctx.target->tlsGotRel, *got, - sym.getGotOffset(ctx), sym); - } if (flags & NEEDS_GOT_DTPREL) { got->addEntry(sym); got->addConstant( {R_ABS, ctx.target->tlsOffsetRel, sym.getGotOffset(ctx), 0, &sym}); } - if ((flags & NEEDS_TLSIE) && !(flags & NEEDS_TLSGD_TO_IE)) + if (flags & NEEDS_TLSIE) addTpOffsetGotEntry(ctx, sym); }; diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp index 4b9c941..b61dc647 100644 --- a/lld/ELF/ScriptParser.cpp +++ b/lld/ELF/ScriptParser.cpp @@ -450,7 +450,7 @@ static std::pair<ELFKind, uint16_t> parseBfdName(StringRef s) { .Case("elf64-powerpc", {ELF64BEKind, EM_PPC64}) .Case("elf64-powerpcle", {ELF64LEKind, EM_PPC64}) .Case("elf64-x86-64", {ELF64LEKind, EM_X86_64}) - .Cases("elf32-tradbigmips", "elf32-bigmips", {ELF32BEKind, EM_MIPS}) + .Cases({"elf32-tradbigmips", "elf32-bigmips"}, {ELF32BEKind, EM_MIPS}) .Case("elf32-ntradbigmips", {ELF32BEKind, EM_MIPS}) .Case("elf32-tradlittlemips", {ELF32LEKind, EM_MIPS}) .Case("elf32-ntradlittlemips", {ELF32LEKind, EM_MIPS}) @@ -463,7 +463,8 @@ static std::pair<ELFKind, uint16_t> parseBfdName(StringRef s) { .Case("elf32-loongarch", {ELF32LEKind, EM_LOONGARCH}) .Case("elf64-loongarch", {ELF64LEKind, EM_LOONGARCH}) .Case("elf64-s390", {ELF64BEKind, EM_S390}) - .Cases("elf32-hexagon", "elf32-littlehexagon", {ELF32LEKind, EM_HEXAGON}) + .Cases({"elf32-hexagon", "elf32-littlehexagon"}, + {ELF32LEKind, EM_HEXAGON}) .Default({ELFNoneKind, EM_NONE}); } @@ -745,7 +746,7 @@ StringMatcher ScriptParser::readFilePatterns() { SortSectionPolicy ScriptParser::peekSortKind() { return StringSwitch<SortSectionPolicy>(peek()) .Case("REVERSE", SortSectionPolicy::Reverse) - .Cases("SORT", "SORT_BY_NAME", SortSectionPolicy::Name) + .Cases({"SORT", "SORT_BY_NAME"}, SortSectionPolicy::Name) .Case("SORT_BY_ALIGNMENT", SortSectionPolicy::Alignment) .Case("SORT_BY_INIT_PRIORITY", SortSectionPolicy::Priority) .Case("SORT_NONE", SortSectionPolicy::None) diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h index c117e3b..034c873 100644 --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -48,7 +48,7 @@ enum { NEEDS_COPY = 1 << 3, NEEDS_TLSDESC = 1 << 4, NEEDS_TLSGD = 1 << 5, - NEEDS_TLSGD_TO_IE = 1 << 6, + // 1 << 6 unused NEEDS_GOT_DTPREL = 1 << 7, NEEDS_TLSIE = 1 << 8, NEEDS_GOT_AUTH = 1 << 9, @@ -313,6 +313,8 @@ public: // represents the Verdef index within the input DSO, which will be converted // to a Verneed index in the output. Otherwise, this represents the Verdef // index (VER_NDX_LOCAL, VER_NDX_GLOBAL, or a named version). + // VER_NDX_LOCAL indicates a defined symbol that has been localized by a + // version script's local: directive or --exclude-libs. uint16_t versionId; LLVM_PREFERRED_TYPE(bool) uint8_t versionScriptAssigned : 1; @@ -350,7 +352,7 @@ public: bool needsDynReloc() const { return flags.load(std::memory_order_relaxed) & (NEEDS_COPY | NEEDS_GOT | NEEDS_PLT | NEEDS_TLSDESC | NEEDS_TLSGD | - NEEDS_TLSGD_TO_IE | NEEDS_GOT_DTPREL | NEEDS_TLSIE); + NEEDS_GOT_DTPREL | NEEDS_TLSIE); } void allocateAux(Ctx &ctx) { assert(auxIdx == 0); diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index a4150eb..1e9d44f 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -54,8 +54,6 @@ using llvm::support::endian::read32le; using llvm::support::endian::write32le; using llvm::support::endian::write64le; -constexpr size_t MergeNoTailSection::numShards; - static uint64_t readUint(Ctx &ctx, uint8_t *buf) { return ctx.arg.is64 ? read64(ctx, buf) : read32(ctx, buf); } @@ -542,43 +540,6 @@ void EhFrameSection::finalizeContents() { this->size = off; } -// Returns data for .eh_frame_hdr. .eh_frame_hdr is a binary search table -// to get an FDE from an address to which FDE is applied. This function -// returns a list of such pairs. -SmallVector<EhFrameSection::FdeData, 0> EhFrameSection::getFdeData() const { - uint8_t *buf = ctx.bufferStart + getParent()->offset + outSecOff; - SmallVector<FdeData, 0> ret; - - uint64_t va = getPartition(ctx).ehFrameHdr->getVA(); - for (CieRecord *rec : cieRecords) { - uint8_t enc = getFdeEncoding(rec->cie); - for (EhSectionPiece *fde : rec->fdes) { - uint64_t pc = getFdePc(buf, fde->outputOff, enc); - uint64_t fdeVA = getParent()->addr + fde->outputOff; - if (!isInt<32>(pc - va)) { - Err(ctx) << fde->sec << ": PC offset is too large: 0x" - << Twine::utohexstr(pc - va); - continue; - } - ret.push_back({uint32_t(pc - va), uint32_t(fdeVA - va)}); - } - } - - // Sort the FDE list by their PC and uniqueify. Usually there is only - // one FDE for a PC (i.e. function), but if ICF merges two functions - // into one, there can be more than one FDEs pointing to the address. - auto less = [](const FdeData &a, const FdeData &b) { - return a.pcRel < b.pcRel; - }; - llvm::stable_sort(ret, less); - auto eq = [](const FdeData &a, const FdeData &b) { - return a.pcRel == b.pcRel; - }; - ret.erase(llvm::unique(ret, eq), ret.end()); - - return ret; -} - static uint64_t readFdeAddr(Ctx &ctx, uint8_t *buf, int size) { switch (size) { case DW_EH_PE_udata2: @@ -632,14 +593,79 @@ void EhFrameSection::writeTo(uint8_t *buf) { } } - // Apply relocations. .eh_frame section contents are not contiguous - // in the output buffer, but relocateAlloc() still works because - // getOffset() takes care of discontiguous section pieces. + // Apply relocations to .eh_frame entries. This includes CIE personality + // pointers, FDE initial_location fields, and LSDA pointers. for (EhInputSection *s : sections) ctx.target->relocateEh(*s, buf); - if (getPartition(ctx).ehFrameHdr && getPartition(ctx).ehFrameHdr->getParent()) - getPartition(ctx).ehFrameHdr->write(); + EhFrameHeader *hdr = getPartition(ctx).ehFrameHdr.get(); + if (!hdr || !hdr->getParent()) + return; + + // Write the .eh_frame_hdr section, which contains a binary search table of + // pointers to FDEs. This must be written after .eh_frame relocation since + // the content depends on relocated initial_location fields in FDEs. + using FdeData = EhFrameSection::FdeData; + SmallVector<FdeData, 0> fdes; + uint64_t va = hdr->getVA(); + for (CieRecord *rec : cieRecords) { + uint8_t enc = getFdeEncoding(rec->cie); + for (EhSectionPiece *fde : rec->fdes) { + uint64_t pc = getFdePc(buf, fde->outputOff, enc); + uint64_t fdeVA = getParent()->addr + fde->outputOff; + if (!isInt<32>(pc - va)) { + Err(ctx) << fde->sec << ": PC offset is too large: 0x" + << Twine::utohexstr(pc - va); + continue; + } + fdes.push_back({uint32_t(pc - va), uint32_t(fdeVA - va)}); + } + } + + // Sort the FDE list by their PC and uniqueify. Usually there is only + // one FDE for a PC (i.e. function), but if ICF merges two functions + // into one, there can be more than one FDEs pointing to the address. + llvm::stable_sort(fdes, [](const FdeData &a, const FdeData &b) { + return a.pcRel < b.pcRel; + }); + fdes.erase( + llvm::unique(fdes, [](auto &a, auto &b) { return a.pcRel == b.pcRel; }), + fdes.end()); + + // Write header. + uint8_t *hdrBuf = ctx.bufferStart + hdr->getParent()->offset + hdr->outSecOff; + hdrBuf[0] = 1; // version + hdrBuf[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4; // eh_frame_ptr_enc + hdrBuf[2] = DW_EH_PE_udata4; // fde_count_enc + hdrBuf[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4; // table_enc + write32(ctx, hdrBuf + 4, + getParent()->addr - hdr->getVA() - 4); // eh_frame_ptr + write32(ctx, hdrBuf + 8, fdes.size()); // fde_count + hdrBuf += 12; + + // Write binary search table. Each entry describes the starting PC and the FDE + // address. + for (FdeData &fde : fdes) { + write32(ctx, hdrBuf, fde.pcRel); + write32(ctx, hdrBuf + 4, fde.fdeVARel); + hdrBuf += 8; + } +} + +EhFrameHeader::EhFrameHeader(Ctx &ctx) + : SyntheticSection(ctx, ".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, 4) {} + +void EhFrameHeader::writeTo(uint8_t *buf) { + // The section content is written during EhFrameSection::writeTo. +} + +size_t EhFrameHeader::getSize() const { + // .eh_frame_hdr has a 12 bytes header followed by an array of FDEs. + return 12 + getPartition(ctx).ehFrame->numFdes * 8; +} + +bool EhFrameHeader::isNeeded() const { + return isLive() && getPartition(ctx).ehFrame->isNeeded(); } GotSection::GotSection(Ctx &ctx) @@ -2749,9 +2775,9 @@ RelroPaddingSection::RelroPaddingSection(Ctx &ctx) : SyntheticSection(ctx, ".relro_padding", SHT_NOBITS, SHF_ALLOC | SHF_WRITE, 1) {} -PaddingSection::PaddingSection(Ctx &ctx, uint64_t size, OutputSection *parent) - : SyntheticSection(ctx, ".padding", SHT_PROGBITS, SHF_ALLOC, 1), - size(size) { +PaddingSection::PaddingSection(Ctx &ctx, uint64_t amount, OutputSection *parent) + : SyntheticSection(ctx, ".padding", SHT_PROGBITS, SHF_ALLOC, 1) { + size = amount; this->parent = parent; } @@ -3660,51 +3686,6 @@ void GdbIndexSection::writeTo(uint8_t *buf) { bool GdbIndexSection::isNeeded() const { return !chunks.empty(); } -EhFrameHeader::EhFrameHeader(Ctx &ctx) - : SyntheticSection(ctx, ".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, 4) {} - -void EhFrameHeader::writeTo(uint8_t *buf) { - // Unlike most sections, the EhFrameHeader section is written while writing - // another section, namely EhFrameSection, which calls the write() function - // below from its writeTo() function. This is necessary because the contents - // of EhFrameHeader depend on the relocated contents of EhFrameSection and we - // don't know which order the sections will be written in. -} - -// .eh_frame_hdr contains a binary search table of pointers to FDEs. -// Each entry of the search table consists of two values, -// the starting PC from where FDEs covers, and the FDE's address. -// It is sorted by PC. -void EhFrameHeader::write() { - uint8_t *buf = ctx.bufferStart + getParent()->offset + outSecOff; - using FdeData = EhFrameSection::FdeData; - SmallVector<FdeData, 0> fdes = getPartition(ctx).ehFrame->getFdeData(); - - buf[0] = 1; - buf[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4; - buf[2] = DW_EH_PE_udata4; - buf[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4; - write32(ctx, buf + 4, - getPartition(ctx).ehFrame->getParent()->addr - this->getVA() - 4); - write32(ctx, buf + 8, fdes.size()); - buf += 12; - - for (FdeData &fde : fdes) { - write32(ctx, buf, fde.pcRel); - write32(ctx, buf + 4, fde.fdeVARel); - buf += 8; - } -} - -size_t EhFrameHeader::getSize() const { - // .eh_frame_hdr has a 12 bytes header followed by an array of FDEs. - return 12 + getPartition(ctx).ehFrame->numFdes * 8; -} - -bool EhFrameHeader::isNeeded() const { - return isLive() && getPartition(ctx).ehFrame->isNeeded(); -} - VersionDefinitionSection::VersionDefinitionSection(Ctx &ctx) : SyntheticSection(ctx, ".gnu.version_d", SHT_GNU_verdef, SHF_ALLOC, sizeof(uint32_t)) {} @@ -3786,9 +3767,10 @@ void VersionTableSection::writeTo(uint8_t *buf) { buf += 2; for (const SymbolTableEntry &s : getPartition(ctx).dynSymTab->getSymbols()) { // For an unextracted lazy symbol (undefined weak), it must have been - // converted to Undefined and have VER_NDX_GLOBAL version here. + // converted to Undefined. assert(!s.sym->isLazy()); - write16(ctx, buf, s.sym->versionId); + // Undefined symbols should use index 0 when unversioned. + write16(ctx, buf, s.sym->isUndefined() ? 0 : s.sym->versionId); buf += 2; } } diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h index 38e6811..e01a5ad 100644 --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -68,7 +68,6 @@ public: uint32_t fdeVARel; }; - SmallVector<FdeData, 0> getFdeData() const; ArrayRef<CieRecord *> getCieRecords() const { return cieRecords; } template <class ELFT> void iterateFDEWithLSDA(llvm::function_ref<void(InputSection &)> fn); @@ -78,8 +77,6 @@ private: // allocating one for each EhInputSection. llvm::DenseMap<size_t, CieRecord *> offsetToCie; - uint64_t size = 0; - template <llvm::endianness E> void addRecords(EhInputSection *s); template <class ELFT> void iterateFDEWithLSDAAux(EhInputSection &sec, @@ -97,6 +94,17 @@ private: llvm::DenseMap<std::pair<ArrayRef<uint8_t>, Symbol *>, CieRecord *> cieMap; }; +// .eh_frame_hdr contains a binary search table for .eh_frame FDEs. The section +// is covered by a PT_GNU_EH_FRAME segment, which allows the runtime unwinder to +// locate it via functions like `dl_iterate_phdr`. +class EhFrameHeader final : public SyntheticSection { +public: + EhFrameHeader(Ctx &); + void writeTo(uint8_t *buf) override; + size_t getSize() const override; + bool isNeeded() const override; +}; + class GotSection final : public SyntheticSection { public: GotSection(Ctx &); @@ -127,7 +135,6 @@ public: protected: size_t numEntries = 0; uint32_t tlsIndexOff = -1; - uint64_t size = 0; struct AuthEntryInfo { size_t offset; bool isSymbolFunc; @@ -182,7 +189,6 @@ public: static bool classof(const SectionBase *s) { return isa<SyntheticSection>(s) && cast<SyntheticSection>(s)->bss; } - uint64_t size; }; class MipsGotSection final : public SyntheticSection { @@ -312,8 +318,6 @@ private: // Number of "Header" entries. static const unsigned headerEntriesNum = 2; - uint64_t size = 0; - // Symbol and addend. using GotEntry = std::pair<Symbol *, int64_t>; @@ -407,8 +411,6 @@ public: private: const bool dynamic; - uint64_t size = 0; - llvm::DenseMap<llvm::CachedHashStringRef, unsigned> stringMap; SmallVector<StringRef, 0> strings; }; @@ -475,7 +477,6 @@ public: private: std::vector<std::pair<int32_t, uint64_t>> computeContents(); - uint64_t size = 0; }; class RelocationBaseSection : public SyntheticSection { @@ -780,10 +781,8 @@ public: }; class PaddingSection final : public SyntheticSection { - uint64_t size; - public: - PaddingSection(Ctx &ctx, uint64_t size, OutputSection *parent); + PaddingSection(Ctx &ctx, uint64_t amount, OutputSection *parent); size_t getSize() const override { return size; } void writeTo(uint8_t *buf) override; }; @@ -978,24 +977,6 @@ private: size_t size; }; -// --eh-frame-hdr option tells linker to construct a header for all the -// .eh_frame sections. This header is placed to a section named .eh_frame_hdr -// and also to a PT_GNU_EH_FRAME segment. -// At runtime the unwinder then can find all the PT_GNU_EH_FRAME segments by -// calling dl_iterate_phdr. -// This section contains a lookup table for quick binary search of FDEs. -// Detailed info about internals can be found in Ian Lance Taylor's blog: -// http://www.airs.com/blog/archives/460 (".eh_frame") -// http://www.airs.com/blog/archives/462 (".eh_frame_hdr") -class EhFrameHeader final : public SyntheticSection { -public: - EhFrameHeader(Ctx &); - void write(); - void writeTo(uint8_t *buf) override; - size_t getSize() const override; - bool isNeeded() const override; -}; - // For more information about .gnu.version and .gnu.version_r see: // https://www.akkadia.org/drepper/symbol-versioning diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp index 89e4dbe..3fc3e3f 100644 --- a/lld/ELF/Target.cpp +++ b/lld/ELF/Target.cpp @@ -24,6 +24,7 @@ //===----------------------------------------------------------------------===// #include "Target.h" +#include "Arch/RISCVInternalRelocations.h" #include "InputFiles.h" #include "OutputSections.h" #include "RelocScan.h" @@ -40,6 +41,14 @@ using namespace lld::elf; std::string elf::toStr(Ctx &ctx, RelType type) { StringRef s = getELFRelocationTypeName(ctx.arg.emachine, type); + if (ctx.arg.emachine == EM_RISCV && s == "Unknown") { + auto VendorString = getRISCVVendorString(type); + if (VendorString) + s = getRISCVVendorRelocationTypeName(type & ~INTERNAL_RISCV_VENDOR_MASK, + *VendorString); + if (s == "Unknown") + return ("Unknown vendor-specific (" + Twine(type) + ")").str(); + } if (s == "Unknown") return ("Unknown (" + Twine(type) + ")").str(); return std::string(s); diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h index 90d8ddf..8da0b5c 100644 --- a/lld/ELF/Target.h +++ b/lld/ELF/Target.h @@ -145,6 +145,7 @@ public: RelType relativeRel = 0; RelType iRelativeRel = 0; RelType symbolicRel = 0; + RelType iRelSymbolicRel = 0; RelType tlsDescRel = 0; RelType tlsGotRel = 0; RelType tlsModuleIndexRel = 0; |
