aboutsummaryrefslogtreecommitdiff
path: root/lld/ELF
diff options
context:
space:
mode:
Diffstat (limited to 'lld/ELF')
-rw-r--r--lld/ELF/Arch/AArch64.cpp7
-rw-r--r--lld/ELF/Arch/RISCV.cpp49
-rw-r--r--lld/ELF/Arch/RISCVInternalRelocations.h113
-rw-r--r--lld/ELF/Driver.cpp18
-rw-r--r--lld/ELF/InputFiles.cpp5
-rw-r--r--lld/ELF/Options.td2
-rw-r--r--lld/ELF/Relocations.cpp30
-rw-r--r--lld/ELF/ScriptParser.cpp7
-rw-r--r--lld/ELF/Symbols.h6
-rw-r--r--lld/ELF/SyntheticSections.cpp170
-rw-r--r--lld/ELF/SyntheticSections.h43
-rw-r--r--lld/ELF/Target.cpp9
-rw-r--r--lld/ELF/Target.h1
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;