summaryrefslogtreecommitdiff
path: root/gnu/llvm/lld
diff options
context:
space:
mode:
authorPatrick Wildt <patrick@cvs.openbsd.org>2021-12-17 14:47:15 +0000
committerPatrick Wildt <patrick@cvs.openbsd.org>2021-12-17 14:47:15 +0000
commit85441880e8b445d58571a3bb2446a3bd1846c848 (patch)
treeb1f340cd667e6ca70ae89a44e42a0e2b54943d9d /gnu/llvm/lld
parentb46545b801f382e6ea8682095cd6bc75963b5866 (diff)
Merge LLVM 13.0.0.
Diffstat (limited to 'gnu/llvm/lld')
-rw-r--r--gnu/llvm/lld/ELF/Arch/PPC.cpp10
-rw-r--r--gnu/llvm/lld/ELF/Config.h37
-rw-r--r--gnu/llvm/lld/ELF/Driver.cpp624
-rw-r--r--gnu/llvm/lld/ELF/DriverUtils.cpp14
-rw-r--r--gnu/llvm/lld/ELF/InputSection.cpp156
-rw-r--r--gnu/llvm/lld/ELF/LinkerScript.cpp336
-rw-r--r--gnu/llvm/lld/ELF/Options.td130
-rw-r--r--gnu/llvm/lld/ELF/Relocations.cpp288
-rw-r--r--gnu/llvm/lld/ELF/Symbols.cpp88
-rw-r--r--gnu/llvm/lld/ELF/Symbols.h23
-rw-r--r--gnu/llvm/lld/ELF/SyntheticSections.cpp268
-rw-r--r--gnu/llvm/lld/ELF/Writer.cpp487
-rw-r--r--gnu/llvm/lld/MachO/MergedOutputSection.cpp74
-rw-r--r--gnu/llvm/lld/MachO/MergedOutputSection.h56
-rw-r--r--gnu/llvm/lld/docs/ld.lld.1121
-rw-r--r--gnu/llvm/lld/tools/lld/lld.cpp112
-rw-r--r--gnu/llvm/lld/wasm/InputEvent.h62
-rw-r--r--gnu/llvm/lld/wasm/InputGlobal.h55
18 files changed, 1896 insertions, 1045 deletions
diff --git a/gnu/llvm/lld/ELF/Arch/PPC.cpp b/gnu/llvm/lld/ELF/Arch/PPC.cpp
index 90329315a37..aaecef6ee94 100644
--- a/gnu/llvm/lld/ELF/Arch/PPC.cpp
+++ b/gnu/llvm/lld/ELF/Arch/PPC.cpp
@@ -45,8 +45,7 @@ public:
bool inBranchRange(RelType type, uint64_t src, uint64_t dst) const override;
void relocate(uint8_t *loc, const Relocation &rel,
uint64_t val) const override;
- RelExpr adjustRelaxExpr(RelType type, const uint8_t *data,
- RelExpr expr) const override;
+ RelExpr adjustTlsExpr(RelType type, RelExpr expr) const override;
int getTlsGdRelaxSkip(RelType type) const override;
void relaxTlsGdToIe(uint8_t *loc, const Relocation &rel,
uint64_t val) const override;
@@ -261,7 +260,7 @@ RelExpr PPC::getRelExpr(RelType type, const Symbol &s,
case R_PPC_TPREL16_HA:
case R_PPC_TPREL16_LO:
case R_PPC_TPREL16_HI:
- return R_TLS;
+ return R_TPREL;
default:
error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
") against symbol " + toString(s));
@@ -347,8 +346,8 @@ void PPC::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
write32(loc, (read32(loc) & ~mask) | (val & mask));
break;
}
- case R_PPC_REL24:
case R_PPC_ADDR24:
+ case R_PPC_REL24:
case R_PPC_LOCAL24PC:
case R_PPC_PLTREL24: {
uint32_t mask = 0x03FFFFFC;
@@ -362,8 +361,7 @@ void PPC::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
}
}
-RelExpr PPC::adjustRelaxExpr(RelType type, const uint8_t *data,
- RelExpr expr) const {
+RelExpr PPC::adjustTlsExpr(RelType type, RelExpr expr) const {
if (expr == R_RELAX_TLS_GD_TO_IE)
return R_RELAX_TLS_GD_TO_IE_GOT_OFF;
if (expr == R_RELAX_TLS_LD_TO_LE)
diff --git a/gnu/llvm/lld/ELF/Config.h b/gnu/llvm/lld/ELF/Config.h
index 941dc2455a4..e61c698e146 100644
--- a/gnu/llvm/lld/ELF/Config.h
+++ b/gnu/llvm/lld/ELF/Config.h
@@ -10,7 +10,9 @@
#define LLD_ELF_CONFIG_H
#include "lld/Common/ErrorHandler.h"
+#include "llvm/ADT/CachedHashString.h"
#include "llvm/ADT/MapVector.h"
+#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/BinaryFormat/ELF.h"
@@ -18,6 +20,7 @@
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/GlobPattern.h"
+#include "llvm/Support/PrettyStackTrace.h"
#include <atomic>
#include <vector>
@@ -35,6 +38,10 @@ enum ELFKind {
ELF64BEKind
};
+// For -Bno-symbolic, -Bsymbolic-non-weak-functions, -Bsymbolic-functions,
+// -Bsymbolic.
+enum class BsymbolicKind { None, NonWeakFunctions, Functions, All };
+
// For --build-id.
enum class BuildIdKind { None, Fast, Md5, Sha1, Hexstring, Uuid };
@@ -79,7 +86,8 @@ struct SymbolVersion {
struct VersionDefinition {
llvm::StringRef name;
uint16_t id;
- std::vector<SymbolVersion> patterns;
+ std::vector<SymbolVersion> nonLocalPatterns;
+ std::vector<SymbolVersion> localPatterns;
};
// This struct contains the global configuration for the linker.
@@ -90,11 +98,13 @@ struct Configuration {
uint8_t osabi = 0;
uint32_t andFeatures = 0;
llvm::CachePruningPolicy thinLTOCachePolicy;
+ llvm::SetVector<llvm::CachedHashString> dependencyFiles; // for --dependency-file
llvm::StringMap<uint64_t> sectionStartMap;
llvm::StringRef bfdname;
llvm::StringRef chroot;
- llvm::StringRef dynamicLinker;
+ llvm::StringRef dependencyFile;
llvm::StringRef dwoDir;
+ llvm::StringRef dynamicLinker;
llvm::StringRef entry;
llvm::StringRef emulation;
llvm::StringRef fini;
@@ -107,6 +117,7 @@ struct Configuration {
llvm::StringRef mapFile;
llvm::StringRef outputFile;
llvm::StringRef optRemarksFilename;
+ llvm::Optional<uint64_t> optRemarksHotnessThreshold = 0;
llvm::StringRef optRemarksPasses;
llvm::StringRef optRemarksFormat;
llvm::StringRef progName;
@@ -133,16 +144,15 @@ struct Configuration {
uint64_t>
callGraphProfile;
bool allowMultipleDefinition;
- bool allowShlibUndefined;
bool androidPackDynRelocs;
bool armHasBlx = false;
bool armHasMovtMovw = false;
bool armJ1J2BranchEncoding = false;
bool asNeeded = false;
- bool bsymbolic;
- bool bsymbolicFunctions;
+ BsymbolicKind bsymbolic = BsymbolicKind::None;
bool callGraphProfileSort;
bool checkSections;
+ bool checkDynamicRelocs;
bool compressDebugSections;
bool cref;
std::vector<std::pair<llvm::GlobPattern, uint64_t>> deadRelocInNonAlloc;
@@ -159,6 +169,7 @@ struct Configuration {
bool fixCortexA53Errata843419;
bool fixCortexA8;
bool formatBinary = false;
+ bool fortranCommon;
bool gcSections;
bool gdbIndex;
bool gnuHash = false;
@@ -170,6 +181,7 @@ struct Configuration {
bool ltoDebugPassManager;
bool ltoEmitAsm;
bool ltoNewPassManager;
+ bool ltoPseudoProbeForProfiling;
bool ltoUniqueBasicBlockSectionNames;
bool ltoWholeProgramVisibility;
bool mergeArmExidx;
@@ -181,6 +193,8 @@ struct Configuration {
bool nostdlib;
bool oFormatBinary;
bool omagic;
+ bool optEB = false;
+ bool optEL = false;
bool optimizeBBJumps;
bool optRemarksWithHotness;
bool picThunk;
@@ -190,7 +204,7 @@ struct Configuration {
bool relocatable;
bool relrPackDynRelocs;
bool saveTemps;
- llvm::Optional<uint32_t> shuffleSectionSeed;
+ std::vector<std::pair<llvm::GlobPattern, uint32_t>> shuffleSections;
bool singleRoRx;
bool shared;
bool symbolic;
@@ -202,13 +216,13 @@ struct Configuration {
bool thinLTOIndexOnly;
bool timeTraceEnabled;
bool tocOptimize;
+ bool pcRelOptimize;
bool undefinedVersion;
bool unique;
bool useAndroidRelrTags = false;
bool warnBackrefs;
std::vector<llvm::GlobPattern> warnBackrefsExclude;
bool warnCommon;
- bool warnIfuncTextrel;
bool warnMissingEntry;
bool warnSymbolOrdering;
bool writeAddends;
@@ -231,6 +245,7 @@ struct Configuration {
bool zRelro;
bool zRodynamic;
bool zShstk;
+ bool zStartStopGC;
uint8_t zStartStopVisibility;
bool zText;
bool zRetpolineplt;
@@ -242,7 +257,9 @@ struct Configuration {
SortSectionPolicy sortSection;
StripPolicy strip;
UnresolvedPolicy unresolvedSymbols;
+ UnresolvedPolicy unresolvedSymbolsInShlib;
Target2Policy target2;
+ bool Power10Stub;
ARMVFPArgKind armVFPArgs = ARMVFPArgKind::Default;
BuildIdKind buildId = BuildIdKind::None;
SeparateSegmentKind zSeparate;
@@ -350,6 +367,12 @@ static inline void errorOrWarn(const Twine &msg) {
else
warn(msg);
}
+
+static inline void internalLinkerError(StringRef loc, const Twine &msg) {
+ errorOrWarn(loc + "internal linker error: " + msg + "\n" +
+ llvm::getBugReportMsg());
+}
+
} // namespace elf
} // namespace lld
diff --git a/gnu/llvm/lld/ELF/Driver.cpp b/gnu/llvm/lld/ELF/Driver.cpp
index dc06998cc37..633cc3d5143 100644
--- a/gnu/llvm/lld/ELF/Driver.cpp
+++ b/gnu/llvm/lld/ELF/Driver.cpp
@@ -47,7 +47,9 @@
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Config/llvm-config.h"
#include "llvm/LTO/LTO.h"
+#include "llvm/Remarks/HotnessThresholdParser.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compression.h"
#include "llvm/Support/GlobPattern.h"
@@ -80,6 +82,27 @@ bool elf::link(ArrayRef<const char *> args, bool canExitEarly,
lld::stdoutOS = &stdoutOS;
lld::stderrOS = &stderrOS;
+ errorHandler().cleanupCallback = []() {
+ freeArena();
+
+ inputSections.clear();
+ outputSections.clear();
+ archiveFiles.clear();
+ binaryFiles.clear();
+ bitcodeFiles.clear();
+ lazyObjFiles.clear();
+ objectFiles.clear();
+ sharedFiles.clear();
+ backwardReferences.clear();
+
+ tar = nullptr;
+ memset(&in, 0, sizeof(in));
+
+ partitions = {Partition()};
+
+ SharedFile::vernauxNum = 0;
+ };
+
errorHandler().logName = args::getFilenameWithoutExe(args[0]);
errorHandler().errorLimitExceededMsg =
"too many errors emitted, stopping now (use "
@@ -87,31 +110,16 @@ bool elf::link(ArrayRef<const char *> args, bool canExitEarly,
errorHandler().exitEarly = canExitEarly;
stderrOS.enable_colors(stderrOS.has_colors());
- inputSections.clear();
- outputSections.clear();
- archiveFiles.clear();
- binaryFiles.clear();
- bitcodeFiles.clear();
- lazyObjFiles.clear();
- objectFiles.clear();
- sharedFiles.clear();
- backwardReferences.clear();
-
config = make<Configuration>();
driver = make<LinkerDriver>();
script = make<LinkerScript>();
symtab = make<SymbolTable>();
- tar = nullptr;
- memset(&in, 0, sizeof(in));
-
partitions = {Partition()};
- SharedFile::vernauxNum = 0;
-
config->progName = args[0];
- driver->main(args);
+ driver->linkerMain(args);
// Exit immediately if we don't need to return to the caller.
// This saves time because the overhead of calling destructors
@@ -119,8 +127,10 @@ bool elf::link(ArrayRef<const char *> args, bool canExitEarly,
if (canExitEarly)
exitLld(errorCount() ? 1 : 0);
- freeArena();
- return !errorCount();
+ bool ret = errorCount() == 0;
+ if (!canExitEarly)
+ errorHandler().reset();
+ return ret;
}
// Parses a linker -m option.
@@ -134,14 +144,15 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef emul) {
std::pair<ELFKind, uint16_t> ret =
StringSwitch<std::pair<ELFKind, uint16_t>>(s)
- .Cases("aarch64elf", "aarch64linux", "aarch64_elf64_le_vec",
- {ELF64LEKind, EM_AARCH64})
+ .Cases("aarch64elf", "aarch64linux", {ELF64LEKind, EM_AARCH64})
+ .Cases("aarch64elfb", "aarch64linuxb", {ELF64BEKind, EM_AARCH64})
.Cases("armelf", "armelf_linux_eabi", {ELF32LEKind, EM_ARM})
.Case("elf32_x86_64", {ELF32LEKind, EM_X86_64})
.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})
.Case("elf64btsmip", {ELF64BEKind, EM_MIPS})
.Case("elf64ltsmip", {ELF64LEKind, EM_MIPS})
.Case("elf64lriscv", {ELF64LEKind, EM_RISCV})
@@ -151,10 +162,13 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef emul) {
.Case("elf_i386", {ELF32LEKind, EM_386})
.Case("elf_iamcu", {ELF32LEKind, EM_IAMCU})
.Case("elf64_sparc", {ELF64BEKind, EM_SPARCV9})
+ .Case("msp430elf", {ELF32LEKind, EM_MSP430})
.Default({ELFNoneKind, EM_NONE});
if (ret.first == ELFNoneKind)
error("unknown emulation: " + emul);
+ if (ret.second == EM_MSP430)
+ osabi = ELFOSABI_STANDALONE;
return std::make_tuple(ret.first, ret.second, osabi);
}
@@ -278,7 +292,7 @@ void LinkerDriver::addLibrary(StringRef name) {
if (Optional<std::string> path = searchLibrary(name))
addFile(*path, /*withLOption=*/true);
else
- error("unable to find library -l" + name);
+ error("unable to find library -l" + name, ErrorTag::LibNotFound, {name});
}
// This function is called on startup. We need this for LTO since
@@ -307,7 +321,10 @@ static void checkOptions() {
error("--fix-cortex-a8 is only supported on ARM targets");
if (config->tocOptimize && config->emachine != EM_PPC64)
- error("--toc-optimize is only supported on the PowerPC64 target");
+ error("--toc-optimize is only supported on PowerPC64 targets");
+
+ if (config->pcRelOptimize && config->emachine != EM_PPC64)
+ error("--pcrel-optimize is only supported on PowerPC64 targets");
if (config->pie && config->shared)
error("-shared and -pie may not be used together");
@@ -330,8 +347,6 @@ static void checkOptions() {
if (config->relocatable) {
if (config->shared)
error("-r and -shared may not be used together");
- if (config->gcSections)
- error("-r and --gc-sections may not be used together");
if (config->gdbIndex)
error("-r and --gdb-index may not be used together");
if (config->icf != ICFLevel::None)
@@ -436,11 +451,12 @@ static bool isKnownZFlag(StringRef s) {
s == "initfirst" || s == "interpose" ||
s == "keep-text-section-prefix" || s == "lazy" || s == "muldefs" ||
s == "separate-code" || s == "separate-loadable-segments" ||
- s == "nocombreloc" || s == "nocopyreloc" || s == "nodefaultlib" ||
- s == "nodelete" || s == "nodlopen" || s == "noexecstack" ||
- s == "nognustack" || s == "nokeep-text-section-prefix" ||
- s == "norelro" || s == "noretpolineplt" ||
- s == "noseparate-code" || s == "notext" ||
+ s == "start-stop-gc" || s == "nocombreloc" || s == "nocopyreloc" ||
+ s == "nodefaultlib" || s == "nodelete" || s == "nodlopen" ||
+ s == "noexecstack" || s == "nognustack" ||
+ s == "nokeep-text-section-prefix" || s == "norelro" ||
+ s == "noretpolineplt" ||
+ s == "noseparate-code" || s == "nostart-stop-gc" || s == "notext" ||
s == "now" || s == "origin" || s == "pac-plt" || s == "rel" ||
s == "rela" || s == "relro" || s == "retpolineplt" ||
s == "rodynamic" || s == "shstk" || s == "text" || s == "undefs" ||
@@ -457,7 +473,7 @@ static void checkZOptions(opt::InputArgList &args) {
error("unknown -z value: " + StringRef(arg->getValue()));
}
-void LinkerDriver::main(ArrayRef<const char *> argsArr) {
+void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
ELFOptTable parser;
opt::InputArgList args = parser.parse(argsArr.slice(1));
@@ -498,6 +514,9 @@ void LinkerDriver::main(ArrayRef<const char *> argsArr) {
tar = std::move(*errOrWriter);
tar->append("response.txt", createResponseFile(args));
tar->append("version.txt", getLLDVersion() + "\n");
+ StringRef ltoSampleProfile = args.getLastArgValue(OPT_lto_sample_profile);
+ if (!ltoSampleProfile.empty())
+ readFile(ltoSampleProfile);
} else {
error("--reproduce: " + toString(errOrWriter.takeError()));
}
@@ -573,40 +592,58 @@ static std::string getRpath(opt::InputArgList &args) {
// Determines what we should do if there are remaining unresolved
// symbols after the name resolution.
-static UnresolvedPolicy getUnresolvedSymbolPolicy(opt::InputArgList &args) {
+static void setUnresolvedSymbolPolicy(opt::InputArgList &args) {
UnresolvedPolicy errorOrWarn = args.hasFlag(OPT_error_unresolved_symbols,
OPT_warn_unresolved_symbols, true)
? UnresolvedPolicy::ReportError
: UnresolvedPolicy::Warn;
+ // -shared implies -unresolved-symbols=ignore-all because missing
+ // symbols are likely to be resolved at runtime.
+ bool diagRegular = !config->shared, diagShlib = false;
- // Process the last of -unresolved-symbols, -no-undefined or -z defs.
- for (auto *arg : llvm::reverse(args)) {
+ for (const opt::Arg *arg : args) {
switch (arg->getOption().getID()) {
case OPT_unresolved_symbols: {
StringRef s = arg->getValue();
- if (s == "ignore-all" || s == "ignore-in-object-files")
- return UnresolvedPolicy::Ignore;
- if (s == "ignore-in-shared-libs" || s == "report-all")
- return errorOrWarn;
- error("unknown --unresolved-symbols value: " + s);
- continue;
+ if (s == "ignore-all") {
+ diagRegular = false;
+ diagShlib = false;
+ } else if (s == "ignore-in-object-files") {
+ diagRegular = false;
+ diagShlib = true;
+ } else if (s == "ignore-in-shared-libs") {
+ diagRegular = true;
+ diagShlib = false;
+ } else if (s == "report-all") {
+ diagRegular = true;
+ diagShlib = true;
+ } else {
+ error("unknown --unresolved-symbols value: " + s);
+ }
+ break;
}
case OPT_no_undefined:
- return errorOrWarn;
+ diagRegular = true;
+ break;
case OPT_z:
if (StringRef(arg->getValue()) == "defs")
- return errorOrWarn;
- if (StringRef(arg->getValue()) == "undefs")
- return UnresolvedPolicy::Ignore;
- continue;
+ diagRegular = true;
+ else if (StringRef(arg->getValue()) == "undefs")
+ diagRegular = false;
+ break;
+ case OPT_allow_shlib_undefined:
+ diagShlib = false;
+ break;
+ case OPT_no_allow_shlib_undefined:
+ diagShlib = true;
+ break;
}
}
- // -shared implies -unresolved-symbols=ignore-all because missing
- // symbols are likely to be resolved at runtime using other DSOs.
- if (config->shared)
- return UnresolvedPolicy::Ignore;
- return errorOrWarn;
+ config->unresolvedSymbols =
+ diagRegular ? errorOrWarn : UnresolvedPolicy::Ignore;
+ config->unresolvedSymbolsInShlib =
+ diagShlib ? errorOrWarn : UnresolvedPolicy::Ignore;
}
static Target2Policy getTarget2(opt::InputArgList &args) {
@@ -725,6 +762,20 @@ static OrphanHandlingPolicy getOrphanHandling(opt::InputArgList &args) {
return OrphanHandlingPolicy::Place;
}
+// Parses --power10-stubs= flags, to disable or enable Power 10
+// instructions in stubs.
+static bool getP10StubOpt(opt::InputArgList &args) {
+
+ if (args.getLastArgValue(OPT_power10_stubs_eq)== "no")
+ return false;
+
+ if (!args.hasArg(OPT_power10_stubs_eq) &&
+ args.hasArg(OPT_no_power10_stubs))
+ return false;
+
+ return true;
+}
+
// Parse --build-id or --build-id=<style>. We handle "tree" as a
// synonym for "sha1" because all our hash functions including
// -build-id=sha1 are actually tree hashes for performance reasons.
@@ -805,13 +856,66 @@ static void readCallGraph(MemoryBufferRef mb) {
}
}
+// If SHT_LLVM_CALL_GRAPH_PROFILE and its relocation section exist, returns
+// true and populates cgProfile and symbolIndices.
+template <class ELFT>
+static bool
+processCallGraphRelocations(SmallVector<uint32_t, 32> &symbolIndices,
+ ArrayRef<typename ELFT::CGProfile> &cgProfile,
+ ObjFile<ELFT> *inputObj) {
+ symbolIndices.clear();
+ const ELFFile<ELFT> &obj = inputObj->getObj();
+ ArrayRef<Elf_Shdr_Impl<ELFT>> objSections =
+ CHECK(obj.sections(), "could not retrieve object sections");
+
+ if (inputObj->cgProfileSectionIndex == SHN_UNDEF)
+ return false;
+
+ cgProfile =
+ check(obj.template getSectionContentsAsArray<typename ELFT::CGProfile>(
+ objSections[inputObj->cgProfileSectionIndex]));
+
+ for (size_t i = 0, e = objSections.size(); i < e; ++i) {
+ const Elf_Shdr_Impl<ELFT> &sec = objSections[i];
+ if (sec.sh_info == inputObj->cgProfileSectionIndex) {
+ if (sec.sh_type == SHT_RELA) {
+ ArrayRef<typename ELFT::Rela> relas =
+ CHECK(obj.relas(sec), "could not retrieve cg profile rela section");
+ for (const typename ELFT::Rela &rel : relas)
+ symbolIndices.push_back(rel.getSymbol(config->isMips64EL));
+ break;
+ }
+ if (sec.sh_type == SHT_REL) {
+ ArrayRef<typename ELFT::Rel> rels =
+ CHECK(obj.rels(sec), "could not retrieve cg profile rel section");
+ for (const typename ELFT::Rel &rel : rels)
+ symbolIndices.push_back(rel.getSymbol(config->isMips64EL));
+ break;
+ }
+ }
+ }
+ if (symbolIndices.empty())
+ warn("SHT_LLVM_CALL_GRAPH_PROFILE exists, but relocation section doesn't");
+ return !symbolIndices.empty();
+}
+
template <class ELFT> static void readCallGraphsFromObjectFiles() {
+ SmallVector<uint32_t, 32> symbolIndices;
+ ArrayRef<typename ELFT::CGProfile> cgProfile;
for (auto file : objectFiles) {
auto *obj = cast<ObjFile<ELFT>>(file);
+ if (!processCallGraphRelocations(symbolIndices, cgProfile, obj))
+ continue;
+
+ if (symbolIndices.size() != cgProfile.size() * 2)
+ fatal("number of relocations doesn't match Weights");
- for (const Elf_CGProfile_Impl<ELFT> &cgpe : obj->cgProfile) {
- auto *fromSym = dyn_cast<Defined>(&obj->getSymbol(cgpe.cgp_from));
- auto *toSym = dyn_cast<Defined>(&obj->getSymbol(cgpe.cgp_to));
+ for (uint32_t i = 0, size = cgProfile.size(); i < size; ++i) {
+ const Elf_CGProfile_Impl<ELFT> &cgpe = cgProfile[i];
+ uint32_t fromIndex = symbolIndices[i * 2];
+ uint32_t toIndex = symbolIndices[i * 2 + 1];
+ auto *fromSym = dyn_cast<Defined>(&obj->getSymbol(fromIndex));
+ auto *toSym = dyn_cast<Defined>(&obj->getSymbol(toIndex));
if (!fromSym || !toSym)
continue;
@@ -902,22 +1006,28 @@ static void readConfigs(opt::InputArgList &args) {
args.hasFlag(OPT_allow_multiple_definition,
OPT_no_allow_multiple_definition, false) ||
hasZOption(args, "muldefs");
- config->allowShlibUndefined =
- args.hasFlag(OPT_allow_shlib_undefined, OPT_no_allow_shlib_undefined,
- args.hasArg(OPT_shared));
config->auxiliaryList = args::getStrings(args, OPT_auxiliary);
- config->bsymbolic = args.hasArg(OPT_Bsymbolic);
- config->bsymbolicFunctions = args.hasArg(OPT_Bsymbolic_functions);
+ if (opt::Arg *arg =
+ args.getLastArg(OPT_Bno_symbolic, OPT_Bsymbolic_non_weak_functions,
+ OPT_Bsymbolic_functions, OPT_Bsymbolic)) {
+ if (arg->getOption().matches(OPT_Bsymbolic_non_weak_functions))
+ config->bsymbolic = BsymbolicKind::NonWeakFunctions;
+ else if (arg->getOption().matches(OPT_Bsymbolic_functions))
+ config->bsymbolic = BsymbolicKind::Functions;
+ else if (arg->getOption().matches(OPT_Bsymbolic))
+ config->bsymbolic = BsymbolicKind::All;
+ }
config->checkSections =
args.hasFlag(OPT_check_sections, OPT_no_check_sections, true);
config->chroot = args.getLastArgValue(OPT_chroot);
config->compressDebugSections = getCompressDebugSections(args);
- config->cref = args.hasFlag(OPT_cref, OPT_no_cref, false);
+ config->cref = args.hasArg(OPT_cref);
config->defineCommon = args.hasFlag(OPT_define_common, OPT_no_define_common,
!args.hasArg(OPT_relocatable));
config->optimizeBBJumps =
args.hasFlag(OPT_optimize_bb_jumps, OPT_no_optimize_bb_jumps, false);
config->demangle = args.hasFlag(OPT_demangle, OPT_no_demangle, true);
+ config->dependencyFile = args.getLastArgValue(OPT_dependency_file);
config->dependentLibraries = args.hasFlag(OPT_dependent_libraries, OPT_no_dependent_libraries, true);
config->disableVerify = args.hasArg(OPT_disable_verify);
config->discard = getDiscard(args);
@@ -932,6 +1042,10 @@ static void readConfigs(opt::InputArgList &args) {
config->enableNewDtags =
args.hasFlag(OPT_enable_new_dtags, OPT_disable_new_dtags, true);
config->entry = args.getLastArgValue(OPT_entry);
+
+ errorHandler().errorHandlingScript =
+ args.getLastArgValue(OPT_error_handling_script);
+
config->executeOnly =
args.hasFlag(OPT_execute_only, OPT_no_execute_only, false);
config->exportDynamic =
@@ -942,6 +1056,8 @@ static void readConfigs(opt::InputArgList &args) {
!args.hasArg(OPT_relocatable);
config->fixCortexA8 =
args.hasArg(OPT_fix_cortex_a8) && !args.hasArg(OPT_relocatable);
+ config->fortranCommon =
+ args.hasFlag(OPT_fortran_common, OPT_no_fortran_common, true);
config->gcSections = args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, false);
config->gnuUnique = args.hasFlag(OPT_gnu_unique, OPT_no_gnu_unique, true);
config->gdbIndex = args.hasFlag(OPT_gdb_index, OPT_no_gdb_index, false);
@@ -957,19 +1073,24 @@ static void readConfigs(opt::InputArgList &args) {
config->ltoCSProfileFile = args.getLastArgValue(OPT_lto_cs_profile_file);
config->ltoDebugPassManager = args.hasArg(OPT_lto_debug_pass_manager);
config->ltoEmitAsm = args.hasArg(OPT_lto_emit_asm);
- config->ltoNewPassManager = args.hasArg(OPT_lto_new_pass_manager);
+ config->ltoNewPassManager =
+ args.hasFlag(OPT_no_lto_legacy_pass_manager, OPT_lto_legacy_pass_manager,
+ LLVM_ENABLE_NEW_PASS_MANAGER);
config->ltoNewPmPasses = args.getLastArgValue(OPT_lto_newpm_passes);
config->ltoWholeProgramVisibility =
- args.hasArg(OPT_lto_whole_program_visibility);
+ args.hasFlag(OPT_lto_whole_program_visibility,
+ OPT_no_lto_whole_program_visibility, false);
config->ltoo = args::getInteger(args, OPT_lto_O, 2);
config->ltoObjPath = args.getLastArgValue(OPT_lto_obj_path_eq);
config->ltoPartitions = args::getInteger(args, OPT_lto_partitions, 1);
+ config->ltoPseudoProbeForProfiling =
+ args.hasArg(OPT_lto_pseudo_probe_for_profiling);
config->ltoSampleProfile = args.getLastArgValue(OPT_lto_sample_profile);
config->ltoBasicBlockSections =
- args.getLastArgValue(OPT_lto_basicblock_sections);
+ args.getLastArgValue(OPT_lto_basic_block_sections);
config->ltoUniqueBasicBlockSectionNames =
- args.hasFlag(OPT_lto_unique_bb_section_names,
- OPT_no_lto_unique_bb_section_names, false);
+ args.hasFlag(OPT_lto_unique_basic_block_section_names,
+ OPT_no_lto_unique_basic_block_section_names, false);
config->mapFile = args.getLastArgValue(OPT_Map);
config->mipsGotSize = args::getInteger(args, OPT_mips_got_size, 0xfff0);
config->mergeArmExidx =
@@ -982,6 +1103,17 @@ static void readConfigs(opt::InputArgList &args) {
config->oFormatBinary = isOutputFormatBinary(args);
config->omagic = args.hasFlag(OPT_omagic, OPT_no_omagic, false);
config->optRemarksFilename = args.getLastArgValue(OPT_opt_remarks_filename);
+
+ // Parse remarks hotness threshold. Valid value is either integer or 'auto'.
+ if (auto *arg = args.getLastArg(OPT_opt_remarks_hotness_threshold)) {
+ auto resultOrErr = remarks::parseHotnessThresholdOption(arg->getValue());
+ if (!resultOrErr)
+ error(arg->getSpelling() + ": invalid argument '" + arg->getValue() +
+ "', only integer or 'auto' is supported");
+ else
+ config->optRemarksHotnessThreshold = *resultOrErr;
+ }
+
config->optRemarksPasses = args.getLastArgValue(OPT_opt_remarks_passes);
config->optRemarksWithHotness = args.hasArg(OPT_opt_remarks_with_hotness);
config->optRemarksFormat = args.getLastArgValue(OPT_opt_remarks_format);
@@ -1004,8 +1136,6 @@ static void readConfigs(opt::InputArgList &args) {
config->rpath = getRpath(args);
config->relocatable = args.hasArg(OPT_relocatable);
config->saveTemps = args.hasArg(OPT_save_temps);
- if (args.hasArg(OPT_shuffle_sections))
- config->shuffleSectionSeed = args::getInteger(args, OPT_shuffle_sections, 0);
config->searchPaths = args::getStrings(args, OPT_library_path);
config->sectionStartMap = getSectionStartMap(args);
config->shared = args.hasArg(OPT_shared);
@@ -1041,12 +1171,9 @@ static void readConfigs(opt::InputArgList &args) {
config->unique = args.hasArg(OPT_unique);
config->useAndroidRelrTags = args.hasFlag(
OPT_use_android_relr_tags, OPT_no_use_android_relr_tags, false);
- config->unresolvedSymbols = getUnresolvedSymbolPolicy(args);
config->warnBackrefs =
args.hasFlag(OPT_warn_backrefs, OPT_no_warn_backrefs, false);
config->warnCommon = args.hasFlag(OPT_warn_common, OPT_no_warn_common, false);
- config->warnIfuncTextrel =
- args.hasFlag(OPT_warn_ifunc_textrel, OPT_no_warn_ifunc_textrel, false);
config->warnSymbolOrdering =
args.hasFlag(OPT_warn_symbol_ordering, OPT_no_warn_symbol_ordering, true);
config->zCombreloc = getZFlag(args, "combreloc", "nocombreloc", true);
@@ -1077,9 +1204,38 @@ static void readConfigs(opt::InputArgList &args) {
config->zSeparate = getZSeparate(args);
config->zShstk = hasZOption(args, "shstk");
config->zStackSize = args::getZOptionValue(args, OPT_z, "stack-size", 0);
+ config->zStartStopGC =
+ getZFlag(args, "start-stop-gc", "nostart-stop-gc", true);
config->zStartStopVisibility = getZStartStopVisibility(args);
config->zText = getZFlag(args, "text", "notext", true);
config->zWxneeded = hasZOption(args, "wxneeded");
+ setUnresolvedSymbolPolicy(args);
+ config->Power10Stub = getP10StubOpt(args);
+
+ if (opt::Arg *arg = args.getLastArg(OPT_eb, OPT_el)) {
+ if (arg->getOption().matches(OPT_eb))
+ config->optEB = true;
+ else
+ config->optEL = true;
+ }
+
+ for (opt::Arg *arg : args.filtered(OPT_shuffle_sections)) {
+ constexpr StringRef errPrefix = "--shuffle-sections=: ";
+ std::pair<StringRef, StringRef> kv = StringRef(arg->getValue()).split('=');
+ if (kv.first.empty() || kv.second.empty()) {
+ error(errPrefix + "expected <section_glob>=<seed>, but got '" +
+ arg->getValue() + "'");
+ continue;
+ }
+ // Signed so that <section_glob>=-1 is allowed.
+ int64_t v;
+ if (!to_integer(kv.second, v))
+ error(errPrefix + "expected an integer, but got '" + kv.second + "'");
+ else if (Expected<GlobPattern> pat = GlobPattern::create(kv.first))
+ config->shuffleSections.emplace_back(std::move(*pat), uint32_t(v));
+ else
+ error(errPrefix + toString(pat.takeError()));
+ }
for (opt::Arg *arg : args.filtered(OPT_z)) {
std::pair<StringRef, StringRef> option =
@@ -1102,6 +1258,8 @@ static void readConfigs(opt::InputArgList &args) {
error(errPrefix + toString(pat.takeError()));
}
+ cl::ResetAllOptionOccurrences();
+
// Parse LTO options.
if (auto *arg = args.getLastArg(OPT_plugin_opt_mcpu_eq))
parseClangOption(saver.save("-mcpu=" + StringRef(arg->getValue())),
@@ -1204,18 +1362,19 @@ static void readConfigs(opt::InputArgList &args) {
}
assert(config->versionDefinitions.empty());
- config->versionDefinitions.push_back({"local", (uint16_t)VER_NDX_LOCAL, {}});
config->versionDefinitions.push_back(
- {"global", (uint16_t)VER_NDX_GLOBAL, {}});
+ {"local", (uint16_t)VER_NDX_LOCAL, {}, {}});
+ config->versionDefinitions.push_back(
+ {"global", (uint16_t)VER_NDX_GLOBAL, {}, {}});
// If --retain-symbol-file is used, we'll keep only the symbols listed in
// the file and discard all others.
if (auto *arg = args.getLastArg(OPT_retain_symbols_file)) {
- config->versionDefinitions[VER_NDX_LOCAL].patterns.push_back(
+ config->versionDefinitions[VER_NDX_LOCAL].nonLocalPatterns.push_back(
{"*", /*isExternCpp=*/false, /*hasWildcard=*/true});
if (Optional<MemoryBufferRef> buffer = readFile(arg->getValue()))
for (StringRef s : args::getLines(*buffer))
- config->versionDefinitions[VER_NDX_GLOBAL].patterns.push_back(
+ config->versionDefinitions[VER_NDX_GLOBAL].nonLocalPatterns.push_back(
{s, /*isExternCpp=*/false, /*hasWildcard=*/false});
}
@@ -1228,10 +1387,10 @@ static void readConfigs(opt::InputArgList &args) {
}
// When producing an executable, --dynamic-list specifies non-local defined
- // symbols whith are required to be exported. When producing a shared object,
+ // symbols which are required to be exported. When producing a shared object,
// symbols not specified by --dynamic-list are non-preemptible.
config->symbolic =
- args.hasArg(OPT_Bsymbolic) || args.hasArg(OPT_dynamic_list);
+ config->bsymbolic == BsymbolicKind::All || args.hasArg(OPT_dynamic_list);
for (auto *arg : args.filtered(OPT_dynamic_list))
if (Optional<MemoryBufferRef> buffer = readFile(arg->getValue()))
readDynamicList(*buffer);
@@ -1294,9 +1453,23 @@ static void setConfigs(opt::InputArgList &args) {
config->writeAddends = args.hasFlag(OPT_apply_dynamic_relocs,
OPT_no_apply_dynamic_relocs, false) ||
!config->isRela;
-
+ // Validation of dynamic relocation addends is on by default for assertions
+ // builds (for supported targets) and disabled otherwise. Ideally we would
+ // enable the debug checks for all targets, but currently not all targets
+ // have support for reading Elf_Rel addends, so we only enable for a subset.
+#ifndef NDEBUG
+ bool checkDynamicRelocsDefault = m == EM_ARM || m == EM_386 || m == EM_MIPS ||
+ m == EM_X86_64 || m == EM_RISCV;
+#else
+ bool checkDynamicRelocsDefault = false;
+#endif
+ config->checkDynamicRelocs =
+ args.hasFlag(OPT_check_dynamic_relocations,
+ OPT_no_check_dynamic_relocations, checkDynamicRelocsDefault);
config->tocOptimize =
args.hasFlag(OPT_toc_optimize, OPT_no_toc_optimize, m == EM_PPC64);
+ config->pcRelOptimize =
+ args.hasFlag(OPT_pcrel_optimize, OPT_no_pcrel_optimize, m == EM_PPC64);
}
// Returns a value of "-format" option.
@@ -1311,10 +1484,12 @@ static bool isFormatBinary(StringRef s) {
}
void LinkerDriver::createFiles(opt::InputArgList &args) {
+ llvm::TimeTraceScope timeScope("Load input files");
// For --{push,pop}-state.
std::vector<std::tuple<bool, bool, bool>> stack;
// Iterate over argv to process input files and positional arguments.
+ InputFile::isInGroup = false;
for (auto *arg : args) {
switch (arg->getOption().getID()) {
case OPT_library:
@@ -1584,11 +1759,81 @@ static void handleLibcall(StringRef name) {
sym->fetch();
}
+// Handle --dependency-file=<path>. If that option is given, lld creates a
+// file at a given path with the following contents:
+//
+// <output-file>: <input-file> ...
+//
+// <input-file>:
+//
+// where <output-file> is a pathname of an output file and <input-file>
+// ... is a list of pathnames of all input files. `make` command can read a
+// file in the above format and interpret it as a dependency info. We write
+// phony targets for every <input-file> to avoid an error when that file is
+// removed.
+//
+// This option is useful if you want to make your final executable to depend
+// on all input files including system libraries. Here is why.
+//
+// When you write a Makefile, you usually write it so that the final
+// executable depends on all user-generated object files. Normally, you
+// don't make your executable to depend on system libraries (such as libc)
+// because you don't know the exact paths of libraries, even though system
+// libraries that are linked to your executable statically are technically a
+// part of your program. By using --dependency-file option, you can make
+// lld to dump dependency info so that you can maintain exact dependencies
+// easily.
+static void writeDependencyFile() {
+ std::error_code ec;
+ raw_fd_ostream os(config->dependencyFile, ec, sys::fs::OF_None);
+ if (ec) {
+ error("cannot open " + config->dependencyFile + ": " + ec.message());
+ return;
+ }
+
+ // We use the same escape rules as Clang/GCC which are accepted by Make/Ninja:
+ // * A space is escaped by a backslash which itself must be escaped.
+ // * A hash sign is escaped by a single backslash.
+ // * $ is escapes as $$.
+ auto printFilename = [](raw_fd_ostream &os, StringRef filename) {
+ llvm::SmallString<256> nativePath;
+ llvm::sys::path::native(filename.str(), nativePath);
+ llvm::sys::path::remove_dots(nativePath, /*remove_dot_dot=*/true);
+ for (unsigned i = 0, e = nativePath.size(); i != e; ++i) {
+ if (nativePath[i] == '#') {
+ os << '\\';
+ } else if (nativePath[i] == ' ') {
+ os << '\\';
+ unsigned j = i;
+ while (j > 0 && nativePath[--j] == '\\')
+ os << '\\';
+ } else if (nativePath[i] == '$') {
+ os << '$';
+ }
+ os << nativePath[i];
+ }
+ };
+
+ os << config->outputFile << ":";
+ for (StringRef path : config->dependencyFiles) {
+ os << " \\\n ";
+ printFilename(os, path);
+ }
+ os << "\n";
+
+ for (StringRef path : config->dependencyFiles) {
+ os << "\n";
+ printFilename(os, path);
+ os << ":\n";
+ }
+}
+
// Replaces common symbols with defined symbols reside in .bss sections.
// This function is called after all symbol names are resolved. As a
// result, the passes after the symbol resolution won't see any
// symbols of type CommonSymbol.
static void replaceCommonSymbols() {
+ llvm::TimeTraceScope timeScope("Replace common symbols");
for (Symbol *sym : symtab->symbols()) {
auto *s = dyn_cast<CommonSymbol>(sym);
if (!s)
@@ -1608,6 +1853,7 @@ static void replaceCommonSymbols() {
// created from the DSO. Otherwise, they become dangling references
// that point to a non-existent DSO.
static void demoteSharedSymbols() {
+ llvm::TimeTraceScope timeScope("Demote shared symbols");
for (Symbol *sym : symtab->symbols()) {
auto *s = dyn_cast<SharedSymbol>(sym);
if (!s || s->getFile().isNeeded)
@@ -1663,7 +1909,7 @@ static void findKeepUniqueSections(opt::InputArgList &args) {
ArrayRef<Symbol *> syms = obj->getSymbols();
if (obj->addrsigSec) {
ArrayRef<uint8_t> contents =
- check(obj->getObj().getSectionContents(obj->addrsigSec));
+ check(obj->getObj().getSectionContents(*obj->addrsigSec));
const uint8_t *cur = contents.begin();
while (cur != contents.end()) {
unsigned size;
@@ -1737,8 +1983,9 @@ static Symbol *addUndefined(StringRef name) {
Undefined{nullptr, name, STB_GLOBAL, STV_DEFAULT, 0});
}
-static Symbol *addUnusedUndefined(StringRef name) {
- Undefined sym{nullptr, name, STB_GLOBAL, STV_DEFAULT, 0};
+static Symbol *addUnusedUndefined(StringRef name,
+ uint8_t binding = STB_GLOBAL) {
+ Undefined sym{nullptr, name, binding, STV_DEFAULT, 0};
sym.isUsedInRegularObj = false;
return symtab->addSymbol(sym);
}
@@ -1771,9 +2018,9 @@ template <class ELFT> void LinkerDriver::compileBitcodeFiles() {
// The --wrap option is a feature to rename symbols so that you can write
// wrappers for existing functions. If you pass `-wrap=foo`, all
-// occurrences of symbol `foo` are resolved to `wrap_foo` (so, you are
-// expected to write `wrap_foo` function as a wrapper). The original
-// symbol becomes accessible as `real_foo`, so you can call that from your
+// occurrences of symbol `foo` are resolved to `__wrap_foo` (so, you are
+// expected to write `__wrap_foo` function as a wrapper). The original
+// symbol becomes accessible as `__real_foo`, so you can call that from your
// wrapper.
//
// This data structure is instantiated for each -wrap option.
@@ -1801,8 +2048,9 @@ static std::vector<WrappedSymbol> addWrappedSymbols(opt::InputArgList &args) {
if (!sym)
continue;
- Symbol *real = addUndefined(saver.save("__real_" + name));
- Symbol *wrap = addUndefined(saver.save("__wrap_" + name));
+ Symbol *real = addUnusedUndefined(saver.save("__real_" + name));
+ Symbol *wrap =
+ addUnusedUndefined(saver.save("__wrap_" + name), sym->binding);
v.push_back({sym, real, wrap});
// We want to tell LTO not to inline symbols to be overwritten
@@ -1812,22 +2060,72 @@ static std::vector<WrappedSymbol> addWrappedSymbols(opt::InputArgList &args) {
// Tell LTO not to eliminate these symbols.
sym->isUsedInRegularObj = true;
- wrap->isUsedInRegularObj = true;
+ // If sym is referenced in any object file, bitcode file or shared object,
+ // retain wrap which is the redirection target of sym. If the object file
+ // defining sym has sym references, we cannot easily distinguish the case
+ // from cases where sym is not referenced. Retain wrap because we choose to
+ // wrap sym references regardless of whether sym is defined
+ // (https://sourceware.org/bugzilla/show_bug.cgi?id=26358).
+ if (sym->referenced || sym->isDefined())
+ wrap->isUsedInRegularObj = true;
}
return v;
}
-// Do renaming for -wrap by updating pointers to symbols.
+// Do renaming for -wrap and foo@v1 by updating pointers to symbols.
//
// When this function is executed, only InputFiles and symbol table
// contain pointers to symbol objects. We visit them to replace pointers,
// so that wrapped symbols are swapped as instructed by the command line.
-static void wrapSymbols(ArrayRef<WrappedSymbol> wrapped) {
+static void redirectSymbols(ArrayRef<WrappedSymbol> wrapped) {
+ llvm::TimeTraceScope timeScope("Redirect symbols");
DenseMap<Symbol *, Symbol *> map;
for (const WrappedSymbol &w : wrapped) {
map[w.sym] = w.wrap;
map[w.real] = w.sym;
}
+ for (Symbol *sym : symtab->symbols()) {
+ // Enumerate symbols with a non-default version (foo@v1).
+ StringRef name = sym->getName();
+ const char *suffix1 = sym->getVersionSuffix();
+ if (suffix1[0] != '@' || suffix1[1] == '@')
+ continue;
+
+ // Check the existing symbol foo. We have two special cases to handle:
+ //
+ // * There is a definition of foo@v1 and foo@@v1.
+ // * There is a definition of foo@v1 and foo.
+ Defined *sym2 = dyn_cast_or_null<Defined>(symtab->find(name));
+ if (!sym2)
+ continue;
+ const char *suffix2 = sym2->getVersionSuffix();
+ if (suffix2[0] == '@' && suffix2[1] == '@' &&
+ strcmp(suffix1 + 1, suffix2 + 2) == 0) {
+ // foo@v1 and foo@@v1 should be merged, so redirect foo@v1 to foo@@v1.
+ map.try_emplace(sym, sym2);
+ // If both foo@v1 and foo@@v1 are defined and non-weak, report a duplicate
+ // definition error.
+ sym2->resolve(*sym);
+ // Eliminate foo@v1 from the symbol table.
+ sym->symbolKind = Symbol::PlaceholderKind;
+ } else if (auto *sym1 = dyn_cast<Defined>(sym)) {
+ if (sym2->versionId > VER_NDX_GLOBAL
+ ? config->versionDefinitions[sym2->versionId].name == suffix1 + 1
+ : sym1->section == sym2->section && sym1->value == sym2->value) {
+ // Due to an assembler design flaw, if foo is defined, .symver foo,
+ // foo@v1 defines both foo and foo@v1. Unless foo is bound to a
+ // different version, GNU ld makes foo@v1 canonical and elimiates foo.
+ // Emulate its behavior, otherwise we would have foo or foo@@v1 beside
+ // foo@v1. foo@v1 and foo combining does not apply if they are not
+ // defined in the same place.
+ map.try_emplace(sym2, sym);
+ sym2->symbolKind = Symbol::PlaceholderKind;
+ }
+ }
+ }
+
+ if (map.empty())
+ return;
// Update pointers in input files.
parallelForEach(objectFiles, [&](InputFile *file) {
@@ -1903,10 +2201,14 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
// Fail early if the output file or map file is not writable. If a user has a
// long link, e.g. due to a large LTO link, they do not wish to run it and
// find that it failed because there was a mistake in their command-line.
- if (auto e = tryCreateFile(config->outputFile))
- error("cannot open output file " + config->outputFile + ": " + e.message());
- if (auto e = tryCreateFile(config->mapFile))
- error("cannot open map file " + config->mapFile + ": " + e.message());
+ {
+ llvm::TimeTraceScope timeScope("Create output files");
+ if (auto e = tryCreateFile(config->outputFile))
+ error("cannot open output file " + config->outputFile + ": " +
+ e.message());
+ if (auto e = tryCreateFile(config->mapFile))
+ error("cannot open map file " + config->mapFile + ": " + e.message());
+ }
if (errorCount())
return;
@@ -1925,7 +2227,7 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
// Handle -u/--undefined before input files. If both a.a and b.so define foo,
// -u foo a.a b.so will fetch a.a.
for (StringRef name : config->undefined)
- addUnusedUndefined(name);
+ addUnusedUndefined(name)->referenced = true;
// Add all files to the symbol table. This will add almost all
// symbols that we need to the symbol table. This process might
@@ -1933,8 +2235,10 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
// appended to the Files vector.
{
llvm::TimeTraceScope timeScope("Parse input files");
- for (size_t i = 0; i < files.size(); ++i)
+ for (size_t i = 0; i < files.size(); ++i) {
+ llvm::TimeTraceScope timeScope("Parse input files", files[i]->getName());
parseFile(files[i]);
+ }
}
// Now that we have every file, we can decide if we will need a
@@ -2000,7 +2304,11 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
// They also might be exported if referenced by DSOs.
script->declareSymbols();
- // Handle the -exclude-libs option.
+ // Handle --exclude-libs. This is before scanVersionScript() due to a
+ // workaround for Android ndk: for a defined versioned symbol in an archive
+ // without a version node in the version script, Android does not expect a
+ // 'has undefined version' error in -shared --exclude-libs=ALL mode (PR36295).
+ // GNU ld errors in this case.
if (args.hasArg(OPT_exclude_libs))
excludeLibs(args);
@@ -2021,8 +2329,10 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
// For a relocatable output, version scripts don't make sense, and
// parsing a symbol version string (e.g. dropping "@ver1" from a symbol
// name "foo@ver1") rather do harm, so we don't call this if -r is given.
- if (!config->relocatable)
+ if (!config->relocatable) {
+ llvm::TimeTraceScope timeScope("Process symbol versions");
symtab->scanVersionScript();
+ }
// Do link-time optimization if given files are LLVM bitcode files.
// This compiles bitcode files into real object files.
@@ -2031,6 +2341,12 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
// except a few linker-synthesized ones will be added to the symbol table.
compileBitcodeFiles<ELFT>();
+ // Handle --exclude-libs again because lto.tmp may reference additional
+ // libcalls symbols defined in an excluded archive. This may override
+ // versionId set by scanVersionScript().
+ if (args.hasArg(OPT_exclude_libs))
+ excludeLibs(args);
+
// Symbol resolution finished. Report backward reference problems.
reportBackrefs();
if (errorCount())
@@ -2041,48 +2357,58 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
// in addCombinedLTOObject, so we are done if that's the case.
// Likewise, --plugin-opt=emit-llvm and --plugin-opt=emit-asm are the
// options to create output files in bitcode or assembly code
- // repsectively. No object files are generated.
+ // respectively. No object files are generated.
// Also bail out here when only certain thinLTO modules are specified for
// compilation. The intermediate object file are the expected output.
if (config->thinLTOIndexOnly || config->emitLLVM || config->ltoEmitAsm ||
!config->thinLTOModulesToCompile.empty())
return;
- // Apply symbol renames for -wrap.
- if (!wrapped.empty())
- wrapSymbols(wrapped);
-
- // Now that we have a complete list of input files.
- // Beyond this point, no new files are added.
- // Aggregate all input sections into one place.
- for (InputFile *f : objectFiles)
- for (InputSectionBase *s : f->getSections())
- if (s && s != &InputSection::discarded)
- inputSections.push_back(s);
- for (BinaryFile *f : binaryFiles)
- for (InputSectionBase *s : f->getSections())
- inputSections.push_back(cast<InputSection>(s));
-
- llvm::erase_if(inputSections, [](InputSectionBase *s) {
- if (s->type == SHT_LLVM_SYMPART) {
- readSymbolPartitionSection<ELFT>(s);
- return true;
- }
+ // Apply symbol renames for -wrap and combine foo@v1 and foo@@v1.
+ redirectSymbols(wrapped);
- // We do not want to emit debug sections if --strip-all
- // or -strip-debug are given.
- if (config->strip == StripPolicy::None)
- return false;
+ {
+ llvm::TimeTraceScope timeScope("Aggregate sections");
+ // Now that we have a complete list of input files.
+ // Beyond this point, no new files are added.
+ // Aggregate all input sections into one place.
+ for (InputFile *f : objectFiles)
+ for (InputSectionBase *s : f->getSections())
+ if (s && s != &InputSection::discarded)
+ inputSections.push_back(s);
+ for (BinaryFile *f : binaryFiles)
+ for (InputSectionBase *s : f->getSections())
+ inputSections.push_back(cast<InputSection>(s));
+ }
- if (isDebugSection(*s))
- return true;
- if (auto *isec = dyn_cast<InputSection>(s))
- if (InputSectionBase *rel = isec->getRelocatedSection())
- if (isDebugSection(*rel))
- return true;
+ {
+ llvm::TimeTraceScope timeScope("Strip sections");
+ llvm::erase_if(inputSections, [](InputSectionBase *s) {
+ if (s->type == SHT_LLVM_SYMPART) {
+ readSymbolPartitionSection<ELFT>(s);
+ return true;
+ }
- return false;
- });
+ // We do not want to emit debug sections if --strip-all
+ // or -strip-debug are given.
+ if (config->strip == StripPolicy::None)
+ return false;
+
+ if (isDebugSection(*s))
+ return true;
+ if (auto *isec = dyn_cast<InputSection>(s))
+ if (InputSectionBase *rel = isec->getRelocatedSection())
+ if (isDebugSection(*rel))
+ return true;
+
+ return false;
+ });
+ }
+
+ // Since we now have a complete set of input files, we can create
+ // a .d file to record build dependencies.
+ if (!config->dependencyFile.empty())
+ writeDependencyFile();
// Now that the number of partitions is fixed, save a pointer to the main
// partition.
@@ -2154,23 +2480,33 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
if (!config->relocatable)
combineEhSections();
- // Create output sections described by SECTIONS commands.
- script->processSectionCommands();
-
- // Linker scripts control how input sections are assigned to output sections.
- // Input sections that were not handled by scripts are called "orphans", and
- // they are assigned to output sections by the default rule. Process that.
- script->addOrphanSections();
-
- // Migrate InputSectionDescription::sectionBases to sections. This includes
- // merging MergeInputSections into a single MergeSyntheticSection. From this
- // point onwards InputSectionDescription::sections should be used instead of
- // sectionBases.
- for (BaseCommand *base : script->sectionCommands)
- if (auto *sec = dyn_cast<OutputSection>(base))
- sec->finalizeInputSections();
- llvm::erase_if(inputSections,
- [](InputSectionBase *s) { return isa<MergeInputSection>(s); });
+ {
+ llvm::TimeTraceScope timeScope("Assign sections");
+
+ // Create output sections described by SECTIONS commands.
+ script->processSectionCommands();
+
+ // Linker scripts control how input sections are assigned to output
+ // sections. Input sections that were not handled by scripts are called
+ // "orphans", and they are assigned to output sections by the default rule.
+ // Process that.
+ script->addOrphanSections();
+ }
+
+ {
+ llvm::TimeTraceScope timeScope("Merge/finalize input sections");
+
+ // Migrate InputSectionDescription::sectionBases to sections. This includes
+ // merging MergeInputSections into a single MergeSyntheticSection. From this
+ // point onwards InputSectionDescription::sections should be used instead of
+ // sectionBases.
+ for (BaseCommand *base : script->sectionCommands)
+ if (auto *sec = dyn_cast<OutputSection>(base))
+ sec->finalizeInputSections();
+ llvm::erase_if(inputSections, [](InputSectionBase *s) {
+ return isa<MergeInputSection>(s);
+ });
+ }
// Two input sections with different output sections should not be folded.
// ICF runs after processSectionCommands() so that we know the output sections.
diff --git a/gnu/llvm/lld/ELF/DriverUtils.cpp b/gnu/llvm/lld/ELF/DriverUtils.cpp
index c9b00c6a625..6b164e30677 100644
--- a/gnu/llvm/lld/ELF/DriverUtils.cpp
+++ b/gnu/llvm/lld/ELF/DriverUtils.cpp
@@ -26,6 +26,7 @@
#include "llvm/Support/Host.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
+#include "llvm/Support/TimeProfiler.h"
using namespace llvm;
using namespace llvm::sys;
@@ -132,7 +133,7 @@ opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> argv) {
if (missingCount)
error(Twine(args.getArgString(missingIndex)) + ": missing argument");
- for (auto *arg : args.filtered(OPT_UNKNOWN)) {
+ for (opt::Arg *arg : args.filtered(OPT_UNKNOWN)) {
std::string nearest;
if (findNearest(arg->getAsString(args), nearest) > 1)
error("unknown argument '" + arg->getAsString(args) + "'");
@@ -144,7 +145,7 @@ opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> argv) {
}
void elf::printHelp() {
- ELFOptTable().PrintHelp(
+ ELFOptTable().printHelp(
lld::outs(), (config->progName + " [options] file...").str().c_str(),
"lld", false /*ShowHidden*/, true /*ShowAllAliases*/);
lld::outs() << "\n";
@@ -183,10 +184,16 @@ std::string elf::createResponseFile(const opt::InputArgList &args) {
// fail because the archive we are creating doesn't contain empty
// directories for the output path (-o doesn't create directories).
// Strip directories to prevent the issue.
- os << "-o " << quote(sys::path::filename(arg->getValue())) << "\n";
+ os << "-o " << quote(path::filename(arg->getValue())) << "\n";
break;
+ case OPT_lto_sample_profile:
+ os << arg->getSpelling() << quote(rewritePath(arg->getValue())) << "\n";
+ break;
+ case OPT_call_graph_ordering_file:
case OPT_dynamic_list:
+ case OPT_just_symbols:
case OPT_library_path:
+ case OPT_retain_symbols_file:
case OPT_rpath:
case OPT_script:
case OPT_symbol_ordering_file:
@@ -265,6 +272,7 @@ Optional<std::string> elf::searchLibraryBaseName(StringRef name) {
// This is for -l<namespec>.
Optional<std::string> elf::searchLibrary(StringRef name) {
+ llvm::TimeTraceScope timeScope("Locate library", name);
if (name.startswith(":"))
return findFromSearchPaths(name.substr(1));
return searchLibraryBaseName(name);
diff --git a/gnu/llvm/lld/ELF/InputSection.cpp b/gnu/llvm/lld/ELF/InputSection.cpp
index 9e341a6ae67..7d952e9037f 100644
--- a/gnu/llvm/lld/ELF/InputSection.cpp
+++ b/gnu/llvm/lld/ELF/InputSection.cpp
@@ -28,6 +28,7 @@
#include <algorithm>
#include <mutex>
#include <set>
+#include <unordered_set>
#include <vector>
using namespace llvm;
@@ -52,7 +53,7 @@ static ArrayRef<uint8_t> getSectionContents(ObjFile<ELFT> &file,
const typename ELFT::Shdr &hdr) {
if (hdr.sh_type == SHT_NOBITS)
return makeArrayRef<uint8_t>(nullptr, hdr.sh_size);
- return check(file.getObj().getSectionContents(&hdr));
+ return check(file.getObj().getSectionContents(hdr));
}
InputSectionBase::InputSectionBase(InputFile *file, uint64_t flags,
@@ -87,7 +88,22 @@ InputSectionBase::InputSectionBase(InputFile *file, uint64_t flags,
if (!zlib::isAvailable())
error(toString(file) + ": contains a compressed section, " +
"but zlib is not available");
- parseCompressedHeader();
+ switch (config->ekind) {
+ case ELF32LEKind:
+ parseCompressedHeader<ELF32LE>();
+ break;
+ case ELF32BEKind:
+ parseCompressedHeader<ELF32BE>();
+ break;
+ case ELF64LEKind:
+ parseCompressedHeader<ELF64LE>();
+ break;
+ case ELF64BEKind:
+ parseCompressedHeader<ELF64BE>();
+ break;
+ default:
+ llvm_unreachable("unknown ELFT");
+ }
}
}
@@ -209,10 +225,7 @@ OutputSection *SectionBase::getOutputSection() {
// When a section is compressed, `rawData` consists with a header followed
// by zlib-compressed data. This function parses a header to initialize
// `uncompressedSize` member and remove the header from `rawData`.
-void InputSectionBase::parseCompressedHeader() {
- using Chdr64 = typename ELF64LE::Chdr;
- using Chdr32 = typename ELF32LE::Chdr;
-
+template <typename ELFT> void InputSectionBase::parseCompressedHeader() {
// Old-style header
if (name.startswith(".zdebug")) {
if (!toStringRef(rawData).startswith("ZLIB")) {
@@ -238,32 +251,13 @@ void InputSectionBase::parseCompressedHeader() {
assert(flags & SHF_COMPRESSED);
flags &= ~(uint64_t)SHF_COMPRESSED;
- // New-style 64-bit header
- if (config->is64) {
- if (rawData.size() < sizeof(Chdr64)) {
- error(toString(this) + ": corrupted compressed section");
- return;
- }
-
- auto *hdr = reinterpret_cast<const Chdr64 *>(rawData.data());
- if (hdr->ch_type != ELFCOMPRESS_ZLIB) {
- error(toString(this) + ": unsupported compression type");
- return;
- }
-
- uncompressedSize = hdr->ch_size;
- alignment = std::max<uint32_t>(hdr->ch_addralign, 1);
- rawData = rawData.slice(sizeof(*hdr));
- return;
- }
-
- // New-style 32-bit header
- if (rawData.size() < sizeof(Chdr32)) {
+ // New-style header
+ if (rawData.size() < sizeof(typename ELFT::Chdr)) {
error(toString(this) + ": corrupted compressed section");
return;
}
- auto *hdr = reinterpret_cast<const Chdr32 *>(rawData.data());
+ auto *hdr = reinterpret_cast<const typename ELFT::Chdr *>(rawData.data());
if (hdr->ch_type != ELFCOMPRESS_ZLIB) {
error(toString(this) + ": unsupported compression type");
return;
@@ -275,8 +269,9 @@ void InputSectionBase::parseCompressedHeader() {
}
InputSection *InputSectionBase::getLinkOrderDep() const {
- assert(link);
assert(flags & SHF_LINK_ORDER);
+ if (!link)
+ return nullptr;
return cast<InputSection>(file->getSections()[link]);
}
@@ -389,11 +384,16 @@ template <class ELFT> void InputSection::copyShtGroup(uint8_t *buf) {
// The first entry is not a section number but a flag.
*to++ = from[0];
- // Adjust section numbers because section numbers in an input object
- // files are different in the output.
+ // Adjust section numbers because section numbers in an input object files are
+ // different in the output. We also need to handle combined or discarded
+ // members.
ArrayRef<InputSectionBase *> sections = file->getSections();
- for (uint32_t idx : from.slice(1))
- *to++ = sections[idx]->getOutputSection()->sectionIndex;
+ std::unordered_set<uint32_t> seen;
+ for (uint32_t idx : from.slice(1)) {
+ OutputSection *osec = sections[idx]->getOutputSection();
+ if (osec && seen.insert(osec->sectionIndex).second)
+ *to++ = osec->sectionIndex;
+ }
}
InputSectionBase *InputSection::getRelocatedSection() const {
@@ -449,7 +449,7 @@ void InputSection::copyRelocations(uint8_t *buf, ArrayRef<RelTy> rels) {
Elf_Shdr_Impl<ELFT> sec =
CHECK(file->getObj().sections(), file)[secIdx];
warn("relocation refers to a discarded section: " +
- CHECK(file->getObj().getSectionName(&sec), file) +
+ CHECK(file->getObj().getSectionName(sec), file) +
"\n>>> referenced by " + getObjMsg(p->r_offset));
}
p->setSymbolAndType(0, 0, false);
@@ -540,8 +540,7 @@ static uint32_t getARMUndefinedRelativeWeakVA(RelType type, uint32_t a,
}
// The comment above getARMUndefinedRelativeWeakVA applies to this function.
-static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t type, uint64_t a,
- uint64_t p) {
+static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t type, uint64_t p) {
switch (type) {
// Unresolved branch relocations to weak references resolve to next
// instruction, this is 4 bytes on from P.
@@ -549,7 +548,7 @@ static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t type, uint64_t a,
case R_AARCH64_CONDBR19:
case R_AARCH64_JUMP26:
case R_AARCH64_TSTBR14:
- return p + 4 + a;
+ return p + 4;
// Unresolved non branch pc-relative relocations
case R_AARCH64_PREL16:
case R_AARCH64_PREL32:
@@ -557,11 +556,25 @@ static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t type, uint64_t a,
case R_AARCH64_ADR_PREL_LO21:
case R_AARCH64_LD_PREL_LO19:
case R_AARCH64_PLT32:
- return p + a;
+ return p;
}
llvm_unreachable("AArch64 pc-relative relocation expected\n");
}
+static uint64_t getRISCVUndefinedRelativeWeakVA(uint64_t type, uint64_t p) {
+ switch (type) {
+ case R_RISCV_BRANCH:
+ case R_RISCV_JAL:
+ case R_RISCV_CALL:
+ case R_RISCV_CALL_PLT:
+ case R_RISCV_RVC_BRANCH:
+ case R_RISCV_RVC_JUMP:
+ return p;
+ default:
+ return 0;
+ }
+}
+
// ARM SBREL relocations are of the form S + A - B where B is the static base
// The ARM ABI defines base to be "addressing origin of the output segment
// defining the symbol S". We defined the "addressing origin"/static base to be
@@ -698,6 +711,8 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
case R_AARCH64_GOT_PAGE_PC:
case R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC:
return getAArch64Page(sym.getGotVA() + a) - getAArch64Page(p);
+ case R_AARCH64_GOT_PAGE:
+ return sym.getGotVA() + a - getAArch64Page(in.got->getVA());
case R_GOT_PC:
case R_RELAX_TLS_GD_TO_IE:
return sym.getGotVA() + a - p;
@@ -756,14 +771,18 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
// Some PC relative ARM (Thumb) relocations align down the place.
p = p & 0xfffffffc;
if (sym.isUndefWeak()) {
- // On ARM and AArch64 a branch to an undefined weak resolves to the
- // next instruction, otherwise the place.
+ // On ARM and AArch64 a branch to an undefined weak resolves to the next
+ // instruction, otherwise the place. On RISCV, resolve an undefined weak
+ // to the same instruction to cause an infinite loop (making the user
+ // aware of the issue) while ensuring no overflow.
if (config->emachine == EM_ARM)
dest = getARMUndefinedRelativeWeakVA(type, a, p);
else if (config->emachine == EM_AARCH64)
- dest = getAArch64UndefinedRelativeWeakVA(type, a, p);
+ dest = getAArch64UndefinedRelativeWeakVA(type, p) + a;
else if (config->emachine == EM_PPC)
dest = p;
+ else if (config->emachine == EM_RISCV)
+ dest = getRISCVUndefinedRelativeWeakVA(type, p) + a;
else
dest = sym.getVA(a);
} else {
@@ -800,11 +819,12 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
case R_PPC64_TOCBASE:
return getPPC64TocBase() + a;
case R_RELAX_GOT_PC:
+ case R_PPC64_RELAX_GOT_PC:
return sym.getVA(a) - p;
case R_RELAX_TLS_GD_TO_LE:
case R_RELAX_TLS_IE_TO_LE:
case R_RELAX_TLS_LD_TO_LE:
- case R_TLS:
+ case R_TPREL:
// It is not very clear what to return if the symbol is undefined. With
// --noinhibit-exec, even a non-weak undefined reference may reach here.
// Just return A, which matches R_ABS, and the behavior of some dynamic
@@ -813,7 +833,7 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
return a;
return getTlsTpOffset(sym) + a;
case R_RELAX_TLS_GD_TO_LE_NEG:
- case R_NEG_TLS:
+ case R_TPREL_NEG:
if (sym.isUndefined())
return a;
return -getTlsTpOffset(sym) + a;
@@ -829,7 +849,7 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
case R_TLSGD_GOT:
return in.got->getGlobalDynOffset(sym) + a;
case R_TLSGD_GOTPLT:
- return in.got->getVA() + in.got->getGlobalDynOffset(sym) + a - in.gotPlt->getVA();
+ return in.got->getGlobalDynAddr(sym) + a - in.gotPlt->getVA();
case R_TLSGD_PC:
return in.got->getGlobalDynAddr(sym) + a - p;
case R_TLSLD_GOTPLT:
@@ -874,7 +894,7 @@ void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef<RelTy> rels) {
if (config->emachine == EM_386 && type == R_386_GOTPC)
continue;
- uint64_t offset = getOffset(rel.r_offset);
+ uint64_t offset = rel.r_offset;
uint8_t *bufLoc = buf + offset;
int64_t addend = getAddend<ELFT>(rel);
if (!RelTy::IsRela)
@@ -911,8 +931,9 @@ void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef<RelTy> rels) {
// address 0. For bug-compatibilty, we accept them with warnings. We
// know Steel Bank Common Lisp as of 2018 have this bug.
warn(msg);
- target->relocateNoSym(bufLoc, type,
- SignExtend64<bits>(sym.getVA(addend - offset)));
+ target->relocateNoSym(
+ bufLoc, type,
+ SignExtend64<bits>(sym.getVA(addend - offset - outSecOff)));
continue;
}
@@ -971,7 +992,7 @@ static void relocateNonAllocForRelocatable(InputSection *sec, uint8_t *buf) {
for (const Relocation &rel : sec->relocations) {
// InputSection::copyRelocations() adds only R_ABS relocations.
assert(rel.expr == R_ABS);
- uint8_t *bufLoc = buf + rel.offset + sec->outSecOff;
+ uint8_t *bufLoc = buf + rel.offset;
uint64_t targetVA = SignExtend64(rel.sym->getVA(rel.addend), bits);
target->relocate(bufLoc, rel, targetVA);
}
@@ -999,17 +1020,18 @@ void InputSectionBase::relocate(uint8_t *buf, uint8_t *bufEnd) {
void InputSectionBase::relocateAlloc(uint8_t *buf, uint8_t *bufEnd) {
assert(flags & SHF_ALLOC);
const unsigned bits = config->wordsize * 8;
+ uint64_t lastPPCRelaxedRelocOff = UINT64_C(-1);
for (const Relocation &rel : relocations) {
if (rel.expr == R_NONE)
continue;
uint64_t offset = rel.offset;
- if (auto *sec = dyn_cast<InputSection>(this))
- offset += sec->outSecOff;
uint8_t *bufLoc = buf + offset;
RelType type = rel.type;
uint64_t addrLoc = getOutputSection()->addr + offset;
+ if (auto *sec = dyn_cast<InputSection>(this))
+ addrLoc += sec->outSecOff;
RelExpr expr = rel.expr;
uint64_t targetVA = SignExtend64(
getRelocTargetVA(file, type, rel.addend, addrLoc, *rel.sym, expr),
@@ -1020,6 +1042,20 @@ void InputSectionBase::relocateAlloc(uint8_t *buf, uint8_t *bufEnd) {
case R_RELAX_GOT_PC_NOPIC:
target->relaxGot(bufLoc, rel, targetVA);
break;
+ case R_PPC64_RELAX_GOT_PC: {
+ // The R_PPC64_PCREL_OPT relocation must appear immediately after
+ // R_PPC64_GOT_PCREL34 in the relocations table at the same offset.
+ // We can only relax R_PPC64_PCREL_OPT if we have also relaxed
+ // the associated R_PPC64_GOT_PCREL34 since only the latter has an
+ // associated symbol. So save the offset when relaxing R_PPC64_GOT_PCREL34
+ // and only relax the other if the saved offset matches.
+ if (type == R_PPC64_GOT_PCREL34)
+ lastPPCRelaxedRelocOff = offset;
+ if (type == R_PPC64_PCREL_OPT && offset != lastPPCRelaxedRelocOff)
+ break;
+ target->relaxGot(bufLoc, rel, targetVA);
+ break;
+ }
case R_PPC64_RELAX_TOC:
// rel.sym refers to the STT_SECTION symbol associated to the .toc input
// section. If an R_PPC64_TOC16_LO (.toc + addend) references the TOC
@@ -1083,9 +1119,9 @@ void InputSectionBase::relocateAlloc(uint8_t *buf, uint8_t *bufEnd) {
// a jmp insn must be modified to shrink the jmp insn or to flip the jmp
// insn. This is primarily used to relax and optimize jumps created with
// basic block sections.
- if (auto *sec = dyn_cast<InputSection>(this)) {
+ if (isa<InputSection>(this)) {
for (const JumpInstrMod &jumpMod : jumpInstrMods) {
- uint64_t offset = jumpMod.offset + sec->outSecOff;
+ uint64_t offset = jumpMod.offset;
uint8_t *bufLoc = buf + offset;
target->applyJumpInstrMod(bufLoc, jumpMod.original, jumpMod.size);
}
@@ -1183,8 +1219,8 @@ void InputSectionBase::adjustSplitStackFunctionPrologues(uint8_t *buf,
if (Defined *f = getEnclosingFunction<ELFT>(rel.offset)) {
prologues.insert(f);
- if (target->adjustPrologueForCrossSplitStack(buf + getOffset(f->value),
- end, f->stOther))
+ if (target->adjustPrologueForCrossSplitStack(buf + f->value, end,
+ f->stOther))
continue;
if (!getFile<ELFT>()->someNoSplitStack)
error(lld::toString(this) + ": " + f->getName() +
@@ -1232,7 +1268,7 @@ template <class ELFT> void InputSection::writeTo(uint8_t *buf) {
fatal(toString(this) +
": uncompress failed: " + llvm::toString(std::move(e)));
uint8_t *bufEnd = buf + outSecOff + size;
- relocate<ELFT>(buf, bufEnd);
+ relocate<ELFT>(buf + outSecOff, bufEnd);
return;
}
@@ -1240,7 +1276,7 @@ template <class ELFT> void InputSection::writeTo(uint8_t *buf) {
// and then apply relocations.
memcpy(buf + outSecOff, data().data(), data().size());
uint8_t *bufEnd = buf + outSecOff + data().size();
- relocate<ELFT>(buf, bufEnd);
+ relocate<ELFT>(buf + outSecOff, bufEnd);
}
void InputSection::replace(InputSection *other) {
@@ -1300,6 +1336,11 @@ template <class ELFT> void EhInputSection::split() {
template <class ELFT, class RelTy>
void EhInputSection::split(ArrayRef<RelTy> rels) {
+ // getReloc expects the relocations to be sorted by r_offset. See the comment
+ // in scanRelocs.
+ SmallVector<RelTy, 0> storage;
+ rels = sortRels(rels, storage);
+
unsigned relI = 0;
for (size_t off = 0, end = data().size(); off != end;) {
size_t size = readEhRecordSize(this, off);
@@ -1403,8 +1444,7 @@ SectionPiece *MergeInputSection::getSectionPiece(uint64_t offset) {
uint64_t MergeInputSection::getParentOffset(uint64_t offset) const {
// If Offset is not at beginning of a section piece, it is not in the map.
// In that case we need to search from the original section piece vector.
- const SectionPiece &piece =
- *(const_cast<MergeInputSection *>(this)->getSectionPiece (offset));
+ const SectionPiece &piece = *getSectionPiece(offset);
uint64_t addend = offset - piece.inputOff;
return piece.outputOff + addend;
}
diff --git a/gnu/llvm/lld/ELF/LinkerScript.cpp b/gnu/llvm/lld/ELF/LinkerScript.cpp
index 032cd4b6f02..d362cfc0919 100644
--- a/gnu/llvm/lld/ELF/LinkerScript.cpp
+++ b/gnu/llvm/lld/ELF/LinkerScript.cpp
@@ -30,6 +30,7 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Parallel.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/TimeProfiler.h"
#include <algorithm>
#include <cassert>
#include <cstddef>
@@ -250,26 +251,34 @@ getChangedSymbolAssignment(const SymbolAssignmentMap &oldValues) {
// Process INSERT [AFTER|BEFORE] commands. For each command, we move the
// specified output section to the designated place.
void LinkerScript::processInsertCommands() {
+ std::vector<OutputSection *> moves;
for (const InsertCommand &cmd : insertCommands) {
- // If cmd.os is empty, it may have been discarded by
- // adjustSectionsBeforeSorting(). We do not handle such output sections.
- auto from = llvm::find(sectionCommands, cmd.os);
- if (from == sectionCommands.end())
- continue;
- sectionCommands.erase(from);
+ for (StringRef name : cmd.names) {
+ // If base is empty, it may have been discarded by
+ // adjustSectionsBeforeSorting(). We do not handle such output sections.
+ auto from = llvm::find_if(sectionCommands, [&](BaseCommand *base) {
+ return isa<OutputSection>(base) &&
+ cast<OutputSection>(base)->name == name;
+ });
+ if (from == sectionCommands.end())
+ continue;
+ moves.push_back(cast<OutputSection>(*from));
+ sectionCommands.erase(from);
+ }
auto insertPos = llvm::find_if(sectionCommands, [&cmd](BaseCommand *base) {
auto *to = dyn_cast<OutputSection>(base);
return to != nullptr && to->name == cmd.where;
});
if (insertPos == sectionCommands.end()) {
- error("unable to insert " + cmd.os->name +
+ error("unable to insert " + cmd.names[0] +
(cmd.isAfter ? " after " : " before ") + cmd.where);
} else {
if (cmd.isAfter)
++insertPos;
- sectionCommands.insert(insertPos, cmd.os);
+ sectionCommands.insert(insertPos, moves.begin(), moves.end());
}
+ moves.clear();
}
}
@@ -320,20 +329,33 @@ void LinkerScript::assignSymbol(SymbolAssignment *cmd, bool inSec) {
cmd->sym->type = v.type;
}
-static std::string getFilename(InputFile *file) {
- if (!file)
- return "";
- if (file->archiveName.empty())
- return std::string(file->getName());
- return (file->archiveName + ':' + file->getName()).str();
+static inline StringRef getFilename(const InputFile *file) {
+ return file ? file->getNameForScript() : StringRef();
}
-bool LinkerScript::shouldKeep(InputSectionBase *s) {
- if (keptSections.empty())
+bool InputSectionDescription::matchesFile(const InputFile *file) const {
+ if (filePat.isTrivialMatchAll())
+ return true;
+
+ if (!matchesFileCache || matchesFileCache->first != file)
+ matchesFileCache.emplace(file, filePat.match(getFilename(file)));
+
+ return matchesFileCache->second;
+}
+
+bool SectionPattern::excludesFile(const InputFile *file) const {
+ if (excludedFilePat.empty())
return false;
- std::string filename = getFilename(s->file);
+
+ if (!excludesFileCache || excludesFileCache->first != file)
+ excludesFileCache.emplace(file, excludedFilePat.match(getFilename(file)));
+
+ return excludesFileCache->second;
+}
+
+bool LinkerScript::shouldKeep(InputSectionBase *s) {
for (InputSectionDescription *id : keptSections)
- if (id->filePat.match(filename))
+ if (id->matchesFile(s->file))
for (SectionPattern &p : id->sectionPatterns)
if (p.sectionPat.match(s->name) &&
(s->flags & id->withFlags) == id->withFlags &&
@@ -395,15 +417,16 @@ static void sortSections(MutableArrayRef<InputSectionBase *> vec,
// 3. If one SORT command is given, and if it is SORT_NONE, don't sort.
// 4. If no SORT command is given, sort according to --sort-section.
static void sortInputSections(MutableArrayRef<InputSectionBase *> vec,
- const SectionPattern &pat) {
- if (pat.sortOuter == SortSectionPolicy::None)
+ SortSectionPolicy outer,
+ SortSectionPolicy inner) {
+ if (outer == SortSectionPolicy::None)
return;
- if (pat.sortInner == SortSectionPolicy::Default)
+ if (inner == SortSectionPolicy::Default)
sortSections(vec, config->sortSection);
else
- sortSections(vec, pat.sortInner);
- sortSections(vec, pat.sortOuter);
+ sortSections(vec, inner);
+ sortSections(vec, outer);
}
// Compute and remember which sections the InputSectionDescription matches.
@@ -411,13 +434,27 @@ std::vector<InputSectionBase *>
LinkerScript::computeInputSections(const InputSectionDescription *cmd,
ArrayRef<InputSectionBase *> sections) {
std::vector<InputSectionBase *> ret;
+ std::vector<size_t> indexes;
+ DenseSet<size_t> seen;
+ auto sortByPositionThenCommandLine = [&](size_t begin, size_t end) {
+ llvm::sort(MutableArrayRef<size_t>(indexes).slice(begin, end - begin));
+ for (size_t i = begin; i != end; ++i)
+ ret[i] = sections[indexes[i]];
+ sortInputSections(
+ MutableArrayRef<InputSectionBase *>(ret).slice(begin, end - begin),
+ config->sortSection, SortSectionPolicy::None);
+ };
// Collects all sections that satisfy constraints of Cmd.
+ size_t sizeAfterPrevSort = 0;
for (const SectionPattern &pat : cmd->sectionPatterns) {
- size_t sizeBefore = ret.size();
+ size_t sizeBeforeCurrPat = ret.size();
- for (InputSectionBase *sec : sections) {
- if (!sec->isLive() || sec->parent)
+ for (size_t i = 0, e = sections.size(); i != e; ++i) {
+ // Skip if the section is dead or has been matched by a previous input
+ // section description or a previous pattern.
+ InputSectionBase *sec = sections[i];
+ if (!sec->isLive() || sec->parent || seen.contains(i))
continue;
// For -emit-relocs we have to ignore entries like
@@ -433,19 +470,37 @@ LinkerScript::computeInputSections(const InputSectionDescription *cmd,
if (!pat.sectionPat.match(sec->name))
continue;
- std::string filename = getFilename(sec->file);
- if (!cmd->filePat.match(filename) ||
- pat.excludedFilePat.match(filename) ||
+ if (!cmd->matchesFile(sec->file) || pat.excludesFile(sec->file) ||
(sec->flags & cmd->withFlags) != cmd->withFlags ||
(sec->flags & cmd->withoutFlags) != 0)
continue;
ret.push_back(sec);
+ indexes.push_back(i);
+ seen.insert(i);
}
+ if (pat.sortOuter == SortSectionPolicy::Default)
+ continue;
+
+ // Matched sections are ordered by radix sort with the keys being (SORT*,
+ // --sort-section, input order), where SORT* (if present) is most
+ // significant.
+ //
+ // Matched sections between the previous SORT* and this SORT* are sorted by
+ // (--sort-alignment, input order).
+ sortByPositionThenCommandLine(sizeAfterPrevSort, sizeBeforeCurrPat);
+ // Matched sections by this SORT* pattern are sorted using all 3 keys.
+ // ret[sizeBeforeCurrPat,ret.size()) are already in the input order, so we
+ // just sort by sortOuter and sortInner.
sortInputSections(
- MutableArrayRef<InputSectionBase *>(ret).slice(sizeBefore), pat);
+ MutableArrayRef<InputSectionBase *>(ret).slice(sizeBeforeCurrPat),
+ pat.sortOuter, pat.sortInner);
+ sizeAfterPrevSort = ret.size();
}
+ // Matched sections after the last SORT* are sorted by (--sort-alignment,
+ // input order).
+ sortByPositionThenCommandLine(sizeAfterPrevSort, ret.size());
return ret;
}
@@ -500,52 +555,73 @@ LinkerScript::createInputSectionList(OutputSection &outCmd) {
// Create output sections described by SECTIONS commands.
void LinkerScript::processSectionCommands() {
- size_t i = 0;
- for (BaseCommand *base : sectionCommands) {
- if (auto *sec = dyn_cast<OutputSection>(base)) {
- std::vector<InputSectionBase *> v = createInputSectionList(*sec);
-
- // The output section name `/DISCARD/' is special.
- // Any input section assigned to it is discarded.
- if (sec->name == "/DISCARD/") {
- for (InputSectionBase *s : v)
- discard(s);
- discardSynthetic(*sec);
- sec->sectionCommands.clear();
- continue;
- }
+ auto process = [this](OutputSection *osec) {
+ std::vector<InputSectionBase *> v = createInputSectionList(*osec);
+
+ // The output section name `/DISCARD/' is special.
+ // Any input section assigned to it is discarded.
+ if (osec->name == "/DISCARD/") {
+ for (InputSectionBase *s : v)
+ discard(s);
+ discardSynthetic(*osec);
+ osec->sectionCommands.clear();
+ return false;
+ }
- // This is for ONLY_IF_RO and ONLY_IF_RW. An output section directive
- // ".foo : ONLY_IF_R[OW] { ... }" is handled only if all member input
- // sections satisfy a given constraint. If not, a directive is handled
- // as if it wasn't present from the beginning.
- //
- // Because we'll iterate over SectionCommands many more times, the easy
- // way to "make it as if it wasn't present" is to make it empty.
- if (!matchConstraints(v, sec->constraint)) {
- for (InputSectionBase *s : v)
- s->parent = nullptr;
- sec->sectionCommands.clear();
- continue;
- }
+ // This is for ONLY_IF_RO and ONLY_IF_RW. An output section directive
+ // ".foo : ONLY_IF_R[OW] { ... }" is handled only if all member input
+ // sections satisfy a given constraint. If not, a directive is handled
+ // as if it wasn't present from the beginning.
+ //
+ // Because we'll iterate over SectionCommands many more times, the easy
+ // way to "make it as if it wasn't present" is to make it empty.
+ if (!matchConstraints(v, osec->constraint)) {
+ for (InputSectionBase *s : v)
+ s->parent = nullptr;
+ osec->sectionCommands.clear();
+ return false;
+ }
- // Handle subalign (e.g. ".foo : SUBALIGN(32) { ... }"). If subalign
- // is given, input sections are aligned to that value, whether the
- // given value is larger or smaller than the original section alignment.
- if (sec->subalignExpr) {
- uint32_t subalign = sec->subalignExpr().getValue();
- for (InputSectionBase *s : v)
- s->alignment = subalign;
- }
+ // Handle subalign (e.g. ".foo : SUBALIGN(32) { ... }"). If subalign
+ // is given, input sections are aligned to that value, whether the
+ // given value is larger or smaller than the original section alignment.
+ if (osec->subalignExpr) {
+ uint32_t subalign = osec->subalignExpr().getValue();
+ for (InputSectionBase *s : v)
+ s->alignment = subalign;
+ }
- // Set the partition field the same way OutputSection::recordSection()
- // does. Partitions cannot be used with the SECTIONS command, so this is
- // always 1.
- sec->partition = 1;
+ // Set the partition field the same way OutputSection::recordSection()
+ // does. Partitions cannot be used with the SECTIONS command, so this is
+ // always 1.
+ osec->partition = 1;
+ return true;
+ };
- sec->sectionIndex = i++;
+ // Process OVERWRITE_SECTIONS first so that it can overwrite the main script
+ // or orphans.
+ DenseMap<StringRef, OutputSection *> map;
+ size_t i = 0;
+ for (OutputSection *osec : overwriteSections)
+ if (process(osec) && !map.try_emplace(osec->name, osec).second)
+ warn("OVERWRITE_SECTIONS specifies duplicate " + osec->name);
+ for (BaseCommand *&base : sectionCommands)
+ if (auto *osec = dyn_cast<OutputSection>(base)) {
+ if (OutputSection *overwrite = map.lookup(osec->name)) {
+ log(overwrite->location + " overwrites " + osec->name);
+ overwrite->sectionIndex = i++;
+ base = overwrite;
+ } else if (process(osec)) {
+ osec->sectionIndex = i++;
+ }
}
- }
+
+ // If an OVERWRITE_SECTIONS specified output section is not in
+ // sectionCommands, append it to the end. The section will be inserted by
+ // orphan placement.
+ for (OutputSection *osec : overwriteSections)
+ if (osec->partition == 1 && osec->sectionIndex == UINT32_MAX)
+ sectionCommands.push_back(osec);
}
void LinkerScript::processSymbolAssignments() {
@@ -725,7 +801,7 @@ void LinkerScript::addOrphanSections() {
add(depSec);
};
- // For futher --emit-reloc handling code we need target output section
+ // For further --emit-reloc handling code we need target output section
// to be created before we create relocation output section, so we want
// to create target sections first. We do not want priority handling
// for synthetic sections because them are special.
@@ -754,6 +830,9 @@ void LinkerScript::addOrphanSections() {
}
void LinkerScript::diagnoseOrphanHandling() const {
+ llvm::TimeTraceScope timeScope("Diagnose orphan sections");
+ if (config->orphanHandling == OrphanHandlingPolicy::Place)
+ return;
for (const InputSectionBase *sec : orphanSections) {
// Input SHT_REL[A] retained by --emit-relocs are ignored by
// computeInputSections(). Don't warn/error.
@@ -764,23 +843,14 @@ void LinkerScript::diagnoseOrphanHandling() const {
StringRef name = getOutputSectionName(sec);
if (config->orphanHandling == OrphanHandlingPolicy::Error)
error(toString(sec) + " is being placed in '" + name + "'");
- else if (config->orphanHandling == OrphanHandlingPolicy::Warn)
+ else
warn(toString(sec) + " is being placed in '" + name + "'");
}
}
uint64_t LinkerScript::advance(uint64_t size, unsigned alignment) {
- bool isTbss =
- (ctx->outSec->flags & SHF_TLS) && ctx->outSec->type == SHT_NOBITS;
- uint64_t start = isTbss ? dot + ctx->threadBssOffset : dot;
- start = alignTo(start, alignment);
- uint64_t end = start + size;
-
- if (isTbss)
- ctx->threadBssOffset = end - dot;
- else
- dot = end;
- return end;
+ dot = alignTo(dot, alignment) + size;
+ return dot;
}
void LinkerScript::output(InputSection *s) {
@@ -852,26 +922,37 @@ static OutputSection *findFirstSection(PhdrEntry *load) {
// This function assigns offsets to input sections and an output section
// for a single sections command (e.g. ".text { *(.text); }").
void LinkerScript::assignOffsets(OutputSection *sec) {
- if (!(sec->flags & SHF_ALLOC))
- dot = 0;
-
+ const bool isTbss = (sec->flags & SHF_TLS) && sec->type == SHT_NOBITS;
const bool sameMemRegion = ctx->memRegion == sec->memRegion;
const bool prevLMARegionIsDefault = ctx->lmaRegion == nullptr;
+ const uint64_t savedDot = dot;
ctx->memRegion = sec->memRegion;
ctx->lmaRegion = sec->lmaRegion;
- if (ctx->memRegion)
- dot = ctx->memRegion->curPos;
- if ((sec->flags & SHF_ALLOC) && sec->addrExpr)
- setDot(sec->addrExpr, sec->location, false);
-
- // If the address of the section has been moved forward by an explicit
- // expression so that it now starts past the current curPos of the enclosing
- // region, we need to expand the current region to account for the space
- // between the previous section, if any, and the start of this section.
- if (ctx->memRegion && ctx->memRegion->curPos < dot)
- expandMemoryRegion(ctx->memRegion, dot - ctx->memRegion->curPos,
- ctx->memRegion->name, sec->name);
+ if (!(sec->flags & SHF_ALLOC)) {
+ // Non-SHF_ALLOC sections have zero addresses.
+ dot = 0;
+ } else if (isTbss) {
+ // Allow consecutive SHF_TLS SHT_NOBITS output sections. The address range
+ // starts from the end address of the previous tbss section.
+ if (ctx->tbssAddr == 0)
+ ctx->tbssAddr = dot;
+ else
+ dot = ctx->tbssAddr;
+ } else {
+ if (ctx->memRegion)
+ dot = ctx->memRegion->curPos;
+ if (sec->addrExpr)
+ setDot(sec->addrExpr, sec->location, false);
+
+ // If the address of the section has been moved forward by an explicit
+ // expression so that it now starts past the current curPos of the enclosing
+ // region, we need to expand the current region to account for the space
+ // between the previous section, if any, and the start of this section.
+ if (ctx->memRegion && ctx->memRegion->curPos < dot)
+ expandMemoryRegion(ctx->memRegion, dot - ctx->memRegion->curPos,
+ ctx->memRegion->name, sec->name);
+ }
// ctx->lmaOffset is LMA minus VMA. If LMA is explicitly specified via AT() or
@@ -924,17 +1005,22 @@ void LinkerScript::assignOffsets(OutputSection *sec) {
for (InputSection *sec : cast<InputSectionDescription>(base)->sections)
output(sec);
}
+
+ // Non-SHF_ALLOC sections do not affect the addresses of other OutputSections
+ // as they are not part of the process image.
+ if (!(sec->flags & SHF_ALLOC)) {
+ dot = savedDot;
+ } else if (isTbss) {
+ // NOBITS TLS sections are similar. Additionally save the end address.
+ ctx->tbssAddr = dot;
+ dot = savedDot;
+ }
}
static bool isDiscardable(OutputSection &sec) {
if (sec.name == "/DISCARD/")
return true;
- // We do not remove empty sections that are explicitly
- // assigned to any segment.
- if (!sec.phdrs.empty())
- return false;
-
// We do not want to remove OutputSections with expressions that reference
// symbols even if the OutputSection is empty. We want to ensure that the
// expressions can be evaluated and report an error if they cannot.
@@ -960,6 +1046,18 @@ static bool isDiscardable(OutputSection &sec) {
return true;
}
+static void maybePropagatePhdrs(OutputSection &sec,
+ std::vector<StringRef> &phdrs) {
+ if (sec.phdrs.empty()) {
+ // To match the bfd linker script behaviour, only propagate program
+ // headers to sections that are allocated.
+ if (sec.flags & SHF_ALLOC)
+ sec.phdrs = phdrs;
+ } else {
+ phdrs = sec.phdrs;
+ }
+}
+
void LinkerScript::adjustSectionsBeforeSorting() {
// If the output section contains only symbol assignments, create a
// corresponding output section. The issue is what to do with linker script
@@ -983,6 +1081,7 @@ void LinkerScript::adjustSectionsBeforeSorting() {
// the previous sections. Only a few flags are needed to keep the impact low.
uint64_t flags = SHF_ALLOC;
+ std::vector<StringRef> defPhdrs;
for (BaseCommand *&cmd : sectionCommands) {
auto *sec = dyn_cast<OutputSection>(cmd);
if (!sec)
@@ -1005,6 +1104,18 @@ void LinkerScript::adjustSectionsBeforeSorting() {
sec->flags = flags & ((sec->nonAlloc ? 0 : (uint64_t)SHF_ALLOC) |
SHF_WRITE | SHF_EXECINSTR);
+ // The code below may remove empty output sections. We should save the
+ // specified program headers (if exist) and propagate them to subsequent
+ // sections which do not specify program headers.
+ // An example of such a linker script is:
+ // SECTIONS { .empty : { *(.empty) } :rw
+ // .foo : { *(.foo) } }
+ // Note: at this point the order of output sections has not been finalized,
+ // because orphans have not been inserted into their expected positions. We
+ // will handle them in adjustSectionsAfterSorting().
+ if (sec->sectionIndex != UINT32_MAX)
+ maybePropagatePhdrs(*sec, defPhdrs);
+
if (isEmpty && isDiscardable(*sec)) {
sec->markDead();
cmd = nullptr;
@@ -1049,20 +1160,9 @@ void LinkerScript::adjustSectionsAfterSorting() {
// Walk the commands and propagate the program headers to commands that don't
// explicitly specify them.
- for (BaseCommand *base : sectionCommands) {
- auto *sec = dyn_cast<OutputSection>(base);
- if (!sec)
- continue;
-
- if (sec->phdrs.empty()) {
- // To match the bfd linker script behaviour, only propagate program
- // headers to sections that are allocated.
- if (sec->flags & SHF_ALLOC)
- sec->phdrs = defPhdrs;
- } else {
- defPhdrs = sec->phdrs;
- }
- }
+ for (BaseCommand *base : sectionCommands)
+ if (auto *sec = dyn_cast<OutputSection>(base))
+ maybePropagatePhdrs(*sec, defPhdrs);
}
static uint64_t computeBase(uint64_t min, bool allocateHeaders) {
diff --git a/gnu/llvm/lld/ELF/Options.td b/gnu/llvm/lld/ELF/Options.td
index 470e92ab7aa..b13e0c50cc3 100644
--- a/gnu/llvm/lld/ELF/Options.td
+++ b/gnu/llvm/lld/ELF/Options.td
@@ -36,10 +36,15 @@ multiclass B<string name, string help1, string help2> {
defm auxiliary: Eq<"auxiliary", "Set DT_AUXILIARY field to the specified name">;
-def Bsymbolic: F<"Bsymbolic">, HelpText<"Bind defined symbols locally">;
+def Bno_symbolic: F<"Bno-symbolic">, HelpText<"Don't bind default visibility defined symbols locally for -shared (default)">;
+
+def Bsymbolic: F<"Bsymbolic">, HelpText<"Bind default visibility defined symbols locally for -shared">;
def Bsymbolic_functions: F<"Bsymbolic-functions">,
- HelpText<"Bind defined function symbols locally">;
+ HelpText<"Bind default visibility defined function symbols locally for -shared">;
+
+def Bsymbolic_non_weak_functions: F<"Bsymbolic-non-weak-functions">,
+ HelpText<"Bind default visibility defined STB_GLOBAL function symbols locally for -shared">;
def Bdynamic: F<"Bdynamic">, HelpText<"Link against shared libraries (default)">;
@@ -64,6 +69,10 @@ defm optimize_bb_jumps: BB<"optimize-bb-jumps",
"Remove direct jumps at the end to the next basic block",
"Do not remove any direct jumps at the end to the next basic block (default)">;
+defm fortran_common : BB<"fortran-common",
+ "Search archive members for definitions to override COMMON symbols (default)",
+ "Do not search archive members for definitions to override COMMON symbols">;
+
defm split_stack_adjust_size
: Eq<"split-stack-adjust-size",
"Specify adjustment to stack size when a split-stack function calls a "
@@ -113,16 +122,14 @@ defm call_graph_profile_sort: BB<"call-graph-profile-sort",
// -chroot doesn't have a help text because it is an internal option.
def chroot: Separate<["--", "-"], "chroot">;
-def color_diagnostics: F<"color-diagnostics">,
- HelpText<"Alias for --color-diagnostics=always">;
-
+defm color_diagnostics: B<"color-diagnostics",
+ "Alias for --color-diagnostics=always",
+ "Alias for --color-diagnostics=never">;
def color_diagnostics_eq: J<"color-diagnostics=">,
- HelpText<"Use colors in diagnostics">,
+ HelpText<"Use colors in diagnostics (default: auto)">,
MetaVarName<"[auto,always,never]">;
-defm cref: B<"cref",
- "Output cross reference table",
- "Do not output cross reference table">;
+def cref: FF<"cref">, HelpText<"Output cross reference table">;
defm define_common: B<"define-common",
"Assign space to common symbols",
@@ -132,6 +139,9 @@ defm demangle: B<"demangle",
"Demangle symbol names (default)",
"Do not demangle symbol names">;
+defm dependency_file: EEq<"dependency-file", "Write a dependency file">,
+ MetaVarName<"<file>">;
+
def disable_new_dtags: F<"disable-new-dtags">,
HelpText<"Disable new dynamic tags">;
@@ -152,6 +162,9 @@ defm dynamic_list : Eq<"dynamic-list",
"shared object. Implies -Bsymbolic but does not set DF_SYMBOLIC">,
MetaVarName<"<file>">;
+def eb: F<"EB">, HelpText<"Select the big-endian format in OUTPUT_FORMAT">;
+def el: F<"EL">, HelpText<"Select the little-endian format in OUTPUT_FORMAT">;
+
defm eh_frame_hdr: B<"eh-frame-hdr",
"Request creation of .eh_frame_hdr section and PT_GNU_EH_FRAME segment header",
"Do not create .eh_frame_hdr section">;
@@ -176,6 +189,9 @@ defm error_limit:
def error_unresolved_symbols: F<"error-unresolved-symbols">,
HelpText<"Report unresolved symbols as errors">;
+defm error_handling_script: EEq<"error-handling-script",
+ "Specify an error handling script">;
+
defm exclude_libs: Eq<"exclude-libs", "Exclude static libraries from automatic export">;
defm execute_only: BB<"execute-only",
@@ -269,9 +285,6 @@ def nmagic: F<"nmagic">, MetaVarName<"<magic>">,
def nostdlib: F<"nostdlib">,
HelpText<"Only search directories specified on the command line">;
-def no_color_diagnostics: F<"no-color-diagnostics">,
- HelpText<"Do not use colors in diagnostics">;
-
def no_dynamic_linker: F<"no-dynamic-linker">,
HelpText<"Inhibit output of .interp section">;
@@ -338,7 +351,9 @@ def push_state: F<"push-state">,
def print_map: F<"print-map">,
HelpText<"Print a link map to the standard output">;
-defm reproduce: Eq<"reproduce", "Write a tar file containing input files and command line options to reproduce link">;
+defm reproduce:
+ Eq<"reproduce",
+ "Write tar file containing inputs and command to reproduce link">;
defm rosegment: BB<"rosegment",
"Put read-only non-executable sections in their own segment (default)",
@@ -370,7 +385,7 @@ def start_group: F<"start-group">,
def start_lib: F<"start-lib">,
HelpText<"Start a grouping of objects that should be treated as if they were together in an archive">;
-def strip_all: F<"strip-all">, HelpText<"Strip all symbols">;
+def strip_all: F<"strip-all">, HelpText<"Strip all symbols. Implies --strip-debug">;
def strip_debug: F<"strip-debug">, HelpText<"Strip debugging information">;
@@ -392,16 +407,20 @@ defm threads
"Number of threads. '1' disables multi-threading. By default all "
"available hardware threads are used">;
-def time_trace: F<"time-trace">, HelpText<"Record time trace">;
-def time_trace_file_eq: J<"time-trace-file=">, HelpText<"Specify time trace output file">;
+def time_trace: FF<"time-trace">, HelpText<"Record time trace">;
+def time_trace_file_eq: JJ<"time-trace-file=">, HelpText<"Specify time trace output file">;
-defm time_trace_granularity: Eq<"time-trace-granularity",
+defm time_trace_granularity: EEq<"time-trace-granularity",
"Minimum time granularity (in microseconds) traced by time profiler">;
-defm toc_optimize : B<"toc-optimize",
+defm toc_optimize : BB<"toc-optimize",
"(PowerPC64) Enable TOC related optimizations (default)",
"(PowerPC64) Disable TOC related optimizations">;
+defm pcrel_optimize : BB<"pcrel-optimize",
+ "(PowerPC64) Enable PC-relative optimizations (default)",
+ "(PowerPC64) Disable PC-relative optimizations">;
+
def trace: F<"trace">, HelpText<"Print the names of the input files">;
defm trace_symbol: Eq<"trace-symbol", "Trace references to symbols">;
@@ -409,7 +428,7 @@ defm trace_symbol: Eq<"trace-symbol", "Trace references to symbols">;
defm undefined: Eq<"undefined", "Force undefined symbol during linking">,
MetaVarName<"<symbol>">;
-defm undefined_glob: Eq<"undefined-glob", "Force undefined symbol during linking">,
+defm undefined_glob: EEq<"undefined-glob", "Force undefined symbol during linking">,
MetaVarName<"<pattern>">;
def unique: F<"unique">, HelpText<"Creates a separate output section for every orphan input section">;
@@ -430,6 +449,17 @@ def verbose: F<"verbose">, HelpText<"Verbose mode">;
def version: F<"version">, HelpText<"Display the version number and exit">;
+def power10_stubs: F<"power10-stubs">, HelpText<"Alias for --power10-stubs=auto">;
+
+def no_power10_stubs: F<"no-power10-stubs">, HelpText<"Alias for --power10-stubs=no">;
+
+def power10_stubs_eq:
+ J<"power10-stubs=">, HelpText<
+ "Enables Power10 instructions in all stubs without options, "
+ "options override previous flags."
+ "auto: Allow Power10 instructions in stubs if applicable."
+ "no: No Power10 instructions in stubs.">;
+
defm version_script: Eq<"version-script", "Read a version script">;
defm warn_backrefs: BB<"warn-backrefs",
@@ -461,8 +491,9 @@ defm whole_archive: B<"whole-archive",
"Force load of all members in a static library",
"Do not force load of all members in a static library (default)">;
-defm wrap: Eq<"wrap", "Use wrapper functions for symbol">,
- MetaVarName<"<symbol>=<symbol>">;
+defm wrap : Eq<"wrap", "Redirect symbol references to __wrap_symbol and "
+ "__real_symbol references to symbol">,
+ MetaVarName<"<symbol>">;
def z: JoinedOrSeparate<["-"], "z">, MetaVarName<"<option>">,
HelpText<"Linker option extensions">;
@@ -519,8 +550,9 @@ def lto_debug_pass_manager: FF<"lto-debug-pass-manager">,
HelpText<"Debug new pass manager">;
def lto_emit_asm: FF<"lto-emit-asm">,
HelpText<"Emit assembly code">;
-def lto_new_pass_manager: FF<"lto-new-pass-manager">,
- HelpText<"Use new pass manager">;
+defm lto_legacy_pass_manager: BB<"lto-legacy-pass-manager",
+ "Use the legacy pass manager in LLVM",
+ "Use the new pass manager in LLVM">;
def lto_newpm_passes: JJ<"lto-newpm-passes=">,
HelpText<"Passes to run during LTO">;
def lto_O: JJ<"lto-O">, MetaVarName<"<opt-level>">,
@@ -534,26 +566,35 @@ def lto_cs_profile_file: JJ<"lto-cs-profile-file=">,
def lto_obj_path_eq: JJ<"lto-obj-path=">;
def lto_sample_profile: JJ<"lto-sample-profile=">,
HelpText<"Sample profile file path">;
-def lto_whole_program_visibility: FF<"lto-whole-program-visibility">,
- HelpText<"Asserts that the LTO link has whole program visibility">;
+defm lto_whole_program_visibility: BB<"lto-whole-program-visibility",
+ "Asserts that the LTO link has whole program visibility",
+ "Asserts that the LTO link does not have whole program visibility">;
+def lto_pseudo_probe_for_profiling: F<"lto-pseudo-probe-for-profiling">,
+ HelpText<"Emit pseudo probes for sample profiling">;
def disable_verify: F<"disable-verify">;
defm mllvm: Eq<"mllvm", "Additional arguments to forward to LLVM's option processing">;
def opt_remarks_filename: Separate<["--"], "opt-remarks-filename">,
HelpText<"YAML output file for optimization remarks">;
+defm opt_remarks_hotness_threshold: EEq<"opt-remarks-hotness-threshold",
+ "Minimum profile count required for an optimization remark to be output."
+ " Use 'auto' to apply the threshold from profile summary.">,
+ MetaVarName<"<value>">;
def opt_remarks_passes: Separate<["--"], "opt-remarks-passes">,
HelpText<"Regex for the passes that need to be serialized to the output file">;
def opt_remarks_with_hotness: FF<"opt-remarks-with-hotness">,
HelpText<"Include hotness information in the optimization remarks file">;
def opt_remarks_format: Separate<["--"], "opt-remarks-format">,
HelpText<"The format used for serializing remarks (default: YAML)">;
-def save_temps: F<"save-temps">;
-def lto_basicblock_sections: JJ<"lto-basicblock-sections=">,
+def save_temps: F<"save-temps">, HelpText<"Save intermediate LTO compilation results">;
+def lto_basic_block_sections: JJ<"lto-basic-block-sections=">,
HelpText<"Enable basic block sections for LTO">;
-defm lto_unique_bb_section_names: BB<"lto-unique-bb-section-names",
+defm lto_unique_basic_block_section_names: BB<"lto-unique-basic-block-section-names",
"Give unique names to every basic block section for LTO",
"Do not give unique names to every basic block section for LTO (default)">;
-def shuffle_sections: JJ<"shuffle-sections=">, MetaVarName<"<seed>">,
- HelpText<"Shuffle input sections using the given seed. If 0, use a random seed">;
+defm shuffle_sections: EEq<"shuffle-sections",
+ "Shuffle matched sections using the given seed before mapping them to the output sections. "
+ "If -1, reverse the section order. If 0, use a random seed">,
+ MetaVarName<"<section-glob>=<seed>">;
def thinlto_cache_dir: JJ<"thinlto-cache-dir=">,
HelpText<"Path to ThinLTO cached object file directory">;
defm thinlto_cache_policy: EEq<"thinlto-cache-policy", "Pruning policy for the ThinLTO cache">;
@@ -580,7 +621,9 @@ def: J<"plugin-opt=jobs=">, Alias<thinlto_jobs>, HelpText<"Alias for --thinlto-j
def: J<"plugin-opt=lto-partitions=">, Alias<lto_partitions>, HelpText<"Alias for --lto-partitions">;
def plugin_opt_mcpu_eq: J<"plugin-opt=mcpu=">;
def: F<"plugin-opt=new-pass-manager">,
- Alias<lto_new_pass_manager>, HelpText<"Alias for --lto-new-pass-manager">;
+ Alias<no_lto_legacy_pass_manager>, HelpText<"Alias for --no-lto-legacy-pass-manager">;
+def: F<"plugin-opt=legacy-pass-manager">,
+ Alias<lto_legacy_pass_manager>, HelpText<"Alias for --no-legacy-pass-manager">;
def: F<"plugin-opt=cs-profile-generate">,
Alias<lto_cs_profile_generate>, HelpText<"Alias for --lto-cs-profile-generate">;
def: J<"plugin-opt=cs-profile-path=">,
@@ -588,6 +631,23 @@ def: J<"plugin-opt=cs-profile-path=">,
def: J<"plugin-opt=obj-path=">,
Alias<lto_obj_path_eq>,
HelpText<"Alias for --lto-obj-path=">;
+def: J<"plugin-opt=opt-remarks-filename=">,
+ Alias<opt_remarks_filename>,
+ HelpText<"Alias for --opt-remarks-filename">;
+def: J<"plugin-opt=opt-remarks-passes=">,
+ Alias<opt_remarks_passes>,
+ HelpText<"Alias for --opt-remarks-passes">;
+def: J<"plugin-opt=opt-remarks-format=">,
+ Alias<opt_remarks_format>,
+ HelpText<"Alias for --opt-remarks-format">;
+def: F<"plugin-opt=opt-remarks-with-hotness">,
+ Alias<opt_remarks_with_hotness>,
+ HelpText<"Alias for --opt-remarks-with_hotness">;
+def: J<"plugin-opt=opt-remarks-hotness-threshold=">,
+ Alias<opt_remarks_hotness_threshold>,
+ HelpText<"Alias for --opt-remarks-hotness-threshold">;
+def: J<"plugin-opt=pseudo-probe-for-profiling">,
+ Alias<lto_pseudo_probe_for_profiling>, HelpText<"Alias for --lto-pseudo-probe-for-profiling">;
def: J<"plugin-opt=sample-profile=">,
Alias<lto_sample_profile>, HelpText<"Alias for --lto-sample-profile">;
def: F<"plugin-opt=save-temps">, Alias<save_temps>, HelpText<"Alias for --save-temps">;
@@ -648,8 +708,6 @@ def: F<"stats">;
def: F<"warn-execstack">;
def: F<"warn-once">;
def: F<"warn-shared-textrel">;
-def: F<"EB">;
-def: F<"EL">;
def: JoinedOrSeparate<["-"], "G">;
def: F<"Qy">;
@@ -657,3 +715,9 @@ def: F<"Qy">;
defm mips_got_size:
Eq<"mips-got-size", "Max size of a single MIPS GOT. 0x10000 by default.">,
Flags<[HelpHidden]>;
+
+// Hidden option used to opt-in to additional output checks.
+defm check_dynamic_relocations: BB<"check-dynamic-relocations",
+ "Perform additional validation of the written dynamic relocations",
+ "Do not perform additional validation of the written dynamic relocations">,
+ Flags<[HelpHidden]>;
diff --git a/gnu/llvm/lld/ELF/Relocations.cpp b/gnu/llvm/lld/ELF/Relocations.cpp
index 751ded39776..bf576752c54 100644
--- a/gnu/llvm/lld/ELF/Relocations.cpp
+++ b/gnu/llvm/lld/ELF/Relocations.cpp
@@ -74,12 +74,12 @@ static Optional<std::string> getLinkerScriptLocation(const Symbol &sym) {
}
static std::string getDefinedLocation(const Symbol &sym) {
- std::string msg = "\n>>> defined in ";
+ const char msg[] = "\n>>> defined in ";
if (sym.file)
- msg += toString(sym.file);
- else if (Optional<std::string> loc = getLinkerScriptLocation(sym))
- msg += *loc;
- return msg;
+ return msg + toString(sym.file);
+ if (Optional<std::string> loc = getLinkerScriptLocation(sym))
+ return msg + *loc;
+ return "";
}
// Construct a message in the following format.
@@ -113,6 +113,17 @@ void elf::reportRangeError(uint8_t *loc, const Relocation &rel, const Twine &v,
", " + Twine(max).str() + "]" + hint);
}
+void elf::reportRangeError(uint8_t *loc, int64_t v, int n, const Symbol &sym,
+ const Twine &msg) {
+ ErrorPlace errPlace = getErrorPlace(loc);
+ std::string hint;
+ if (!sym.getName().empty())
+ hint = "; references " + lld::toString(sym) + getDefinedLocation(sym);
+ errorOrWarn(errPlace.loc + msg + " is out of range: " + Twine(v) +
+ " is not in [" + Twine(llvm::minIntN(n)) + ", " +
+ Twine(llvm::maxIntN(n)) + "]" + hint);
+}
+
namespace {
// Build a bitmask with one bit set for each RelExpr.
//
@@ -189,17 +200,21 @@ handleTlsRelocation(RelType type, Symbol &sym, InputSectionBase &c,
config->shared) {
if (in.got->addDynTlsEntry(sym)) {
uint64_t off = in.got->getGlobalDynOffset(sym);
- mainPart->relaDyn->addReloc(
- {target->tlsDescRel, in.got, off, !sym.isPreemptible, &sym, 0});
+ mainPart->relaDyn->addAddendOnlyRelocIfNonPreemptible(
+ target->tlsDescRel, in.got, off, sym, target->tlsDescRel);
}
if (expr != R_TLSDESC_CALL)
c.relocations.push_back({expr, type, offset, addend, &sym});
return 1;
}
+ // ARM, Hexagon and RISC-V do not support GD/LD to IE/LE relaxation. For
+ // PPC64, if the file has missing R_PPC64_TLSGD/R_PPC64_TLSLD, disable
+ // relaxation as well.
bool toExecRelax = !config->shared && config->emachine != EM_ARM &&
config->emachine != EM_HEXAGON &&
- config->emachine != EM_RISCV;
+ config->emachine != EM_RISCV &&
+ !c.file->ppc64DisableTLSRelax;
// If we are producing an executable and the symbol is non-preemptable, it
// must be defined and the code sequence can be relaxed to use Local-Exec.
@@ -219,8 +234,8 @@ handleTlsRelocation(RelType type, Symbol &sym, InputSectionBase &c,
// Local-Dynamic relocs can be relaxed to Local-Exec.
if (toExecRelax) {
c.relocations.push_back(
- {target->adjustRelaxExpr(type, nullptr, R_RELAX_TLS_LD_TO_LE), type,
- offset, addend, &sym});
+ {target->adjustTlsExpr(type, R_RELAX_TLS_LD_TO_LE), type, offset,
+ addend, &sym});
return target->getTlsGdRelaxSkip(type);
}
if (expr == R_TLSLD_HINT)
@@ -230,8 +245,8 @@ handleTlsRelocation(RelType type, Symbol &sym, InputSectionBase &c,
in.got->relocations.push_back(
{R_ADDEND, target->symbolicRel, in.got->getTlsIndexOff(), 1, &sym});
else
- mainPart->relaDyn->addReloc(target->tlsModuleIndexRel, in.got,
- in.got->getTlsIndexOff(), nullptr);
+ mainPart->relaDyn->addReloc(
+ {target->tlsModuleIndexRel, in.got, in.got->getTlsIndexOff()});
}
c.relocations.push_back({expr, type, offset, addend, &sym});
return 1;
@@ -239,9 +254,8 @@ handleTlsRelocation(RelType type, Symbol &sym, InputSectionBase &c,
// Local-Dynamic relocs can be relaxed to Local-Exec.
if (expr == R_DTPREL && toExecRelax) {
- c.relocations.push_back(
- {target->adjustRelaxExpr(type, nullptr, R_RELAX_TLS_LD_TO_LE), type,
- offset, addend, &sym});
+ c.relocations.push_back({target->adjustTlsExpr(type, R_RELAX_TLS_LD_TO_LE),
+ type, offset, addend, &sym});
return 1;
}
@@ -269,14 +283,15 @@ handleTlsRelocation(RelType type, Symbol &sym, InputSectionBase &c,
in.got->relocations.push_back(
{R_ADDEND, target->symbolicRel, off, 1, &sym});
else
- mainPart->relaDyn->addReloc(target->tlsModuleIndexRel, in.got, off, &sym);
+ mainPart->relaDyn->addSymbolReloc(target->tlsModuleIndexRel, in.got,
+ off, sym);
// If the symbol is preemptible we need the dynamic linker to write
// the offset too.
uint64_t offsetOff = off + config->wordsize;
if (sym.isPreemptible)
- mainPart->relaDyn->addReloc(target->tlsOffsetRel, in.got, offsetOff,
- &sym);
+ mainPart->relaDyn->addSymbolReloc(target->tlsOffsetRel, in.got,
+ offsetOff, sym);
else
in.got->relocations.push_back(
{R_ABS, target->tlsOffsetRel, offsetOff, 0, &sym});
@@ -289,17 +304,17 @@ handleTlsRelocation(RelType type, Symbol &sym, InputSectionBase &c,
// depending on the symbol being locally defined or not.
if (sym.isPreemptible) {
c.relocations.push_back(
- {target->adjustRelaxExpr(type, nullptr, R_RELAX_TLS_GD_TO_IE), type,
- offset, addend, &sym});
+ {target->adjustTlsExpr(type, R_RELAX_TLS_GD_TO_IE), type, offset,
+ addend, &sym});
if (!sym.isInGot()) {
in.got->addEntry(sym);
- mainPart->relaDyn->addReloc(target->tlsGotRel, in.got, sym.getGotOffset(),
- &sym);
+ mainPart->relaDyn->addSymbolReloc(target->tlsGotRel, in.got,
+ sym.getGotOffset(), sym);
}
} else {
c.relocations.push_back(
- {target->adjustRelaxExpr(type, nullptr, R_RELAX_TLS_GD_TO_LE), type,
- offset, addend, &sym});
+ {target->adjustTlsExpr(type, R_RELAX_TLS_GD_TO_LE), type, offset,
+ addend, &sym});
}
return target->getTlsGdRelaxSkip(type);
}
@@ -367,8 +382,8 @@ static bool needsPlt(RelExpr expr) {
// TLS variables uses GOT differently than the regular variables.
static bool needsGot(RelExpr expr) {
return oneof<R_GOT, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE, R_MIPS_GOT_OFF,
- R_MIPS_GOT_OFF32, R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTPLT>(
- expr);
+ R_MIPS_GOT_OFF32, R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTPLT,
+ R_AARCH64_GOT_PAGE>(expr);
}
// True if this expression is of the form Sym - X, where X is a position in the
@@ -376,7 +391,7 @@ static bool needsGot(RelExpr expr) {
static bool isRelExpr(RelExpr expr) {
return oneof<R_PC, R_GOTREL, R_GOTPLTREL, R_MIPS_GOTREL, R_PPC64_CALL,
R_PPC64_RELAX_TOC, R_AARCH64_PAGE_PC, R_RELAX_GOT_PC,
- R_RISCV_PC_INDIRECT>(expr);
+ R_RISCV_PC_INDIRECT, R_PPC64_RELAX_GOT_PC>(expr);
}
// Returns true if a given relocation can be computed at link-time.
@@ -397,7 +412,8 @@ static bool isStaticLinkTimeConstant(RelExpr e, RelType type, const Symbol &sym,
R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC, R_GOTPLTONLY_PC,
R_PLT_PC, R_TLSGD_GOT, R_TLSGD_GOTPLT, R_TLSGD_PC, R_PPC32_PLTREL,
R_PPC64_CALL_PLT, R_PPC64_RELAX_TOC, R_RISCV_ADD, R_TLSDESC_CALL,
- R_TLSDESC_PC, R_AARCH64_TLSDESC_PAGE, R_TLSLD_HINT, R_TLSIE_HINT>(
+ R_TLSDESC_PC, R_AARCH64_TLSDESC_PAGE, R_TLSLD_HINT, R_TLSIE_HINT,
+ R_AARCH64_GOT_PAGE>(
e))
return true;
@@ -511,6 +527,13 @@ static SmallSet<SharedSymbol *, 4> getSymbolsAt(SharedSymbol &ss) {
if (auto *alias = dyn_cast_or_null<SharedSymbol>(sym))
ret.insert(alias);
}
+
+ // The loop does not check SHT_GNU_verneed, so ret does not contain
+ // non-default version symbols. If ss has a non-default version, ret won't
+ // contain ss. Just add ss unconditionally. If a non-default version alias is
+ // separately copy relocated, it and ss will have different addresses.
+ // Fortunately this case is impractical and fails with GNU ld as well.
+ ret.insert(&ss);
return ret;
}
@@ -603,7 +626,7 @@ template <class ELFT> static void addCopyRelSymbol(SharedSymbol &ss) {
for (SharedSymbol *sym : getSymbolsAt<ELFT>(ss))
replaceWithDefined(*sym, sec, 0, sym->size);
- mainPart->relaDyn->addReloc(target->copyRel, sec, 0, &ss);
+ mainPart->relaDyn->addSymbolReloc(target->copyRel, sec, 0, ss);
}
// MIPS has an odd notion of "paired" relocations to calculate addends.
@@ -681,7 +704,7 @@ static std::string maybeReportDiscarded(Undefined &sym) {
if (sym.type == ELF::STT_SECTION) {
msg = "relocation refers to a discarded section: ";
msg += CHECK(
- file->getObj().getSectionName(&objSections[sym.discardedSecIdx]), file);
+ file->getObj().getSectionName(objSections[sym.discardedSecIdx]), file);
} else {
msg = "relocation refers to a symbol in a discarded section: " +
toString(sym);
@@ -748,7 +771,7 @@ static const Symbol *getAlternativeSpelling(const Undefined &sym,
// Build a map of local defined symbols.
for (const Symbol *s : sym.file->getSymbols())
- if (s->isLocal() && s->isDefined())
+ if (s->isLocal() && s->isDefined() && !s->getName().empty())
map.try_emplace(s->getName(), s);
}
@@ -805,10 +828,10 @@ static const Symbol *getAlternativeSpelling(const Undefined &sym,
// Case mismatch, e.g. Foo vs FOO.
for (auto &it : map)
- if (name.equals_lower(it.first))
+ if (name.equals_insensitive(it.first))
return it.second;
for (Symbol *sym : symtab->symbols())
- if (!sym->isUndefined() && name.equals_lower(sym->getName()))
+ if (!sym->isUndefined() && name.equals_insensitive(sym->getName()))
return sym;
// The reference may be a mangled name while the definition is not. Suggest a
@@ -908,7 +931,7 @@ static void reportUndefinedSymbol(const UndefinedDiag &undef,
if (undef.isWarning)
warn(msg);
else
- error(msg);
+ error(msg, ErrorTag::SymbolNotFound, {sym.getName()});
}
template <class ELFT> void elf::reportUndefinedSymbols() {
@@ -935,7 +958,15 @@ template <class ELFT> void elf::reportUndefinedSymbols() {
// Returns true if the undefined symbol will produce an error message.
static bool maybeReportUndefined(Symbol &sym, InputSectionBase &sec,
uint64_t offset) {
- if (!sym.isUndefined() || sym.isWeak())
+ if (!sym.isUndefined())
+ return false;
+ // If versioned, issue an error (even if the symbol is weak) because we don't
+ // know the defining filename which is required to construct a Verneed entry.
+ if (*sym.getVersionSuffix() == '@') {
+ undefs.push_back({&sym, {{&sec, offset}}, false});
+ return true;
+ }
+ if (sym.isWeak())
return false;
bool canBeExternal = !sym.isLocal() && sym.visibility == STV_DEFAULT;
@@ -1024,7 +1055,7 @@ private:
} // namespace
static void addRelativeReloc(InputSectionBase *isec, uint64_t offsetInSec,
- Symbol *sym, int64_t addend, RelExpr expr,
+ Symbol &sym, int64_t addend, RelExpr expr,
RelType type) {
Partition &part = isec->getPartition();
@@ -1035,12 +1066,12 @@ static void addRelativeReloc(InputSectionBase *isec, uint64_t offsetInSec,
// don't store the addend values, so we must write it to the relocated
// address.
if (part.relrDyn && isec->alignment >= 2 && offsetInSec % 2 == 0) {
- isec->relocations.push_back({expr, type, offsetInSec, addend, sym});
+ isec->relocations.push_back({expr, type, offsetInSec, addend, &sym});
part.relrDyn->relocs.push_back({isec, offsetInSec});
return;
}
- part.relaDyn->addReloc(target->relativeRel, isec, offsetInSec, sym, addend,
- expr, type);
+ part.relaDyn->addRelativeReloc(target->relativeRel, isec, offsetInSec, sym,
+ addend, type, expr);
}
template <class PltSection, class GotPltSection>
@@ -1048,14 +1079,16 @@ static void addPltEntry(PltSection *plt, GotPltSection *gotPlt,
RelocationBaseSection *rel, RelType type, Symbol &sym) {
plt->addEntry(sym);
gotPlt->addEntry(sym);
- rel->addReloc(
- {type, gotPlt, sym.getGotPltOffset(), !sym.isPreemptible, &sym, 0});
+ rel->addReloc({type, gotPlt, sym.getGotPltOffset(),
+ sym.isPreemptible ? DynamicReloc::AgainstSymbol
+ : DynamicReloc::AddendOnlyWithTargetVA,
+ sym, 0, R_ABS});
}
static void addGotEntry(Symbol &sym) {
in.got->addEntry(sym);
- RelExpr expr = sym.isTls() ? R_TLS : R_ABS;
+ RelExpr expr = sym.isTls() ? R_TPREL : R_ABS;
uint64_t off = sym.getGotOffset();
// If a GOT slot value can be calculated at link-time, which is now,
@@ -1074,13 +1107,13 @@ static void addGotEntry(Symbol &sym) {
// Otherwise, we emit a dynamic relocation to .rel[a].dyn so that
// the GOT slot will be fixed at load-time.
- if (!sym.isTls() && !sym.isPreemptible && config->isPic && !isAbsolute(sym)) {
- addRelativeReloc(in.got, off, &sym, 0, R_ABS, target->symbolicRel);
+ if (!sym.isTls() && !sym.isPreemptible && config->isPic) {
+ addRelativeReloc(in.got, off, sym, 0, R_ABS, target->symbolicRel);
return;
}
- mainPart->relaDyn->addReloc(
- sym.isTls() ? target->tlsGotRel : target->gotRel, in.got, off, &sym, 0,
- sym.isPreemptible ? R_ADDEND : R_ABS, target->symbolicRel);
+ mainPart->relaDyn->addAddendOnlyRelocIfNonPreemptible(
+ sym.isTls() ? target->tlsGotRel : target->gotRel, in.got, off, sym,
+ target->symbolicRel);
}
// Return true if we can define a symbol in the executable that
@@ -1124,11 +1157,18 @@ static void processRelocAux(InputSectionBase &sec, RelExpr expr, RelType type,
// relocation will be created, pass the control to relocateAlloc() or
// relocateNonAlloc() to resolve it.
//
- // The behavior of an undefined weak reference is implementation defined. If
- // the relocation is to a weak undef, and we are producing an executable, let
- // relocate{,Non}Alloc() resolve it.
+ // The behavior of an undefined weak reference is implementation defined. For
+ // non-link-time constants, we resolve relocations statically (let
+ // relocate{,Non}Alloc() resolve them) for -no-pie and try producing dynamic
+ // relocations for -pie and -shared.
+ //
+ // The general expectation of -no-pie static linking is that there is no
+ // dynamic relocation (except IRELATIVE). Emitting dynamic relocations for
+ // -shared matches the spirit of its -z undefs default. -pie has freedom on
+ // choices, and we choose dynamic relocations to be consistent with the
+ // handling of GOT-generating relocations.
if (isStaticLinkTimeConstant(expr, type, sym, sec, offset) ||
- (!config->shared && sym.isUndefWeak())) {
+ (!config->isPic && sym.isUndefWeak())) {
sec.relocations.push_back({expr, type, offset, addend, &sym});
return;
}
@@ -1137,13 +1177,13 @@ static void processRelocAux(InputSectionBase &sec, RelExpr expr, RelType type,
if (canWrite) {
RelType rel = target->getDynRel(type);
if (expr == R_GOT || (rel == target->symbolicRel && !sym.isPreemptible)) {
- addRelativeReloc(&sec, offset, &sym, addend, expr, type);
+ addRelativeReloc(&sec, offset, sym, addend, expr, type);
return;
} else if (rel != 0) {
if (config->emachine == EM_MIPS && rel == target->symbolicRel)
rel = target->relativeRel;
- sec.getPartition().relaDyn->addReloc(rel, &sec, offset, &sym, addend,
- R_ADDEND, type);
+ sec.getPartition().relaDyn->addSymbolReloc(rel, &sec, offset, sym, addend,
+ type);
// MIPS ABI turns using of GOT and dynamic relocations inside out.
// While regular ABI uses dynamic relocations to fill up GOT entries
@@ -1263,7 +1303,7 @@ static void processRelocAux(InputSectionBase &sec, RelExpr expr, RelType type,
template <class ELFT, class RelTy>
static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
- RelTy *end) {
+ RelTy *start, RelTy *end) {
const RelTy &rel = *i;
uint32_t symIndex = rel.getSymbol(config->isMips64EL);
Symbol &sym = sec.getFile<ELFT>()->getSymbol(symIndex);
@@ -1294,16 +1334,6 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
if (expr == R_NONE)
return;
- if (sym.isGnuIFunc() && !config->zText && config->warnIfuncTextrel) {
- warn("using ifunc symbols when text relocations are allowed may produce "
- "a binary that will segfault, if the object file is linked with "
- "old version of glibc (glibc 2.28 and earlier). If this applies to "
- "you, consider recompiling the object files without -fPIC and "
- "without -Wl,-z,notext option. Use -no-warn-ifunc-textrel to "
- "turn off this warning." +
- getLocation(sec, sym, offset));
- }
-
// Read an addend.
int64_t addend = computeAddend<ELFT>(rel, end, sec, expr, sym.isLocal());
@@ -1324,6 +1354,21 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
if (type == R_PPC64_TOC16_LO && sym.isSection() && isa<Defined>(sym) &&
cast<Defined>(sym).section->name == ".toc")
ppc64noTocRelax.insert({&sym, addend});
+
+ if ((type == R_PPC64_TLSGD && expr == R_TLSDESC_CALL) ||
+ (type == R_PPC64_TLSLD && expr == R_TLSLD_HINT)) {
+ if (i == end) {
+ errorOrWarn("R_PPC64_TLSGD/R_PPC64_TLSLD may not be the last "
+ "relocation" +
+ getLocation(sec, sym, offset));
+ return;
+ }
+
+ // Offset the 4-byte aligned R_PPC64_TLSGD by one byte in the NOTOC case,
+ // so we can discern it later from the toc-case.
+ if (i->getType(/*isMips64EL=*/false) == R_PPC64_REL24_NOTOC)
+ ++offset;
+ }
}
// Relax relocations.
@@ -1335,9 +1380,7 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
// runtime, because the main executable is always at the beginning of a search
// list. We can leverage that fact.
if (!sym.isPreemptible && (!sym.isGnuIFunc() || config->zIfuncNoplt)) {
- if (expr == R_GOT_PC && !isAbsoluteValue(sym)) {
- expr = target->adjustRelaxExpr(type, relocatedAddr, expr);
- } else {
+ if (expr != R_GOT_PC) {
// The 0x8000 bit of r_addend of R_PPC_PLTREL24 is used to choose call
// stub type. It should be ignored if optimized to R_PC.
if (config->emachine == EM_PPC && expr == R_PPC32_PLTREL)
@@ -1349,6 +1392,8 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
type == R_HEX_GD_PLT_B22_PCREL_X ||
type == R_HEX_GD_PLT_B32_PCREL_X)))
expr = fromPlt(expr);
+ } else if (!isAbsoluteValue(sym)) {
+ expr = target->adjustGotPcExpr(type, addend, relocatedAddr);
}
}
@@ -1358,15 +1403,22 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
// The 4 types that relative GOTPLT are all x86 and x86-64 specific.
if (oneof<R_GOTPLTONLY_PC, R_GOTPLTREL, R_GOTPLT, R_TLSGD_GOTPLT>(expr)) {
in.gotPlt->hasGotPltOffRel = true;
- } else if (oneof<R_GOTONLY_PC, R_GOTREL, R_PPC64_TOCBASE, R_PPC64_RELAX_TOC>(
- expr)) {
+ } else if (oneof<R_GOTONLY_PC, R_GOTREL, R_PPC32_PLTREL, R_PPC64_TOCBASE,
+ R_PPC64_RELAX_TOC>(expr)) {
in.got->hasGotOffRel = true;
}
- // Process some TLS relocations, including relaxing TLS relocations.
- // Note that this function does not handle all TLS relocations.
- if (unsigned processed =
- handleTlsRelocation<ELFT>(type, sym, sec, offset, addend, expr)) {
+ // Process TLS relocations, including relaxing TLS relocations. Note that
+ // R_TPREL and R_TPREL_NEG relocations are resolved in processRelocAux.
+ if (expr == R_TPREL || expr == R_TPREL_NEG) {
+ if (config->shared) {
+ errorOrWarn("relocation " + toString(type) + " against " + toString(sym) +
+ " cannot be used with -shared" +
+ getLocation(sec, sym, offset));
+ return;
+ }
+ } else if (unsigned processed = handleTlsRelocation<ELFT>(
+ type, sym, sec, offset, addend, expr)) {
i += (processed - 1);
return;
}
@@ -1375,7 +1427,7 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
// direct relocation on through.
if (sym.isGnuIFunc() && config->zIfuncNoplt) {
sym.exportDynamic = true;
- mainPart->relaDyn->addReloc(type, &sec, offset, &sym, addend, R_ADDEND, type);
+ mainPart->relaDyn->addSymbolReloc(type, &sec, offset, sym, addend, type);
return;
}
@@ -1494,6 +1546,43 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
processRelocAux<ELFT>(sec, expr, type, offset, sym, rel, addend);
}
+// R_PPC64_TLSGD/R_PPC64_TLSLD is required to mark `bl __tls_get_addr` for
+// General Dynamic/Local Dynamic code sequences. If a GD/LD GOT relocation is
+// found but no R_PPC64_TLSGD/R_PPC64_TLSLD is seen, we assume that the
+// instructions are generated by very old IBM XL compilers. Work around the
+// issue by disabling GD/LD to IE/LE relaxation.
+template <class RelTy>
+static void checkPPC64TLSRelax(InputSectionBase &sec, ArrayRef<RelTy> rels) {
+ // Skip if sec is synthetic (sec.file is null) or if sec has been marked.
+ if (!sec.file || sec.file->ppc64DisableTLSRelax)
+ return;
+ bool hasGDLD = false;
+ for (const RelTy &rel : rels) {
+ RelType type = rel.getType(false);
+ switch (type) {
+ case R_PPC64_TLSGD:
+ case R_PPC64_TLSLD:
+ return; // Found a marker
+ case R_PPC64_GOT_TLSGD16:
+ case R_PPC64_GOT_TLSGD16_HA:
+ case R_PPC64_GOT_TLSGD16_HI:
+ case R_PPC64_GOT_TLSGD16_LO:
+ case R_PPC64_GOT_TLSLD16:
+ case R_PPC64_GOT_TLSLD16_HA:
+ case R_PPC64_GOT_TLSLD16_HI:
+ case R_PPC64_GOT_TLSLD16_LO:
+ hasGDLD = true;
+ break;
+ }
+ }
+ if (hasGDLD) {
+ sec.file->ppc64DisableTLSRelax = true;
+ warn(toString(sec.file) +
+ ": disable TLS relaxation due to R_PPC64_GOT_TLS* relocations without "
+ "R_PPC64_TLSGD/R_PPC64_TLSLD relocations");
+ }
+}
+
template <class ELFT, class RelTy>
static void scanRelocs(InputSectionBase &sec, ArrayRef<RelTy> rels) {
OffsetGetter getOffset(sec);
@@ -1501,8 +1590,18 @@ static void scanRelocs(InputSectionBase &sec, ArrayRef<RelTy> rels) {
// Not all relocations end up in Sec.Relocations, but a lot do.
sec.relocations.reserve(rels.size());
+ if (config->emachine == EM_PPC64)
+ checkPPC64TLSRelax<RelTy>(sec, rels);
+
+ // For EhInputSection, OffsetGetter expects the relocations to be sorted by
+ // r_offset. In rare cases (.eh_frame pieces are reordered by a linker
+ // script), the relocations may be unordered.
+ SmallVector<RelTy, 0> storage;
+ if (isa<EhInputSection>(sec))
+ rels = sortRels(rels, storage);
+
for (auto i = rels.begin(), end = rels.end(); i != end;)
- scanReloc<ELFT>(sec, getOffset, i, end);
+ scanReloc<ELFT>(sec, getOffset, i, rels.begin(), end);
// Sort relocations by offset for more efficient searching for
// R_RISCV_PCREL_HI20 and R_PPC64_ADDR64.
@@ -1688,14 +1787,17 @@ void ThunkCreator::mergeThunks(ArrayRef<OutputSection *> outputSections) {
// Find or create a ThunkSection within the InputSectionDescription (ISD) that
// is in range of Src. An ISD maps to a range of InputSections described by a
// linker script section pattern such as { .text .text.* }.
-ThunkSection *ThunkCreator::getISDThunkSec(OutputSection *os, InputSection *isec,
+ThunkSection *ThunkCreator::getISDThunkSec(OutputSection *os,
+ InputSection *isec,
InputSectionDescription *isd,
- uint32_t type, uint64_t src) {
+ const Relocation &rel,
+ uint64_t src) {
for (std::pair<ThunkSection *, uint32_t> tp : isd->thunkSections) {
ThunkSection *ts = tp.first;
- uint64_t tsBase = os->addr + ts->outSecOff;
- uint64_t tsLimit = tsBase + ts->getSize();
- if (target->inBranchRange(type, src, (src > tsLimit) ? tsBase : tsLimit))
+ uint64_t tsBase = os->addr + ts->outSecOff + rel.addend;
+ uint64_t tsLimit = tsBase + ts->getSize() + rel.addend;
+ if (target->inBranchRange(rel.type, src,
+ (src > tsLimit) ? tsBase : tsLimit))
return ts;
}
@@ -1705,9 +1807,11 @@ ThunkSection *ThunkCreator::getISDThunkSec(OutputSection *os, InputSection *isec
// possible. Error if InputSection is so large we cannot place ThunkSection
// anywhere in Range.
uint64_t thunkSecOff = isec->outSecOff;
- if (!target->inBranchRange(type, src, os->addr + thunkSecOff)) {
+ if (!target->inBranchRange(rel.type, src,
+ os->addr + thunkSecOff + rel.addend)) {
thunkSecOff = isec->outSecOff + isec->getSize();
- if (!target->inBranchRange(type, src, os->addr + thunkSecOff))
+ if (!target->inBranchRange(rel.type, src,
+ os->addr + thunkSecOff + rel.addend))
fatal("InputSection too large for range extension thunk " +
isec->getObjMsg(src - (os->addr + isec->outSecOff)));
}
@@ -1858,7 +1962,11 @@ static int64_t getPCBias(RelType type) {
std::pair<Thunk *, bool> ThunkCreator::getThunk(InputSection *isec,
Relocation &rel, uint64_t src) {
std::vector<Thunk *> *thunkVec = nullptr;
- int64_t addend = rel.addend + getPCBias(rel.type);
+ // Arm and Thumb have a PC Bias of 8 and 4 respectively, this is cancelled
+ // out in the relocation addend. We compensate for the PC bias so that
+ // an Arm and Thumb relocation to the same destination get the same keyAddend,
+ // which is usually 0.
+ int64_t keyAddend = rel.addend + getPCBias(rel.type);
// We use a ((section, offset), addend) pair to find the thunk position if
// possible so that we create only one thunk for aliased symbols or ICFed
@@ -1868,17 +1976,16 @@ std::pair<Thunk *, bool> ThunkCreator::getThunk(InputSection *isec,
if (auto *d = dyn_cast<Defined>(rel.sym))
if (!d->isInPlt() && d->section)
thunkVec = &thunkedSymbolsBySectionAndAddend[{
- {d->section->repl, d->value}, addend}];
+ {d->section->repl, d->value}, keyAddend}];
if (!thunkVec)
- thunkVec = &thunkedSymbols[{rel.sym, addend}];
+ thunkVec = &thunkedSymbols[{rel.sym, keyAddend}];
// Check existing Thunks for Sym to see if they can be reused
for (Thunk *t : *thunkVec)
if (isThunkSectionCompatible(isec, t->getThunkTargetSym()->section) &&
t->isCompatibleWith(*isec, rel) &&
target->inBranchRange(rel.type, src,
- t->getThunkTargetSym()->getVA(rel.addend) +
- getPCBias(rel.type)))
+ t->getThunkTargetSym()->getVA(rel.addend)))
return std::make_pair(t, false);
// No existing compatible Thunk in range, create a new one
@@ -1893,8 +2000,7 @@ std::pair<Thunk *, bool> ThunkCreator::getThunk(InputSection *isec,
// relocation back to its original non-Thunk target.
bool ThunkCreator::normalizeExistingThunk(Relocation &rel, uint64_t src) {
if (Thunk *t = thunks.lookup(rel.sym)) {
- if (target->inBranchRange(rel.type, src,
- rel.sym->getVA(rel.addend) + getPCBias(rel.type)))
+ if (target->inBranchRange(rel.type, src, rel.sym->getVA(rel.addend)))
return true;
rel.sym = &t->destination;
rel.addend = t->addend;
@@ -1966,7 +2072,7 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> outputSections) {
if (auto *tis = t->getTargetInputSection())
ts = getISThunkSec(tis);
else
- ts = getISDThunkSec(os, isec, isd, rel.type, src);
+ ts = getISDThunkSec(os, isec, isd, rel, src);
ts->addThunk(t);
thunks[t->getThunkTargetSym()] = t;
}
diff --git a/gnu/llvm/lld/ELF/Symbols.cpp b/gnu/llvm/lld/ELF/Symbols.cpp
index 8371b3a389d..81385011736 100644
--- a/gnu/llvm/lld/ELF/Symbols.cpp
+++ b/gnu/llvm/lld/ELF/Symbols.cpp
@@ -37,11 +37,9 @@ std::string lld::toString(const elf::Symbol &sym) {
StringRef name = sym.getName();
std::string ret = demangle(name);
- // If sym has a non-default version, its name may have been truncated at '@'
- // by Symbol::parseSymbolVersion(). Add the trailing part. This check is safe
- // because every symbol name ends with '\0'.
- if (name.data()[name.size()] == '@')
- ret += name.data() + name.size();
+ const char *suffix = sym.getVersionSuffix();
+ if (*suffix == '@')
+ ret += suffix;
return ret;
}
@@ -65,7 +63,8 @@ Defined *ElfSym::relaIpltStart;
Defined *ElfSym::relaIpltEnd;
Defined *ElfSym::riscvGlobalPointer;
Defined *ElfSym::tlsModuleBase;
-DenseMap<const Symbol *, const InputFile *> elf::backwardReferences;
+DenseMap<const Symbol *, std::pair<const InputFile *, const InputFile *>>
+ elf::backwardReferences;
static uint64_t getSymVA(const Symbol &sym, int64_t &addend) {
switch (sym.kind()) {
@@ -162,7 +161,9 @@ uint64_t Symbol::getGotVA() const {
return in.got->getVA() + getGotOffset();
}
-uint64_t Symbol::getGotOffset() const { return gotIndex * config->wordsize; }
+uint64_t Symbol::getGotOffset() const {
+ return gotIndex * target->gotEntrySize;
+}
uint64_t Symbol::getGotPltVA() const {
if (isInIplt)
@@ -172,8 +173,8 @@ uint64_t Symbol::getGotPltVA() const {
uint64_t Symbol::getGotPltOffset() const {
if (isInIplt)
- return pltIndex * config->wordsize;
- return (pltIndex + target->gotPltHeaderEntriesNum) * config->wordsize;
+ return pltIndex * target->gotEntrySize;
+ return (pltIndex + target->gotPltHeaderEntriesNum) * target->gotEntrySize;
}
uint64_t Symbol::getPltVA() const {
@@ -208,6 +209,9 @@ OutputSection *Symbol::getOutputSection() const {
// If a symbol name contains '@', the characters after that is
// a symbol version name. This function parses that.
void Symbol::parseSymbolVersion() {
+ // Return if localized by a local: pattern in a version script.
+ if (versionId == VER_NDX_LOCAL)
+ return;
StringRef s = getName();
size_t pos = s.find('@');
if (pos == 0 || pos == StringRef::npos)
@@ -279,7 +283,7 @@ uint8_t Symbol::computeBinding() const {
if (config->relocatable)
return binding;
if ((visibility != STV_DEFAULT && visibility != STV_PROTECTED) ||
- (versionId == VER_NDX_LOCAL && isDefined()))
+ (versionId == VER_NDX_LOCAL && !isLazy()))
return STB_LOCAL;
if (!config->gnuUnique && binding == STB_GNU_UNIQUE)
return STB_GLOBAL;
@@ -368,8 +372,12 @@ bool elf::computeIsPreemptible(const Symbol &sym) {
// If -Bsymbolic or --dynamic-list is specified, or -Bsymbolic-functions is
// specified and the symbol is STT_FUNC, the symbol is preemptible iff it is
- // in the dynamic list.
- if (config->symbolic || (config->bsymbolicFunctions && sym.isFunc()))
+ // in the dynamic list. -Bsymbolic-non-weak-functions is a non-weak subset of
+ // -Bsymbolic-functions.
+ if (config->symbolic ||
+ (config->bsymbolic == BsymbolicKind::Functions && sym.isFunc()) ||
+ (config->bsymbolic == BsymbolicKind::NonWeakFunctions && sym.isFunc() &&
+ sym.binding != STB_WEAK))
return sym.inDynamicList;
return true;
}
@@ -377,8 +385,18 @@ bool elf::computeIsPreemptible(const Symbol &sym) {
void elf::reportBackrefs() {
for (auto &it : backwardReferences) {
const Symbol &sym = *it.first;
- warn("backward reference detected: " + sym.getName() + " in " +
- toString(it.second) + " refers to " + toString(sym.file));
+ std::string to = toString(it.second.second);
+ // Some libraries have known problems and can cause noise. Filter them out
+ // with --warn-backrefs-exclude=. to may look like *.o or *.a(*.o).
+ bool exclude = false;
+ for (const llvm::GlobPattern &pat : config->warnBackrefsExclude)
+ if (pat.match(to)) {
+ exclude = true;
+ break;
+ }
+ if (!exclude)
+ warn("backward reference detected: " + sym.getName() + " in " +
+ toString(it.second.first) + " refers to " + to);
}
}
@@ -514,17 +532,6 @@ void Symbol::resolveUndefined(const Undefined &other) {
// group assignment rule simulates the traditional linker's semantics.
bool backref = config->warnBackrefs && other.file &&
file->groupId < other.file->groupId;
- if (backref) {
- // Some libraries have known problems and can cause noise. Filter them out
- // with --warn-backrefs-exclude=.
- StringRef name =
- !file->archiveName.empty() ? file->archiveName : file->getName();
- for (const llvm::GlobPattern &pat : config->warnBackrefsExclude)
- if (pat.match(name)) {
- backref = false;
- break;
- }
- }
fetch();
// We don't report backward references to weak symbols as they can be
@@ -533,9 +540,10 @@ void Symbol::resolveUndefined(const Undefined &other) {
// A traditional linker does not error for -ldef1 -lref -ldef2 (linking
// sandwich), where def2 may or may not be the same as def1. We don't want
// to warn for this case, so dismiss the warning if we see a subsequent lazy
- // definition.
+ // definition. this->file needs to be saved because in the case of LTO it
+ // may be reset to nullptr or be replaced with a file named lto.tmp.
if (backref && !isWeak())
- backwardReferences.try_emplace(this, other.file);
+ backwardReferences.try_emplace(this, std::make_pair(other.file, file));
return;
}
@@ -691,7 +699,33 @@ void Symbol::resolveDefined(const Defined &other) {
other.value);
}
+template <class LazyT>
+static void replaceCommon(Symbol &oldSym, const LazyT &newSym) {
+ backwardReferences.erase(&oldSym);
+ oldSym.replace(newSym);
+ newSym.fetch();
+}
+
template <class LazyT> void Symbol::resolveLazy(const LazyT &other) {
+ // For common objects, we want to look for global or weak definitions that
+ // should be fetched as the canonical definition instead.
+ if (isCommon() && elf::config->fortranCommon) {
+ if (auto *laSym = dyn_cast<LazyArchive>(&other)) {
+ ArchiveFile *archive = cast<ArchiveFile>(laSym->file);
+ const Archive::Symbol &archiveSym = laSym->sym;
+ if (archive->shouldFetchForCommon(archiveSym)) {
+ replaceCommon(*this, other);
+ return;
+ }
+ } else if (auto *loSym = dyn_cast<LazyObject>(&other)) {
+ LazyObjFile *obj = cast<LazyObjFile>(loSym->file);
+ if (obj->shouldFetchForCommon(loSym->getName())) {
+ replaceCommon(*this, other);
+ return;
+ }
+ }
+ }
+
if (!isUndefined()) {
// See the comment in resolveUndefined().
if (isDefined())
diff --git a/gnu/llvm/lld/ELF/Symbols.h b/gnu/llvm/lld/ELF/Symbols.h
index 097b96a34f6..d4a589ee600 100644
--- a/gnu/llvm/lld/ELF/Symbols.h
+++ b/gnu/llvm/lld/ELF/Symbols.h
@@ -132,9 +132,11 @@ public:
// doesn't know the final contents of the symbol.
uint8_t canInline : 1;
- // Used by Undefined and SharedSymbol to track if there has been at least one
- // undefined reference to the symbol. The binding may change to STB_WEAK if
- // the first undefined reference from a non-shared object is weak.
+ // Used to track if there has been at least one undefined reference to the
+ // symbol. For Undefined and SharedSymbol, the binding may change to STB_WEAK
+ // if the first undefined reference from a non-shared object is weak.
+ //
+ // This is also used to retain __wrap_foo when foo is referenced.
uint8_t referenced : 1;
// True if this symbol is specified by --trace-symbol option.
@@ -178,6 +180,15 @@ public:
void parseSymbolVersion();
+ // Get the NUL-terminated version suffix ("", "@...", or "@@...").
+ //
+ // For @@, the name has been truncated by insert(). For @, the name has been
+ // truncated by Symbol::parseSymbolVersion().
+ const char *getVersionSuffix() const {
+ (void)getName();
+ return nameData + nameSize;
+ }
+
bool isInGot() const { return gotIndex != -1U; }
bool isInPlt() const { return pltIndex != -1U; }
@@ -212,13 +223,13 @@ public:
// non-lazy object causes a runtime error.
void fetch() const;
-private:
static bool isExportDynamic(Kind k, uint8_t visibility) {
if (k == SharedKind)
return visibility == llvm::ELF::STV_DEFAULT;
return config->shared || config->exportDynamic;
}
+private:
void resolveUndefined(const Undefined &other);
void resolveCommon(const CommonSymbol &other);
void resolveDefined(const Defined &other);
@@ -570,7 +581,9 @@ void reportBackrefs();
// A mapping from a symbol to an InputFile referencing it backward. Used by
// --warn-backrefs.
-extern llvm::DenseMap<const Symbol *, const InputFile *> backwardReferences;
+extern llvm::DenseMap<const Symbol *,
+ std::pair<const InputFile *, const InputFile *>>
+ backwardReferences;
} // namespace elf
} // namespace lld
diff --git a/gnu/llvm/lld/ELF/SyntheticSections.cpp b/gnu/llvm/lld/ELF/SyntheticSections.cpp
index 7f8bc16fbb8..187b2ac90c2 100644
--- a/gnu/llvm/lld/ELF/SyntheticSections.cpp
+++ b/gnu/llvm/lld/ELF/SyntheticSections.cpp
@@ -28,7 +28,6 @@
#include "lld/Common/Strings.h"
#include "lld/Common/Version.h"
#include "llvm/ADT/SetOperations.h"
-#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
@@ -371,10 +370,10 @@ CieRecord *EhFrameSection::addCie(EhSectionPiece &cie, ArrayRef<RelTy> rels) {
return rec;
}
-// There is one FDE per function. Returns true if a given FDE
-// points to a live function.
+// There is one FDE per function. Returns a non-null pointer to the function
+// symbol if the given FDE points to a live function.
template <class ELFT, class RelTy>
-bool EhFrameSection::isFdeLive(EhSectionPiece &fde, ArrayRef<RelTy> rels) {
+Defined *EhFrameSection::isFdeLive(EhSectionPiece &fde, ArrayRef<RelTy> rels) {
auto *sec = cast<EhInputSection>(fde.sec);
unsigned firstRelI = fde.firstRelocation;
@@ -384,7 +383,7 @@ bool EhFrameSection::isFdeLive(EhSectionPiece &fde, ArrayRef<RelTy> rels) {
// corresponding FDEs, which results in creating bad .eh_frame sections.
// To deal with that, we ignore such FDEs.
if (firstRelI == (unsigned)-1)
- return false;
+ return nullptr;
const RelTy &rel = rels[firstRelI];
Symbol &b = sec->template getFile<ELFT>()->getRelocTargetSym(rel);
@@ -392,9 +391,9 @@ bool EhFrameSection::isFdeLive(EhSectionPiece &fde, ArrayRef<RelTy> rels) {
// FDEs for garbage-collected or merged-by-ICF sections, or sections in
// another partition, are dead.
if (auto *d = dyn_cast<Defined>(&b))
- if (SectionBase *sec = d->section)
- return sec->partition == partition;
- return false;
+ if (d->section && d->section->partition == partition)
+ return d;
+ return nullptr;
}
// .eh_frame is a sequence of CIE or FDE records. In general, there
@@ -448,6 +447,51 @@ void EhFrameSection::addSection(EhInputSection *sec) {
dependentSections.push_back(ds);
}
+// Used by ICF<ELFT>::handleLSDA(). This function is very similar to
+// EhFrameSection::addRecords().
+template <class ELFT, class RelTy>
+void EhFrameSection::iterateFDEWithLSDAAux(
+ EhInputSection &sec, ArrayRef<RelTy> rels, DenseSet<size_t> &ciesWithLSDA,
+ llvm::function_ref<void(InputSection &)> fn) {
+ for (EhSectionPiece &piece : sec.pieces) {
+ // Skip ZERO terminator.
+ if (piece.size == 4)
+ continue;
+
+ size_t offset = piece.inputOff;
+ uint32_t id =
+ endian::read32<ELFT::TargetEndianness>(piece.data().data() + 4);
+ if (id == 0) {
+ if (hasLSDA(piece))
+ ciesWithLSDA.insert(offset);
+ continue;
+ }
+ uint32_t cieOffset = offset + 4 - id;
+ if (ciesWithLSDA.count(cieOffset) == 0)
+ continue;
+
+ // The CIE has a LSDA argument. Call fn with d's section.
+ if (Defined *d = isFdeLive<ELFT>(piece, rels))
+ if (auto *s = dyn_cast_or_null<InputSection>(d->section))
+ fn(*s);
+ }
+}
+
+template <class ELFT>
+void EhFrameSection::iterateFDEWithLSDA(
+ llvm::function_ref<void(InputSection &)> fn) {
+ DenseSet<size_t> ciesWithLSDA;
+ for (EhInputSection *sec : sections) {
+ ciesWithLSDA.clear();
+ if (sec->areRelocsRela)
+ iterateFDEWithLSDAAux<ELFT>(*sec, sec->template relas<ELFT>(),
+ ciesWithLSDA, fn);
+ else
+ iterateFDEWithLSDAAux<ELFT>(*sec, sec->template rels<ELFT>(),
+ ciesWithLSDA, fn);
+ }
+}
+
static void writeCieFde(uint8_t *buf, ArrayRef<uint8_t> d) {
memcpy(buf, d.data(), d.size());
@@ -600,15 +644,9 @@ void EhFrameSection::writeTo(uint8_t *buf) {
}
GotSection::GotSection()
- : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, config->wordsize,
- ".got") {
- // If ElfSym::globalOffsetTable is relative to .got and is referenced,
- // increase numEntries by the number of entries used to emit
- // ElfSym::globalOffsetTable.
- if (ElfSym::globalOffsetTable && !target->gotBaseSymInGotPlt)
- numEntries += target->gotHeaderEntriesNum;
- else if (config->emachine == EM_PPC && !config->relocatable)
- numEntries += target->gotHeaderEntriesNum;
+ : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
+ target->gotEntrySize, ".got") {
+ numEntries = target->gotHeaderEntriesNum;
}
void GotSection::addEntry(Symbol &sym) {
@@ -644,21 +682,22 @@ uint64_t GotSection::getGlobalDynOffset(const Symbol &b) const {
}
void GotSection::finalizeContents() {
- size = numEntries * config->wordsize;
+ if (config->emachine == EM_PPC64 &&
+ numEntries <= target->gotHeaderEntriesNum && !ElfSym::globalOffsetTable)
+ size = 0;
+ else
+ size = numEntries * config->wordsize;
}
bool GotSection::isNeeded() const {
- // We need to emit a GOT even if it's empty if there's a relocation that is
- // relative to GOT(such as GOTOFFREL).
- return numEntries || hasGotOffRel;
+ // Needed if the GOT symbol is used or the number of entries is more than just
+ // the header. A GOT with just the header may not be needed.
+ return hasGotOffRel || numEntries > target->gotHeaderEntriesNum;
}
void GotSection::writeTo(uint8_t *buf) {
- // Buf points to the start of this section's buffer,
- // whereas InputSectionBase::relocateAlloc() expects its argument
- // to point to the start of the output section.
target->writeGotHeader(buf);
- relocateAlloc(buf - outSecOff, buf - outSecOff + size);
+ relocateAlloc(buf, buf + size);
}
static uint64_t getMipsPageAddr(uint64_t addr) {
@@ -946,30 +985,37 @@ void MipsGotSection::build() {
for (std::pair<Symbol *, size_t> &p : got.tls) {
Symbol *s = p.first;
uint64_t offset = p.second * config->wordsize;
- if (s->isPreemptible)
- mainPart->relaDyn->addReloc(target->tlsGotRel, this, offset, s);
+ // When building a shared library we still need a dynamic relocation
+ // for the TP-relative offset as we don't know how much other data will
+ // be allocated before us in the static TLS block.
+ if (s->isPreemptible || config->shared)
+ mainPart->relaDyn->addReloc({target->tlsGotRel, this, offset,
+ DynamicReloc::AgainstSymbolWithTargetVA,
+ *s, 0, R_ABS});
}
for (std::pair<Symbol *, size_t> &p : got.dynTlsSymbols) {
Symbol *s = p.first;
uint64_t offset = p.second * config->wordsize;
if (s == nullptr) {
- if (!config->isPic)
+ if (!config->shared)
continue;
- mainPart->relaDyn->addReloc(target->tlsModuleIndexRel, this, offset, s);
+ mainPart->relaDyn->addReloc({target->tlsModuleIndexRel, this, offset});
} else {
// When building a shared library we still need a dynamic relocation
// for the module index. Therefore only checking for
// S->isPreemptible is not sufficient (this happens e.g. for
// thread-locals that have been marked as local through a linker script)
- if (!s->isPreemptible && !config->isPic)
+ if (!s->isPreemptible && !config->shared)
continue;
- mainPart->relaDyn->addReloc(target->tlsModuleIndexRel, this, offset, s);
+ mainPart->relaDyn->addSymbolReloc(target->tlsModuleIndexRel, this,
+ offset, *s);
// However, we can skip writing the TLS offset reloc for non-preemptible
// symbols since it is known even in shared libraries
if (!s->isPreemptible)
continue;
offset += config->wordsize;
- mainPart->relaDyn->addReloc(target->tlsOffsetRel, this, offset, s);
+ mainPart->relaDyn->addSymbolReloc(target->tlsOffsetRel, this, offset,
+ *s);
}
}
@@ -981,7 +1027,8 @@ void MipsGotSection::build() {
// Dynamic relocations for "global" entries.
for (const std::pair<Symbol *, size_t> &p : got.global) {
uint64_t offset = p.second * config->wordsize;
- mainPart->relaDyn->addReloc(target->relativeRel, this, offset, p.first);
+ mainPart->relaDyn->addSymbolReloc(target->relativeRel, this, offset,
+ *p.first);
}
if (!config->isPic)
continue;
@@ -992,13 +1039,14 @@ void MipsGotSection::build() {
for (size_t pi = 0; pi < pageCount; ++pi) {
uint64_t offset = (l.second.firstIndex + pi) * config->wordsize;
mainPart->relaDyn->addReloc({target->relativeRel, this, offset, l.first,
- int64_t(pi * 0x10000)});
+ int64_t(pi * 0x10000)});
}
}
for (const std::pair<GotEntry, size_t> &p : got.local16) {
uint64_t offset = p.second * config->wordsize;
- mainPart->relaDyn->addReloc({target->relativeRel, this, offset, true,
- p.first.first, p.first.second});
+ mainPart->relaDyn->addReloc({target->relativeRel, this, offset,
+ DynamicReloc::AddendOnlyWithTargetVA,
+ *p.first.first, p.first.second, R_ABS});
}
}
}
@@ -1054,7 +1102,7 @@ void MipsGotSection::writeTo(uint8_t *buf) {
// If TLS entry has a corresponding dynamic relocations, leave it
// initialized by zero. Write down adjusted TLS symbol's values otherwise.
// To calculate the adjustments use offsets for thread-local storage.
- // https://www.linux-mips.org/wiki/NPTL
+ // http://web.archive.org/web/20190324223224/https://www.linux-mips.org/wiki/NPTL
for (const std::pair<GotEntry, size_t> &p : g.local16)
write(p.second, p.first.first, p.first.second);
// Write VA to the primary GOT only. For secondary GOTs that
@@ -1065,15 +1113,16 @@ void MipsGotSection::writeTo(uint8_t *buf) {
for (const std::pair<Symbol *, size_t> &p : g.relocs)
write(p.second, p.first, 0);
for (const std::pair<Symbol *, size_t> &p : g.tls)
- write(p.second, p.first, p.first->isPreemptible ? 0 : -0x7000);
+ write(p.second, p.first,
+ p.first->isPreemptible || config->shared ? 0 : -0x7000);
for (const std::pair<Symbol *, size_t> &p : g.dynTlsSymbols) {
- if (p.first == nullptr && !config->isPic)
+ if (p.first == nullptr && !config->shared)
write(p.second, nullptr, 1);
else if (p.first && !p.first->isPreemptible) {
- // If we are emitting PIC code with relocations we mustn't write
+ // If we are emitting a shared libary with relocations we mustn't write
// anything to the GOT here. When using Elf_Rel relocations the value
// one will be treated as an addend and will cause crashes at runtime
- if (!config->isPic)
+ if (!config->shared)
write(p.second, nullptr, 1);
write(p.second + 1, p.first, -0x8000);
}
@@ -1102,15 +1151,16 @@ void GotPltSection::addEntry(Symbol &sym) {
}
size_t GotPltSection::getSize() const {
- return (target->gotPltHeaderEntriesNum + entries.size()) * config->wordsize;
+ return (target->gotPltHeaderEntriesNum + entries.size()) *
+ target->gotEntrySize;
}
void GotPltSection::writeTo(uint8_t *buf) {
target->writeGotPltHeader(buf);
- buf += target->gotPltHeaderEntriesNum * config->wordsize;
+ buf += target->gotPltHeaderEntriesNum * target->gotEntrySize;
for (const Symbol *b : entries) {
target->writeGotPlt(buf, *b);
- buf += config->wordsize;
+ buf += target->gotEntrySize;
}
}
@@ -1138,7 +1188,7 @@ static StringRef getIgotPltName() {
IgotPltSection::IgotPltSection()
: SyntheticSection(SHF_ALLOC | SHF_WRITE,
config->emachine == EM_PPC64 ? SHT_NOBITS : SHT_PROGBITS,
- config->wordsize, getIgotPltName()) {}
+ target->gotEntrySize, getIgotPltName()) {}
void IgotPltSection::addEntry(Symbol &sym) {
assert(sym.pltIndex == entries.size());
@@ -1146,13 +1196,13 @@ void IgotPltSection::addEntry(Symbol &sym) {
}
size_t IgotPltSection::getSize() const {
- return entries.size() * config->wordsize;
+ return entries.size() * target->gotEntrySize;
}
void IgotPltSection::writeTo(uint8_t *buf) {
for (const Symbol *b : entries) {
target->writeIgotPlt(buf, *b);
- buf += config->wordsize;
+ buf += target->gotEntrySize;
}
}
@@ -1306,7 +1356,7 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
// Set DT_FLAGS and DT_FLAGS_1.
uint32_t dtFlags = 0;
uint32_t dtFlags1 = 0;
- if (config->bsymbolic)
+ if (config->bsymbolic == BsymbolicKind::All)
dtFlags |= DF_SYMBOLIC;
if (config->zGlobal)
dtFlags1 |= DF_1_GLOBAL;
@@ -1397,6 +1447,13 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
case EM_SPARCV9:
addInSec(DT_PLTGOT, in.plt);
break;
+ case EM_AARCH64:
+ if (llvm::find_if(in.relaPlt->relocs, [](const DynamicReloc &r) {
+ return r.type == target->pltRel &&
+ r.sym->stOther & STO_AARCH64_VARIANT_PCS;
+ }) != in.relaPlt->relocs.end())
+ addInt(DT_AARCH64_VARIANT_PCS, 0);
+ LLVM_FALLTHROUGH;
default:
addInSec(DT_PLTGOT, in.gotPlt);
break;
@@ -1517,16 +1574,26 @@ uint64_t DynamicReloc::getOffset() const {
}
int64_t DynamicReloc::computeAddend() const {
- if (useSymVA)
- return sym->getVA(addend);
- if (!outputSec)
+ switch (kind) {
+ case AddendOnly:
+ assert(sym == nullptr);
+ return addend;
+ case AgainstSymbol:
+ assert(sym != nullptr);
return addend;
- // See the comment in the DynamicReloc ctor.
- return getMipsPageAddr(outputSec->addr) + addend;
+ case AddendOnlyWithTargetVA:
+ case AgainstSymbolWithTargetVA:
+ return InputSection::getRelocTargetVA(inputSec->file, type, addend,
+ getOffset(), *sym, expr);
+ case MipsMultiGotPage:
+ assert(sym == nullptr);
+ return getMipsPageAddr(outputSec->addr) + addend;
+ }
+ llvm_unreachable("Unknown DynamicReloc::Kind enum");
}
uint32_t DynamicReloc::getSymIndex(SymbolTableBaseSection *symTab) const {
- if (sym && !useSymVA)
+ if (needsDynSymIndex())
return symTab->getSymbolIndex(sym);
return 0;
}
@@ -1537,21 +1604,51 @@ RelocationBaseSection::RelocationBaseSection(StringRef name, uint32_t type,
: SyntheticSection(SHF_ALLOC, type, config->wordsize, name),
dynamicTag(dynamicTag), sizeDynamicTag(sizeDynamicTag) {}
-void RelocationBaseSection::addReloc(RelType dynType, InputSectionBase *isec,
- uint64_t offsetInSec, Symbol *sym) {
- addReloc({dynType, isec, offsetInSec, false, sym, 0});
+void RelocationBaseSection::addSymbolReloc(RelType dynType,
+ InputSectionBase *isec,
+ uint64_t offsetInSec, Symbol &sym,
+ int64_t addend,
+ Optional<RelType> addendRelType) {
+ addReloc(DynamicReloc::AgainstSymbol, dynType, isec, offsetInSec, sym, addend,
+ R_ADDEND, addendRelType ? *addendRelType : target->noneRel);
+}
+
+void RelocationBaseSection::addRelativeReloc(
+ RelType dynType, InputSectionBase *inputSec, uint64_t offsetInSec,
+ Symbol &sym, int64_t addend, RelType addendRelType, RelExpr expr) {
+ // This function should only be called for non-preemptible symbols or
+ // RelExpr values that refer to an address inside the output file (e.g. the
+ // address of the GOT entry for a potentially preemptible symbol).
+ assert((!sym.isPreemptible || expr == R_GOT) &&
+ "cannot add relative relocation against preemptible symbol");
+ assert(expr != R_ADDEND && "expected non-addend relocation expression");
+ addReloc(DynamicReloc::AddendOnlyWithTargetVA, dynType, inputSec, offsetInSec,
+ sym, addend, expr, addendRelType);
+}
+
+void RelocationBaseSection::addAddendOnlyRelocIfNonPreemptible(
+ RelType dynType, InputSectionBase *isec, uint64_t offsetInSec, Symbol &sym,
+ RelType addendRelType) {
+ // No need to write an addend to the section for preemptible symbols.
+ if (sym.isPreemptible)
+ addReloc({dynType, isec, offsetInSec, DynamicReloc::AgainstSymbol, sym, 0,
+ R_ABS});
+ else
+ addReloc(DynamicReloc::AddendOnlyWithTargetVA, dynType, isec, offsetInSec,
+ sym, 0, R_ABS, addendRelType);
}
-void RelocationBaseSection::addReloc(RelType dynType,
+void RelocationBaseSection::addReloc(DynamicReloc::Kind kind, RelType dynType,
InputSectionBase *inputSec,
- uint64_t offsetInSec, Symbol *sym,
+ uint64_t offsetInSec, Symbol &sym,
int64_t addend, RelExpr expr,
- RelType type) {
+ RelType addendRelType) {
// Write the addends to the relocated address if required. We skip
// it if the written value would be zero.
if (config->writeAddends && (expr != R_ADDEND || addend != 0))
- inputSec->relocations.push_back({expr, type, offsetInSec, addend, sym});
- addReloc({dynType, inputSec, offsetInSec, expr != R_ADDEND, sym, addend});
+ inputSec->relocations.push_back(
+ {expr, addendRelType, offsetInSec, addend, &sym});
+ addReloc({dynType, inputSec, offsetInSec, kind, sym, addend, expr});
}
void RelocationBaseSection::addReloc(const DynamicReloc &reloc) {
@@ -1571,10 +1668,14 @@ void RelocationBaseSection::finalizeContents() {
else
getParent()->link = 0;
- if (in.relaPlt == this)
+ if (in.relaPlt == this) {
+ getParent()->flags |= ELF::SHF_INFO_LINK;
getParent()->info = in.gotPlt->getParent()->sectionIndex;
- if (in.relaIplt == this)
+ }
+ if (in.relaIplt == this) {
+ getParent()->flags |= ELF::SHF_INFO_LINK;
getParent()->info = in.igotPlt->getParent()->sectionIndex;
+ }
}
RelrBaseSection::RelrBaseSection()
@@ -2138,6 +2239,10 @@ template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *buf) {
// See getPPC64GlobalEntryToLocalEntryOffset() for more details.
if (config->emachine == EM_PPC64)
eSym->st_other |= sym->stOther & 0xe0;
+ // The most significant bit of st_other is used by AArch64 ABI for the
+ // variant PCS.
+ else if (config->emachine == EM_AARCH64)
+ eSym->st_other |= sym->stOther & STO_AARCH64_VARIANT_PCS;
eSym->st_name = ent.strTabOffset;
if (isDefinedHere)
@@ -2155,9 +2260,8 @@ template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *buf) {
else
eSym->st_size = sym->getSize();
- // st_value is usually an address of a symbol, but that has a
- // special meaning for uninstantiated common symbols (this can
- // occur if -r is given).
+ // st_value is usually an address of a symbol, but that has a special
+ // meaning for uninstantiated common symbols (--no-define-common).
if (BssSection *commonSec = getCommonSec(ent.sym))
eSym->st_value = commonSec->alignment;
else if (isDefinedHere)
@@ -2826,6 +2930,13 @@ template <class ELFT> GdbIndexSection *GdbIndexSection::create() {
else if (isec->name == ".debug_info")
files.insert(isec->file);
}
+ // Drop .rel[a].debug_gnu_pub{names,types} for --emit-relocs.
+ llvm::erase_if(inputSections, [](InputSectionBase *s) {
+ if (auto *isec = dyn_cast<InputSection>(s))
+ if (InputSectionBase *rel = isec->getRelocatedSection())
+ return !rel->isLive();
+ return !s->isLive();
+ });
std::vector<GdbChunk> chunks(files.size());
std::vector<std::vector<NameAttrEntry>> nameAttrs(files.size());
@@ -2875,7 +2986,8 @@ void GdbIndexSection::writeTo(uint8_t *buf) {
uint32_t cuOff = 0;
for (GdbChunk &chunk : chunks) {
for (AddressEntry &e : chunk.addressAreas) {
- uint64_t baseAddr = e.section->getVA(0);
+ // In the case of ICF there may be duplicate address range entries.
+ const uint64_t baseAddr = e.section->repl->getVA(0);
write64le(buf, baseAddr + e.lowAddress);
write64le(buf + 8, baseAddr + e.highAddress);
write32le(buf + 16, e.cuIndex + cuOff);
@@ -3049,7 +3161,10 @@ size_t VersionTableSection::getSize() const {
void VersionTableSection::writeTo(uint8_t *buf) {
buf += 2;
for (const SymbolTableEntry &s : getPartition().dynSymTab->getSymbols()) {
- write16(buf, s.sym->versionId);
+ // Use the original versionId for an unfetched lazy symbol (undefined weak),
+ // which must be VER_NDX_GLOBAL (an undefined versioned symbol is an error).
+ write16(buf, s.sym->isLazy() ? static_cast<uint16_t>(VER_NDX_GLOBAL)
+ : s.sym->versionId);
buf += 2;
}
}
@@ -3456,7 +3571,7 @@ void ARMExidxSyntheticSection::writeTo(uint8_t *buf) {
assert(isec->getParent() != nullptr);
if (InputSection *d = findExidxSection(isec)) {
memcpy(buf + offset, d->data().data(), d->data().size());
- d->relocateAlloc(buf, buf + d->getSize());
+ d->relocateAlloc(buf + d->outSecOff, buf + d->outSecOff + d->getSize());
offset += d->getSize();
} else {
// A Linker generated CANTUNWIND section.
@@ -3486,8 +3601,8 @@ bool ARMExidxSyntheticSection::classof(const SectionBase *d) {
}
ThunkSection::ThunkSection(OutputSection *os, uint64_t off)
- : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 4,
- ".text.thunk") {
+ : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS,
+ config->emachine == EM_PPC64 ? 16 : 4, ".text.thunk") {
this->parent = os;
this->outSecOff = off;
}
@@ -3763,6 +3878,15 @@ template class elf::MipsOptionsSection<ELF32BE>;
template class elf::MipsOptionsSection<ELF64LE>;
template class elf::MipsOptionsSection<ELF64BE>;
+template void EhFrameSection::iterateFDEWithLSDA<ELF32LE>(
+ function_ref<void(InputSection &)>);
+template void EhFrameSection::iterateFDEWithLSDA<ELF32BE>(
+ function_ref<void(InputSection &)>);
+template void EhFrameSection::iterateFDEWithLSDA<ELF64LE>(
+ function_ref<void(InputSection &)>);
+template void EhFrameSection::iterateFDEWithLSDA<ELF64BE>(
+ function_ref<void(InputSection &)>);
+
template class elf::MipsReginfoSection<ELF32LE>;
template class elf::MipsReginfoSection<ELF32BE>;
template class elf::MipsReginfoSection<ELF64LE>;
diff --git a/gnu/llvm/lld/ELF/Writer.cpp b/gnu/llvm/lld/ELF/Writer.cpp
index c271294208e..9e6692b3709 100644
--- a/gnu/llvm/lld/ELF/Writer.cpp
+++ b/gnu/llvm/lld/ELF/Writer.cpp
@@ -19,6 +19,7 @@
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
+#include "lld/Common/Arrays.h"
#include "lld/Common/Filesystem.h"
#include "lld/Common/Memory.h"
#include "lld/Common/Strings.h"
@@ -45,10 +46,9 @@ namespace {
// The writer writes a SymbolTable result to a file.
template <class ELFT> class Writer {
public:
+ LLVM_ELF_IMPORT_TYPES_ELFT(ELFT)
+
Writer() : buffer(errorHandler().outputBuffer) {}
- using Elf_Shdr = typename ELFT::Shdr;
- using Elf_Ehdr = typename ELFT::Ehdr;
- using Elf_Phdr = typename ELFT::Phdr;
void run();
@@ -131,9 +131,14 @@ StringRef elf::getOutputSectionName(const InputSectionBase *s) {
// SampleFDO is used, if a function doesn't have sample, it could be very
// cold or it could be a new function never being sampled. Those functions
// will be kept in the ".text.unknown" section.
+ // ".text.split." holds symbols which are split out from functions in other
+ // input sections. For example, with -fsplit-machine-functions, placing the
+ // cold parts in .text.split instead of .text.unlikely mitigates against poor
+ // profile inaccuracy. Techniques such as hugepage remapping can make
+ // conservative decisions at the section granularity.
if (config->zKeepTextSectionPrefix)
for (StringRef v : {".text.hot.", ".text.unknown.", ".text.unlikely.",
- ".text.startup.", ".text.exit."})
+ ".text.startup.", ".text.exit.", ".text.split."})
if (isSectionPrefix(v, s->name))
return v.drop_back();
@@ -154,7 +159,6 @@ static bool needsInterpSection() {
}
template <class ELFT> void elf::writeResult() {
- llvm::TimeTraceScope timeScope("Write output file");
Writer<ELFT>().run();
}
@@ -201,6 +205,7 @@ void elf::copySectionsIntoPartitions() {
}
void elf::combineEhSections() {
+ llvm::TimeTraceScope timeScope("Combine EH sections");
for (InputSectionBase *&s : inputSections) {
// Ignore dead sections and the partition end marker (.part.end),
// whose partition number is out of bounds.
@@ -633,28 +638,32 @@ template <class ELFT> void Writer<ELFT>::run() {
// It does not make sense try to open the file if we have error already.
if (errorCount())
return;
- // Write the result down to a file.
- openFile();
- if (errorCount())
- return;
- if (!config->oFormatBinary) {
- if (config->zSeparate != SeparateSegmentKind::None)
- writeTrapInstr();
- writeHeader();
- writeSections();
- } else {
- writeSectionsBinary();
- }
+ {
+ llvm::TimeTraceScope timeScope("Write output file");
+ // Write the result down to a file.
+ openFile();
+ if (errorCount())
+ return;
- // Backfill .note.gnu.build-id section content. This is done at last
- // because the content is usually a hash value of the entire output file.
- writeBuildId();
- if (errorCount())
- return;
+ if (!config->oFormatBinary) {
+ if (config->zSeparate != SeparateSegmentKind::None)
+ writeTrapInstr();
+ writeHeader();
+ writeSections();
+ } else {
+ writeSectionsBinary();
+ }
- if (auto e = buffer->commit())
- error("failed to write to the output file: " + toString(std::move(e)));
+ // Backfill .note.gnu.build-id section content. This is done at last
+ // because the content is usually a hash value of the entire output file.
+ writeBuildId();
+ if (errorCount())
+ return;
+
+ if (auto e = buffer->commit())
+ error("failed to write to the output file: " + toString(std::move(e)));
+ }
}
template <class ELFT, class RelTy>
@@ -760,6 +769,7 @@ static bool includeInSymtab(const Symbol &b) {
template <class ELFT> void Writer<ELFT>::copyLocalSymbols() {
if (!in.symTab)
return;
+ llvm::TimeTraceScope timeScope("Add local symbols");
if (config->copyRelocs && config->discard != DiscardPolicy::None)
markUsedLocalSymbols<ELFT>();
for (InputFile *file : objectFiles) {
@@ -808,9 +818,12 @@ template <class ELFT> void Writer<ELFT>::addSectionSymbols() {
if (isa<SyntheticSection>(isec) && !(isec->flags & SHF_MERGE))
continue;
+ // Set the symbol to be relative to the output section so that its st_value
+ // equals the output section address. Note, there may be a gap between the
+ // start of the output section and isec.
auto *sym =
make<Defined>(isec->file, "", STB_LOCAL, /*stOther=*/0, STT_SECTION,
- /*value=*/0, /*size=*/0, isec);
+ /*value=*/0, /*size=*/0, isec->getOutputSection());
in.symTab->addSymbol(sym);
}
}
@@ -1081,7 +1094,7 @@ void PhdrEntry::add(OutputSection *sec) {
// need these symbols, since IRELATIVE relocs are resolved through GOT
// and PLT. For details, see http://www.airs.com/blog/archives/403.
template <class ELFT> void Writer<ELFT>::addRelIpltSymbols() {
- if (config->relocatable || needsInterpSection())
+ if (config->relocatable || config->isPic)
return;
// By default, __rela_iplt_{start,end} belong to a dummy section 0
@@ -1288,22 +1301,39 @@ findOrphanPos(std::vector<BaseCommand *>::iterator b,
// Adds random priorities to sections not already in the map.
static void maybeShuffle(DenseMap<const InputSectionBase *, int> &order) {
- if (!config->shuffleSectionSeed)
+ if (config->shuffleSections.empty())
return;
- std::vector<int> priorities(inputSections.size() - order.size());
+ std::vector<InputSectionBase *> matched, sections = inputSections;
+ matched.reserve(sections.size());
+ for (const auto &patAndSeed : config->shuffleSections) {
+ matched.clear();
+ for (InputSectionBase *sec : sections)
+ if (patAndSeed.first.match(sec->name))
+ matched.push_back(sec);
+ const uint32_t seed = patAndSeed.second;
+ if (seed == UINT32_MAX) {
+ // If --shuffle-sections <section-glob>=-1, reverse the section order. The
+ // section order is stable even if the number of sections changes. This is
+ // useful to catch issues like static initialization order fiasco
+ // reliably.
+ std::reverse(matched.begin(), matched.end());
+ } else {
+ std::mt19937 g(seed ? seed : std::random_device()());
+ llvm::shuffle(matched.begin(), matched.end(), g);
+ }
+ size_t i = 0;
+ for (InputSectionBase *&sec : sections)
+ if (patAndSeed.first.match(sec->name))
+ sec = matched[i++];
+ }
+
// Existing priorities are < 0, so use priorities >= 0 for the missing
// sections.
- int curPrio = 0;
- for (int &prio : priorities)
- prio = curPrio++;
- uint32_t seed = *config->shuffleSectionSeed;
- std::mt19937 g(seed ? seed : std::random_device()());
- llvm::shuffle(priorities.begin(), priorities.end(), g);
- int prioIndex = 0;
- for (InputSectionBase *sec : inputSections) {
- if (order.try_emplace(sec, priorities[prioIndex]).second)
- ++prioIndex;
+ int prio = 0;
+ for (InputSectionBase *sec : sections) {
+ if (order.try_emplace(sec, prio).second)
+ ++prio;
}
}
@@ -1355,9 +1385,11 @@ static DenseMap<const InputSectionBase *, int> buildSectionOrder() {
addSym(*sym);
for (InputFile *file : objectFiles)
- for (Symbol *sym : file->getSymbols())
- if (sym->isLocal())
- addSym(*sym);
+ for (Symbol *sym : file->getSymbols()) {
+ if (!sym->isLocal())
+ break;
+ addSym(*sym);
+ }
if (config->warnSymbolOrdering)
for (auto orderEntry : symbolOrder)
@@ -1440,6 +1472,14 @@ static void sortSection(OutputSection *sec,
if (name == ".init" || name == ".fini")
return;
+ // IRelative relocations that usually live in the .rel[a].dyn section should
+ // be processed last by the dynamic loader. To achieve that we add synthetic
+ // sections in the required order from the beginning so that the in.relaIplt
+ // section is placed last in an output section. Here we just do not apply
+ // sorting for an output section which holds the in.relaIplt section.
+ if (in.relaIplt->getParent() == sec)
+ return;
+
// Sort input sections by priority using the list provided by
// --symbol-ordering-file or --shuffle-sections=. This is a least significant
// digit radix sort. The sections may be sorted stably again by a more
@@ -1495,6 +1535,7 @@ template <class ELFT> void Writer<ELFT>::sortInputSections() {
}
template <class ELFT> void Writer<ELFT>::sortSections() {
+ llvm::TimeTraceScope timeScope("Sort sections");
script->adjustSectionsBeforeSorting();
// Don't sort if using -r. It is not necessary and we want to preserve the
@@ -1613,8 +1654,12 @@ template <class ELFT> void Writer<ELFT>::sortSections() {
}
static bool compareByFilePosition(InputSection *a, InputSection *b) {
- InputSection *la = a->getLinkOrderDep();
- InputSection *lb = b->getLinkOrderDep();
+ InputSection *la = a->flags & SHF_LINK_ORDER ? a->getLinkOrderDep() : nullptr;
+ InputSection *lb = b->flags & SHF_LINK_ORDER ? b->getLinkOrderDep() : nullptr;
+ // SHF_LINK_ORDER sections with non-zero sh_link are ordered before
+ // non-SHF_LINK_ORDER sections and SHF_LINK_ORDER sections with zero sh_link.
+ if (!la || !lb)
+ return la && !lb;
OutputSection *aOut = la->getParent();
OutputSection *bOut = lb->getParent();
@@ -1624,6 +1669,7 @@ static bool compareByFilePosition(InputSection *a, InputSection *b) {
}
template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() {
+ llvm::TimeTraceScope timeScope("Resolve SHF_LINK_ORDER");
for (OutputSection *sec : outputSections) {
if (!(sec->flags & SHF_LINK_ORDER))
continue;
@@ -1634,50 +1680,42 @@ template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() {
sec->type == SHT_ARM_EXIDX)
continue;
- // Link order may be distributed across several InputSectionDescriptions
- // but sort must consider them all at once.
+ // Link order may be distributed across several InputSectionDescriptions.
+ // Sorting is performed separately.
std::vector<InputSection **> scriptSections;
std::vector<InputSection *> sections;
- bool started = false, stopped = false;
for (BaseCommand *base : sec->sectionCommands) {
- if (auto *isd = dyn_cast<InputSectionDescription>(base)) {
- for (InputSection *&isec : isd->sections) {
- if (!(isec->flags & SHF_LINK_ORDER)) {
- if (started)
- stopped = true;
- } else if (stopped) {
- error(toString(isec) + ": SHF_LINK_ORDER sections in " + sec->name +
- " are not contiguous");
- } else {
- started = true;
-
- scriptSections.push_back(&isec);
- sections.push_back(isec);
-
- InputSection *link = isec->getLinkOrderDep();
- if (!link->getParent())
- error(toString(isec) + ": sh_link points to discarded section " +
- toString(link));
- }
+ auto *isd = dyn_cast<InputSectionDescription>(base);
+ if (!isd)
+ continue;
+ bool hasLinkOrder = false;
+ scriptSections.clear();
+ sections.clear();
+ for (InputSection *&isec : isd->sections) {
+ if (isec->flags & SHF_LINK_ORDER) {
+ InputSection *link = isec->getLinkOrderDep();
+ if (link && !link->getParent())
+ error(toString(isec) + ": sh_link points to discarded section " +
+ toString(link));
+ hasLinkOrder = true;
}
- } else if (started) {
- stopped = true;
+ scriptSections.push_back(&isec);
+ sections.push_back(isec);
+ }
+ if (hasLinkOrder && errorCount() == 0) {
+ llvm::stable_sort(sections, compareByFilePosition);
+ for (int i = 0, n = sections.size(); i != n; ++i)
+ *scriptSections[i] = sections[i];
}
}
-
- if (errorCount())
- continue;
-
- llvm::stable_sort(sections, compareByFilePosition);
-
- for (int i = 0, n = sections.size(); i < n; ++i)
- *scriptSections[i] = sections[i];
}
}
static void finalizeSynthetic(SyntheticSection *sec) {
- if (sec && sec->isNeeded() && sec->getParent())
+ if (sec && sec->isNeeded() && sec->getParent()) {
+ llvm::TimeTraceScope timeScope("Finalize synthetic sections", sec->name);
sec->finalizeContents();
+ }
}
// We need to generate and finalize the content that depends on the address of
@@ -1685,6 +1723,7 @@ static void finalizeSynthetic(SyntheticSection *sec) {
// addresses we must converge to a fixed point. We do that here. See the comment
// in Writer<ELFT>::finalizeSections().
template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() {
+ llvm::TimeTraceScope timeScope("Finalize address dependent content");
ThunkCreator tc;
AArch64Err843419Patcher a64p;
ARMErr657417Patcher a32p;
@@ -1706,8 +1745,8 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() {
bool changed = target->needsThunks && tc.createThunks(outputSections);
// With Thunk Size much smaller than branch range we expect to
- // converge quickly; if we get to 10 something has gone wrong.
- if (changed && tc.pass >= 10) {
+ // converge quickly; if we get to 15 something has gone wrong.
+ if (changed && tc.pass >= 15) {
error("thunk creation not converged");
break;
}
@@ -1757,7 +1796,7 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() {
Twine(os->alignment) + ")");
}
-// If Input Sections have been shrinked (basic block sections) then
+// If Input Sections have been shrunk (basic block sections) then
// update symbol values and sizes associated with these sections. With basic
// block sections, input sections can shrink when the jump instructions at
// the end of the section are relaxed.
@@ -1859,26 +1898,44 @@ template <class ELFT> void Writer<ELFT>::optimizeBasicBlockJumps() {
// out to be empty.
static void removeUnusedSyntheticSections() {
// All input synthetic sections that can be empty are placed after
- // all regular ones. We iterate over them all and exit at first
- // non-synthetic.
- for (InputSectionBase *s : llvm::reverse(inputSections)) {
- SyntheticSection *ss = dyn_cast<SyntheticSection>(s);
- if (!ss)
- return;
- OutputSection *os = ss->getParent();
- if (!os || ss->isNeeded())
- continue;
+ // all regular ones. Reverse iterate to find the first synthetic section
+ // after a non-synthetic one which will be our starting point.
+ auto start = std::find_if(inputSections.rbegin(), inputSections.rend(),
+ [](InputSectionBase *s) {
+ return !isa<SyntheticSection>(s);
+ })
+ .base();
+
+ DenseSet<InputSectionDescription *> isdSet;
+ // Mark unused synthetic sections for deletion
+ auto end = std::stable_partition(
+ start, inputSections.end(), [&](InputSectionBase *s) {
+ SyntheticSection *ss = dyn_cast<SyntheticSection>(s);
+ OutputSection *os = ss->getParent();
+ if (!os || ss->isNeeded())
+ return true;
- // If we reach here, then ss is an unused synthetic section and we want to
- // remove it from the corresponding input section description, and
- // orphanSections.
- for (BaseCommand *b : os->sectionCommands)
- if (auto *isd = dyn_cast<InputSectionDescription>(b))
- llvm::erase_if(isd->sections,
- [=](InputSection *isec) { return isec == ss; });
- llvm::erase_if(script->orphanSections,
- [=](const InputSectionBase *isec) { return isec == ss; });
- }
+ // If we reach here, then ss is an unused synthetic section and we want
+ // to remove it from the corresponding input section description, and
+ // orphanSections.
+ for (BaseCommand *b : os->sectionCommands)
+ if (auto *isd = dyn_cast<InputSectionDescription>(b))
+ isdSet.insert(isd);
+
+ llvm::erase_if(
+ script->orphanSections,
+ [=](const InputSectionBase *isec) { return isec == ss; });
+
+ return false;
+ });
+
+ DenseSet<InputSectionBase *> unused(end, inputSections.end());
+ for (auto *isd : isdSet)
+ llvm::erase_if(isd->sections,
+ [=](InputSection *isec) { return unused.count(isec); });
+
+ // Erase unused synthetic sections.
+ inputSections.erase(end, inputSections.end());
}
// Create output section objects and add them to OutputSections.
@@ -1941,11 +1998,14 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
}
}
- // This responsible for splitting up .eh_frame section into
- // pieces. The relocation scan uses those pieces, so this has to be
- // earlier.
- for (Partition &part : partitions)
- finalizeSynthetic(part.ehFrame);
+ {
+ llvm::TimeTraceScope timeScope("Finalize .eh_frame");
+ // This responsible for splitting up .eh_frame section into
+ // pieces. The relocation scan uses those pieces, so this has to be
+ // earlier.
+ for (Partition &part : partitions)
+ finalizeSynthetic(part.ehFrame);
+ }
for (Symbol *sym : symtab->symbols())
sym->isPreemptible = computeIsPreemptible(*sym);
@@ -1954,14 +2014,17 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// by declareSymbols) to actual definitions.
script->processSymbolAssignments();
- // Scan relocations. This must be done after every symbol is declared so that
- // we can correctly decide if a dynamic relocation is needed. This is called
- // after processSymbolAssignments() because it needs to know whether a
- // linker-script-defined symbol is absolute.
- ppc64noTocRelax.clear();
- if (!config->relocatable) {
- forEachRelSec(scanRelocations<ELFT>);
- reportUndefinedSymbols<ELFT>();
+ {
+ llvm::TimeTraceScope timeScope("Scan relocations");
+ // Scan relocations. This must be done after every symbol is declared so
+ // that we can correctly decide if a dynamic relocation is needed. This is
+ // called after processSymbolAssignments() because it needs to know whether
+ // a linker-script-defined symbol is absolute.
+ ppc64noTocRelax.clear();
+ if (!config->relocatable) {
+ forEachRelSec(scanRelocations<ELFT>);
+ reportUndefinedSymbols<ELFT>();
+ }
}
if (in.plt && in.plt->isNeeded())
@@ -1969,7 +2032,11 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
if (in.iplt && in.iplt->isNeeded())
in.iplt->addSymbols();
- if (!config->allowShlibUndefined) {
+ if (config->unresolvedSymbolsInShlib != UnresolvedPolicy::Ignore) {
+ auto diagnose =
+ config->unresolvedSymbolsInShlib == UnresolvedPolicy::ReportError
+ ? errorOrWarn
+ : warn;
// Error on undefined symbols in a shared object, if all of its DT_NEEDED
// entries are seen. These cases would otherwise lead to runtime errors
// reported by the dynamic linker.
@@ -1977,45 +2044,49 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// ld.bfd traces all DT_NEEDED to emulate the logic of the dynamic linker to
// catch more cases. That is too much for us. Our approach resembles the one
// used in ld.gold, achieves a good balance to be useful but not too smart.
- for (SharedFile *file : sharedFiles)
- file->allNeededIsKnown =
+ for (SharedFile *file : sharedFiles) {
+ bool allNeededIsKnown =
llvm::all_of(file->dtNeeded, [&](StringRef needed) {
return symtab->soNames.count(needed);
});
-
- for (Symbol *sym : symtab->symbols())
- if (sym->isUndefined() && !sym->isWeak())
- if (auto *f = dyn_cast_or_null<SharedFile>(sym->file))
- if (f->allNeededIsKnown)
- errorOrWarn(toString(f) + ": undefined reference to " +
- toString(*sym) + " [--no-allow-shlib-undefined]");
+ if (!allNeededIsKnown)
+ continue;
+ for (Symbol *sym : file->requiredSymbols)
+ if (sym->isUndefined() && !sym->isWeak())
+ diagnose(toString(file) + ": undefined reference to " +
+ toString(*sym) + " [--no-allow-shlib-undefined]");
+ }
}
- // Now that we have defined all possible global symbols including linker-
- // synthesized ones. Visit all symbols to give the finishing touches.
- for (Symbol *sym : symtab->symbols()) {
- if (!includeInSymtab(*sym))
- continue;
- if (in.symTab)
- in.symTab->addSymbol(sym);
-
- if (sym->includeInDynsym()) {
- partitions[sym->partition - 1].dynSymTab->addSymbol(sym);
- if (auto *file = dyn_cast_or_null<SharedFile>(sym->file))
- if (file->isNeeded && !sym->isUndefined())
- addVerneed(sym);
+ {
+ llvm::TimeTraceScope timeScope("Add symbols to symtabs");
+ // Now that we have defined all possible global symbols including linker-
+ // synthesized ones. Visit all symbols to give the finishing touches.
+ for (Symbol *sym : symtab->symbols()) {
+ if (!includeInSymtab(*sym))
+ continue;
+ if (in.symTab)
+ in.symTab->addSymbol(sym);
+
+ if (sym->includeInDynsym()) {
+ partitions[sym->partition - 1].dynSymTab->addSymbol(sym);
+ if (auto *file = dyn_cast_or_null<SharedFile>(sym->file))
+ if (file->isNeeded && !sym->isUndefined())
+ addVerneed(sym);
+ }
}
- }
- // We also need to scan the dynamic relocation tables of the other partitions
- // and add any referenced symbols to the partition's dynsym.
- for (Partition &part : MutableArrayRef<Partition>(partitions).slice(1)) {
- DenseSet<Symbol *> syms;
- for (const SymbolTableEntry &e : part.dynSymTab->getSymbols())
- syms.insert(e.sym);
- for (DynamicReloc &reloc : part.relaDyn->relocs)
- if (reloc.sym && !reloc.useSymVA && syms.insert(reloc.sym).second)
- part.dynSymTab->addSymbol(reloc.sym);
+ // We also need to scan the dynamic relocation tables of the other
+ // partitions and add any referenced symbols to the partition's dynsym.
+ for (Partition &part : MutableArrayRef<Partition>(partitions).slice(1)) {
+ DenseSet<Symbol *> syms;
+ for (const SymbolTableEntry &e : part.dynSymTab->getSymbols())
+ syms.insert(e.sym);
+ for (DynamicReloc &reloc : part.relaDyn->relocs)
+ if (reloc.sym && reloc.needsDynSymIndex() &&
+ syms.insert(reloc.sym).second)
+ part.dynSymTab->addSymbol(reloc.sym);
+ }
}
// Do not proceed if there was an undefined symbol.
@@ -2096,35 +2167,39 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// have the headers, we can find out which sections they point to.
setReservedSymbolSections();
- finalizeSynthetic(in.bss);
- finalizeSynthetic(in.bssRelRo);
- finalizeSynthetic(in.symTabShndx);
- finalizeSynthetic(in.shStrTab);
- finalizeSynthetic(in.strTab);
- finalizeSynthetic(in.got);
- finalizeSynthetic(in.mipsGot);
- finalizeSynthetic(in.igotPlt);
- finalizeSynthetic(in.gotPlt);
- finalizeSynthetic(in.relaIplt);
- finalizeSynthetic(in.relaPlt);
- finalizeSynthetic(in.plt);
- finalizeSynthetic(in.iplt);
- finalizeSynthetic(in.ppc32Got2);
- finalizeSynthetic(in.partIndex);
-
- // Dynamic section must be the last one in this list and dynamic
- // symbol table section (dynSymTab) must be the first one.
- for (Partition &part : partitions) {
- finalizeSynthetic(part.dynSymTab);
- finalizeSynthetic(part.gnuHashTab);
- finalizeSynthetic(part.hashTab);
- finalizeSynthetic(part.verDef);
- finalizeSynthetic(part.relaDyn);
- finalizeSynthetic(part.relrDyn);
- finalizeSynthetic(part.ehFrameHdr);
- finalizeSynthetic(part.verSym);
- finalizeSynthetic(part.verNeed);
- finalizeSynthetic(part.dynamic);
+ {
+ llvm::TimeTraceScope timeScope("Finalize synthetic sections");
+
+ finalizeSynthetic(in.bss);
+ finalizeSynthetic(in.bssRelRo);
+ finalizeSynthetic(in.symTabShndx);
+ finalizeSynthetic(in.shStrTab);
+ finalizeSynthetic(in.strTab);
+ finalizeSynthetic(in.got);
+ finalizeSynthetic(in.mipsGot);
+ finalizeSynthetic(in.igotPlt);
+ finalizeSynthetic(in.gotPlt);
+ finalizeSynthetic(in.relaIplt);
+ finalizeSynthetic(in.relaPlt);
+ finalizeSynthetic(in.plt);
+ finalizeSynthetic(in.iplt);
+ finalizeSynthetic(in.ppc32Got2);
+ finalizeSynthetic(in.partIndex);
+
+ // Dynamic section must be the last one in this list and dynamic
+ // symbol table section (dynSymTab) must be the first one.
+ for (Partition &part : partitions) {
+ finalizeSynthetic(part.dynSymTab);
+ finalizeSynthetic(part.gnuHashTab);
+ finalizeSynthetic(part.hashTab);
+ finalizeSynthetic(part.verDef);
+ finalizeSynthetic(part.relaDyn);
+ finalizeSynthetic(part.relrDyn);
+ finalizeSynthetic(part.ehFrameHdr);
+ finalizeSynthetic(part.verSym);
+ finalizeSynthetic(part.verNeed);
+ finalizeSynthetic(part.dynamic);
+ }
}
if (!script->hasSectionsCommand && !config->relocatable)
@@ -2155,9 +2230,13 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
if (errorCount())
return;
- // finalizeAddressDependentContent may have added local symbols to the static symbol table.
- finalizeSynthetic(in.symTab);
- finalizeSynthetic(in.ppc64LongBranchTarget);
+ {
+ llvm::TimeTraceScope timeScope("Finalize synthetic sections");
+ // finalizeAddressDependentContent may have added local symbols to the
+ // static symbol table.
+ finalizeSynthetic(in.symTab);
+ finalizeSynthetic(in.ppc64LongBranchTarget);
+ }
// Relaxation to delete inter-basic block jumps created by basic block
// sections. Run after in.symTab is finalized as optimizeBasicBlockJumps
@@ -2245,7 +2324,7 @@ void Writer<ELFT>::addStartStopSymbols(OutputSection *sec) {
}
static bool needsPtLoad(OutputSection *sec) {
- if (!(sec->flags & SHF_ALLOC) || sec->noload)
+ if (!(sec->flags & SHF_ALLOC))
return false;
// Don't allocate VA space for TLS NOBITS sections. The PT_TLS PHDR is
@@ -2335,8 +2414,6 @@ std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs(Partition &part) {
}
for (OutputSection *sec : outputSections) {
- if (!(sec->flags & SHF_ALLOC))
- break;
if (!needsPtLoad(sec))
continue;
@@ -2581,11 +2658,24 @@ static uint64_t setFileOffset(OutputSection *os, uint64_t off) {
}
template <class ELFT> void Writer<ELFT>::assignFileOffsetsBinary() {
- uint64_t off = 0;
+ // Compute the minimum LMA of all non-empty non-NOBITS sections as minAddr.
+ auto needsOffset = [](OutputSection &sec) {
+ return sec.type != SHT_NOBITS && (sec.flags & SHF_ALLOC) && sec.size > 0;
+ };
+ uint64_t minAddr = UINT64_MAX;
for (OutputSection *sec : outputSections)
- if (sec->flags & SHF_ALLOC)
- off = setFileOffset(sec, off);
- fileSize = alignTo(off, config->wordsize);
+ if (needsOffset(*sec)) {
+ sec->offset = sec->getLMA();
+ minAddr = std::min(minAddr, sec->offset);
+ }
+
+ // Sections are laid out at LMA minus minAddr.
+ fileSize = 0;
+ for (OutputSection *sec : outputSections)
+ if (needsOffset(*sec)) {
+ sec->offset -= minAddr;
+ fileSize = std::max(fileSize, sec->offset + sec->size);
+ }
}
static std::string rangeToString(uint64_t addr, uint64_t len) {
@@ -2604,7 +2694,11 @@ template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
if (p->p_type == PT_LOAD && (p->p_flags & PF_X))
lastRX = p;
+ // Layout SHF_ALLOC sections before non-SHF_ALLOC sections. A non-SHF_ALLOC
+ // will not occupy file offsets contained by a PT_LOAD.
for (OutputSection *sec : outputSections) {
+ if (!(sec->flags & SHF_ALLOC))
+ continue;
off = setFileOffset(sec, off);
// If this is a last section of the last executable segment and that
@@ -2614,6 +2708,9 @@ template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
lastRX->lastSec == sec)
off = alignTo(off, config->commonPageSize);
}
+ for (OutputSection *sec : outputSections)
+ if (!(sec->flags & SHF_ALLOC))
+ off = setFileOffset(sec, off);
sectionHeaderOff = alignTo(off, config->wordsize);
fileSize = sectionHeaderOff + (outputSections.size() + 1) * sizeof(Elf_Shdr);
@@ -2845,7 +2942,13 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
template <class ELFT> void Writer<ELFT>::openFile() {
uint64_t maxSize = config->is64 ? INT64_MAX : UINT32_MAX;
if (fileSize != size_t(fileSize) || maxSize < fileSize) {
- error("output file too large: " + Twine(fileSize) + " bytes");
+ std::string msg;
+ raw_string_ostream s(msg);
+ s << "output file too large: " << Twine(fileSize) << " bytes\n"
+ << "section sizes:\n";
+ for (OutputSection *os : outputSections)
+ s << os->name << ' ' << os->size << "\n";
+ error(s.str());
return;
}
@@ -2920,19 +3023,13 @@ template <class ELFT> void Writer<ELFT>::writeSections() {
for (OutputSection *sec : outputSections)
if (sec->type != SHT_REL && sec->type != SHT_RELA)
sec->writeTo<ELFT>(Out::bufferStart + sec->offset);
-}
-// Split one uint8 array into small pieces of uint8 arrays.
-static std::vector<ArrayRef<uint8_t>> split(ArrayRef<uint8_t> arr,
- size_t chunkSize) {
- std::vector<ArrayRef<uint8_t>> ret;
- while (arr.size() > chunkSize) {
- ret.push_back(arr.take_front(chunkSize));
- arr = arr.drop_front(chunkSize);
+ // Finally, check that all dynamic relocation addends were written correctly.
+ if (config->checkDynamicRelocs && config->writeAddends) {
+ for (OutputSection *sec : outputSections)
+ if (sec->type == SHT_REL || sec->type == SHT_RELA)
+ sec->checkDynRelAddends(Out::bufferStart);
}
- if (!arr.empty())
- ret.push_back(arr);
- return ret;
}
// Computes a hash value of Data using a given hash function.
diff --git a/gnu/llvm/lld/MachO/MergedOutputSection.cpp b/gnu/llvm/lld/MachO/MergedOutputSection.cpp
deleted file mode 100644
index 2d0be253834..00000000000
--- a/gnu/llvm/lld/MachO/MergedOutputSection.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-//===- OutputSection.cpp --------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "MergedOutputSection.h"
-#include "lld/Common/ErrorHandler.h"
-#include "lld/Common/Memory.h"
-#include "llvm/BinaryFormat/MachO.h"
-
-using namespace llvm;
-using namespace llvm::MachO;
-using namespace lld;
-using namespace lld::macho;
-
-void MergedOutputSection::mergeInput(InputSection *input) {
- if (inputs.empty()) {
- align = input->align;
- flags = input->flags;
- } else {
- mergeFlags(input->flags);
- align = std::max(align, input->align);
- }
-
- inputs.push_back(input);
- input->parent = this;
-}
-
-void MergedOutputSection::finalize() {
- uint64_t isecAddr = addr;
- uint64_t isecFileOff = fileOff;
- for (InputSection *isec : inputs) {
- isecAddr = alignTo(isecAddr, isec->align);
- isecFileOff = alignTo(isecFileOff, isec->align);
- isec->outSecOff = isecAddr - addr;
- isec->outSecFileOff = isecFileOff - fileOff;
- isecAddr += isec->getSize();
- isecFileOff += isec->getFileSize();
- }
- size = isecAddr - addr;
- fileSize = isecFileOff - fileOff;
-}
-
-void MergedOutputSection::writeTo(uint8_t *buf) const {
- for (InputSection *isec : inputs) {
- isec->writeTo(buf + isec->outSecFileOff);
- }
-}
-
-// TODO: this is most likely wrong; reconsider how section flags
-// are actually merged. The logic presented here was written without
-// any form of informed research.
-void MergedOutputSection::mergeFlags(uint32_t inputFlags) {
- uint8_t sectionFlag = MachO::SECTION_TYPE & inputFlags;
- if (sectionFlag != (MachO::SECTION_TYPE & flags))
- error("Cannot add merge section; inconsistent type flags " +
- Twine(sectionFlag));
-
- uint32_t inconsistentFlags =
- MachO::S_ATTR_DEBUG | MachO::S_ATTR_STRIP_STATIC_SYMS |
- MachO::S_ATTR_NO_DEAD_STRIP | MachO::S_ATTR_LIVE_SUPPORT;
- if ((inputFlags ^ flags) & inconsistentFlags)
- error("Cannot add merge section; cannot merge inconsistent flags");
-
- // Negate pure instruction presence if any section isn't pure.
- uint32_t pureMask = ~MachO::S_ATTR_PURE_INSTRUCTIONS | (inputFlags & flags);
-
- // Merge the rest
- flags |= inputFlags;
- flags &= pureMask;
-}
diff --git a/gnu/llvm/lld/MachO/MergedOutputSection.h b/gnu/llvm/lld/MachO/MergedOutputSection.h
deleted file mode 100644
index 279a7e0f75c..00000000000
--- a/gnu/llvm/lld/MachO/MergedOutputSection.h
+++ /dev/null
@@ -1,56 +0,0 @@
-//===- OutputSection.h ------------------------------------------*- C++ -*-===//
-//
-// 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_MACHO_MERGED_OUTPUT_SECTION_H
-#define LLD_MACHO_MERGED_OUTPUT_SECTION_H
-
-#include "InputSection.h"
-#include "OutputSection.h"
-#include "lld/Common/LLVM.h"
-#include "llvm/ADT/MapVector.h"
-
-namespace lld {
-namespace macho {
-
-// Linking multiple files will inevitably mean resolving sections in different
-// files that are labeled with the same segment and section name. This class
-// contains all such sections and writes the data from each section sequentially
-// in the final binary.
-class MergedOutputSection : public OutputSection {
-public:
- MergedOutputSection(StringRef name) : OutputSection(MergedKind, name) {}
-
- const InputSection *firstSection() const { return inputs.front(); }
- const InputSection *lastSection() const { return inputs.back(); }
-
- // These accessors will only be valid after finalizing the section
- uint64_t getSize() const override { return size; }
- uint64_t getFileSize() const override { return fileSize; }
-
- void mergeInput(InputSection *input);
- void finalize() override;
-
- void writeTo(uint8_t *buf) const override;
-
- std::vector<InputSection *> inputs;
-
- static bool classof(const OutputSection *sec) {
- return sec->kind() == MergedKind;
- }
-
-private:
- void mergeFlags(uint32_t inputFlags);
-
- size_t size = 0;
- uint64_t fileSize = 0;
-};
-
-} // namespace macho
-} // namespace lld
-
-#endif
diff --git a/gnu/llvm/lld/docs/ld.lld.1 b/gnu/llvm/lld/docs/ld.lld.1
index 92d67b17e24..86d47f24378 100644
--- a/gnu/llvm/lld/docs/ld.lld.1
+++ b/gnu/llvm/lld/docs/ld.lld.1
@@ -57,7 +57,7 @@ Do not error if a symbol is defined multiple times.
The first definition will be used.
.It Fl -allow-shlib-undefined
Allow unresolved references in shared libraries.
-This option is enabled by default when linking a shared library.
+This option is enabled by default.
.It Fl -apply-dynamic-relocs
Apply link-time values for dynamic relocations.
.It Fl -as-needed
@@ -72,10 +72,22 @@ field to the specified name.
Link against shared libraries.
.It Fl -Bstatic , Fl -static , Fl -dn
Do not link against shared libraries.
-.It Fl -Bsymbolic
-Bind defined symbols locally.
-.It Fl -Bsymbolic-functions
-Bind defined function symbols locally.
+.It Fl Bno-symbolic
+Don't bind default visibility defined symbols locally for
+.Fl shared
+(default).
+.It Fl Bsymbolic
+Bind default visibility defined symbols locally for
+.Fl shared.
+Also set the
+.Dv DF_SYMBOLIC
+flag.
+.It Fl Bsymbolic-functions
+Bind default visibility defined function symbols locally for
+.Fl shared.
+.It Fl Bsymbolic-non-weak-functions
+Bind default visibility defined STB_GLOBAL function symbols locally for
+.Fl shared.
.It Fl -build-id Ns = Ns Ar value
Generate a build ID note.
.Ar value
@@ -157,6 +169,14 @@ This is recorded in an ELF segment of type
.It Fl -dynamic-list Ns = Ns Ar file
Read a list of dynamic symbols from
.Ar file .
+(executable) Put matched non-local defined symbols to the dynamic symbol table.
+(shared object) References to matched non-local STV_DEFAULT symbols shouldn't be bound to definitions within the shared object. Implies
+.Cm -Bsymbolic
+but does not set DF_SYMBOLIC
+.It Fl -EB
+Select the big-endian format in the OUTPUT_FORMAT command.
+.It Fl -EL
+Select the little-endian format in the OUTPUT_FORMAT command.
.It Fl -eh-frame-hdr
Request creation of
.Li .eh_frame_hdr
@@ -177,6 +197,19 @@ Maximum number of errors to emit before stopping.
A value of zero indicates that there is no limit.
.It Fl -error-unresolved-symbols
Report unresolved symbols as errors.
+.It Fl -error-handing-script Ns = Ns Ar script_path
+Call script
+.Ar script_path
+upon some error, with
+.Ar tag
+as first argument, and an extra parameter as second argument. The script is
+expected to return 0 on success. Any other value is considered a generic error.
+.Ar tag
+may be
+.Cm missing-lib
+followed by the name of the missing library.
+.Cm undefined-symbol
+followed by the name of the undefined symbol.
.It Fl -execute-only
Mark executable sections unreadable.
This option is currently only supported on AArch64.
@@ -184,10 +217,14 @@ This option is currently only supported on AArch64.
Exclude static libraries from automatic export.
.It Fl -export-dynamic , Fl E
Put symbols in the dynamic symbol table.
-.It Fl -export-dynamic-symbol Ns = Ns Ar symbol
-Include
-.Ar symbol
-in the dynamic symbol table.
+.It Fl -export-dynamic-symbol Ns = Ns Ar glob
+(executable) Put matched non-local defined symbols to the dynamic symbol table.
+(shared object) References to matched non-local STV_DEFAULT symbols shouldn't be bound to definitions within the shared object even if they would otherwise be due to
+.Cm -Bsymbolic
+,
+.Cm -Bsymbolic-functions
+or
+.Cm --dynamic-list
.It Fl -fatal-warnings
Treat warnings as errors.
.It Fl -filter Ns = Ns Ar value , Fl F Ar value
@@ -275,7 +312,7 @@ Print a link map to
Do not page align sections, link against static libraries.
.It Fl -no-allow-shlib-undefined
Do not allow unresolved references in shared libraries.
-This option is enabled by default when linking an executable.
+This option is disabled by default.
.It Fl -no-as-needed
Always set
.Dv DT_NEEDED
@@ -290,6 +327,8 @@ Do not demangle symbol names.
Inhibit output of an
.Li .interp
section.
+.It Fl -no-fortran-common
+Do not search archive members for definitions to override COMMON symbols.
.It Fl -no-gc-sections
Disable garbage collection of unused sections.
.It Fl -no-gnu-unique
@@ -300,10 +339,10 @@ Disable merging .ARM.exidx entries.
Page align sections.
.It Fl -no-omagic
Do not set the text data sections to be writable, page align sections.
+.It Fl -no-relax
+Disable target-specific relaxations. This is currently a no-op.
.It Fl -no-rosegment
Do not put read-only non-executable sections in their own segment.
-.It Fl -no-threads
-Do not run the linker multi-threaded.
.It Fl -no-undefined-version
Report version scripts that refer undefined symbols.
.It Fl -no-undefined
@@ -416,6 +455,9 @@ List removed unused sections.
List identical folded sections.
.It Fl -print-map
Print a link map to the standard output.
+.It Fl -print-archive-stats Ns = Ns Ar file
+Write archive usage statistics to the specified file.
+Print the numbers of members and fetched members for each archive.
.It Fl -push-state
Save the current state of
.Fl -as-needed ,
@@ -456,6 +498,9 @@ were concatenated in the order they appeared on the command line.
Set address of section.
.It Fl -shared , Fl -Bsharable
Build a shared object.
+.It Fl -shuffle-sections Ns = Ns Ar seed
+Shuffle matched sections using the given seed before mapping them to the output sections.
+If -1, reverse the section order. If 0, use a random seed.
.It Fl -soname Ns = Ns Ar value , Fl h Ar value
Set
.Dv DT_SONAME
@@ -470,6 +515,8 @@ Start a grouping of objects that should be treated as if they were together
in an archive.
.It Fl -strip-all , Fl s
Strip all symbols.
+Implies
+.Fl -strip-debug .
.It Fl -strip-debug , Fl S
Strip debugging information.
.It Fl -symbol-ordering-file Ns = Ns Ar file
@@ -523,9 +570,19 @@ Path to ThinLTO cached object file directory.
Pruning policy for the ThinLTO cache.
.It Fl -thinlto-jobs Ns = Ns Ar value
Number of ThinLTO jobs.
-.It Fl -threads
-Run the linker multi-threaded.
-This option is enabled by default.
+.It Fl -threads Ns = Ns Ar N
+Number of threads.
+.Cm all
+(default) means all of concurrent threads supported.
+.Cm 1
+disables multi-threading.
+.It Fl -time-trace
+Record time trace.
+.It Fl -time-trace-file Ns = Ns Ar file
+Write time trace output to
+.Ar file .
+.It Fl -time-trace-granularity Ns = Ns Ar value
+Minimum time granularity (in microseconds) traced by time profiler.
.It Fl -trace
Print the names of the input files.
.It Fl -trace-symbol Ns = Ns Ar symbol , Fl y Ar symbol
@@ -551,6 +608,8 @@ matches the characters within brackets.
All symbols that match
a given pattern are handled as if they were given as arguments of
.Fl -undefined .
+.It Fl -unique
+Creates a separate output section for every orphan input section.
.It Fl -unresolved-symbols Ns = Ns Ar value
Determine how to handle unresolved symbols.
.It Fl -use-android-relr-tags
@@ -569,6 +628,10 @@ Read version script from
Warn about reverse or cyclic dependencies to or between static archives.
This can be used to ensure linker invocation remains compatible with
traditional Unix-like linkers.
+.It Fl -warn-backrefs-exclude Ns = Ns Ar glob
+Glob describing an archive (or an object file within --start-lib)
+which should be ignored for
+.Fl -warn-backrefs
.It Fl -warn-common
Warn about duplicate common symbols.
.It Fl -warn-ifunc-textrel
@@ -591,11 +654,25 @@ Report unresolved symbols as warnings.
.It Fl -whole-archive
Force load of all members in a static library.
.It Fl -wrap Ns = Ns Ar symbol
-Use wrapper functions for symbol.
+Redirect
+.Ar symbol
+references to
+.Ar __wrap_symbol
+and
+.Ar __real_symbol
+references to
+.Ar symbol.
.It Fl z Ar option
Linker option extensions.
.Bl -tag -width indent -compact
.Pp
+.It Cm dead-reloc-in-nonalloc Ns = Ns Ar section_glob=value
+Resolve a relocation in a matched non-SHF_ALLOC section referencing a discarded symbol to
+.Ar value
+Accepts globs, in the event of a section matching more than one option, the last
+option takes precedence. An order of least specific to most specific match is
+recommended.
+.Pp
.It Cm execstack
Make the main stack executable.
Stack permissions are recorded in the
@@ -701,6 +778,12 @@ processing.
.It Cm pac-plt
AArch64 only, use pointer authentication in PLT.
.Pp
+.It Cm rel
+Use REL format for dynamic relocations.
+.Pp
+.It Cm rela
+Use RELA format for dynamic relocations.
+.Pp
.It Cm retpolineplt
Emit retpoline format PLT entries as a mitigation for CVE-2017-5715.
.Pp
@@ -734,6 +817,12 @@ The stack size is recorded as the size of the
.Dv PT_GNU_STACK
program segment.
.Pp
+.It Cm start-stop-gc
+Don't let __start_/__stop_ references retain the associated C identifier name sections (default).
+.Pp
+.It Cm nostart-stop-gc
+Let __start_/__stop_ references retain the associated C identifier name sections.
+.Pp
.It Cm text
Do not allow relocations against read-only segments.
This is the default.
diff --git a/gnu/llvm/lld/tools/lld/lld.cpp b/gnu/llvm/lld/tools/lld/lld.cpp
index 4b3d54d1be4..8d76f25b372 100644
--- a/gnu/llvm/lld/tools/lld/lld.cpp
+++ b/gnu/llvm/lld/tools/lld/lld.cpp
@@ -26,6 +26,7 @@
//===----------------------------------------------------------------------===//
#include "lld/Common/Driver.h"
+#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
@@ -33,6 +34,7 @@
#include "llvm/ADT/Triple.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/Path.h"
@@ -48,11 +50,11 @@ enum Flavor {
Gnu, // -flavor gnu
WinLink, // -flavor link
Darwin, // -flavor darwin
- DarwinNew, // -flavor darwinnew
+ DarwinOld, // -flavor darwinold
Wasm, // -flavor wasm
};
-LLVM_ATTRIBUTE_NORETURN static void die(const Twine &s) {
+[[noreturn]] static void die(const Twine &s) {
llvm::errs() << s << "\n";
exit(1);
}
@@ -62,8 +64,9 @@ static Flavor getFlavor(StringRef s) {
.CasesLower("ld", "ld.lld", "gnu", Gnu)
.CasesLower("wasm", "ld-wasm", Wasm)
.CaseLower("link", WinLink)
- .CasesLower("ld64", "ld64.lld", "darwin", Darwin)
- .CaseLower("darwinnew", DarwinNew)
+ .CasesLower("ld64", "ld64.lld", "darwin", "darwinnew",
+ "ld64.lld.darwinnew", Darwin)
+ .CasesLower("darwinold", "ld64.lld.darwinold", DarwinOld)
.Default(Invalid);
}
@@ -93,7 +96,12 @@ static bool isPETarget(std::vector<const char *> &v) {
continue;
return isPETargetName(*(it + 1));
}
+
+#ifdef LLD_DEFAULT_LD_LLD_IS_MINGW
+ return true;
+#else
return false;
+#endif
}
#endif
@@ -125,41 +133,32 @@ static Flavor parseFlavor(std::vector<const char *> &v) {
// Deduct the flavor from argv[0].
StringRef arg0 = path::filename(v[0]);
- if (arg0.endswith_lower(".exe"))
+ if (arg0.endswith_insensitive(".exe"))
arg0 = arg0.drop_back(4);
return parseProgname(arg0);
}
-// If this function returns true, lld calls _exit() so that it quickly
-// exits without invoking destructors of globally allocated objects.
-//
-// We don't want to do that if we are running tests though, because
-// doing that breaks leak sanitizer. So, lit sets this environment variable,
-// and we use it to detect whether we are running tests or not.
-static bool canExitEarly() { return StringRef(getenv("LLD_IN_TEST")) != "1"; }
-
/// Universal linker main(). This linker emulates the gnu, darwin, or
/// windows linker based on the argv[0] or -flavor option.
-int main(int argc, const char **argv) {
- InitLLVM x(argc, argv);
-
+static int lldMain(int argc, const char **argv, llvm::raw_ostream &stdoutOS,
+ llvm::raw_ostream &stderrOS, bool exitEarly = true) {
std::vector<const char *> args(argv, argv + argc);
switch (parseFlavor(args)) {
case Gnu:
#ifndef __OpenBSD__
if (isPETarget(args))
- return !mingw::link(args, canExitEarly(), llvm::outs(), llvm::errs());
+ return !mingw::link(args, exitEarly, stdoutOS, stderrOS);
#endif
- return !elf::link(args, canExitEarly(), llvm::outs(), llvm::errs());
+ return !elf::link(args, exitEarly, stdoutOS, stderrOS);
#ifndef __OpenBSD__
case WinLink:
- return !coff::link(args, canExitEarly(), llvm::outs(), llvm::errs());
+ return !coff::link(args, exitEarly, stdoutOS, stderrOS);
case Darwin:
- return !mach_o::link(args, canExitEarly(), llvm::outs(), llvm::errs());
- case DarwinNew:
- return !macho::link(args, canExitEarly(), llvm::outs(), llvm::errs());
+ return !macho::link(args, exitEarly, stdoutOS, stderrOS);
+ case DarwinOld:
+ return !mach_o::link(args, exitEarly, stdoutOS, stderrOS);
case Wasm:
- return !wasm::link(args, canExitEarly(), llvm::outs(), llvm::errs());
+ return !lld::wasm::link(args, exitEarly, stdoutOS, stderrOS);
#endif
default:
die("lld is a generic driver.\n"
@@ -167,3 +166,70 @@ int main(int argc, const char **argv) {
" (WebAssembly) instead");
}
}
+
+// Similar to lldMain except that exceptions are caught.
+SafeReturn lld::safeLldMain(int argc, const char **argv,
+ llvm::raw_ostream &stdoutOS,
+ llvm::raw_ostream &stderrOS) {
+ int r = 0;
+ {
+ // The crash recovery is here only to be able to recover from arbitrary
+ // control flow when fatal() is called (through setjmp/longjmp or
+ // __try/__except).
+ llvm::CrashRecoveryContext crc;
+ if (!crc.RunSafely([&]() {
+ r = lldMain(argc, argv, stdoutOS, stderrOS, /*exitEarly=*/false);
+ }))
+ return {crc.RetCode, /*canRunAgain=*/false};
+ }
+
+ // Cleanup memory and reset everything back in pristine condition. This path
+ // is only taken when LLD is in test, or when it is used as a library.
+ llvm::CrashRecoveryContext crc;
+ if (!crc.RunSafely([&]() { errorHandler().reset(); })) {
+ // The memory is corrupted beyond any possible recovery.
+ return {r, /*canRunAgain=*/false};
+ }
+ return {r, /*canRunAgain=*/true};
+}
+
+// When in lit tests, tells how many times the LLD tool should re-execute the
+// main loop with the same inputs. When not in test, returns a value of 0 which
+// signifies that LLD shall not release any memory after execution, to speed up
+// process destruction.
+static unsigned inTestVerbosity() {
+ unsigned v = 0;
+ StringRef(getenv("LLD_IN_TEST")).getAsInteger(10, v);
+ return v;
+}
+
+int main(int argc, const char **argv) {
+ InitLLVM x(argc, argv);
+
+ // Not running in lit tests, just take the shortest codepath with global
+ // exception handling and no memory cleanup on exit.
+ if (!inTestVerbosity())
+ return lldMain(argc, argv, llvm::outs(), llvm::errs());
+
+ Optional<int> mainRet;
+ CrashRecoveryContext::Enable();
+
+ for (unsigned i = inTestVerbosity(); i > 0; --i) {
+ // Disable stdout/stderr for all iterations but the last one.
+ if (i != 1)
+ errorHandler().disableOutput = true;
+
+ // Execute one iteration.
+ auto r = safeLldMain(argc, argv, llvm::outs(), llvm::errs());
+ if (!r.canRunAgain)
+ exitLld(r.ret); // Exit now, can't re-execute again.
+
+ if (!mainRet) {
+ mainRet = r.ret;
+ } else if (r.ret != *mainRet) {
+ // Exit now, to fail the tests if the result is different between runs.
+ return r.ret;
+ }
+ }
+ return *mainRet;
+}
diff --git a/gnu/llvm/lld/wasm/InputEvent.h b/gnu/llvm/lld/wasm/InputEvent.h
deleted file mode 100644
index 98cfdf7bfc7..00000000000
--- a/gnu/llvm/lld/wasm/InputEvent.h
+++ /dev/null
@@ -1,62 +0,0 @@
-//===- InputEvent.h ---------------------------------------------*- C++ -*-===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-//
-// Wasm events are features that suspend the current execution and transfer the
-// control flow to a corresponding handler. Currently the only supported event
-// kind is exceptions.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_WASM_INPUT_EVENT_H
-#define LLD_WASM_INPUT_EVENT_H
-
-#include "Config.h"
-#include "InputFiles.h"
-#include "WriterUtils.h"
-#include "lld/Common/ErrorHandler.h"
-#include "llvm/Object/Wasm.h"
-
-namespace lld {
-namespace wasm {
-
-// Represents a single Wasm Event within an input file. These are combined to
-// form the final EVENTS section.
-class InputEvent {
-public:
- InputEvent(const WasmSignature &s, const WasmEvent &e, ObjFile *f)
- : file(f), event(e), signature(s), live(!config->gcSections) {}
-
- StringRef getName() const { return event.SymbolName; }
- const WasmEventType &getType() const { return event.Type; }
-
- uint32_t getEventIndex() const { return eventIndex.getValue(); }
- bool hasEventIndex() const { return eventIndex.hasValue(); }
- void setEventIndex(uint32_t index) {
- assert(!hasEventIndex());
- eventIndex = index;
- }
-
- ObjFile *file;
- WasmEvent event;
- const WasmSignature &signature;
-
- bool live = false;
-
-protected:
- llvm::Optional<uint32_t> eventIndex;
-};
-
-} // namespace wasm
-
-inline std::string toString(const wasm::InputEvent *e) {
- return (toString(e->file) + ":(" + e->getName() + ")").str();
-}
-
-} // namespace lld
-
-#endif // LLD_WASM_INPUT_EVENT_H
diff --git a/gnu/llvm/lld/wasm/InputGlobal.h b/gnu/llvm/lld/wasm/InputGlobal.h
deleted file mode 100644
index 89cde8423c8..00000000000
--- a/gnu/llvm/lld/wasm/InputGlobal.h
+++ /dev/null
@@ -1,55 +0,0 @@
-//===- InputGlobal.h --------------------------------------------*- C++ -*-===//
-//
-// 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_WASM_INPUT_GLOBAL_H
-#define LLD_WASM_INPUT_GLOBAL_H
-
-#include "Config.h"
-#include "InputFiles.h"
-#include "WriterUtils.h"
-#include "lld/Common/ErrorHandler.h"
-#include "llvm/Object/Wasm.h"
-
-namespace lld {
-namespace wasm {
-
-// Represents a single Wasm Global Variable within an input file. These are
-// combined to form the final GLOBALS section.
-class InputGlobal {
-public:
- InputGlobal(const WasmGlobal &g, ObjFile *f)
- : file(f), global(g), live(!config->gcSections) {}
-
- StringRef getName() const { return global.SymbolName; }
- const WasmGlobalType &getType() const { return global.Type; }
-
- uint32_t getGlobalIndex() const { return globalIndex.getValue(); }
- bool hasGlobalIndex() const { return globalIndex.hasValue(); }
- void setGlobalIndex(uint32_t index) {
- assert(!hasGlobalIndex());
- globalIndex = index;
- }
-
- ObjFile *file;
- WasmGlobal global;
-
- bool live = false;
-
-protected:
- llvm::Optional<uint32_t> globalIndex;
-};
-
-} // namespace wasm
-
-inline std::string toString(const wasm::InputGlobal *g) {
- return (toString(g->file) + ":(" + g->getName() + ")").str();
-}
-
-} // namespace lld
-
-#endif // LLD_WASM_INPUT_GLOBAL_H