summaryrefslogtreecommitdiff
path: root/gnu/llvm/tools/lld
diff options
context:
space:
mode:
authorPatrick Wildt <patrick@cvs.openbsd.org>2019-01-27 16:55:49 +0000
committerPatrick Wildt <patrick@cvs.openbsd.org>2019-01-27 16:55:49 +0000
commitd2b88c64b549558966af5953df1c67566469d7f6 (patch)
treefde23164f74edc9d75011244cc82cefe9fae7b31 /gnu/llvm/tools/lld
parentb6a478d7aa2abf7e6e7aeb293b0c77a6b00edb64 (diff)
Merge LLVM 7.0.1 release.
With fixes from mortimer@ (thanks!) Tested by many, especially naddy@ (thanks!)
Diffstat (limited to 'gnu/llvm/tools/lld')
-rw-r--r--gnu/llvm/tools/lld/ELF/Config.h59
-rw-r--r--gnu/llvm/tools/lld/ELF/Driver.cpp619
-rw-r--r--gnu/llvm/tools/lld/ELF/DriverUtils.cpp57
-rw-r--r--gnu/llvm/tools/lld/ELF/LinkerScript.cpp383
-rw-r--r--gnu/llvm/tools/lld/ELF/Options.td524
-rw-r--r--gnu/llvm/tools/lld/ELF/OutputSections.cpp81
-rw-r--r--gnu/llvm/tools/lld/ELF/Relocations.cpp809
-rw-r--r--gnu/llvm/tools/lld/ELF/SymbolTable.cpp297
-rw-r--r--gnu/llvm/tools/lld/ELF/Symbols.cpp97
-rw-r--r--gnu/llvm/tools/lld/ELF/Symbols.h159
-rw-r--r--gnu/llvm/tools/lld/ELF/SyntheticSections.cpp1538
-rw-r--r--gnu/llvm/tools/lld/ELF/Writer.cpp741
-rw-r--r--gnu/llvm/tools/lld/docs/ld.lld.1178
-rw-r--r--gnu/llvm/tools/lld/tools/lld/lld.cpp49
14 files changed, 3560 insertions, 2031 deletions
diff --git a/gnu/llvm/tools/lld/ELF/Config.h b/gnu/llvm/tools/lld/ELF/Config.h
index c7b58cf5b86..81c141ca011 100644
--- a/gnu/llvm/tools/lld/ELF/Config.h
+++ b/gnu/llvm/tools/lld/ELF/Config.h
@@ -10,6 +10,7 @@
#ifndef LLD_ELF_CONFIG_H
#define LLD_ELF_CONFIG_H
+#include "lld/Common/ErrorHandler.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
@@ -17,13 +18,13 @@
#include "llvm/Support/CachePruning.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/Endian.h"
-
#include <vector>
namespace lld {
namespace elf {
class InputFile;
+class InputSectionBase;
enum ELFKind {
ELFNoneKind,
@@ -39,6 +40,9 @@ enum class BuildIdKind { None, Fast, Md5, Sha1, Hexstring, Uuid };
// For --discard-{all,locals,none}.
enum class DiscardPolicy { Default, All, Locals, None };
+// For --icf={none,safe,all}.
+enum class ICFLevel { None, Safe, All };
+
// For --strip-{all,debug}.
enum class StripPolicy { None, All, Debug };
@@ -54,6 +58,9 @@ enum class SortSectionPolicy { Default, None, Alignment, Name, Priority };
// For --target2
enum class Target2Policy { Abs, Rel, GotRel };
+// For tracking ARM Float Argument PCS
+enum class ARMVFPArgKind { Default, Base, VFP, ToolChain };
+
struct SymbolVersion {
llvm::StringRef Name;
bool IsExternCpp;
@@ -79,21 +86,27 @@ struct Configuration {
llvm::StringMap<uint64_t> SectionStartMap;
llvm::StringRef Chroot;
llvm::StringRef DynamicLinker;
+ llvm::StringRef DwoDir;
llvm::StringRef Entry;
llvm::StringRef Emulation;
llvm::StringRef Fini;
llvm::StringRef Init;
llvm::StringRef LTOAAPipeline;
llvm::StringRef LTONewPmPasses;
+ llvm::StringRef LTOObjPath;
+ llvm::StringRef LTOSampleProfile;
llvm::StringRef MapFile;
llvm::StringRef OutputFile;
llvm::StringRef OptRemarksFilename;
+ llvm::StringRef ProgName;
llvm::StringRef SoName;
llvm::StringRef Sysroot;
llvm::StringRef ThinLTOCacheDir;
+ llvm::StringRef ThinLTOIndexOnlyArg;
+ std::pair<llvm::StringRef, llvm::StringRef> ThinLTOObjectSuffixReplace;
+ std::pair<llvm::StringRef, llvm::StringRef> ThinLTOPrefixReplace;
std::string Rpath;
std::vector<VersionDefinition> VersionDefinitions;
- std::vector<llvm::StringRef> Argv;
std::vector<llvm::StringRef> AuxiliaryList;
std::vector<llvm::StringRef> FilterList;
std::vector<llvm::StringRef> SearchPaths;
@@ -103,34 +116,41 @@ struct Configuration {
std::vector<SymbolVersion> VersionScriptGlobals;
std::vector<SymbolVersion> VersionScriptLocals;
std::vector<uint8_t> BuildIdVector;
+ llvm::MapVector<std::pair<const InputSectionBase *, const InputSectionBase *>,
+ uint64_t>
+ CallGraphProfile;
bool AllowMultipleDefinition;
- bool AndroidPackDynRelocs = false;
+ bool AndroidPackDynRelocs;
bool ARMHasBlx = false;
bool ARMHasMovtMovw = false;
bool ARMJ1J2BranchEncoding = false;
bool AsNeeded = false;
bool Bsymbolic;
bool BsymbolicFunctions;
+ bool CheckSections;
bool CompressDebugSections;
+ bool Cref;
bool DefineCommon;
bool Demangle = true;
bool DisableVerify;
bool EhFrameHdr;
bool EmitRelocs;
bool EnableNewDtags;
+ bool ExecuteOnly;
bool ExportDynamic;
bool FixCortexA53Errata843419;
bool GcSections;
bool GdbIndex;
bool GnuHash = false;
+ bool GnuUnique;
bool HasDynamicList = false;
bool HasDynSymTab;
- bool ICF;
- bool ICFData;
+ bool IgnoreDataAddressEquality;
+ bool IgnoreFunctionAddressEquality;
+ bool LTODebugPassManager;
+ bool LTONewPassManager;
bool MergeArmExidx;
bool MipsN32Abi = false;
- bool NoGnuUnique;
- bool NoUndefinedVersion;
bool NoinhibitExec;
bool Nostdlib;
bool OFormatBinary;
@@ -138,7 +158,9 @@ struct Configuration {
bool OptRemarksWithHotness;
bool Pie;
bool PrintGcSections;
+ bool PrintIcfSections;
bool Relocatable;
+ bool RelrPackDynRelocs;
bool SaveTemps;
bool SingleRoRx;
bool Shared;
@@ -146,13 +168,22 @@ struct Configuration {
bool SysvHash = false;
bool Target1Rel;
bool Trace;
- bool Verbose;
+ bool ThinLTOEmitImportsFiles;
+ bool ThinLTOIndexOnly;
+ bool UndefinedVersion;
+ bool UseAndroidRelrTags = false;
+ bool WarnBackrefs;
bool WarnCommon;
bool WarnMissingEntry;
+ bool WarnSymbolOrdering;
+ bool WriteAddends;
bool ZCombreloc;
+ bool ZCopyreloc;
bool ZExecstack;
+ bool ZHazardplt;
bool ZInitfirst;
- bool ZNocopyreloc;
+ bool ZInterpose;
+ bool ZKeepTextSectionPrefix;
bool ZNodelete;
bool ZNodlopen;
bool ZNow;
@@ -161,20 +192,22 @@ struct Configuration {
bool ZRodynamic;
bool ZText;
bool ZRetpolineplt;
- bool ExitEarly;
bool ZWxneeded;
DiscardPolicy Discard;
+ ICFLevel ICF;
OrphanHandlingPolicy OrphanHandling;
SortSectionPolicy SortSection;
StripPolicy Strip;
UnresolvedPolicy UnresolvedSymbols;
Target2Policy Target2;
+ ARMVFPArgKind ARMVFPArgs = ARMVFPArgKind::Default;
BuildIdKind BuildId = BuildIdKind::None;
ELFKind EKind = ELFNoneKind;
uint16_t DefaultSymbolVersion = llvm::ELF::VER_NDX_GLOBAL;
uint16_t EMachine = llvm::ELF::EM_NONE;
llvm::Optional<uint64_t> ImageBase;
uint64_t MaxPageSize;
+ uint64_t MipsGotSize;
uint64_t ZStackSize;
unsigned LTOPartitions;
unsigned LTOO;
@@ -240,6 +273,12 @@ struct Configuration {
// The only instance of Configuration struct.
extern Configuration *Config;
+static inline void errorOrWarn(const Twine &Msg) {
+ if (!Config->NoinhibitExec)
+ error(Msg);
+ else
+ warn(Msg);
+}
} // namespace elf
} // namespace lld
diff --git a/gnu/llvm/tools/lld/ELF/Driver.cpp b/gnu/llvm/tools/lld/ELF/Driver.cpp
index 602c72058c4..5d8e5d84a37 100644
--- a/gnu/llvm/tools/lld/ELF/Driver.cpp
+++ b/gnu/llvm/tools/lld/ELF/Driver.cpp
@@ -30,9 +30,9 @@
#include "InputFiles.h"
#include "InputSection.h"
#include "LinkerScript.h"
+#include "MarkLive.h"
#include "OutputSections.h"
#include "ScriptParser.h"
-#include "Strings.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "SyntheticSections.h"
@@ -42,12 +42,16 @@
#include "lld/Common/Driver.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
+#include "lld/Common/Strings.h"
+#include "lld/Common/TargetOptionsCommandFlags.h"
#include "lld/Common/Threads.h"
#include "lld/Common/Version.h"
+#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compression.h"
+#include "llvm/Support/LEB128.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/TarWriter.h"
#include "llvm/Support/TargetSelect.h"
@@ -66,16 +70,18 @@ using namespace lld::elf;
Configuration *elf::Config;
LinkerDriver *elf::Driver;
-static void setConfigs();
+static void setConfigs(opt::InputArgList &Args);
bool elf::link(ArrayRef<const char *> Args, bool CanExitEarly,
raw_ostream &Error) {
- errorHandler().LogName = Args[0];
+ errorHandler().LogName = sys::path::filename(Args[0]);
errorHandler().ErrorLimitExceededMsg =
"too many errors emitted, stopping now (use "
"-error-limit=0 to see all errors)";
errorHandler().ErrorOS = &Error;
+ errorHandler().ExitEarly = CanExitEarly;
errorHandler().ColorDiagnostics = Error.has_colors();
+
InputSections.clear();
OutputSections.clear();
Tar = nullptr;
@@ -88,14 +94,14 @@ bool elf::link(ArrayRef<const char *> Args, bool CanExitEarly,
Driver = make<LinkerDriver>();
Script = make<LinkerScript>();
Symtab = make<SymbolTable>();
- Config->Argv = {Args.begin(), Args.end()};
+ Config->ProgName = Args[0];
- Driver->main(Args, CanExitEarly);
+ Driver->main(Args);
// Exit immediately if we don't need to return to the caller.
// This saves time because the overhead of calling destructors
// for all globally-allocated objects is not negligible.
- if (Config->ExitEarly)
+ if (CanExitEarly)
exitLld(errorCount() ? 1 : 0);
freeArena();
@@ -113,7 +119,8 @@ 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", {ELF64LEKind, EM_AARCH64})
+ .Cases("aarch64elf", "aarch64linux", "aarch64_elf64_le_vec",
+ {ELF64LEKind, EM_AARCH64})
.Cases("armelf", "armelf_linux_eabi", {ELF32LEKind, EM_ARM})
.Case("elf32_x86_64", {ELF32LEKind, EM_X86_64})
.Cases("elf32btsmip", "elf32btsmipn32", {ELF32BEKind, EM_MIPS})
@@ -122,6 +129,7 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef Emul) {
.Case("elf64btsmip", {ELF64BEKind, EM_MIPS})
.Case("elf64ltsmip", {ELF64LEKind, EM_MIPS})
.Case("elf64ppc", {ELF64BEKind, EM_PPC64})
+ .Case("elf64lppc", {ELF64LEKind, EM_PPC64})
.Cases("elf_amd64", "elf_x86_64", {ELF64LEKind, EM_X86_64})
.Case("elf_i386", {ELF32LEKind, EM_386})
.Case("elf_iamcu", {ELF32LEKind, EM_IAMCU})
@@ -228,11 +236,15 @@ void LinkerDriver::addFile(StringRef Path, bool WithLOption) {
Files.push_back(
createSharedFile(MBRef, WithLOption ? path::filename(Path) : Path));
return;
- default:
+ case file_magic::bitcode:
+ case file_magic::elf_relocatable:
if (InLib)
Files.push_back(make<LazyObjFile>(MBRef, "", 0));
else
Files.push_back(createObjectFile(MBRef));
+ break;
+ default:
+ error(Path + ": unknown file type");
}
}
@@ -248,18 +260,11 @@ void LinkerDriver::addLibrary(StringRef Name) {
// LTO calls LLVM functions to compile bitcode files to native code.
// Technically this can be delayed until we read bitcode files, but
// we don't bother to do lazily because the initialization is fast.
-static void initLLVM(opt::InputArgList &Args) {
+static void initLLVM() {
InitializeAllTargets();
InitializeAllTargetMCs();
InitializeAllAsmPrinters();
InitializeAllAsmParsers();
-
- // Parse and evaluate -mllvm options.
- std::vector<const char *> V;
- V.push_back("lld (LLVM option parsing)");
- for (auto *Arg : Args.filtered(OPT_mllvm))
- V.push_back(Arg->getValue());
- cl::ParseCommandLineOptions(V.size(), V.data());
}
// Some command line options or some combinations of them are not allowed.
@@ -290,11 +295,21 @@ static void checkOptions(opt::InputArgList &Args) {
error("-r and -shared may not be used together");
if (Config->GcSections)
error("-r and --gc-sections may not be used together");
- if (Config->ICF)
+ if (Config->GdbIndex)
+ error("-r and --gdb-index may not be used together");
+ if (Config->ICF != ICFLevel::None)
error("-r and --icf may not be used together");
if (Config->Pie)
error("-r and -pie may not be used together");
}
+
+ if (Config->ExecuteOnly) {
+ if (Config->EMachine != EM_AARCH64)
+ error("-execute-only is only supported on AArch64 targets");
+
+ if (Config->SingleRoRx && !Script->HasSectionsCommand)
+ error("-execute-only and -no-rosegment cannot be used together");
+ }
}
static const char *getReproduceOption(opt::InputArgList &Args) {
@@ -310,7 +325,38 @@ static bool hasZOption(opt::InputArgList &Args, StringRef Key) {
return false;
}
-void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) {
+static bool getZFlag(opt::InputArgList &Args, StringRef K1, StringRef K2,
+ bool Default) {
+ for (auto *Arg : Args.filtered_reverse(OPT_z)) {
+ if (K1 == Arg->getValue())
+ return true;
+ if (K2 == Arg->getValue())
+ return false;
+ }
+ return Default;
+}
+
+static bool isKnown(StringRef S) {
+ return S == "combreloc" || S == "copyreloc" || S == "defs" ||
+ S == "execstack" || S == "hazardplt" || S == "initfirst" ||
+ S == "interpose" ||
+ S == "keep-text-section-prefix" || S == "lazy" || S == "muldefs" ||
+ S == "nocombreloc" || S == "nocopyreloc" || S == "nodelete" ||
+ S == "nodlopen" || S == "noexecstack" ||
+ S == "nokeep-text-section-prefix" || S == "norelro" || S == "notext" ||
+ S == "now" || S == "origin" || S == "relro" || S == "retpolineplt" ||
+ S == "rodynamic" || S == "text" || S == "wxneeded" ||
+ S.startswith("max-page-size=") || S.startswith("stack-size=");
+}
+
+// Report an error for an unknown -z option.
+static void checkZOptions(opt::InputArgList &Args) {
+ for (auto *Arg : Args.filtered(OPT_z))
+ if (!isKnown(Arg->getValue()))
+ error("unknown -z value: " + StringRef(Arg->getValue()));
+}
+
+void LinkerDriver::main(ArrayRef<const char *> ArgsArr) {
ELFOptTable Parser;
opt::InputArgList Args = Parser.parse(ArgsArr.slice(1));
@@ -319,7 +365,7 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) {
// Handle -help
if (Args.hasArg(OPT_help)) {
- printHelp(ArgsArr[0]);
+ printHelp();
return;
}
@@ -348,9 +394,6 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) {
if (Args.hasArg(OPT_version))
return;
- Config->ExitEarly = CanExitEarly && !Args.hasArg(OPT_full_shutdown);
- errorHandler().ExitEarly = Config->ExitEarly;
-
if (const char *Path = getReproduceOption(Args)) {
// Note that --reproduce is a debug option so you can ignore it
// if you are trying to understand the whole picture of the code.
@@ -368,10 +411,14 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) {
}
readConfigs(Args);
- initLLVM(Args);
+ checkZOptions(Args);
+ initLLVM();
createFiles(Args);
+ if (errorCount())
+ return;
+
inferMachineType();
- setConfigs();
+ setConfigs(Args);
checkOptions(Args);
if (errorCount())
return;
@@ -455,6 +502,8 @@ static bool isOutputFormatBinary(opt::InputArgList &Args) {
StringRef S = Arg->getValue();
if (S == "binary")
return true;
+ if (S.startswith("elf"))
+ return false;
error("unknown --oformat value: " + S);
}
return false;
@@ -482,6 +531,15 @@ static StringRef getDynamicLinker(opt::InputArgList &Args) {
return Arg->getValue();
}
+static ICFLevel getICF(opt::InputArgList &Args) {
+ auto *Arg = Args.getLastArg(OPT_icf_none, OPT_icf_safe, OPT_icf_all);
+ if (!Arg || Arg->getOption().getID() == OPT_icf_none)
+ return ICFLevel::None;
+ if (Arg->getOption().getID() == OPT_icf_safe)
+ return ICFLevel::Safe;
+ return ICFLevel::All;
+}
+
static StripPolicy getStrip(opt::InputArgList &Args) {
if (Args.hasArg(OPT_relocatable))
return StripPolicy::None;
@@ -556,6 +614,8 @@ getBuildId(opt::InputArgList &Args) {
return {BuildIdKind::Fast, {}};
StringRef S = Arg->getValue();
+ if (S == "fast")
+ return {BuildIdKind::Fast, {}};
if (S == "md5")
return {BuildIdKind::Md5, {}};
if (S == "sha1" || S == "tree")
@@ -570,6 +630,57 @@ getBuildId(opt::InputArgList &Args) {
return {BuildIdKind::None, {}};
}
+static std::pair<bool, bool> getPackDynRelocs(opt::InputArgList &Args) {
+ StringRef S = Args.getLastArgValue(OPT_pack_dyn_relocs, "none");
+ if (S == "android")
+ return {true, false};
+ if (S == "relr")
+ return {false, true};
+ if (S == "android+relr")
+ return {true, true};
+
+ if (S != "none")
+ error("unknown -pack-dyn-relocs format: " + S);
+ return {false, false};
+}
+
+static void readCallGraph(MemoryBufferRef MB) {
+ // Build a map from symbol name to section
+ DenseMap<StringRef, const Symbol *> SymbolNameToSymbol;
+ for (InputFile *File : ObjectFiles)
+ for (Symbol *Sym : File->getSymbols())
+ SymbolNameToSymbol[Sym->getName()] = Sym;
+
+ for (StringRef L : args::getLines(MB)) {
+ SmallVector<StringRef, 3> Fields;
+ L.split(Fields, ' ');
+ uint64_t Count;
+ if (Fields.size() != 3 || !to_integer(Fields[2], Count))
+ fatal(MB.getBufferIdentifier() + ": parse error");
+ const Symbol *FromSym = SymbolNameToSymbol.lookup(Fields[0]);
+ const Symbol *ToSym = SymbolNameToSymbol.lookup(Fields[1]);
+ if (Config->WarnSymbolOrdering) {
+ if (!FromSym)
+ warn(MB.getBufferIdentifier() + ": no such symbol: " + Fields[0]);
+ if (!ToSym)
+ warn(MB.getBufferIdentifier() + ": no such symbol: " + Fields[1]);
+ }
+ if (!FromSym || !ToSym || Count == 0)
+ continue;
+ warnUnorderableSymbol(FromSym);
+ warnUnorderableSymbol(ToSym);
+ const Defined *FromSymD = dyn_cast<Defined>(FromSym);
+ const Defined *ToSymD = dyn_cast<Defined>(ToSym);
+ if (!FromSymD || !ToSymD)
+ continue;
+ const auto *FromSB = dyn_cast_or_null<InputSectionBase>(FromSymD->Section);
+ const auto *ToSB = dyn_cast_or_null<InputSectionBase>(ToSymD->Section);
+ if (!FromSB || !ToSB)
+ continue;
+ Config->CallGraphProfile[std::make_pair(FromSB, ToSB)] += Count;
+ }
+}
+
static bool getCompressDebugSections(opt::InputArgList &Args) {
StringRef S = Args.getLastArgValue(OPT_compress_debug_sections, "none");
if (S == "none")
@@ -581,54 +692,101 @@ static bool getCompressDebugSections(opt::InputArgList &Args) {
return true;
}
-static int parseInt(StringRef S, opt::Arg *Arg) {
- int V = 0;
- if (!to_integer(S, V, 10))
- error(Arg->getSpelling() + ": number expected, but got '" + S + "'");
- return V;
+static std::pair<StringRef, StringRef> getOldNewOptions(opt::InputArgList &Args,
+ unsigned Id) {
+ auto *Arg = Args.getLastArg(Id);
+ if (!Arg)
+ return {"", ""};
+
+ StringRef S = Arg->getValue();
+ std::pair<StringRef, StringRef> Ret = S.split(';');
+ if (Ret.second.empty())
+ error(Arg->getSpelling() + " expects 'old;new' format, but got " + S);
+ return Ret;
+}
+
+// Parse the symbol ordering file and warn for any duplicate entries.
+static std::vector<StringRef> getSymbolOrderingFile(MemoryBufferRef MB) {
+ SetVector<StringRef> Names;
+ for (StringRef S : args::getLines(MB))
+ if (!Names.insert(S) && Config->WarnSymbolOrdering)
+ warn(MB.getBufferIdentifier() + ": duplicate ordered symbol: " + S);
+
+ return Names.takeVector();
+}
+
+static void parseClangOption(StringRef Opt, const Twine &Msg) {
+ std::string Err;
+ raw_string_ostream OS(Err);
+
+ const char *Argv[] = {Config->ProgName.data(), Opt.data()};
+ if (cl::ParseCommandLineOptions(2, Argv, "", &OS))
+ return;
+ OS.flush();
+ error(Msg + ": " + StringRef(Err).trim());
}
// Initializes Config members by the command line options.
void LinkerDriver::readConfigs(opt::InputArgList &Args) {
+ errorHandler().Verbose = Args.hasArg(OPT_verbose);
+ errorHandler().FatalWarnings =
+ Args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false);
+ ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_no_threads, true);
+
Config->AllowMultipleDefinition =
- Args.hasArg(OPT_allow_multiple_definition) || hasZOption(Args, "muldefs");
+ Args.hasFlag(OPT_allow_multiple_definition,
+ OPT_no_allow_multiple_definition, false) ||
+ hasZOption(Args, "muldefs");
Config->AuxiliaryList = args::getStrings(Args, OPT_auxiliary);
Config->Bsymbolic = Args.hasArg(OPT_Bsymbolic);
Config->BsymbolicFunctions = Args.hasArg(OPT_Bsymbolic_functions);
+ 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->DefineCommon = Args.hasFlag(OPT_define_common, OPT_no_define_common,
!Args.hasArg(OPT_relocatable));
Config->Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, true);
Config->DisableVerify = Args.hasArg(OPT_disable_verify);
Config->Discard = getDiscard(Args);
+ Config->DwoDir = Args.getLastArgValue(OPT_plugin_opt_dwo_dir_eq);
Config->DynamicLinker = getDynamicLinker(Args);
Config->EhFrameHdr =
Args.hasFlag(OPT_eh_frame_hdr, OPT_no_eh_frame_hdr, false);
Config->EmitRelocs = Args.hasArg(OPT_emit_relocs);
- Config->EnableNewDtags = !Args.hasArg(OPT_disable_new_dtags);
+ Config->EnableNewDtags =
+ Args.hasFlag(OPT_enable_new_dtags, OPT_disable_new_dtags, true);
Config->Entry = Args.getLastArgValue(OPT_entry);
+ Config->ExecuteOnly =
+ Args.hasFlag(OPT_execute_only, OPT_no_execute_only, false);
Config->ExportDynamic =
Args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, false);
- errorHandler().FatalWarnings =
- Args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false);
Config->FilterList = args::getStrings(Args, OPT_filter);
Config->Fini = Args.getLastArgValue(OPT_fini, "_fini");
Config->FixCortexA53Errata843419 = Args.hasArg(OPT_fix_cortex_a53_843419);
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);
- Config->ICF = Args.hasFlag(OPT_icf_all, OPT_icf_none, false);
- Config->ICFData = Args.hasArg(OPT_icf_data);
+ Config->ICF = getICF(Args);
+ Config->IgnoreDataAddressEquality =
+ Args.hasArg(OPT_ignore_data_address_equality);
+ Config->IgnoreFunctionAddressEquality =
+ Args.hasFlag(OPT_ignore_function_address_equality,
+ OPT_no_ignore_function_address_equality, true);
Config->Init = Args.getLastArgValue(OPT_init, "_init");
Config->LTOAAPipeline = Args.getLastArgValue(OPT_lto_aa_pipeline);
+ Config->LTODebugPassManager = Args.hasArg(OPT_lto_debug_pass_manager);
+ Config->LTONewPassManager = Args.hasArg(OPT_lto_new_pass_manager);
Config->LTONewPmPasses = Args.getLastArgValue(OPT_lto_newpm_passes);
Config->LTOO = args::getInteger(Args, OPT_lto_O, 2);
+ Config->LTOObjPath = Args.getLastArgValue(OPT_plugin_opt_obj_path_eq);
Config->LTOPartitions = args::getInteger(Args, OPT_lto_partitions, 1);
+ Config->LTOSampleProfile = Args.getLastArgValue(OPT_lto_sample_profile);
Config->MapFile = Args.getLastArgValue(OPT_Map);
- Config->NoGnuUnique = Args.hasArg(OPT_no_gnu_unique);
+ Config->MipsGotSize = args::getInteger(Args, OPT_mips_got_size, 0xfff0);
Config->MergeArmExidx =
Args.hasFlag(OPT_merge_exidx_entries, OPT_no_merge_exidx_entries, true);
- Config->NoUndefinedVersion = Args.hasArg(OPT_no_undefined_version);
Config->NoinhibitExec = Args.hasArg(OPT_noinhibit_exec);
Config->Nostdlib = Args.hasArg(OPT_nostdlib);
Config->OFormatBinary = isOutputFormatBinary(Args);
@@ -639,11 +797,13 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
Config->OrphanHandling = getOrphanHandling(Args);
Config->OutputFile = Args.getLastArgValue(OPT_o);
#ifdef __OpenBSD__
- Config->Pie = Args.hasFlag(OPT_pie, OPT_nopie,
+ Config->Pie = Args.hasFlag(OPT_pie, OPT_no_pie,
!Args.hasArg(OPT_shared) && !Args.hasArg(OPT_relocatable));
#else
- Config->Pie = Args.hasFlag(OPT_pie, OPT_nopie, false);
+ Config->Pie = Args.hasFlag(OPT_pie, OPT_no_pie, false);
#endif
+ Config->PrintIcfSections =
+ Args.hasFlag(OPT_print_icf_sections, OPT_no_print_icf_sections, false);
Config->PrintGcSections =
Args.hasFlag(OPT_print_gc_sections, OPT_no_print_gc_sections, false);
Config->Rpath = getRpath(Args);
@@ -663,48 +823,59 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
Config->ThinLTOCachePolicy = CHECK(
parseCachePruningPolicy(Args.getLastArgValue(OPT_thinlto_cache_policy)),
"--thinlto-cache-policy: invalid cache policy");
+ Config->ThinLTOEmitImportsFiles =
+ Args.hasArg(OPT_plugin_opt_thinlto_emit_imports_files);
+ Config->ThinLTOIndexOnly = Args.hasArg(OPT_plugin_opt_thinlto_index_only) ||
+ Args.hasArg(OPT_plugin_opt_thinlto_index_only_eq);
+ Config->ThinLTOIndexOnlyArg =
+ Args.getLastArgValue(OPT_plugin_opt_thinlto_index_only_eq);
Config->ThinLTOJobs = args::getInteger(Args, OPT_thinlto_jobs, -1u);
- ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_no_threads, true);
+ Config->ThinLTOObjectSuffixReplace =
+ getOldNewOptions(Args, OPT_plugin_opt_thinlto_object_suffix_replace_eq);
+ Config->ThinLTOPrefixReplace =
+ getOldNewOptions(Args, OPT_plugin_opt_thinlto_prefix_replace_eq);
Config->Trace = Args.hasArg(OPT_trace);
Config->Undefined = args::getStrings(Args, OPT_undefined);
+ Config->UndefinedVersion =
+ Args.hasFlag(OPT_undefined_version, OPT_no_undefined_version, true);
+ Config->UseAndroidRelrTags = Args.hasFlag(
+ OPT_use_android_relr_tags, OPT_no_use_android_relr_tags, false);
Config->UnresolvedSymbols = getUnresolvedSymbolPolicy(Args);
- Config->Verbose = Args.hasArg(OPT_verbose);
- errorHandler().Verbose = Config->Verbose;
- Config->WarnCommon = Args.hasArg(OPT_warn_common);
- Config->ZCombreloc = !hasZOption(Args, "nocombreloc");
- Config->ZExecstack = hasZOption(Args, "execstack");
+ 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->WarnSymbolOrdering =
+ Args.hasFlag(OPT_warn_symbol_ordering, OPT_no_warn_symbol_ordering, true);
+ Config->ZCombreloc = getZFlag(Args, "combreloc", "nocombreloc", true);
+ Config->ZCopyreloc = getZFlag(Args, "copyreloc", "nocopyreloc", true);
+ Config->ZExecstack = getZFlag(Args, "execstack", "noexecstack", false);
+ Config->ZHazardplt = hasZOption(Args, "hazardplt");
Config->ZInitfirst = hasZOption(Args, "initfirst");
- Config->ZNocopyreloc = hasZOption(Args, "nocopyreloc");
+ Config->ZInterpose = hasZOption(Args, "interpose");
+ Config->ZKeepTextSectionPrefix = getZFlag(
+ Args, "keep-text-section-prefix", "nokeep-text-section-prefix", false);
Config->ZNodelete = hasZOption(Args, "nodelete");
Config->ZNodlopen = hasZOption(Args, "nodlopen");
- Config->ZNow = hasZOption(Args, "now");
+ Config->ZNow = getZFlag(Args, "now", "lazy", false);
Config->ZOrigin = hasZOption(Args, "origin");
- Config->ZRelro = !hasZOption(Args, "norelro");
+ Config->ZRelro = getZFlag(Args, "relro", "norelro", true);
Config->ZRetpolineplt = hasZOption(Args, "retpolineplt");
Config->ZRodynamic = hasZOption(Args, "rodynamic");
Config->ZStackSize = args::getZOptionValue(Args, OPT_z, "stack-size", 0);
- Config->ZText = !hasZOption(Args, "notext");
+ Config->ZText = getZFlag(Args, "text", "notext", true);
Config->ZWxneeded = hasZOption(Args, "wxneeded");
- // Parse LTO plugin-related options for compatibility with gold.
- for (auto *Arg : Args.filtered(OPT_plugin_opt, OPT_plugin_opt_eq)) {
- StringRef S = Arg->getValue();
- if (S == "disable-verify")
- Config->DisableVerify = true;
- else if (S == "save-temps")
- Config->SaveTemps = true;
- else if (S.startswith("O"))
- Config->LTOO = parseInt(S.substr(1), Arg);
- else if (S.startswith("lto-partitions="))
- Config->LTOPartitions = parseInt(S.substr(15), Arg);
- else if (S.startswith("jobs="))
- Config->ThinLTOJobs = parseInt(S.substr(5), Arg);
- else if (!S.startswith("/") && !S.startswith("-fresolution=") &&
- !S.startswith("-pass-through=") && !S.startswith("mcpu=") &&
- !S.startswith("thinlto") && S != "-function-sections" &&
- S != "-data-sections")
- error(Arg->getSpelling() + ": unknown option: " + S);
- }
+ // Parse LTO options.
+ if (auto *Arg = Args.getLastArg(OPT_plugin_opt_mcpu_eq))
+ parseClangOption(Saver.save("-mcpu=" + StringRef(Arg->getValue())),
+ Arg->getSpelling());
+
+ for (auto *Arg : Args.filtered(OPT_plugin_opt))
+ parseClangOption(Arg->getValue(), Arg->getSpelling());
+
+ // Parse -mllvm options.
+ for (auto *Arg : Args.filtered(OPT_mllvm))
+ parseClangOption(Arg->getValue(), Arg->getSpelling());
if (Config->LTOO > 3)
error("invalid optimization level for LTO: " + Twine(Config->LTOO));
@@ -747,17 +918,12 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
std::tie(Config->BuildId, Config->BuildIdVector) = getBuildId(Args);
- if (auto *Arg = Args.getLastArg(OPT_pack_dyn_relocs_eq)) {
- StringRef S = Arg->getValue();
- if (S == "android")
- Config->AndroidPackDynRelocs = true;
- else if (S != "none")
- error("unknown -pack-dyn-relocs format: " + S);
- }
+ std::tie(Config->AndroidPackDynRelocs, Config->RelrPackDynRelocs) =
+ getPackDynRelocs(Args);
if (auto *Arg = Args.getLastArg(OPT_symbol_ordering_file))
if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
- Config->SymbolOrderingFile = args::getLines(*Buffer);
+ Config->SymbolOrderingFile = getSymbolOrderingFile(*Buffer);
// If --retain-symbol-file is used, we'll keep only the symbols listed in
// the file and discard all others.
@@ -785,32 +951,67 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
{Arg->getValue(), /*IsExternCpp*/ false, /*HasWildcard*/ false});
}
+ // If --export-dynamic-symbol=foo is given and symbol foo is defined in
+ // an object file in an archive file, that object file should be pulled
+ // out and linked. (It doesn't have to behave like that from technical
+ // point of view, but this is needed for compatibility with GNU.)
+ for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol))
+ Config->Undefined.push_back(Arg->getValue());
+
for (auto *Arg : Args.filtered(OPT_version_script))
- if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
- readVersionScript(*Buffer);
+ if (Optional<std::string> Path = searchScript(Arg->getValue())) {
+ if (Optional<MemoryBufferRef> Buffer = readFile(*Path))
+ readVersionScript(*Buffer);
+ } else {
+ error(Twine("cannot find version script ") + Arg->getValue());
+ }
}
// Some Config members do not directly correspond to any particular
// command line options, but computed based on other Config values.
// This function initialize such members. See Config.h for the details
// of these values.
-static void setConfigs() {
+static void setConfigs(opt::InputArgList &Args) {
ELFKind Kind = Config->EKind;
uint16_t Machine = Config->EMachine;
- // There is an ILP32 ABI for x86-64, although it's not very popular.
- // It is called the x32 ABI.
- bool IsX32 = (Kind == ELF32LEKind && Machine == EM_X86_64);
-
Config->CopyRelocs = (Config->Relocatable || Config->EmitRelocs);
Config->Is64 = (Kind == ELF64LEKind || Kind == ELF64BEKind);
Config->IsLE = (Kind == ELF32LEKind || Kind == ELF64LEKind);
Config->Endianness =
Config->IsLE ? support::endianness::little : support::endianness::big;
Config->IsMips64EL = (Kind == ELF64LEKind && Machine == EM_MIPS);
- Config->IsRela = Config->Is64 || IsX32 || Config->MipsN32Abi;
Config->Pic = Config->Pie || Config->Shared;
Config->Wordsize = Config->Is64 ? 8 : 4;
+
+ // There is an ILP32 ABI for x86-64, although it's not very popular.
+ // It is called the x32 ABI.
+ bool IsX32 = (Kind == ELF32LEKind && Machine == EM_X86_64);
+
+ // ELF defines two different ways to store relocation addends as shown below:
+ //
+ // Rel: Addends are stored to the location where relocations are applied.
+ // Rela: Addends are stored as part of relocation entry.
+ //
+ // In other words, Rela makes it easy to read addends at the price of extra
+ // 4 or 8 byte for each relocation entry. We don't know why ELF defined two
+ // different mechanisms in the first place, but this is how the spec is
+ // defined.
+ //
+ // You cannot choose which one, Rel or Rela, you want to use. Instead each
+ // ABI defines which one you need to use. The following expression expresses
+ // that.
+ Config->IsRela =
+ (Config->Is64 || IsX32 || Machine == EM_PPC) && Machine != EM_MIPS;
+
+ // If the output uses REL relocations we must store the dynamic relocation
+ // addends to the output sections. We also store addends for RELA relocations
+ // if --apply-dynamic-relocs is used.
+ // We default to not writing the addends when using RELA relocations since
+ // any standard conforming tool can find it in r_addend.
+ Config->WriteAddends = Args.hasFlag(OPT_apply_dynamic_relocs,
+ OPT_no_apply_dynamic_relocs, false) ||
+ !Config->IsRela;
}
// Returns a value of "-format" option.
@@ -825,6 +1026,10 @@ static bool getBinaryOption(StringRef S) {
}
void LinkerDriver::createFiles(opt::InputArgList &Args) {
+ // For --{push,pop}-state.
+ std::vector<std::tuple<bool, bool, bool>> Stack;
+
+ // Iterate over argv to process input files and positional arguments.
for (auto *Arg : Args) {
switch (Arg->getOption().getUnaliasedOption().getID()) {
case OPT_library:
@@ -833,8 +1038,15 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) {
case OPT_INPUT:
addFile(Arg->getValue(), /*WithLOption=*/false);
break;
+ case OPT_defsym: {
+ StringRef From;
+ StringRef To;
+ std::tie(From, To) = StringRef(Arg->getValue()).split('=');
+ readDefsym(From, MemoryBufferRef(To, "-defsym"));
+ break;
+ }
case OPT_script:
- if (Optional<std::string> Path = searchLinkerScript(Arg->getValue())) {
+ if (Optional<std::string> Path = searchScript(Arg->getValue())) {
if (Optional<MemoryBufferRef> MB = readFile(*Path))
readLinkerScript(*MB);
break;
@@ -862,11 +1074,48 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) {
case OPT_no_whole_archive:
InWholeArchive = false;
break;
+ case OPT_just_symbols:
+ if (Optional<MemoryBufferRef> MB = readFile(Arg->getValue())) {
+ Files.push_back(createObjectFile(*MB));
+ Files.back()->JustSymbols = true;
+ }
+ break;
+ case OPT_start_group:
+ if (InputFile::IsInGroup)
+ error("nested --start-group");
+ InputFile::IsInGroup = true;
+ break;
+ case OPT_end_group:
+ if (!InputFile::IsInGroup)
+ error("stray --end-group");
+ InputFile::IsInGroup = false;
+ ++InputFile::NextGroupId;
+ break;
case OPT_start_lib:
+ if (InLib)
+ error("nested --start-lib");
+ if (InputFile::IsInGroup)
+ error("may not nest --start-lib in --start-group");
InLib = true;
+ InputFile::IsInGroup = true;
break;
case OPT_end_lib:
+ if (!InLib)
+ error("stray --end-lib");
InLib = false;
+ InputFile::IsInGroup = false;
+ ++InputFile::NextGroupId;
+ break;
+ case OPT_push_state:
+ Stack.emplace_back(Config->AsNeeded, Config->Static, InWholeArchive);
+ break;
+ case OPT_pop_state:
+ if (Stack.empty()) {
+ error("unbalanced --push-state/--pop-state");
+ break;
+ }
+ std::tie(Config->AsNeeded, Config->Static, InWholeArchive) = Stack.back();
+ Stack.pop_back();
break;
}
}
@@ -939,14 +1188,6 @@ static DenseSet<StringRef> getExcludeLibs(opt::InputArgList &Args) {
return Ret;
}
-static Optional<StringRef> getArchiveName(InputFile *File) {
- if (isa<ArchiveFile>(File))
- return File->getName();
- if (!File->ArchiveName.empty())
- return File->ArchiveName;
- return None;
-}
-
// Handles the -exclude-libs option. If a static library file is specified
// by the -exclude-libs option, all public symbols from the archive become
// private unless otherwise specified by version scripts or something.
@@ -954,18 +1195,140 @@ static Optional<StringRef> getArchiveName(InputFile *File) {
//
// This is not a popular option, but some programs such as bionic libc use it.
template <class ELFT>
-static void excludeLibs(opt::InputArgList &Args, ArrayRef<InputFile *> Files) {
+static void excludeLibs(opt::InputArgList &Args) {
DenseSet<StringRef> Libs = getExcludeLibs(Args);
bool All = Libs.count("ALL");
- for (InputFile *File : Files)
- if (Optional<StringRef> Archive = getArchiveName(File))
- if (All || Libs.count(path::filename(*Archive)))
+ auto Visit = [&](InputFile *File) {
+ if (!File->ArchiveName.empty())
+ if (All || Libs.count(path::filename(File->ArchiveName)))
for (Symbol *Sym : File->getSymbols())
if (!Sym->isLocal() && Sym->File == File)
Sym->VersionId = VER_NDX_LOCAL;
+ };
+
+ for (InputFile *File : ObjectFiles)
+ Visit(File);
+
+ for (BitcodeFile *File : BitcodeFiles)
+ Visit(File);
+}
+
+// Force Sym to be entered in the output. Used for -u or equivalent.
+template <class ELFT> static void handleUndefined(StringRef Name) {
+ Symbol *Sym = Symtab->find(Name);
+ if (!Sym)
+ return;
+
+ // Since symbol S may not be used inside the program, LTO may
+ // eliminate it. Mark the symbol as "used" to prevent it.
+ Sym->IsUsedInRegularObj = true;
+
+ if (Sym->isLazy())
+ Symtab->fetchLazy<ELFT>(Sym);
+}
+
+template <class ELFT> static bool shouldDemote(Symbol &Sym) {
+ // If all references to a DSO happen to be weak, the DSO is not added to
+ // DT_NEEDED. If that happens, we need to eliminate shared symbols created
+ // from the DSO. Otherwise, they become dangling references that point to a
+ // non-existent DSO.
+ if (auto *S = dyn_cast<SharedSymbol>(&Sym))
+ return !S->getFile<ELFT>().IsNeeded;
+
+ // We are done processing archives, so lazy symbols that were used but not
+ // found can be converted to undefined. We could also just delete the other
+ // lazy symbols, but that seems to be more work than it is worth.
+ return Sym.isLazy() && Sym.IsUsedInRegularObj;
}
+// Some files, such as .so or files between -{start,end}-lib may be removed
+// after their symbols are added to the symbol table. If that happens, we
+// need to remove symbols that refer files that no longer exist, so that
+// they won't appear in the symbol table of the output file.
+//
+// We remove symbols by demoting them to undefined symbol.
+template <class ELFT> static void demoteSymbols() {
+ for (Symbol *Sym : Symtab->getSymbols()) {
+ if (shouldDemote<ELFT>(*Sym)) {
+ bool Used = Sym->Used;
+ replaceSymbol<Undefined>(Sym, nullptr, Sym->getName(), Sym->Binding,
+ Sym->StOther, Sym->Type);
+ Sym->Used = Used;
+ }
+ }
+}
+
+// The section referred to by S is considered address-significant. Set the
+// KeepUnique flag on the section if appropriate.
+static void markAddrsig(Symbol *S) {
+ if (auto *D = dyn_cast_or_null<Defined>(S))
+ if (D->Section)
+ // We don't need to keep text sections unique under --icf=all even if they
+ // are address-significant.
+ if (Config->ICF == ICFLevel::Safe || !(D->Section->Flags & SHF_EXECINSTR))
+ D->Section->KeepUnique = true;
+}
+
+// Record sections that define symbols mentioned in --keep-unique <symbol>
+// and symbols referred to by address-significance tables. These sections are
+// ineligible for ICF.
+template <class ELFT>
+static void findKeepUniqueSections(opt::InputArgList &Args) {
+ for (auto *Arg : Args.filtered(OPT_keep_unique)) {
+ StringRef Name = Arg->getValue();
+ auto *D = dyn_cast_or_null<Defined>(Symtab->find(Name));
+ if (!D || !D->Section) {
+ warn("could not find symbol " + Name + " to keep unique");
+ continue;
+ }
+ D->Section->KeepUnique = true;
+ }
+
+ // --icf=all --ignore-data-address-equality means that we can ignore
+ // the dynsym and address-significance tables entirely.
+ if (Config->ICF == ICFLevel::All && Config->IgnoreDataAddressEquality)
+ return;
+
+ // Symbols in the dynsym could be address-significant in other executables
+ // or DSOs, so we conservatively mark them as address-significant.
+ for (Symbol *S : Symtab->getSymbols())
+ if (S->includeInDynsym())
+ markAddrsig(S);
+
+ // Visit the address-significance table in each object file and mark each
+ // referenced symbol as address-significant.
+ for (InputFile *F : ObjectFiles) {
+ auto *Obj = cast<ObjFile<ELFT>>(F);
+ ArrayRef<Symbol *> Syms = Obj->getSymbols();
+ if (Obj->AddrsigSec) {
+ ArrayRef<uint8_t> Contents =
+ check(Obj->getObj().getSectionContents(Obj->AddrsigSec));
+ const uint8_t *Cur = Contents.begin();
+ while (Cur != Contents.end()) {
+ unsigned Size;
+ const char *Err;
+ uint64_t SymIndex = decodeULEB128(Cur, &Size, Contents.end(), &Err);
+ if (Err)
+ fatal(toString(F) + ": could not decode addrsig section: " + Err);
+ markAddrsig(Syms[SymIndex]);
+ Cur += Size;
+ }
+ } else {
+ // If an object file does not have an address-significance table,
+ // conservatively mark all of its symbols as address-significant.
+ for (Symbol *S : Syms)
+ markAddrsig(S);
+ }
+ }
+}
+
+static const char *LibcallRoutineNames[] = {
+#define HANDLE_LIBCALL(code, name) name,
+#include "llvm/IR/RuntimeLibcalls.def"
+#undef HANDLE_LIBCALL
+};
+
// Do actual linking. Note that when this function is called,
// all linker scripts have already been parsed.
template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
@@ -1014,14 +1377,6 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
for (InputFile *F : Files)
Symtab->addFile<ELFT>(F);
- // Process -defsym option.
- for (auto *Arg : Args.filtered(OPT_defsym)) {
- StringRef From;
- StringRef To;
- std::tie(From, To) = StringRef(Arg->getValue()).split('=');
- readDefsym(From, MemoryBufferRef(To, "-defsym"));
- }
-
// Now that we have every file, we can decide if we will need a
// dynamic symbol table.
// We need one if we were asked to export dynamic symbols or if we are
@@ -1038,24 +1393,39 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
// Handle the `--undefined <sym>` options.
for (StringRef S : Config->Undefined)
- Symtab->fetchIfLazy<ELFT>(S);
+ handleUndefined<ELFT>(S);
- // If an entry symbol is in a static archive, pull out that file now
- // to complete the symbol table. After this, no new names except a
- // few linker-synthesized ones will be added to the symbol table.
- Symtab->fetchIfLazy<ELFT>(Config->Entry);
+ // If an entry symbol is in a static archive, pull out that file now.
+ handleUndefined<ELFT>(Config->Entry);
+
+ // If any of our inputs are bitcode files, the LTO code generator may create
+ // references to certain library functions that might not be explicit in the
+ // bitcode file's symbol table. If any of those library functions are defined
+ // in a bitcode file in an archive member, we need to arrange to use LTO to
+ // compile those archive members by adding them to the link beforehand.
+ //
+ // With this the symbol table should be complete. After this, no new names
+ // except a few linker-synthesized ones will be added to the symbol table.
+ if (!BitcodeFiles.empty())
+ for (const char *S : LibcallRoutineNames)
+ handleUndefined<ELFT>(S);
// Return if there were name resolution errors.
if (errorCount())
return;
- // Handle undefined symbols in DSOs.
- if (!Config->Shared)
- Symtab->scanShlibUndefined<ELFT>();
+ // Now when we read all script files, we want to finalize order of linker
+ // script commands, which can be not yet final because of INSERT commands.
+ Script->processInsertCommands();
+
+ // We want to declare linker script's symbols early,
+ // so that we can version them.
+ // They also might be exported if referenced by DSOs.
+ Script->declareSymbols();
// Handle the -exclude-libs option.
if (Args.hasArg(OPT_exclude_libs))
- excludeLibs<ELFT>(Args, Files);
+ excludeLibs<ELFT>(Args);
// Create ElfHeader early. We need a dummy section in
// addReservedSymbols to mark the created symbols as not absolute.
@@ -1078,10 +1448,18 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
for (auto *Arg : Args.filtered(OPT_wrap))
Symtab->addSymbolWrap<ELFT>(Arg->getValue());
+ // Do link-time optimization if given files are LLVM bitcode files.
+ // This compiles bitcode files into real object files.
Symtab->addCombinedLTOObject<ELFT>();
if (errorCount())
return;
+ // If -thinlto-index-only is given, we should create only "index
+ // files" and not object files. Index file creation is already done
+ // in addCombinedLTOObject, so we are done if that's the case.
+ if (Config->ThinLTOIndexOnly)
+ return;
+
// Apply symbol renames for -wrap.
Symtab->applySymbolWrap();
@@ -1128,11 +1506,20 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
// Do size optimizations: garbage collection, merging of SHF_MERGE sections
// and identical code folding.
- markLive<ELFT>();
decompressSections();
+ splitSections<ELFT>();
+ markLive<ELFT>();
+ demoteSymbols<ELFT>();
mergeSections();
- if (Config->ICF)
+ if (Config->ICF != ICFLevel::None) {
+ findKeepUniqueSections<ELFT>(Args);
doIcf<ELFT>();
+ }
+
+ // Read the callgraph now that we know what was gced or icfed
+ if (auto *Arg = Args.getLastArg(OPT_call_graph_ordering_file))
+ if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
+ readCallGraph(*Buffer);
// Write the result to the file.
writeResult<ELFT>();
diff --git a/gnu/llvm/tools/lld/ELF/DriverUtils.cpp b/gnu/llvm/tools/lld/ELF/DriverUtils.cpp
index ddb1977a992..c9273ff1fca 100644
--- a/gnu/llvm/tools/lld/ELF/DriverUtils.cpp
+++ b/gnu/llvm/tools/lld/ELF/DriverUtils.cpp
@@ -29,6 +29,7 @@
using namespace llvm;
using namespace llvm::sys;
+using namespace llvm::opt;
using namespace lld;
using namespace lld::elf;
@@ -58,18 +59,18 @@ static void handleColorDiagnostics(opt::InputArgList &Args) {
OPT_no_color_diagnostics);
if (!Arg)
return;
- else if (Arg->getOption().getID() == OPT_color_diagnostics)
+ if (Arg->getOption().getID() == OPT_color_diagnostics) {
errorHandler().ColorDiagnostics = true;
- else if (Arg->getOption().getID() == OPT_no_color_diagnostics)
+ } else if (Arg->getOption().getID() == OPT_no_color_diagnostics) {
errorHandler().ColorDiagnostics = false;
- else {
+ } else {
StringRef S = Arg->getValue();
if (S == "always")
errorHandler().ColorDiagnostics = true;
else if (S == "never")
errorHandler().ColorDiagnostics = false;
else if (S != "auto")
- error("unknown option: -color-diagnostics=" + S);
+ error("unknown option: --color-diagnostics=" + S);
}
}
@@ -87,6 +88,29 @@ static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &Args) {
return cl::TokenizeGNUCommandLine;
}
+// Gold LTO plugin takes a `--plugin-opt foo=bar` option as an alias for
+// `--plugin-opt=foo=bar`. We want to handle `--plugin-opt=foo=` as an
+// option name and `bar` as a value. Unfortunately, OptParser cannot
+// handle an option with a space in it.
+//
+// In this function, we concatenate command line arguments so that
+// `--plugin-opt <foo>` is converted to `--plugin-opt=<foo>`. This is a
+// bit hacky, but looks like it is still better than handling --plugin-opt
+// options by hand.
+static void concatLTOPluginOptions(SmallVectorImpl<const char *> &Args) {
+ SmallVector<const char *, 256> V;
+ for (size_t I = 0, E = Args.size(); I != E; ++I) {
+ StringRef S = Args[I];
+ if ((S == "-plugin-opt" || S == "--plugin-opt") && I + 1 != E) {
+ V.push_back(Saver.save(S + "=" + Args[I + 1]).data());
+ ++I;
+ } else {
+ V.push_back(Args[I]);
+ }
+ }
+ Args = std::move(V);
+}
+
// Parses a given list of options.
opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) {
// Make InputArgList from string vectors.
@@ -102,6 +126,7 @@ opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) {
// Expand response files (arguments in the form of @<filename>)
// and then parse the argument again.
cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), Vec);
+ concatLTOPluginOptions(Vec);
Args = this->ParseArgs(Vec, MissingIndex, MissingCount);
handleColorDiagnostics(Args);
@@ -113,9 +138,9 @@ opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) {
return Args;
}
-void elf::printHelp(const char *Argv0) {
- ELFOptTable().PrintHelp(outs(), Argv0, "lld", false /*ShowHidden*/,
- true /*ShowAllAliases*/);
+void elf::printHelp() {
+ ELFOptTable().PrintHelp(outs(), Config->ProgName.data(), "lld",
+ false /*ShowHidden*/, true /*ShowAllAliases*/);
outs() << "\n";
// Scripts generated by Libtool versions up to at least 2.4.6 (the most
@@ -123,13 +148,7 @@ void elf::printHelp(const char *Argv0) {
// in a message for the -help option. If it doesn't match, the scripts
// assume that the linker doesn't support very basic features such as
// shared libraries. Therefore, we need to print out at least "elf".
- // Here, we print out all the targets that we support.
- outs() << Argv0 << ": supported targets: "
- << "elf32-i386 elf32-iamcu elf32-littlearm elf32-ntradbigmips "
- << "elf32-ntradlittlemips elf32-powerpc elf32-tradbigmips "
- << "elf32-tradlittlemips elf32-x86-64 "
- << "elf64-amdgpu elf64-littleaarch64 elf64-powerpc elf64-tradbigmips "
- << "elf64-tradlittlemips elf64-x86-64\n";
+ outs() << Config->ProgName << ": supported targets: elf\n";
}
// Reconstructs command line arguments so that so that you can re-run
@@ -208,7 +227,7 @@ Optional<std::string> elf::searchLibrary(StringRef Name) {
int MaxMaj = -1, MaxMin = -1;
std::error_code EC;
for (fs::directory_iterator LI(Dir, EC), LE;
- !EC && LI != LE; LI = LI.increment(EC)) {
+ LI != LE; LI = LI.increment(EC)) {
StringRef FilePath = LI->path();
StringRef FileName = path::filename(FilePath);
if (!(FileName.startswith(LibName)))
@@ -234,10 +253,10 @@ Optional<std::string> elf::searchLibrary(StringRef Name) {
return None;
}
-// If a linker script doesn't exist in the current directory, we also look for
-// the script in the '-L' search paths. This matches the behaviour of both '-T'
-// and linker script INPUT() directives in ld.bfd.
-Optional<std::string> elf::searchLinkerScript(StringRef Name) {
+// If a linker/version script doesn't exist in the current directory, we also
+// look for the script in the '-L' search paths. This matches the behaviour of
+// '-T', --version-script=, and linker script INPUT() command in ld.bfd.
+Optional<std::string> elf::searchScript(StringRef Name) {
if (fs::exists(Name))
return Name.str();
return findFromSearchPaths(Name);
diff --git a/gnu/llvm/tools/lld/ELF/LinkerScript.cpp b/gnu/llvm/tools/lld/ELF/LinkerScript.cpp
index 57f4adc5156..42ad9396fab 100644
--- a/gnu/llvm/tools/lld/ELF/LinkerScript.cpp
+++ b/gnu/llvm/tools/lld/ELF/LinkerScript.cpp
@@ -15,13 +15,13 @@
#include "Config.h"
#include "InputSection.h"
#include "OutputSections.h"
-#include "Strings.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "Writer.h"
#include "lld/Common/Memory.h"
+#include "lld/Common/Strings.h"
#include "lld/Common/Threads.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
@@ -74,7 +74,7 @@ uint64_t ExprValue::getSectionOffset() const {
// If the alignment is trivial, we don't have to compute the full
// value to know the offset. This allows this function to succeed in
// cases where the output section is not yet known.
- if (Alignment == 1)
+ if (Alignment == 1 && (!Sec || !Sec->getOutputSection()))
return Val;
return getValue() - getSecAddr();
}
@@ -102,28 +102,68 @@ OutputSection *LinkerScript::getOrCreateOutputSection(StringRef Name) {
return CmdRef;
}
+// Expands the memory region by the specified size.
+static void expandMemoryRegion(MemoryRegion *MemRegion, uint64_t Size,
+ StringRef RegionName, StringRef SecName) {
+ MemRegion->CurPos += Size;
+ uint64_t NewSize = MemRegion->CurPos - MemRegion->Origin;
+ if (NewSize > MemRegion->Length)
+ error("section '" + SecName + "' will not fit in region '" + RegionName +
+ "': overflowed by " + Twine(NewSize - MemRegion->Length) + " bytes");
+}
+
+void LinkerScript::expandMemoryRegions(uint64_t Size) {
+ if (Ctx->MemRegion)
+ expandMemoryRegion(Ctx->MemRegion, Size, Ctx->MemRegion->Name,
+ Ctx->OutSec->Name);
+ // Only expand the LMARegion if it is different from MemRegion.
+ if (Ctx->LMARegion && Ctx->MemRegion != Ctx->LMARegion)
+ expandMemoryRegion(Ctx->LMARegion, Size, Ctx->LMARegion->Name,
+ Ctx->OutSec->Name);
+}
+
+void LinkerScript::expandOutputSection(uint64_t Size) {
+ Ctx->OutSec->Size += Size;
+ expandMemoryRegions(Size);
+}
+
void LinkerScript::setDot(Expr E, const Twine &Loc, bool InSec) {
uint64_t Val = E().getValue();
if (Val < Dot && InSec)
error(Loc + ": unable to move location counter backward for: " +
Ctx->OutSec->Name);
- Dot = Val;
// Update to location counter means update to section size.
if (InSec)
- Ctx->OutSec->Size = Dot - Ctx->OutSec->Addr;
+ expandOutputSection(Val - Dot);
+ else
+ expandMemoryRegions(Val - Dot);
+
+ Dot = Val;
}
-// This function is called from processSectionCommands,
-// while we are fixing the output section layout.
-void LinkerScript::addSymbol(SymbolAssignment *Cmd) {
+// Used for handling linker symbol assignments, for both finalizing
+// their values and doing early declarations. Returns true if symbol
+// should be defined from linker script.
+static bool shouldDefineSym(SymbolAssignment *Cmd) {
if (Cmd->Name == ".")
- return;
+ return false;
- // If a symbol was in PROVIDE(), we need to define it only when
- // it is a referenced undefined symbol.
+ if (!Cmd->Provide)
+ return true;
+
+ // If a symbol was in PROVIDE(), we need to define it only
+ // when it is a referenced undefined symbol.
Symbol *B = Symtab->find(Cmd->Name);
- if (Cmd->Provide && (!B || B->isDefined()))
+ if (B && !B->isDefined())
+ return true;
+ return false;
+}
+
+// This function is called from processSectionCommands,
+// while we are fixing the output section layout.
+void LinkerScript::addSymbol(SymbolAssignment *Cmd) {
+ if (!shouldDefineSym(Cmd))
return;
// Define a symbol.
@@ -153,6 +193,76 @@ void LinkerScript::addSymbol(SymbolAssignment *Cmd) {
Cmd->Sym = cast<Defined>(Sym);
}
+// This function is called from LinkerScript::declareSymbols.
+// It creates a placeholder symbol if needed.
+static void declareSymbol(SymbolAssignment *Cmd) {
+ if (!shouldDefineSym(Cmd))
+ return;
+
+ // We can't calculate final value right now.
+ Symbol *Sym;
+ uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT;
+ std::tie(Sym, std::ignore) = Symtab->insert(Cmd->Name, /*Type*/ 0, Visibility,
+ /*CanOmitFromDynSym*/ false,
+ /*File*/ nullptr);
+ replaceSymbol<Defined>(Sym, nullptr, Cmd->Name, STB_GLOBAL, Visibility,
+ STT_NOTYPE, 0, 0, nullptr);
+ Cmd->Sym = cast<Defined>(Sym);
+ Cmd->Provide = false;
+}
+
+// This method is used to handle INSERT AFTER statement. Here we rebuild
+// the list of script commands to mix sections inserted into.
+void LinkerScript::processInsertCommands() {
+ std::vector<BaseCommand *> V;
+ auto Insert = [&](std::vector<BaseCommand *> &From) {
+ V.insert(V.end(), From.begin(), From.end());
+ From.clear();
+ };
+
+ for (BaseCommand *Base : SectionCommands) {
+ if (auto *OS = dyn_cast<OutputSection>(Base)) {
+ Insert(InsertBeforeCommands[OS->Name]);
+ V.push_back(Base);
+ Insert(InsertAfterCommands[OS->Name]);
+ continue;
+ }
+ V.push_back(Base);
+ }
+
+ for (auto &Cmds : {InsertBeforeCommands, InsertAfterCommands})
+ for (const std::pair<StringRef, std::vector<BaseCommand *>> &P : Cmds)
+ if (!P.second.empty())
+ error("unable to INSERT AFTER/BEFORE " + P.first +
+ ": section not defined");
+
+ SectionCommands = std::move(V);
+}
+
+// Symbols defined in script should not be inlined by LTO. At the same time
+// we don't know their final values until late stages of link. Here we scan
+// over symbol assignment commands and create placeholder symbols if needed.
+void LinkerScript::declareSymbols() {
+ assert(!Ctx);
+ for (BaseCommand *Base : SectionCommands) {
+ if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) {
+ declareSymbol(Cmd);
+ continue;
+ }
+
+ // If the output section directive has constraints,
+ // we can't say for sure if it is going to be included or not.
+ // Skip such sections for now. Improve the checks if we ever
+ // need symbols from that sections to be declared early.
+ auto *Sec = cast<OutputSection>(Base);
+ if (Sec->Constraint != ConstraintKind::NoConstraint)
+ continue;
+ for (BaseCommand *Base2 : Sec->SectionCommands)
+ if (auto *Cmd = dyn_cast<SymbolAssignment>(Base2))
+ declareSymbol(Cmd);
+ }
+}
+
// This function is called from assignAddresses, while we are
// fixing the output section addresses. This function is supposed
// to set the final value for a given symbol assignment.
@@ -249,23 +359,11 @@ static void sortSections(MutableArrayRef<InputSection *> Vec,
// --sort-section is handled as an inner SORT command.
// 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.
-// 5. If no SORT commands are given and --sort-section is not specified,
-// apply sorting provided by --symbol-ordering-file if any exist.
-static void sortInputSections(
- MutableArrayRef<InputSection *> Vec, const SectionPattern &Pat,
- const DenseMap<SectionBase *, int> &Order) {
+static void sortInputSections(MutableArrayRef<InputSection *> Vec,
+ const SectionPattern &Pat) {
if (Pat.SortOuter == SortSectionPolicy::None)
return;
- if (Pat.SortOuter == SortSectionPolicy::Default &&
- Config->SortSection == SortSectionPolicy::Default) {
- // If -symbol-ordering-file was given, sort accordingly.
- // Usually, Order is empty.
- if (!Order.empty())
- sortByOrder(Vec, [&](InputSectionBase *S) { return Order.lookup(S); });
- return;
- }
-
if (Pat.SortInner == SortSectionPolicy::Default)
sortSections(Vec, Config->SortSection);
else
@@ -275,8 +373,7 @@ static void sortInputSections(
// Compute and remember which sections the InputSectionDescription matches.
std::vector<InputSection *>
-LinkerScript::computeInputSections(const InputSectionDescription *Cmd,
- const DenseMap<SectionBase *, int> &Order) {
+LinkerScript::computeInputSections(const InputSectionDescription *Cmd) {
std::vector<InputSection *> Ret;
// Collects all sections that satisfy constraints of Cmd.
@@ -290,8 +387,11 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd,
// For -emit-relocs we have to ignore entries like
// .rela.dyn : { *(.rela.data) }
// which are common because they are in the default bfd script.
- if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA)
- continue;
+ // We do not ignore SHT_REL[A] linker-synthesized sections here because
+ // want to support scripts that do custom layout for them.
+ if (auto *IS = dyn_cast<InputSection>(Sec))
+ if (IS->getRelocatedSection())
+ continue;
std::string Filename = getFilename(Sec->File);
if (!Cmd->FilePat.match(Filename) ||
@@ -307,7 +407,7 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd,
}
sortInputSections(MutableArrayRef<InputSection *>(Ret).slice(SizeBefore),
- Pat, Order);
+ Pat);
}
return Ret;
}
@@ -315,22 +415,31 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd,
void LinkerScript::discard(ArrayRef<InputSection *> V) {
for (InputSection *S : V) {
if (S == InX::ShStrTab || S == InX::Dynamic || S == InX::DynSymTab ||
- S == InX::DynStrTab)
+ S == InX::DynStrTab || S == InX::RelaPlt || S == InX::RelaDyn ||
+ S == InX::RelrDyn)
error("discarding " + S->Name + " section is not allowed");
+ // You can discard .hash and .gnu.hash sections by linker scripts. Since
+ // they are synthesized sections, we need to handle them differently than
+ // other regular sections.
+ if (S == InX::GnuHashTab)
+ InX::GnuHashTab = nullptr;
+ if (S == InX::HashTab)
+ InX::HashTab = nullptr;
+
S->Assigned = false;
S->Live = false;
discard(S->DependentSections);
}
}
-std::vector<InputSection *> LinkerScript::createInputSectionList(
- OutputSection &OutCmd, const DenseMap<SectionBase *, int> &Order) {
+std::vector<InputSection *>
+LinkerScript::createInputSectionList(OutputSection &OutCmd) {
std::vector<InputSection *> Ret;
for (BaseCommand *Base : OutCmd.SectionCommands) {
if (auto *Cmd = dyn_cast<InputSectionDescription>(Base)) {
- Cmd->Sections = computeInputSections(Cmd, Order);
+ Cmd->Sections = computeInputSections(Cmd);
Ret.insert(Ret.end(), Cmd->Sections.begin(), Cmd->Sections.end());
}
}
@@ -359,7 +468,6 @@ void LinkerScript::processSectionCommands() {
Ctx->OutSec = Aether;
size_t I = 0;
- DenseMap<SectionBase *, int> Order = buildSectionOrder();
// Add input sections to output sections.
for (BaseCommand *Base : SectionCommands) {
// Handle symbol assignments outside of any output section.
@@ -369,12 +477,13 @@ void LinkerScript::processSectionCommands() {
}
if (auto *Sec = dyn_cast<OutputSection>(Base)) {
- std::vector<InputSection *> V = createInputSectionList(*Sec, Order);
+ std::vector<InputSection *> V = createInputSectionList(*Sec);
// The output section name `/DISCARD/' is special.
// Any input section assigned to it is discarded.
if (Sec->Name == "/DISCARD/") {
discard(V);
+ Sec->SectionCommands.clear();
continue;
}
@@ -414,6 +523,8 @@ void LinkerScript::processSectionCommands() {
Sec->SectionIndex = I++;
if (Sec->Noload)
Sec->Type = SHT_NOBITS;
+ if (Sec->NonAlloc)
+ Sec->Flags &= ~(uint64_t)SHF_ALLOC;
}
}
Ctx = nullptr;
@@ -484,7 +595,7 @@ static OutputSection *addInputSec(StringMap<OutputSection *> &Map,
// ignored. We should not have two output .text sections just because one was
// in a group and another was not for example.
//
- // It also seems that that wording was a late addition and didn't get the
+ // It also seems that wording was a late addition and didn't get the
// necessary scrutiny.
//
// Merging sections with different flags is expected by some users. One
@@ -529,11 +640,11 @@ static OutputSection *addInputSec(StringMap<OutputSection *> &Map,
void LinkerScript::addOrphanSections() {
unsigned End = SectionCommands.size();
StringMap<OutputSection *> Map;
-
std::vector<OutputSection *> V;
- for (InputSectionBase *S : InputSections) {
+
+ auto Add = [&](InputSectionBase *S) {
if (!S->Live || S->Parent)
- continue;
+ return;
StringRef Name = getOutputSectionName(S);
@@ -545,12 +656,24 @@ void LinkerScript::addOrphanSections() {
if (OutputSection *Sec =
findByName(makeArrayRef(SectionCommands).slice(0, End), Name)) {
Sec->addSection(cast<InputSection>(S));
- continue;
+ return;
}
if (OutputSection *OS = addInputSec(Map, S, Name))
V.push_back(OS);
- assert(S->getOutputSection()->SectionIndex == INT_MAX);
+ assert(S->getOutputSection()->SectionIndex == UINT32_MAX);
+ };
+
+ // For futher --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.
+ for (InputSectionBase *IS : InputSections) {
+ if (auto *Sec = dyn_cast<InputSection>(IS))
+ if (InputSectionBase *Rel = Sec->getRelocatedSection())
+ if (auto *RelIS = dyn_cast_or_null<InputSectionBase>(Rel->Parent))
+ Add(RelIS);
+ Add(IS);
}
// If no SECTIONS command was given, we should insert sections commands
@@ -585,33 +708,15 @@ void LinkerScript::output(InputSection *S) {
// Update output section size after adding each section. This is so that
// SIZEOF works correctly in the case below:
// .foo { *(.aaa) a = SIZEOF(.foo); *(.bbb) }
- Ctx->OutSec->Size = Pos - Ctx->OutSec->Addr;
-
- // If there is a memory region associated with this input section, then
- // place the section in that region and update the region index.
- if (Ctx->LMARegion)
- Ctx->LMARegion->CurPos += Pos - Before;
- // FIXME: should we also produce overflow errors for LMARegion?
-
- if (Ctx->MemRegion) {
- uint64_t &CurOffset = Ctx->MemRegion->CurPos;
- CurOffset += Pos - Before;
- uint64_t CurSize = CurOffset - Ctx->MemRegion->Origin;
- if (CurSize > Ctx->MemRegion->Length) {
- uint64_t OverflowAmt = CurSize - Ctx->MemRegion->Length;
- error("section '" + Ctx->OutSec->Name + "' will not fit in region '" +
- Ctx->MemRegion->Name + "': overflowed by " + Twine(OverflowAmt) +
- " bytes");
- }
- }
+ expandOutputSection(Pos - Before);
}
void LinkerScript::switchTo(OutputSection *Sec) {
- if (Ctx->OutSec == Sec)
- return;
-
Ctx->OutSec = Sec;
+
+ uint64_t Before = advance(0, 1);
Ctx->OutSec->Addr = advance(0, Ctx->OutSec->Alignment);
+ expandMemoryRegions(Ctx->OutSec->Addr - Before);
}
// This function searches for a memory region to place the given output
@@ -646,6 +751,13 @@ MemoryRegion *LinkerScript::findMemoryRegion(OutputSection *Sec) {
return nullptr;
}
+static OutputSection *findFirstSection(PhdrEntry *Load) {
+ for (OutputSection *Sec : OutputSections)
+ if (Sec->PtLoad == Load)
+ return Sec;
+ return nullptr;
+}
+
// 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) {
@@ -659,24 +771,26 @@ void LinkerScript::assignOffsets(OutputSection *Sec) {
if (Ctx->MemRegion)
Dot = Ctx->MemRegion->CurPos;
- switchTo(Sec);
-
if (Sec->LMAExpr)
Ctx->LMAOffset = Sec->LMAExpr().getValue() - Dot;
if (MemoryRegion *MR = Sec->LMARegion)
Ctx->LMAOffset = MR->CurPos - Dot;
+ switchTo(Sec);
+
// If neither AT nor AT> is specified for an allocatable section, the linker
// will set the LMA such that the difference between VMA and LMA for the
// section is the same as the preceding output section in the same region
// https://sourceware.org/binutils/docs-2.20/ld/Output-Section-LMA.html
+ // This, however, should only be done by the first "non-header" section
+ // in the segment.
if (PhdrEntry *L = Ctx->OutSec->PtLoad)
- L->LMAOffset = Ctx->LMAOffset;
+ if (Sec == findFirstSection(L))
+ L->LMAOffset = Ctx->LMAOffset;
- // The Size previously denoted how many InputSections had been added to this
- // section, and was used for sorting SHF_LINK_ORDER sections. Reset it to
- // compute the actual size value.
+ // We can call this method multiple times during the creation of
+ // thunks and want to start over calculation each time.
Sec->Size = 0;
// We visited SectionsCommands from processSectionCommands to
@@ -685,7 +799,9 @@ void LinkerScript::assignOffsets(OutputSection *Sec) {
for (BaseCommand *Base : Sec->SectionCommands) {
// This handles the assignments to symbol or to the dot.
if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) {
+ Cmd->Addr = Dot;
assignSymbol(Cmd, true);
+ Cmd->Size = Dot - Cmd->Addr;
continue;
}
@@ -693,17 +809,7 @@ void LinkerScript::assignOffsets(OutputSection *Sec) {
if (auto *Cmd = dyn_cast<ByteCommand>(Base)) {
Cmd->Offset = Dot - Ctx->OutSec->Addr;
Dot += Cmd->Size;
- if (Ctx->MemRegion)
- Ctx->MemRegion->CurPos += Cmd->Size;
- if (Ctx->LMARegion)
- Ctx->LMARegion->CurPos += Cmd->Size;
- Ctx->OutSec->Size = Dot - Ctx->OutSec->Addr;
- continue;
- }
-
- // Handle ASSERT().
- if (auto *Cmd = dyn_cast<AssertCommand>(Base)) {
- Cmd->Expression();
+ expandOutputSection(Cmd->Size);
continue;
}
@@ -728,24 +834,28 @@ void LinkerScript::assignOffsets(OutputSection *Sec) {
}
}
-void LinkerScript::removeEmptyCommands() {
- // It is common practice to use very generic linker scripts. So for any
- // given run some of the output sections in the script will be empty.
- // We could create corresponding empty output sections, but that would
- // clutter the output.
- // We instead remove trivially empty sections. The bfd linker seems even
- // more aggressive at removing them.
- llvm::erase_if(SectionCommands, [&](BaseCommand *Base) {
- if (auto *Sec = dyn_cast<OutputSection>(Base))
- return !Sec->Live;
+static bool isDiscardable(OutputSection &Sec) {
+ // We do not remove empty sections that are explicitly
+ // assigned to any segment.
+ if (!Sec.Phdrs.empty())
return false;
- });
-}
-static bool isAllSectionDescription(const OutputSection &Cmd) {
- for (BaseCommand *Base : Cmd.SectionCommands)
+ // We do not want to remove sections that reference symbols in address and
+ // other expressions. We add script symbols as undefined, and want to ensure
+ // all of them are defined in the output, hence have to keep them.
+ if (Sec.ExpressionsUseSymbols)
+ return false;
+
+ for (BaseCommand *Base : Sec.SectionCommands) {
+ if (auto Cmd = dyn_cast<SymbolAssignment>(Base))
+ // Don't create empty output sections just for unreferenced PROVIDE
+ // symbols.
+ if (Cmd->Name != "." && !Cmd->Sym)
+ continue;
+
if (!isa<InputSectionDescription>(*Base))
return false;
+ }
return true;
}
@@ -761,7 +871,7 @@ void LinkerScript::adjustSectionsBeforeSorting() {
// Given that we want to create the section, we have to worry what impact
// it will have on the link. For example, if we just create a section with
// 0 for flags, it would change which PT_LOADs are created.
- // We could remember that that particular section is dummy and ignore it in
+ // We could remember that particular section is dummy and ignore it in
// other parts of the linker, but unfortunately there are quite a few places
// that would need to change:
// * The program header creation.
@@ -772,7 +882,7 @@ void LinkerScript::adjustSectionsBeforeSorting() {
// the previous sections. Only a few flags are needed to keep the impact low.
uint64_t Flags = SHF_ALLOC;
- for (BaseCommand *Cmd : SectionCommands) {
+ for (BaseCommand *&Cmd : SectionCommands) {
auto *Sec = dyn_cast<OutputSection>(Cmd);
if (!Sec)
continue;
@@ -782,25 +892,37 @@ void LinkerScript::adjustSectionsBeforeSorting() {
Sec->Alignment =
std::max<uint32_t>(Sec->Alignment, Sec->AlignExpr().getValue());
- if (Sec->Live) {
- Flags = Sec->Flags & (SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR);
- continue;
+ // A live output section means that some input section was added to it. It
+ // might have been removed (if it was empty synthetic section), but we at
+ // least know the flags.
+ if (Sec->Live)
+ Flags = Sec->Flags;
+
+ // We do not want to keep any special flags for output section
+ // in case it is empty.
+ bool IsEmpty = getInputSections(Sec).empty();
+ if (IsEmpty)
+ Sec->Flags = Flags & (SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR);
+
+ if (IsEmpty && isDiscardable(*Sec)) {
+ Sec->Live = false;
+ Cmd = nullptr;
}
-
- if (isAllSectionDescription(*Sec))
- continue;
-
- Sec->Live = true;
- Sec->Flags = Flags;
}
+
+ // It is common practice to use very generic linker scripts. So for any
+ // given run some of the output sections in the script will be empty.
+ // We could create corresponding empty output sections, but that would
+ // clutter the output.
+ // We instead remove trivially empty sections. The bfd linker seems even
+ // more aggressive at removing them.
+ llvm::erase_if(SectionCommands, [&](BaseCommand *Base) { return !Base; });
}
void LinkerScript::adjustSectionsAfterSorting() {
// Try and find an appropriate memory region to assign offsets in.
for (BaseCommand *Base : SectionCommands) {
if (auto *Sec = dyn_cast<OutputSection>(Base)) {
- if (!Sec->Live)
- continue;
if (!Sec->LMARegionName.empty()) {
if (MemoryRegion *M = MemoryRegions.lookup(Sec->LMARegionName))
Sec->LMARegion = M;
@@ -818,9 +940,9 @@ void LinkerScript::adjustSectionsAfterSorting() {
// PHDRS { seg PT_LOAD; }
// SECTIONS { .aaa : { *(.aaa) } }
std::vector<StringRef> DefPhdrs;
- auto FirstPtLoad =
- std::find_if(PhdrsCommands.begin(), PhdrsCommands.end(),
- [](const PhdrsCommand &Cmd) { return Cmd.Type == PT_LOAD; });
+ auto FirstPtLoad = llvm::find_if(PhdrsCommands, [](const PhdrsCommand &Cmd) {
+ return Cmd.Type == PT_LOAD;
+ });
if (FirstPtLoad != PhdrsCommands.end())
DefPhdrs.push_back(FirstPtLoad->Name);
@@ -842,11 +964,13 @@ void LinkerScript::adjustSectionsAfterSorting() {
}
}
-static OutputSection *findFirstSection(PhdrEntry *Load) {
- for (OutputSection *Sec : OutputSections)
- if (Sec->PtLoad == Load)
- return Sec;
- return nullptr;
+static uint64_t computeBase(uint64_t Min, bool AllocateHeaders) {
+ // If there is no SECTIONS or if the linkerscript is explicit about program
+ // headers, do our best to allocate them.
+ if (!Script->HasSectionsCommand || AllocateHeaders)
+ return 0;
+ // Otherwise only allocate program headers if that would not add a page.
+ return alignDown(Min, Config->MaxPageSize);
}
// Try to find an address for the file and program headers output sections,
@@ -872,17 +996,22 @@ void LinkerScript::allocateHeaders(std::vector<PhdrEntry *> &Phdrs) {
return;
PhdrEntry *FirstPTLoad = *It;
+ bool HasExplicitHeaders =
+ llvm::any_of(PhdrsCommands, [](const PhdrsCommand &Cmd) {
+ return Cmd.HasPhdrs || Cmd.HasFilehdr;
+ });
uint64_t HeaderSize = getHeaderSize();
- // When linker script with SECTIONS is being used, don't output headers
- // unless there's a space for them.
- uint64_t Base = HasSectionsCommand ? alignDown(Min, Config->MaxPageSize) : 0;
- if (HeaderSize <= Min - Base || Script->hasPhdrsCommands()) {
+ if (HeaderSize <= Min - computeBase(Min, HasExplicitHeaders)) {
Min = alignDown(Min - HeaderSize, Config->MaxPageSize);
Out::ElfHeader->Addr = Min;
Out::ProgramHeaders->Addr = Min + Out::ElfHeader->Size;
return;
}
+ // Error if we were explicitly asked to allocate headers.
+ if (HasExplicitHeaders)
+ error("could not allocate headers");
+
Out::ElfHeader->PtLoad = nullptr;
Out::ProgramHeaders->PtLoad = nullptr;
FirstPTLoad->FirstSec = findFirstSection(FirstPTLoad);
@@ -926,15 +1055,11 @@ void LinkerScript::assignAddresses() {
for (BaseCommand *Base : SectionCommands) {
if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) {
+ Cmd->Addr = Dot;
assignSymbol(Cmd, false);
+ Cmd->Size = Dot - Cmd->Addr;
continue;
}
-
- if (auto *Cmd = dyn_cast<AssertCommand>(Base)) {
- Cmd->Expression();
- continue;
- }
-
assignOffsets(cast<OutputSection>(Base));
}
Ctx = nullptr;
@@ -998,9 +1123,9 @@ ExprValue LinkerScript::getSymbolValue(StringRef Name, const Twine &Loc) {
if (Symbol *Sym = Symtab->find(Name)) {
if (auto *DS = dyn_cast<Defined>(Sym))
return {DS->Section, false, DS->Value, Loc};
- if (auto *SS = dyn_cast<SharedSymbol>(Sym))
- if (!ErrorOnMissingSection || SS->CopyRelSec)
- return {SS->CopyRelSec, false, 0, Loc};
+ if (isa<SharedSymbol>(Sym))
+ if (!ErrorOnMissingSection)
+ return {nullptr, false, 0, Loc};
}
error(Loc + ": symbol not found: " + Name);
diff --git a/gnu/llvm/tools/lld/ELF/Options.td b/gnu/llvm/tools/lld/ELF/Options.td
index affc0b8a4ae..068ad546db6 100644
--- a/gnu/llvm/tools/lld/ELF/Options.td
+++ b/gnu/llvm/tools/lld/ELF/Options.td
@@ -5,65 +5,90 @@ include "llvm/Option/OptParser.td"
class F<string name>: Flag<["--", "-"], name>;
class J<string name>: Joined<["--", "-"], name>;
-multiclass Eq<string name> {
- def "": Separate<["--", "-"], name>;
- def _eq: Joined<["--", "-"], name # "=">, Alias<!cast<Separate>(NAME)>;
+multiclass Eq<string name, string help> {
+ def NAME: Separate<["--", "-"], name>;
+ def NAME # _eq: Joined<["--", "-"], name # "=">, Alias<!cast<Separate>(NAME)>,
+ HelpText<help>;
}
-defm auxiliary: Eq<"auxiliary">,
- HelpText<"Set DT_AUXILIARY field to the specified name">;
+multiclass B<string name, string help1, string help2> {
+ def NAME: Flag<["--", "-"], name>, HelpText<help1>;
+ def no_ # NAME: Flag<["--", "-"], "no-" # name>, HelpText<help2>;
+}
+
+defm auxiliary: Eq<"auxiliary", "Set DT_AUXILIARY field to the specified name">;
def Bsymbolic: F<"Bsymbolic">, HelpText<"Bind defined symbols locally">;
def Bsymbolic_functions: F<"Bsymbolic-functions">,
HelpText<"Bind defined function symbols locally">;
-def Bdynamic: F<"Bdynamic">, HelpText<"Link against shared libraries">;
+def Bdynamic: F<"Bdynamic">, HelpText<"Link against shared libraries (default)">;
def Bstatic: F<"Bstatic">, HelpText<"Do not link against shared libraries">;
-def build_id: F<"build-id">, HelpText<"Generate build ID note">;
+def build_id: F<"build-id">, HelpText<"Alias for --build-id=fast">;
+
+def build_id_eq: J<"build-id=">, HelpText<"Generate build ID note">,
+ MetaVarName<"[fast,md5,sha,uuid,0x<hexstring>]">;
-def build_id_eq: J<"build-id=">, HelpText<"Generate build ID note">;
+defm check_sections: B<"check-sections",
+ "Check section addresses for overlaps (default)",
+ "Do not check section addresses for overlaps">;
-defm compress_debug_sections : Eq<"compress-debug-sections">,
- HelpText<"Compress DWARF debug sections">;
+defm compress_debug_sections:
+ Eq<"compress-debug-sections", "Compress DWARF debug sections">,
+ MetaVarName<"[none,zlib]">;
-defm defsym: Eq<"defsym">, HelpText<"Define a symbol alias">;
+defm defsym: Eq<"defsym", "Define a symbol alias">, MetaVarName<"<symbol>=<value>">;
-defm library_path: Eq<"library-path">,
- HelpText<"Add a directory to the library search path">, MetaVarName<"<dir>">;
+defm library_path:
+ Eq<"library-path", "Add a directory to the library search path">, MetaVarName<"<dir>">;
def O: JoinedOrSeparate<["-"], "O">, HelpText<"Optimize output file size">;
-defm Tbss: Eq<"Tbss">,
- HelpText<"Same as --section-start with .bss as the sectionname">;
+defm Tbss: Eq<"Tbss", "Same as --section-start with .bss as the sectionname">;
-defm Tdata: Eq<"Tdata">,
- HelpText<"Same as --section-start with .data as the sectionname">;
+defm Tdata: Eq<"Tdata", "Same as --section-start with .data as the sectionname">;
-defm Ttext: Eq<"Ttext">,
- HelpText<"Same as --section-start with .text as the sectionname">;
+defm Ttext: Eq<"Ttext", "Same as --section-start with .text as the sectionname">;
-def allow_multiple_definition: F<"allow-multiple-definition">,
- HelpText<"Allow multiple definitions">;
+defm allow_multiple_definition: B<"allow-multiple-definition",
+ "Allow multiple definitions",
+ "Do not allow multiple definitions (default)">;
-def as_needed: F<"as-needed">,
- HelpText<"Only set DT_NEEDED for shared libraries if used">;
+defm apply_dynamic_relocs: B<"apply-dynamic-relocs",
+ "Apply link-time values for dynamic relocations",
+ "Do not apply link-time values for dynamic relocations (default)">;
+
+defm as_needed: B<"as-needed",
+ "Only set DT_NEEDED for shared libraries if used",
+ "Always set DT_NEEDED for shared libraries (default)">;
+
+defm call_graph_ordering_file:
+ Eq<"call-graph-ordering-file", "Layout sections to optimize the given callgraph">;
// -chroot doesn't have a help text because it is an internal option.
-defm chroot: Eq<"chroot">;
+def chroot: Separate<["--", "-"], "chroot">;
def color_diagnostics: F<"color-diagnostics">,
- HelpText<"Use colors in diagnostics">;
+ HelpText<"Alias for --color-diagnostics=always">;
def color_diagnostics_eq: J<"color-diagnostics=">,
- HelpText<"Use colors in diagnostics">;
+ HelpText<"Use colors in diagnostics">,
+ MetaVarName<"[auto,always,never]">;
+
+defm cref: B<"cref",
+ "Output cross reference table",
+ "Do not output cross reference table">;
-def define_common: F<"define-common">,
- HelpText<"Assign space to common symbols">;
+defm define_common: B<"define-common",
+ "Assign space to common symbols",
+ "Do not assign space to common symbols">;
-def demangle: F<"demangle">, HelpText<"Demangle symbol names">;
+defm demangle: B<"demangle",
+ "Demangle symbol names (default)",
+ "Do not demangle symbol names">;
def disable_new_dtags: F<"disable-new-dtags">,
HelpText<"Disable new dynamic tags">;
@@ -76,158 +101,131 @@ def discard_locals: F<"discard-locals">,
def discard_none: F<"discard-none">,
HelpText<"Keep all symbols in the symbol table">;
-defm dynamic_linker: Eq<"dynamic-linker">,
- HelpText<"Which dynamic linker to use">;
+defm dynamic_linker: Eq<"dynamic-linker", "Which dynamic linker to use">;
-defm dynamic_list: Eq<"dynamic-list">,
- HelpText<"Read a list of dynamic symbols">;
+defm dynamic_list: Eq<"dynamic-list", "Read a list of dynamic symbols">;
-def eh_frame_hdr: F<"eh-frame-hdr">,
- HelpText<"Request creation of .eh_frame_hdr section and PT_GNU_EH_FRAME segment header">;
+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">;
def emit_relocs: F<"emit-relocs">, HelpText<"Generate relocations in output">;
def enable_new_dtags: F<"enable-new-dtags">,
- HelpText<"Enable new dynamic tags">;
+ HelpText<"Enable new dynamic tags (default)">;
+
+def end_group: F<"end-group">,
+ HelpText<"Ignored for compatibility with GNU unless you pass --warn-backrefs">;
def end_lib: F<"end-lib">,
HelpText<"End a grouping of objects that should be treated as if they were together in an archive">;
-defm entry: Eq<"entry">, HelpText<"Name of entry point symbol">,
+defm entry: Eq<"entry", "Name of entry point symbol">,
MetaVarName<"<entry>">;
-defm error_limit: Eq<"error-limit">,
- HelpText<"Maximum number of errors to emit before stopping (0 = no limit)">;
+defm error_limit:
+ Eq<"error-limit", "Maximum number of errors to emit before stopping (0 = no limit)">;
def error_unresolved_symbols: F<"error-unresolved-symbols">,
HelpText<"Report unresolved symbols as errors">;
-defm exclude_libs: Eq<"exclude-libs">,
- HelpText<"Exclude static libraries from automatic export">;
+defm exclude_libs: Eq<"exclude-libs", "Exclude static libraries from automatic export">;
+
+defm execute_only: B<"execute-only",
+ "Do not mark executable sections readable",
+ "Mark executable sections readable (default)">;
-def export_dynamic: F<"export-dynamic">,
- HelpText<"Put symbols in the dynamic symbol table">;
+defm export_dynamic: B<"export-dynamic",
+ "Put symbols in the dynamic symbol table",
+ "Do not put symbols in the dynamic symbol table (default)">;
-defm export_dynamic_symbol: Eq<"export-dynamic-symbol">,
- HelpText<"Put a symbol in the dynamic symbol table">;
+defm export_dynamic_symbol:
+ Eq<"export-dynamic-symbol", "Put a symbol in the dynamic symbol table">;
-def fatal_warnings: F<"fatal-warnings">,
- HelpText<"Treat warnings as errors">;
+defm fatal_warnings: B<"fatal-warnings",
+ "Treat warnings as errors",
+ "Do not treat warnings as errors (default)">;
-defm filter: Eq<"filter">,
- HelpText<"Set DT_FILTER field to the specified name">;
+defm filter: Eq<"filter", "Set DT_FILTER field to the specified name">;
-defm fini: Eq<"fini">,
- HelpText<"Specify a finalizer function">, MetaVarName<"<symbol>">;
+defm fini: Eq<"fini", "Specify a finalizer function">, MetaVarName<"<symbol>">;
def fix_cortex_a53_843419: F<"fix-cortex-a53-843419">,
HelpText<"Apply fixes for AArch64 Cortex-A53 erratum 843419">;
-def full_shutdown : F<"full-shutdown">,
- HelpText<"Perform a full shutdown instead of calling _exit">;
+defm format: Eq<"format", "Change the input format of the inputs following this option">,
+ MetaVarName<"[default,elf,binary]">;
-defm format: Eq<"format">,
- HelpText<"Change the input format of the inputs following this option">,
- MetaVarName<"<input-format>">;
+defm gc_sections: B<"gc-sections",
+ "Enable garbage collection of unused sections",
+ "Disable garbage collection of unused sections (default)">;
-def gc_sections: F<"gc-sections">,
- HelpText<"Enable garbage collection of unused sections">;
+defm gdb_index: B<"gdb-index",
+ "Generate .gdb_index section",
+ "Do not generate .gdb_index section (default)">;
-def gdb_index: F<"gdb-index">,
- HelpText<"Generate .gdb_index section">;
+defm gnu_unique: B<"gnu-unique",
+ "Enable STB_GNU_UNIQUE symbol binding (default)",
+ "Disable STB_GNU_UNIQUE symbol binding">;
-defm hash_style: Eq<"hash-style">,
- HelpText<"Specify hash style (sysv, gnu or both)">;
+defm hash_style: Eq<"hash-style", "Specify hash style (sysv, gnu or both)">;
def help: F<"help">, HelpText<"Print option help">;
def icf_all: F<"icf=all">, HelpText<"Enable identical code folding">;
-def icf_data: F<"icf-data">,
- HelpText<"Enable ICF to also fold identical read only data">;
+def icf_safe: F<"icf=safe">, HelpText<"Enable safe identical code folding">;
+
+def icf_none: F<"icf=none">, HelpText<"Disable identical code folding (default)">;
-def icf_none: F<"icf=none">, HelpText<"Disable identical code folding">;
+defm ignore_function_address_equality: B<"ignore-function-address-equality",
+ "lld can break the address equality of functions",
+ "lld cannot break the address equality of functions">;
-defm image_base : Eq<"image-base">, HelpText<"Set the base address">;
+def ignore_data_address_equality: F<"ignore-data-address-equality">,
+ HelpText<"lld can break the address equality of data">;
-defm init: Eq<"init">, HelpText<"Specify an initializer function">,
+defm image_base: Eq<"image-base", "Set the base address">;
+
+defm init: Eq<"init", "Specify an initializer function">,
MetaVarName<"<symbol>">;
-defm library: Eq<"library">, HelpText<"Root name of library to use">,
- MetaVarName<"<libName>">;
+defm just_symbols: Eq<"just-symbols", "Just link symbols">;
-def lto_O: J<"lto-O">, MetaVarName<"<opt-level>">,
- HelpText<"Optimization level for LTO">;
+defm keep_unique: Eq<"keep-unique", "Do not fold this symbol during ICF">;
+
+defm library: Eq<"library", "Root name of library to use">,
+ MetaVarName<"<libName>">;
def m: JoinedOrSeparate<["-"], "m">, HelpText<"Set target emulation">;
-defm Map: Eq<"Map">, HelpText<"Print a link map to the specified file">;
+defm Map: Eq<"Map", "Print a link map to the specified file">;
-def merge_exidx_entries: F<"merge-exidx-entries">,
- HelpText<"Enable merging .ARM.exidx entries">;
+defm merge_exidx_entries: B<"merge-exidx-entries",
+ "Enable merging .ARM.exidx entries (default)",
+ "Disable merging .ARM.exidx entries">;
def nostdlib: F<"nostdlib">,
HelpText<"Only search directories specified on the command line">;
-def no_as_needed: F<"no-as-needed">,
- HelpText<"Always DT_NEEDED for shared libraries">;
-
def no_color_diagnostics: F<"no-color-diagnostics">,
HelpText<"Do not use colors in diagnostics">;
-def no_define_common: F<"no-define-common">,
- HelpText<"Do not assign space to common symbols">;
-
-def no_demangle: F<"no-demangle">,
- HelpText<"Do not demangle symbol names">;
-
def no_dynamic_linker: F<"no-dynamic-linker">,
HelpText<"Inhibit output of .interp section">;
-def no_eh_frame_hdr: F<"no-eh-frame-hdr">,
- HelpText<"Do not create .eh_frame_hdr section">;
-
-def no_export_dynamic: F<"no-export-dynamic">;
-def no_fatal_warnings: F<"no-fatal-warnings">;
-
-def no_gc_sections: F<"no-gc-sections">,
- HelpText<"Disable garbage collection of unused sections">;
-
-def no_gdb_index: F<"no-gdb-index">,
- HelpText<"Do not generate .gdb_index section">;
-
-def no_gnu_unique: F<"no-gnu-unique">,
- HelpText<"Disable STB_GNU_UNIQUE symbol binding">;
-
-def no_merge_exidx_entries: F<"no-merge-exidx-entries">,
- HelpText<"Disable merging .ARM.exidx entries">;
-
-def no_threads: F<"no-threads">,
- HelpText<"Do not run the linker multi-threaded">;
-
-def no_whole_archive: F<"no-whole-archive">,
- HelpText<"Restores the default behavior of loading archive members">;
-
def noinhibit_exec: F<"noinhibit-exec">,
HelpText<"Retain the executable output file whenever it is still usable">;
-def nopie: F<"nopie">, HelpText<"Do not create a position independent executable">;
-
-def no_omagic: Flag<["--"], "no-omagic">, MetaVarName<"<magic>">,
+def no_omagic: F<"no-omagic">, MetaVarName<"<magic>">,
HelpText<"Do not set the text data sections to be writable">;
-def no_print_gc_sections: F<"no-print-gc-sections">,
- HelpText<"Do not list removed unused sections">;
-
def no_rosegment: F<"no-rosegment">,
HelpText<"Do not put read-only non-executable sections in their own segment">;
def no_undefined: F<"no-undefined">,
HelpText<"Report unresolved symbols even if the linker is creating a shared library">;
-def no_undefined_version: F<"no-undefined-version">,
- HelpText<"Report version scripts that refer undefined symbols">;
-
def o: JoinedOrSeparate<["-"], "o">, MetaVarName<"<path>">,
HelpText<"Path to file to write output">;
@@ -237,42 +235,62 @@ def oformat: Separate<["--"], "oformat">, MetaVarName<"<format>">,
def omagic: Flag<["--"], "omagic">, MetaVarName<"<magic>">,
HelpText<"Set the text and data sections to be readable and writable">;
-defm orphan_handling: Eq<"orphan-handling">,
- HelpText<"Control how orphan sections are handled when linker script used">;
+defm orphan_handling:
+ Eq<"orphan-handling", "Control how orphan sections are handled when linker script used">;
+
+defm pack_dyn_relocs:
+ Eq<"pack-dyn-relocs", "Pack dynamic relocations in the given format">,
+ MetaVarName<"[none,android,relr,android+relr]">;
+
+defm use_android_relr_tags: B<"use-android-relr-tags",
+ "Use SHT_ANDROID_RELR / DT_ANDROID_RELR* tags instead of SHT_RELR / DT_RELR*",
+ "Use SHT_RELR / DT_RELR* tags (default)">;
+
+defm pie: B<"pie",
+ "Create a position independent executable",
+ "Do not create a position independent executable (default)">;
+
+defm print_gc_sections: B<"print-gc-sections",
+ "List removed unused sections",
+ "Do not list removed unused sections (default)">;
-def pack_dyn_relocs_eq: J<"pack-dyn-relocs=">, MetaVarName<"<format>">,
- HelpText<"Pack dynamic relocations in the given format (none or android)">;
+defm print_icf_sections: B<"print-icf-sections",
+ "List identical folded sections",
+ "Do not list identical folded sections (default)">;
-def pie: F<"pie">, HelpText<"Create a position independent executable">;
+def pop_state: F<"pop-state">,
+ HelpText<"Undo the effect of -push-state">;
-def print_gc_sections: F<"print-gc-sections">,
- HelpText<"List removed unused sections">;
+def push_state: F<"push-state">,
+ HelpText<"Save the current state of -as-needed, -static and -whole-archive">;
def print_map: F<"print-map">,
HelpText<"Print a link map to the standard output">;
-defm reproduce: Eq<"reproduce">,
- HelpText<"Dump linker invocation and input files for debugging">;
+defm reproduce: Eq<"reproduce", "Dump linker invocation and input files for debugging">;
-defm rpath: Eq<"rpath">, HelpText<"Add a DT_RUNPATH to the output">;
+defm rpath: Eq<"rpath", "Add a DT_RUNPATH to the output">;
def relocatable: F<"relocatable">, HelpText<"Create relocatable object file">;
-defm retain_symbols_file: Eq<"retain-symbols-file">,
- HelpText<"Retain only the symbols listed in the file">,
+defm retain_symbols_file:
+ Eq<"retain-symbols-file", "Retain only the symbols listed in the file">,
MetaVarName<"<file>">;
-defm script: Eq<"script">, HelpText<"Read linker script">;
+defm script: Eq<"script", "Read linker script">;
-defm section_start: Eq<"section-start">, MetaVarName<"<address>">,
- HelpText<"Set address of section">;
+defm section_start: Eq<"section-start", "Set address of section">,
+ MetaVarName<"<address>">;
def shared: F<"shared">, HelpText<"Build a shared object">;
-defm soname: Eq<"soname">, HelpText<"Set DT_SONAME">;
+defm soname: Eq<"soname", "Set DT_SONAME">;
-defm sort_section: Eq<"sort-section">,
- HelpText<"Specifies sections sorting rule when linkerscript is used">;
+defm sort_section:
+ Eq<"sort-section", "Specifies sections sorting rule when linkerscript is used">;
+
+def start_group: F<"start-group">,
+ HelpText<"Ignored for compatibility with GNU unless you pass --warn-backrefs">;
def start_lib: F<"start-lib">,
HelpText<"Start a grouping of objects that should be treated as if they were together in an archive">;
@@ -281,33 +299,39 @@ def strip_all: F<"strip-all">, HelpText<"Strip all symbols">;
def strip_debug: F<"strip-debug">, HelpText<"Strip debugging information">;
-defm symbol_ordering_file: Eq<"symbol-ordering-file">,
- HelpText<"Layout sections in the order specified by symbol file">;
+defm symbol_ordering_file:
+ Eq<"symbol-ordering-file", "Layout sections to place symbols in the order specified by symbol ordering file">;
-defm sysroot: Eq<"sysroot">, HelpText<"Set the system root">;
+defm sysroot: Eq<"sysroot", "Set the system root">;
def target1_rel: F<"target1-rel">, HelpText<"Interpret R_ARM_TARGET1 as R_ARM_REL32">;
-def target1_abs: F<"target1-abs">, HelpText<"Interpret R_ARM_TARGET1 as R_ARM_ABS32">;
+def target1_abs: F<"target1-abs">, HelpText<"Interpret R_ARM_TARGET1 as R_ARM_ABS32 (default)">;
-defm target2: Eq<"target2">,
- HelpText<"Interpret R_ARM_TARGET2 as <type>, where <type> is one of rel, abs, or got-rel">,
+defm target2:
+ Eq<"target2", "Interpret R_ARM_TARGET2 as <type>, where <type> is one of rel, abs, or got-rel">,
MetaVarName<"<type>">;
-def threads: F<"threads">, HelpText<"Run the linker multi-threaded">;
+defm threads: B<"threads",
+ "Run the linker multi-threaded (default)",
+ "Do not run the linker multi-threaded">;
def trace: F<"trace">, HelpText<"Print the names of the input files">;
-defm trace_symbol : Eq<"trace-symbol">, HelpText<"Trace references to symbols">;
+defm trace_symbol: Eq<"trace-symbol", "Trace references to symbols">;
+
+defm undefined: Eq<"undefined", "Force undefined symbol during linking">,
+ MetaVarName<"<symbol>">;
-defm undefined: Eq<"undefined">,
- HelpText<"Force undefined symbol during linking">;
+defm unresolved_symbols:
+ Eq<"unresolved-symbols", "Determine how to handle unresolved symbols">;
-defm unresolved_symbols: Eq<"unresolved-symbols">,
- HelpText<"Determine how to handle unresolved symbols">;
+defm undefined_version: B<"undefined-version",
+ "Allow unused version in version script (default)",
+ "Report version scripts that refer undefined symbols">;
-defm rsp_quoting: Eq<"rsp-quoting">,
- HelpText<"Quoting style for response files. Values supported: windows|posix">;
+defm rsp_quoting: Eq<"rsp-quoting", "Quoting style for response files">,
+ MetaVarName<"[posix,windows]">;
def v: Flag<["-"], "v">, HelpText<"Display the version number">;
@@ -315,91 +339,124 @@ def verbose: F<"verbose">, HelpText<"Verbose mode">;
def version: F<"version">, HelpText<"Display the version number and exit">;
-defm version_script: Eq<"version-script">, HelpText<"Read a version script">;
+defm version_script: Eq<"version-script", "Read a version script">;
+
+defm warn_backrefs: B<"warn-backrefs",
+ "Warn about backward symbol references to fetch archive members",
+ "Do not warn about backward symbol references to fetch archive members (default)">;
+
+defm warn_common: B<"warn-common",
+ "Warn about duplicate common symbols",
+ "Do not warn about duplicate common symbols (default)">;
-def warn_common: F<"warn-common">,
- HelpText<"Warn about duplicate common symbols">;
+defm warn_symbol_ordering: B<"warn-symbol-ordering",
+ "Warn about problems with the symbol ordering file (default)",
+ "Do not warn about problems with the symbol ordering file">;
def warn_unresolved_symbols: F<"warn-unresolved-symbols">,
HelpText<"Report unresolved symbols as warnings">;
-def whole_archive: F<"whole-archive">,
- HelpText<"Force load of all members in a static library">;
+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">, HelpText<"Use wrapper functions for symbol">,
- MetaVarName<"<symbol>">;
+defm wrap: Eq<"wrap", "Use wrapper functions for symbol">,
+ MetaVarName<"<symbol>=<symbol>">;
def z: JoinedOrSeparate<["-"], "z">, MetaVarName<"<option>">,
HelpText<"Linker option extensions">;
// Aliases
-def alias_auxiliary: Separate<["-"], "f">, Alias<auxiliary>;
-def alias_Bdynamic_call_shared: F<"call_shared">, Alias<Bdynamic>;
-def alias_Bdynamic_dy: F<"dy">, Alias<Bdynamic>;
-def alias_Bstatic_dn: F<"dn">, Alias<Bstatic>;
-def alias_Bstatic_non_shared: F<"non_shared">, Alias<Bstatic>;
-def alias_Bstatic_static: F<"static">, Alias<Bstatic>;
-def alias_define_common_d: Flag<["-"], "d">, Alias<define_common>;
-def alias_define_common_dc: F<"dc">, Alias<define_common>;
-def alias_define_common_dp: F<"dp">, Alias<define_common>;
-def alias_discard_all_x: Flag<["-"], "x">, Alias<discard_all>;
-def alias_discard_locals_X: Flag<["-"], "X">, Alias<discard_locals>;
-def alias_emit_relocs: Flag<["-"], "q">, Alias<emit_relocs>;
-def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias<entry>;
-def alias_export_dynamic_E: Flag<["-"], "E">, Alias<export_dynamic>;
-def alias_filter: Separate<["-"], "F">, Alias<filter>;
-def alias_format_b: Separate<["-"], "b">, Alias<format>;
-def alias_library: JoinedOrSeparate<["-"], "l">, Alias<library>;
-def alias_library_path: JoinedOrSeparate<["-"], "L">, Alias<library_path>;
-def alias_omagic: Flag<["-"], "N">, Alias<omagic>;
-def alias_o_output: Joined<["--"], "output=">, Alias<o>;
-def alias_o_output2 : Separate<["--"], "output">, Alias<o>;
-def alias_pie_pic_executable: F<"pic-executable">, Alias<pie>;
-def alias_print_map_M: Flag<["-"], "M">, Alias<print_map>;
-def alias_relocatable_r: Flag<["-"], "r">, Alias<relocatable>;
-def alias_rpath_R: JoinedOrSeparate<["-"], "R">, Alias<rpath>;
-def alias_script_T: JoinedOrSeparate<["-"], "T">, Alias<script>;
-def alias_shared_Bshareable: F<"Bshareable">, Alias<shared>;
-def alias_soname_h: JoinedOrSeparate<["-"], "h">, Alias<soname>;
-def alias_strip_all: Flag<["-"], "s">, Alias<strip_all>;
-def alias_strip_debug_S: Flag<["-"], "S">, Alias<strip_debug>;
-def alias_trace: Flag<["-"], "t">, Alias<trace>;
-def alias_trace_symbol_y : JoinedOrSeparate<["-"], "y">, Alias<trace_symbol>;
-def alias_Ttext_segment: Separate<["-", "--"], "Ttext-segment">, Alias<Ttext>;
-def alias_Ttext_segment_eq: Joined<["-", "--"], "Ttext-segment=">, Alias<Ttext>;
-def alias_undefined_u: JoinedOrSeparate<["-"], "u">, Alias<undefined>;
-def alias_version_V: Flag<["-"], "V">, Alias<version>;
-
-// Our symbol resolution algorithm handles symbols in archive files differently
-// than traditional linkers, so we don't need --start-group and --end-group.
-// These options are recongized for compatibility but ignored.
-def end_group: F<"end-group">;
-def end_group_paren: Flag<["-"], ")">;
-def start_group: F<"start-group">;
-def start_group_paren: Flag<["-"], "(">;
+def: Separate<["-"], "f">, Alias<auxiliary>, HelpText<"Alias for --auxiliary">;
+def: F<"call_shared">, Alias<Bdynamic>, HelpText<"Alias for --Bdynamic">;
+def: F<"dy">, Alias<Bdynamic>, HelpText<"Alias for --Bdynamic">;
+def: F<"dn">, Alias<Bstatic>, HelpText<"Alias for --Bstatic">;
+def: F<"non_shared">, Alias<Bstatic>, HelpText<"Alias for --Bstatic">;
+def: F<"static">, Alias<Bstatic>, HelpText<"Alias for --Bstatic">;
+def: Flag<["-"], "d">, Alias<define_common>, HelpText<"Alias for --define-common">;
+def: F<"dc">, Alias<define_common>, HelpText<"Alias for --define-common">;
+def: F<"dp">, Alias<define_common>, HelpText<"Alias for --define-common">;
+def: Flag<["-"], "x">, Alias<discard_all>, HelpText<"Alias for --discard-all">;
+def: Flag<["-"], "X">, Alias<discard_locals>, HelpText<"Alias for --discard-locals">;
+def: Flag<["-"], "q">, Alias<emit_relocs>, HelpText<"Alias for --emit-relocs">;
+def: Flag<["-"], ")">, Alias<end_group>, HelpText<"Alias for --end-group">;
+def: JoinedOrSeparate<["-"], "e">, Alias<entry>, HelpText<"Alias for --entry">;
+def: Flag<["-"], "E">, Alias<export_dynamic>, HelpText<"Alias for --export-dynamic">;
+def: Separate<["-"], "F">, Alias<filter>, HelpText<"Alias for --filter">;
+def: Separate<["-"], "b">, Alias<format>, HelpText<"Alias for --format">;
+def: JoinedOrSeparate<["-"], "l">, Alias<library>, HelpText<"Alias for --library">;
+def: JoinedOrSeparate<["-"], "L">, Alias<library_path>, HelpText<"Alias for --library-path">;
+def: F<"nopie">, Alias<no_pie>, HelpText<"Alias for --no-pie">;
+def: F<"no-pic-executable">, Alias<no_pie>, HelpText<"Alias for --no-pie">;
+def: Flag<["-"], "N">, Alias<omagic>, HelpText<"Alias for --omagic">;
+def: Joined<["--"], "output=">, Alias<o>, HelpText<"Alias for -o">;
+def: Separate<["--"], "output">, Alias<o>, HelpText<"Alias for -o">;
+def: F<"pic-executable">, Alias<pie>, HelpText<"Alias for --pie">;
+def: Flag<["-"], "M">, Alias<print_map>, HelpText<"Alias for --print-map">;
+def: Flag<["-"], "r">, Alias<relocatable>, HelpText<"Alias for --relocatable">;
+def: JoinedOrSeparate<["-"], "R">, Alias<rpath>, HelpText<"Alias for --rpath">;
+def: JoinedOrSeparate<["-"], "T">, Alias<script>, HelpText<"Alias for --script">;
+def: F<"Bshareable">, Alias<shared>, HelpText<"Alias for --shared">;
+def: JoinedOrSeparate<["-"], "h">, Alias<soname>, HelpText<"Alias for --soname">;
+def: Flag<["-"], "(">, Alias<start_group>, HelpText<"Alias for --start-group">;
+def: Flag<["-"], "s">, Alias<strip_all>, HelpText<"Alias for --strip-all">;
+def: Flag<["-"], "S">, Alias<strip_debug>, HelpText<"Alias for --strip-debug">;
+def: Flag<["-"], "t">, Alias<trace>, HelpText<"Alias for --trace">;
+def: JoinedOrSeparate<["-"], "y">, Alias<trace_symbol>, HelpText<"Alias for --trace-symbol">;
+def: Separate<["-", "--"], "Ttext-segment">, Alias<Ttext>, HelpText<"Alias for --Ttext">;
+def: Joined<["-", "--"], "Ttext-segment=">, Alias<Ttext>, HelpText<"Alias for --Ttext">;
+def: JoinedOrSeparate<["-"], "u">, Alias<undefined>, HelpText<"Alias for --undefined">;
+def: Flag<["-"], "V">, Alias<version>, HelpText<"Alias for --version">;
// LTO-related options.
def lto_aa_pipeline: J<"lto-aa-pipeline=">,
HelpText<"AA pipeline to run during LTO. Used in conjunction with -lto-newpm-passes">;
+def lto_debug_pass_manager: F<"lto-debug-pass-manager">,
+ HelpText<"Debug new pass manager">;
+def lto_new_pass_manager: F<"lto-new-pass-manager">,
+ HelpText<"Use new pass manager">;
def lto_newpm_passes: J<"lto-newpm-passes=">,
HelpText<"Passes to run during LTO">;
+def lto_O: J<"lto-O">, MetaVarName<"<opt-level>">,
+ HelpText<"Optimization level for LTO">;
def lto_partitions: J<"lto-partitions=">,
HelpText<"Number of LTO codegen partitions">;
+def lto_sample_profile: J<"lto-sample-profile=">,
+ HelpText<"Sample profile file path">;
def disable_verify: F<"disable-verify">;
-defm mllvm: Eq<"mllvm">;
+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">;
def opt_remarks_with_hotness: Flag<["--"], "opt-remarks-with-hotness">,
- HelpText<"Include hotness informations in the optimization remarks file">;
-defm plugin_opt: Eq<"plugin-opt">,
- HelpText<"specifies LTO options for compatibility with GNU linkers">;
+ HelpText<"Include hotness information in the optimization remarks file">;
+defm plugin_opt: Eq<"plugin-opt", "specifies LTO options for compatibility with GNU linkers">;
def save_temps: F<"save-temps">;
def thinlto_cache_dir: J<"thinlto-cache-dir=">,
HelpText<"Path to ThinLTO cached object file directory">;
-defm thinlto_cache_policy: Eq<"thinlto-cache-policy">,
- HelpText<"Pruning policy for the ThinLTO cache">;
+defm thinlto_cache_policy: Eq<"thinlto-cache-policy", "Pruning policy for the ThinLTO cache">;
def thinlto_jobs: J<"thinlto-jobs=">, HelpText<"Number of ThinLTO jobs">;
+def: J<"plugin-opt=O">, Alias<lto_O>, HelpText<"Alias for -lto-O">;
+def: F<"plugin-opt=debug-pass-manager">,
+ Alias<lto_debug_pass_manager>, HelpText<"Alias for -lto-debug-pass-manager">;
+def: F<"plugin-opt=disable-verify">, Alias<disable_verify>, HelpText<"Alias for -disable-verify">;
+def plugin_opt_dwo_dir_eq: J<"plugin-opt=dwo_dir=">,
+ HelpText<"Directory to store .dwo files when LTO and debug fission are used">;
+def: J<"plugin-opt=jobs=">, Alias<thinlto_jobs>, HelpText<"Alias for -thinlto-jobs">;
+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">;
+def plugin_opt_obj_path_eq: J<"plugin-opt=obj-path=">;
+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">;
+def plugin_opt_thinlto_emit_imports_files: F<"plugin-opt=thinlto-emit-imports-files">;
+def plugin_opt_thinlto_index_only: F<"plugin-opt=thinlto-index-only">;
+def plugin_opt_thinlto_index_only_eq: J<"plugin-opt=thinlto-index-only=">;
+def plugin_opt_thinlto_object_suffix_replace_eq: J<"plugin-opt=thinlto-object-suffix-replace=">;
+def plugin_opt_thinlto_prefix_replace_eq: J<"plugin-opt=thinlto-prefix-replace=">;
+
// Ignore LTO plugin-related options.
// clang -flto passes -plugin and -plugin-opt to the linker. This is required
// for ld.gold and ld.bfd to get LTO working. But it's not for lld which doesn't
@@ -407,29 +464,38 @@ def thinlto_jobs: J<"thinlto-jobs=">, HelpText<"Number of ThinLTO jobs">;
// just ignore the option on lld side as it's easier. In fact, the linker could
// be called 'ld' and understanding which linker is used would require parsing of
// --version output.
-defm plugin: Eq<"plugin">;
+defm plugin: Eq<"plugin", "Ignored for compatibility with GNU linkers">;
+
+def plugin_opt_fresolution_eq: J<"plugin-opt=-fresolution=">;
+def plugin_opt_pass_through_eq: J<"plugin-opt=-pass-through=">;
+def plugin_opt_thinlto: J<"plugin-opt=thinlto">;
+def plugin_opt_slash: J<"plugin-opt=/">;
// Options listed below are silently ignored for now for compatibility.
-def allow_shlib_undefined: F<"allow-shlib-undefined">;
-def cref: F<"cref">;
-def detect_odr_violations: F<"detect-odr-violations">;
-def g: Flag<["-"], "g">;
-def long_plt: F<"long-plt">;
-def no_add_needed: F<"no-add-needed">;
-def no_allow_shlib_undefined: F<"no-allow-shlib-undefined">;
-def no_copy_dt_needed_entries: F<"no-copy-dt-needed-entries">;
-def no_ctors_in_init_array: F<"no-ctors-in-init-array">;
-def no_keep_memory: F<"no-keep-memory">;
-def no_mmap_output_file: F<"no-mmap-output-file">;
-def no_warn_common: F<"no-warn-common">;
-def no_warn_mismatch: F<"no-warn-mismatch">;
-defm rpath_link: Eq<"rpath-link">;
-def sort_common: F<"sort-common">;
-def stats: F<"stats">;
-def warn_execstack: F<"warn-execstack">;
-def warn_once: F<"warn-once">;
-def warn_shared_textrel: F<"warn-shared-textrel">;
-def EB : F<"EB">;
-def EL : F<"EL">;
-def G: JoinedOrSeparate<["-"], "G">;
-def Qy : F<"Qy">;
+def: F<"allow-shlib-undefined">;
+def: F<"detect-odr-violations">;
+def: Flag<["-"], "g">;
+def: F<"long-plt">;
+def: F<"no-add-needed">;
+def: F<"no-allow-shlib-undefined">;
+def: F<"no-copy-dt-needed-entries">;
+def: F<"no-ctors-in-init-array">;
+def: F<"no-keep-memory">;
+def: F<"no-mmap-output-file">;
+def: F<"no-warn-mismatch">;
+def: Separate<["--", "-"], "rpath-link">;
+def: J<"rpath-link=">;
+def: F<"sort-common">;
+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">;
+
+// Hidden option used for testing MIPS multi-GOT implementation.
+defm mips_got_size:
+ Eq<"mips-got-size", "Max size of a single MIPS GOT. 0x10000 by default.">,
+ Flags<[HelpHidden]>;
diff --git a/gnu/llvm/tools/lld/ELF/OutputSections.cpp b/gnu/llvm/tools/lld/ELF/OutputSections.cpp
index 94c98284196..8253b18b486 100644
--- a/gnu/llvm/tools/lld/ELF/OutputSections.cpp
+++ b/gnu/llvm/tools/lld/ELF/OutputSections.cpp
@@ -10,11 +10,11 @@
#include "OutputSections.h"
#include "Config.h"
#include "LinkerScript.h"
-#include "Strings.h"
#include "SymbolTable.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "lld/Common/Memory.h"
+#include "lld/Common/Strings.h"
#include "lld/Common/Threads.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/Support/Compression.h"
@@ -25,15 +25,12 @@
using namespace llvm;
using namespace llvm::dwarf;
using namespace llvm::object;
-using namespace llvm::support::endian;
using namespace llvm::ELF;
using namespace lld;
using namespace lld::elf;
uint8_t Out::First;
-OutputSection *Out::Opd;
-uint8_t *Out::OpdBuf;
PhdrEntry *Out::TlsPhdr;
OutputSection *Out::DebugInfo;
OutputSection *Out::ElfHeader;
@@ -45,7 +42,9 @@ OutputSection *Out::FiniArray;
std::vector<OutputSection *> elf::OutputSections;
uint32_t OutputSection::getPhdrFlags() const {
- uint32_t Ret = PF_R;
+ uint32_t Ret = 0;
+ if (Config->EMachine != EM_ARM || !(Flags & SHF_ARM_PURECODE))
+ Ret |= PF_R;
if (Flags & SHF_WRITE)
Ret |= PF_W;
if (Flags & SHF_EXECINSTR)
@@ -70,9 +69,7 @@ void OutputSection::writeHeaderTo(typename ELFT::Shdr *Shdr) {
OutputSection::OutputSection(StringRef Name, uint32_t Type, uint64_t Flags)
: BaseCommand(OutputSectionKind),
SectionBase(Output, Name, Flags, /*Entsize*/ 0, /*Alignment*/ 1, Type,
- /*Info*/ 0,
- /*Link*/ 0),
- SectionIndex(INT_MAX) {
+ /*Info*/ 0, /*Link*/ 0) {
Live = false;
}
@@ -91,13 +88,15 @@ static bool canMergeToProgbits(unsigned Type) {
void OutputSection::addSection(InputSection *IS) {
if (!Live) {
// If IS is the first section to be added to this section,
- // initialize Type and Entsize from IS.
+ // initialize Type, Entsize and flags from IS.
Live = true;
Type = IS->Type;
Entsize = IS->Entsize;
+ Flags = IS->Flags;
} else {
// Otherwise, check if new type or flags are compatible with existing ones.
- if ((Flags & (SHF_ALLOC | SHF_TLS)) != (IS->Flags & (SHF_ALLOC | SHF_TLS)))
+ unsigned Mask = SHF_ALLOC | SHF_TLS | SHF_LINK_ORDER;
+ if ((Flags & Mask) != (IS->Flags & Mask))
error("incompatible section flags for " + Name + "\n>>> " + toString(IS) +
": 0x" + utohexstr(IS->Flags) + "\n>>> output section " + Name +
": 0x" + utohexstr(Flags));
@@ -114,9 +113,14 @@ void OutputSection::addSection(InputSection *IS) {
}
IS->Parent = this;
- Flags |= IS->Flags;
+ uint64_t AndMask =
+ Config->EMachine == EM_ARM ? (uint64_t)SHF_ARM_PURECODE : 0;
+ uint64_t OrMask = ~AndMask;
+ uint64_t AndFlags = (Flags & IS->Flags) & AndMask;
+ uint64_t OrFlags = (Flags | IS->Flags) & OrMask;
+ Flags = AndFlags | OrFlags;
+
Alignment = std::max(Alignment, IS->Alignment);
- IS->OutSecOff = Size++;
// If this section contains a table of fixed-size entries, sh_entsize
// holds the element size. If it contains elements of different size we
@@ -134,8 +138,8 @@ void OutputSection::addSection(InputSection *IS) {
}
}
-void elf::sortByOrder(MutableArrayRef<InputSection *> In,
- std::function<int(InputSectionBase *S)> Order) {
+static void sortByOrder(MutableArrayRef<InputSection *> In,
+ llvm::function_ref<int(InputSectionBase *S)> Order) {
typedef std::pair<int, InputSection *> Pair;
auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; };
@@ -158,11 +162,11 @@ bool OutputSection::classof(const BaseCommand *C) {
return C->Kind == OutputSectionKind;
}
-void OutputSection::sort(std::function<int(InputSectionBase *S)> Order) {
+void OutputSection::sort(llvm::function_ref<int(InputSectionBase *S)> Order) {
assert(Live);
- assert(SectionCommands.size() == 1);
- sortByOrder(cast<InputSectionDescription>(SectionCommands[0])->Sections,
- Order);
+ for (BaseCommand *B : SectionCommands)
+ if (auto *ISD = dyn_cast<InputSectionDescription>(B))
+ sortByOrder(ISD->Sections, Order);
}
// Fill [Buf, Buf + Size) with Filler.
@@ -205,11 +209,11 @@ static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) {
if (Size == 1)
*Buf = Data;
else if (Size == 2)
- write16(Buf, Data, Config->Endianness);
+ write16(Buf, Data);
else if (Size == 4)
- write32(Buf, Data, Config->Endianness);
+ write32(Buf, Data);
else if (Size == 8)
- write64(Buf, Data, Config->Endianness);
+ write64(Buf, Data);
else
llvm_unreachable("unsupported Size argument");
}
@@ -231,12 +235,7 @@ template <class ELFT> void OutputSection::writeTo(uint8_t *Buf) {
}
// Write leading padding.
- std::vector<InputSection *> Sections;
- for (BaseCommand *Cmd : SectionCommands)
- if (auto *ISD = dyn_cast<InputSectionDescription>(Cmd))
- for (InputSection *IS : ISD->Sections)
- if (IS->Live)
- Sections.push_back(IS);
+ std::vector<InputSection *> Sections = getInputSections(this);
uint32_t Filler = getFiller();
if (Filler)
fill(Buf, Sections.empty() ? Size : Sections[0]->OutSecOff, Filler);
@@ -281,17 +280,13 @@ static void finalizeShtGroup(OutputSection *OS,
}
template <class ELFT> void OutputSection::finalize() {
- InputSection *First = nullptr;
- for (BaseCommand *Base : SectionCommands) {
- if (auto *ISD = dyn_cast<InputSectionDescription>(Base)) {
- if (ISD->Sections.empty())
- continue;
- if (First == nullptr)
- First = ISD->Sections.front();
- }
- if (isa<ByteCommand>(Base) && Type == SHT_NOBITS)
- Type = SHT_PROGBITS;
- }
+ if (Type == SHT_NOBITS)
+ for (BaseCommand *Base : SectionCommands)
+ if (isa<ByteCommand>(Base))
+ Type = SHT_PROGBITS;
+
+ std::vector<InputSection *> V = getInputSections(this);
+ InputSection *First = V.empty() ? nullptr : V[0];
if (Flags & SHF_LINK_ORDER) {
// We must preserve the link order dependency of sections with the
@@ -367,8 +362,6 @@ static bool compCtors(const InputSection *A, const InputSection *B) {
assert(Y.startswith(".ctors") || Y.startswith(".dtors"));
X = X.substr(6);
Y = Y.substr(6);
- if (X.empty() && Y.empty())
- return false;
return X < Y;
}
@@ -394,6 +387,14 @@ int elf::getPriority(StringRef S) {
return V;
}
+std::vector<InputSection *> elf::getInputSections(OutputSection *OS) {
+ std::vector<InputSection *> Ret;
+ for (BaseCommand *Base : OS->SectionCommands)
+ if (auto *ISD = dyn_cast<InputSectionDescription>(Base))
+ Ret.insert(Ret.end(), ISD->Sections.begin(), ISD->Sections.end());
+ return Ret;
+}
+
// Sorts input sections by section name suffixes, so that .foo.N comes
// before .foo.M if N < M. Used to sort .{init,fini}_array.N sections.
// We want to keep the original order if the priorities are the same
diff --git a/gnu/llvm/tools/lld/ELF/Relocations.cpp b/gnu/llvm/tools/lld/ELF/Relocations.cpp
index abe5498ba51..467219ad054 100644
--- a/gnu/llvm/tools/lld/ELF/Relocations.cpp
+++ b/gnu/llvm/tools/lld/ELF/Relocations.cpp
@@ -45,14 +45,14 @@
#include "Config.h"
#include "LinkerScript.h"
#include "OutputSections.h"
-#include "Strings.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "Thunks.h"
#include "lld/Common/Memory.h"
-
+#include "lld/Common/Strings.h"
+#include "llvm/ADT/SmallSet.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
@@ -80,55 +80,22 @@ static std::string getLocation(InputSectionBase &S, const Symbol &Sym,
return Msg + S.getObjMsg(Off);
}
-// This is a MIPS-specific rule.
-//
-// In case of MIPS GP-relative relocations always resolve to a definition
-// in a regular input file, ignoring the one-definition rule. So we,
-// for example, should not attempt to create a dynamic relocation even
-// if the target symbol is preemptible. There are two two MIPS GP-relative
-// relocations R_MIPS_GPREL16 and R_MIPS_GPREL32. But only R_MIPS_GPREL16
-// can be against a preemptible symbol.
-//
-// To get MIPS relocation type we apply 0xff mask. In case of O32 ABI all
-// relocation types occupy eight bit. In case of N64 ABI we extract first
-// relocation from 3-in-1 packet because only the first relocation can
-// be against a real symbol.
-static bool isMipsGprel(RelType Type) {
- if (Config->EMachine != EM_MIPS)
- return false;
- Type &= 0xff;
- return Type == R_MIPS_GPREL16 || Type == R_MICROMIPS_GPREL16 ||
- Type == R_MICROMIPS_GPREL7_S2;
-}
-
// This function is similar to the `handleTlsRelocation`. MIPS does not
// support any relaxations for TLS relocations so by factoring out MIPS
// handling in to the separate function we can simplify the code and do not
// pollute other `handleTlsRelocation` by MIPS `ifs` statements.
// Mips has a custom MipsGotSection that handles the writing of GOT entries
// without dynamic relocations.
-template <class ELFT>
static unsigned handleMipsTlsRelocation(RelType Type, Symbol &Sym,
InputSectionBase &C, uint64_t Offset,
int64_t Addend, RelExpr Expr) {
if (Expr == R_MIPS_TLSLD) {
- if (InX::MipsGot->addTlsIndex() && Config->Pic)
- InX::RelaDyn->addReloc({Target->TlsModuleIndexRel, InX::MipsGot,
- InX::MipsGot->getTlsIndexOff(), false, nullptr,
- 0});
+ InX::MipsGot->addTlsIndex(*C.File);
C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
return 1;
}
-
if (Expr == R_MIPS_TLSGD) {
- if (InX::MipsGot->addDynTlsEntry(Sym) && Sym.IsPreemptible) {
- uint64_t Off = InX::MipsGot->getGlobalDynOffset(Sym);
- InX::RelaDyn->addReloc(
- {Target->TlsModuleIndexRel, InX::MipsGot, Off, false, &Sym, 0});
- if (Sym.IsPreemptible)
- InX::RelaDyn->addReloc({Target->TlsOffsetRel, InX::MipsGot,
- Off + Config->Wordsize, false, &Sym, 0});
- }
+ InX::MipsGot->addDynTlsEntry(*C.File, Sym);
C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
return 1;
}
@@ -161,7 +128,7 @@ static unsigned handleARMTlsRelocation(RelType Type, Symbol &Sym,
auto AddTlsReloc = [&](uint64_t Off, RelType Type, Symbol *Dest, bool Dyn) {
if (Dyn)
- InX::RelaDyn->addReloc({Type, InX::Got, Off, false, Dest, 0});
+ InX::RelaDyn->addReloc(Type, InX::Got, Off, Dest);
else
InX::Got->Relocations.push_back({R_ABS, Type, Off, 0, Dest});
};
@@ -207,7 +174,7 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,
if (Config->EMachine == EM_ARM)
return handleARMTlsRelocation<ELFT>(Type, Sym, C, Offset, Addend, Expr);
if (Config->EMachine == EM_MIPS)
- return handleMipsTlsRelocation<ELFT>(Type, Sym, C, Offset, Addend, Expr);
+ return handleMipsTlsRelocation(Type, Sym, C, Offset, Addend, Expr);
if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL>(Expr) &&
Config->Shared) {
@@ -221,40 +188,62 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,
return 1;
}
- if (isRelExprOneOf<R_TLSLD_PC, R_TLSLD>(Expr)) {
+ if (isRelExprOneOf<R_TLSLD_GOT, R_TLSLD_GOT_FROM_END, R_TLSLD_PC,
+ R_TLSLD_HINT>(Expr)) {
// Local-Dynamic relocs can be relaxed to Local-Exec.
if (!Config->Shared) {
C.Relocations.push_back(
- {R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Sym});
- return 2;
+ {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_LD_TO_LE), Type,
+ Offset, Addend, &Sym});
+ return Target->TlsGdRelaxSkip;
}
+ if (Expr == R_TLSLD_HINT)
+ return 1;
if (InX::Got->addTlsIndex())
- InX::RelaDyn->addReloc({Target->TlsModuleIndexRel, InX::Got,
- InX::Got->getTlsIndexOff(), false, nullptr, 0});
+ InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, InX::Got,
+ InX::Got->getTlsIndexOff(), nullptr);
C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
return 1;
}
// Local-Dynamic relocs can be relaxed to Local-Exec.
- if (isRelExprOneOf<R_ABS, R_TLSLD, R_TLSLD_PC>(Expr) && !Config->Shared) {
- C.Relocations.push_back({R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Sym});
+ if (Expr == R_ABS && !Config->Shared) {
+ C.Relocations.push_back(
+ {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_LD_TO_LE), Type,
+ Offset, Addend, &Sym});
return 1;
}
- if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL, R_TLSGD,
- R_TLSGD_PC>(Expr)) {
+ // Local-Dynamic sequence where offset of tls variable relative to dynamic
+ // thread pointer is stored in the got.
+ if (Expr == R_TLSLD_GOT_OFF) {
+ // Local-Dynamic relocs can be relaxed to local-exec
+ if (!Config->Shared) {
+ C.Relocations.push_back({R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Sym});
+ return 1;
+ }
+ if (!Sym.isInGot()) {
+ InX::Got->addEntry(Sym);
+ uint64_t Off = Sym.getGotOffset();
+ InX::Got->Relocations.push_back({R_ABS, Target->TlsOffsetRel, Off, 0, &Sym});
+ }
+ C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
+ return 1;
+ }
+
+ if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL, R_TLSGD_GOT,
+ R_TLSGD_GOT_FROM_END, R_TLSGD_PC>(Expr)) {
if (Config->Shared) {
if (InX::Got->addDynTlsEntry(Sym)) {
uint64_t Off = InX::Got->getGlobalDynOffset(Sym);
- InX::RelaDyn->addReloc(
- {Target->TlsModuleIndexRel, InX::Got, Off, false, &Sym, 0});
+ InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, InX::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)
- InX::RelaDyn->addReloc(
- {Target->TlsOffsetRel, InX::Got, OffsetOff, false, &Sym, 0});
+ InX::RelaDyn->addReloc(Target->TlsOffsetRel, InX::Got, OffsetOff,
+ &Sym);
else
InX::Got->Relocations.push_back(
{R_ABS, Target->TlsOffsetRel, OffsetOff, 0, &Sym});
@@ -271,8 +260,8 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,
Offset, Addend, &Sym});
if (!Sym.isInGot()) {
InX::Got->addEntry(Sym);
- InX::RelaDyn->addReloc(
- {Target->TlsGotRel, InX::Got, Sym.getGotOffset(), false, &Sym, 0});
+ InX::RelaDyn->addReloc(Target->TlsGotRel, InX::Got, Sym.getGotOffset(),
+ &Sym);
}
} else {
C.Relocations.push_back(
@@ -336,7 +325,7 @@ static bool isAbsoluteValue(const Symbol &Sym) {
// Returns true if Expr refers a PLT entry.
static bool needsPlt(RelExpr Expr) {
- return isRelExprOneOf<R_PLT_PC, R_PPC_PLT_OPD, R_PLT, R_PLT_PAGE_PC>(Expr);
+ return isRelExprOneOf<R_PLT_PC, R_PPC_CALL_PLT, R_PLT, R_PLT_PAGE_PC>(Expr);
}
// Returns true if Expr refers a GOT entry. Note that this function
@@ -352,7 +341,8 @@ static bool needsGot(RelExpr Expr) {
// file (PC, or GOT for example).
static bool isRelExpr(RelExpr Expr) {
return isRelExprOneOf<R_PC, R_GOTREL, R_GOTREL_FROM_END, R_MIPS_GOTREL,
- R_PAGE_PC, R_RELAX_GOT_PC>(Expr);
+ R_PPC_CALL, R_PPC_CALL_PLT, R_PAGE_PC,
+ R_RELAX_GOT_PC>(Expr);
}
// Returns true if a given relocation can be computed at link-time.
@@ -367,11 +357,13 @@ static bool isRelExpr(RelExpr Expr) {
static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym,
InputSectionBase &S, uint64_t RelOff) {
// These expressions always compute a constant
- if (isRelExprOneOf<R_GOT_FROM_END, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE,
- R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC,
- R_MIPS_TLSGD, R_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC,
- R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_PC, R_TLSGD,
- R_PPC_PLT_OPD, R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT>(E))
+ if (isRelExprOneOf<
+ R_GOT_FROM_END, R_GOT_OFF, R_TLSLD_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE,
+ R_MIPS_GOTREL, R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC,
+ R_MIPS_TLSGD, R_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC,
+ R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_GOT, R_TLSGD_GOT_FROM_END,
+ R_TLSGD_PC, R_PPC_CALL_PLT, R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT,
+ R_TLSLD_HINT>(E))
return true;
// These never do, except if the entire file is position dependent or if
@@ -417,39 +409,45 @@ static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym,
}
static RelExpr toPlt(RelExpr Expr) {
- if (Expr == R_PPC_OPD)
- return R_PPC_PLT_OPD;
- if (Expr == R_PC)
+ switch (Expr) {
+ case R_PPC_CALL:
+ return R_PPC_CALL_PLT;
+ case R_PC:
return R_PLT_PC;
- if (Expr == R_PAGE_PC)
+ case R_PAGE_PC:
return R_PLT_PAGE_PC;
- if (Expr == R_ABS)
+ case R_ABS:
return R_PLT;
- return Expr;
+ default:
+ return Expr;
+ }
}
static RelExpr fromPlt(RelExpr Expr) {
// We decided not to use a plt. Optimize a reference to the plt to a
// reference to the symbol itself.
- if (Expr == R_PLT_PC)
+ switch (Expr) {
+ case R_PLT_PC:
return R_PC;
- if (Expr == R_PPC_PLT_OPD)
- return R_PPC_OPD;
- if (Expr == R_PLT)
+ case R_PPC_CALL_PLT:
+ return R_PPC_CALL;
+ case R_PLT:
return R_ABS;
- return Expr;
+ default:
+ return Expr;
+ }
}
// Returns true if a given shared symbol is in a read-only segment in a DSO.
-template <class ELFT> static bool isReadOnly(SharedSymbol *SS) {
+template <class ELFT> static bool isReadOnly(SharedSymbol &SS) {
typedef typename ELFT::Phdr Elf_Phdr;
// Determine if the symbol is read-only by scanning the DSO's program headers.
- const SharedFile<ELFT> &File = SS->getFile<ELFT>();
+ const SharedFile<ELFT> &File = SS.getFile<ELFT>();
for (const Elf_Phdr &Phdr : check(File.getObj().program_headers()))
if ((Phdr.p_type == ELF::PT_LOAD || Phdr.p_type == ELF::PT_GNU_RELRO) &&
- !(Phdr.p_flags & ELF::PF_W) && SS->Value >= Phdr.p_vaddr &&
- SS->Value < Phdr.p_vaddr + Phdr.p_memsz)
+ !(Phdr.p_flags & ELF::PF_W) && SS.Value >= Phdr.p_vaddr &&
+ SS.Value < Phdr.p_vaddr + Phdr.p_memsz)
return true;
return false;
}
@@ -458,26 +456,45 @@ template <class ELFT> static bool isReadOnly(SharedSymbol *SS) {
//
// If two or more symbols are at the same offset, and at least one of
// them are copied by a copy relocation, all of them need to be copied.
-// Otherwise, they would refer different places at runtime.
+// Otherwise, they would refer to different places at runtime.
template <class ELFT>
-static std::vector<SharedSymbol *> getSymbolsAt(SharedSymbol *SS) {
+static SmallSet<SharedSymbol *, 4> getSymbolsAt(SharedSymbol &SS) {
typedef typename ELFT::Sym Elf_Sym;
- SharedFile<ELFT> &File = SS->getFile<ELFT>();
+ SharedFile<ELFT> &File = SS.getFile<ELFT>();
- std::vector<SharedSymbol *> Ret;
+ SmallSet<SharedSymbol *, 4> Ret;
for (const Elf_Sym &S : File.getGlobalELFSyms()) {
if (S.st_shndx == SHN_UNDEF || S.st_shndx == SHN_ABS ||
- S.st_value != SS->Value)
+ S.st_value != SS.Value)
continue;
StringRef Name = check(S.getName(File.getStringTable()));
Symbol *Sym = Symtab->find(Name);
if (auto *Alias = dyn_cast_or_null<SharedSymbol>(Sym))
- Ret.push_back(Alias);
+ Ret.insert(Alias);
}
return Ret;
}
+// When a symbol is copy relocated or we create a canonical plt entry, it is
+// effectively a defined symbol. In the case of copy relocation the symbol is
+// in .bss and in the case of a canonical plt entry it is in .plt. This function
+// replaces the existing symbol with a Defined pointing to the appropriate
+// location.
+static void replaceWithDefined(Symbol &Sym, SectionBase *Sec, uint64_t Value,
+ uint64_t Size) {
+ Symbol Old = Sym;
+ replaceSymbol<Defined>(&Sym, Sym.File, Sym.getName(), Sym.Binding,
+ Sym.StOther, Sym.Type, Value, Size, Sec);
+ Sym.PltIndex = Old.PltIndex;
+ Sym.GotIndex = Old.GotIndex;
+ Sym.VerdefIndex = Old.VerdefIndex;
+ Sym.IsPreemptible = true;
+ Sym.ExportDynamic = true;
+ Sym.IsUsedInRegularObj = true;
+ Sym.Used = true;
+}
+
// Reserve space in .bss or .bss.rel.ro for copy relocation.
//
// The copy relocation is pretty much a hack. If you use a copy relocation
@@ -520,17 +537,17 @@ static std::vector<SharedSymbol *> getSymbolsAt(SharedSymbol *SS) {
// to the variable in .bss. This kind of issue is sometimes very hard to
// debug. What's a solution? Instead of exporting a varaible V from a DSO,
// define an accessor getV().
-template <class ELFT> static void addCopyRelSymbol(SharedSymbol *SS) {
+template <class ELFT> static void addCopyRelSymbol(SharedSymbol &SS) {
// Copy relocation against zero-sized symbol doesn't make sense.
- uint64_t SymSize = SS->getSize();
- if (SymSize == 0)
- fatal("cannot create a copy relocation for symbol " + toString(*SS));
+ uint64_t SymSize = SS.getSize();
+ if (SymSize == 0 || SS.Alignment == 0)
+ fatal("cannot create a copy relocation for symbol " + toString(SS));
// See if this symbol is in a read-only segment. If so, preserve the symbol's
// memory protection by reserving space in the .bss.rel.ro section.
bool IsReadOnly = isReadOnly<ELFT>(SS);
BssSection *Sec = make<BssSection>(IsReadOnly ? ".bss.rel.ro" : ".bss",
- SymSize, SS->Alignment);
+ SymSize, SS.Alignment);
if (IsReadOnly)
InX::BssRelRo->getParent()->addSection(Sec);
else
@@ -539,126 +556,10 @@ template <class ELFT> static void addCopyRelSymbol(SharedSymbol *SS) {
// Look through the DSO's dynamic symbol table for aliases and create a
// dynamic symbol for each one. This causes the copy relocation to correctly
// interpose any aliases.
- for (SharedSymbol *Sym : getSymbolsAt<ELFT>(SS)) {
- Sym->CopyRelSec = Sec;
- Sym->IsPreemptible = false;
- Sym->IsUsedInRegularObj = true;
- Sym->Used = true;
- }
+ for (SharedSymbol *Sym : getSymbolsAt<ELFT>(SS))
+ replaceWithDefined(*Sym, Sec, 0, Sym->Size);
- InX::RelaDyn->addReloc({Target->CopyRel, Sec, 0, false, SS, 0});
-}
-
-static void errorOrWarn(const Twine &Msg) {
- if (!Config->NoinhibitExec)
- error(Msg);
- else
- warn(Msg);
-}
-
-// Returns PLT relocation expression.
-//
-// This handles a non PIC program call to function in a shared library. In
-// an ideal world, we could just report an error saying the relocation can
-// overflow at runtime. In the real world with glibc, crt1.o has a
-// R_X86_64_PC32 pointing to libc.so.
-//
-// The general idea on how to handle such cases is to create a PLT entry and
-// use that as the function value.
-//
-// For the static linking part, we just return a plt expr and everything
-// else will use the the PLT entry as the address.
-//
-// The remaining problem is making sure pointer equality still works. We
-// need the help of the dynamic linker for that. We let it know that we have
-// a direct reference to a so symbol by creating an undefined symbol with a
-// non zero st_value. Seeing that, the dynamic linker resolves the symbol to
-// the value of the symbol we created. This is true even for got entries, so
-// pointer equality is maintained. To avoid an infinite loop, the only entry
-// that points to the real function is a dedicated got entry used by the
-// plt. That is identified by special relocation types (R_X86_64_JUMP_SLOT,
-// R_386_JMP_SLOT, etc).
-static RelExpr getPltExpr(Symbol &Sym, RelExpr Expr, bool &IsConstant) {
- Sym.NeedsPltAddr = true;
- Sym.IsPreemptible = false;
- IsConstant = true;
- return toPlt(Expr);
-}
-
-// This modifies the expression if we can use a copy relocation or point the
-// symbol to the PLT.
-template <class ELFT>
-static RelExpr adjustExpr(Symbol &Sym, RelExpr Expr, RelType Type,
- InputSectionBase &S, uint64_t RelOff,
- bool &IsConstant) {
- // If a relocation can be applied at link-time, we don't need to
- // create a dynamic relocation in the first place.
- if (IsConstant)
- return Expr;
-
- // We can create any dynamic relocation supported by the dynamic linker if a
- // section is writable or we are passed -z notext.
- bool CanWrite = (S.Flags & SHF_WRITE) || !Config->ZText;
- if (CanWrite && Target->isPicRel(Type))
- return Expr;
-
- // If the relocation is to a weak undef, and we are producing
- // executable, give up on it and produce a non preemptible 0.
- if (!Config->Shared && Sym.isUndefWeak()) {
- Sym.IsPreemptible = false;
- IsConstant = true;
- return Expr;
- }
-
- // If we got here we know that this relocation would require the dynamic
- // linker to write a value to read only memory or use an unsupported
- // relocation.
-
- // We can hack around it if we are producing an executable and
- // the refered symbol can be preemepted to refer to the executable.
- if (!CanWrite && (Config->Shared || (Config->Pic && !isRelExpr(Expr)))) {
- error(
- "can't create dynamic relocation " + toString(Type) + " against " +
- (Sym.getName().empty() ? "local symbol" : "symbol: " + toString(Sym)) +
- " in readonly segment; recompile object files with -fPIC" +
- getLocation(S, Sym, RelOff));
- return Expr;
- }
-
- // Copy relocations are only possible if we are creating an executable and the
- // symbol is shared.
- if (!Sym.isShared() || Config->Shared)
- return Expr;
-
- if (Sym.getVisibility() != STV_DEFAULT &&
- (Sym.getVisibility() != STV_PROTECTED || !Sym.isFunc())) {
- error("cannot preempt symbol: " + toString(Sym) +
- getLocation(S, Sym, RelOff));
- return Expr;
- }
-
- if (Sym.isObject()) {
- // Produce a copy relocation.
- auto *B = dyn_cast<SharedSymbol>(&Sym);
- if (B && !B->CopyRelSec) {
- if (Config->ZNocopyreloc)
- error("unresolvable relocation " + toString(Type) +
- " against symbol '" + toString(*B) +
- "'; recompile with -fPIC or remove '-z nocopyreloc'" +
- getLocation(S, Sym, RelOff));
-
- addCopyRelSymbol<ELFT>(B);
- }
- IsConstant = true;
- return Expr;
- }
-
- if (Sym.isFunc())
- return getPltExpr(Sym, Expr, IsConstant);
-
- errorOrWarn("symbol '" + toString(Sym) + "' defined in " +
- toString(Sym.File) + " has no type");
- return Expr;
+ InX::RelaDyn->addReloc(Target->CopyRel, Sec, 0, &SS);
}
// MIPS has an odd notion of "paired" relocations to calculate addends.
@@ -733,7 +634,7 @@ static bool maybeReportUndefined(Symbol &Sym, InputSectionBase &Sec,
return false;
bool CanBeExternal =
- Sym.computeBinding() != STB_LOCAL && Sym.getVisibility() == STV_DEFAULT;
+ Sym.computeBinding() != STB_LOCAL && Sym.Visibility == STV_DEFAULT;
if (Config->UnresolvedSymbols == UnresolvedPolicy::Ignore && CanBeExternal)
return false;
@@ -761,12 +662,12 @@ static bool maybeReportUndefined(Symbol &Sym, InputSectionBase &Sec,
// this for the N32 ABI. Iterate over relocation with the same offset and put
// theirs types into the single bit-set.
template <class RelTy> static RelType getMipsN32RelType(RelTy *&Rel, RelTy *End) {
- RelType Type = Rel->getType(Config->IsMips64EL);
+ RelType Type = 0;
uint64_t Offset = Rel->r_offset;
int N = 0;
- while (Rel + 1 != End && (Rel + 1)->r_offset == Offset)
- Type |= (++Rel)->getType(Config->IsMips64EL) << (8 * ++N);
+ while (Rel != End && Rel->r_offset == Offset)
+ Type |= (Rel++)->getType(Config->IsMips64EL) << (8 * N++);
return Type;
}
@@ -816,16 +717,34 @@ private:
};
} // namespace
+static void addRelativeReloc(InputSectionBase *IS, uint64_t OffsetInSec,
+ Symbol *Sym, int64_t Addend, RelExpr Expr,
+ RelType Type) {
+ // Add a relative relocation. If RelrDyn section is enabled, and the
+ // relocation offset is guaranteed to be even, add the relocation to
+ // the RelrDyn section, otherwise add it to the RelaDyn section.
+ // RelrDyn sections don't support odd offsets. Also, RelrDyn sections
+ // don't store the addend values, so we must write it to the relocated
+ // address.
+ if (InX::RelrDyn && IS->Alignment >= 2 && OffsetInSec % 2 == 0) {
+ IS->Relocations.push_back({Expr, Type, OffsetInSec, Addend, Sym});
+ InX::RelrDyn->Relocs.push_back({IS, OffsetInSec});
+ return;
+ }
+ InX::RelaDyn->addReloc(Target->RelativeRel, IS, OffsetInSec, Sym, Addend,
+ Expr, Type);
+}
+
template <class ELFT, class GotPltSection>
static void addPltEntry(PltSection *Plt, GotPltSection *GotPlt,
- RelocationBaseSection *Rel, RelType Type, Symbol &Sym,
- bool UseSymVA) {
+ RelocationBaseSection *Rel, RelType Type, Symbol &Sym) {
Plt->addEntry<ELFT>(Sym);
GotPlt->addEntry(Sym);
- Rel->addReloc({Type, GotPlt, Sym.getGotPltOffset(), UseSymVA, &Sym, 0});
+ Rel->addReloc(
+ {Type, GotPlt, Sym.getGotPltOffset(), !Sym.IsPreemptible, &Sym, 0});
}
-template <class ELFT> static void addGotEntry(Symbol &Sym, bool Preemptible) {
+template <class ELFT> static void addGotEntry(Symbol &Sym) {
InX::Got->addEntry(Sym);
RelExpr Expr = Sym.isTls() ? R_TLS : R_ABS;
@@ -838,7 +757,8 @@ template <class ELFT> static void addGotEntry(Symbol &Sym, bool Preemptible) {
// add a static relocation to a Relocations vector so that
// InputSection::relocate will do the work for us. We may be able
// to just write a value now, but it is a TODO.)
- bool IsLinkTimeConstant = !Preemptible && (!Config->Pic || isAbsolute(Sym));
+ bool IsLinkTimeConstant =
+ !Sym.IsPreemptible && (!Config->Pic || isAbsolute(Sym));
if (IsLinkTimeConstant) {
InX::Got->Relocations.push_back({Expr, Target->GotRel, Off, 0, &Sym});
return;
@@ -846,23 +766,33 @@ template <class ELFT> static void addGotEntry(Symbol &Sym, bool Preemptible) {
// Otherwise, we emit a dynamic relocation to .rel[a].dyn so that
// the GOT slot will be fixed at load-time.
- RelType Type;
- if (Sym.isTls())
- Type = Target->TlsGotRel;
- else if (!Preemptible && Config->Pic && !isAbsolute(Sym))
- Type = Target->RelativeRel;
- else
- Type = Target->GotRel;
- InX::RelaDyn->addReloc({Type, InX::Got, Off, !Preemptible, &Sym, 0});
+ if (!Sym.isTls() && !Sym.IsPreemptible && Config->Pic && !isAbsolute(Sym)) {
+ addRelativeReloc(InX::Got, Off, &Sym, 0, R_ABS, Target->GotRel);
+ return;
+ }
+ InX::RelaDyn->addReloc(Sym.isTls() ? Target->TlsGotRel : Target->GotRel,
+ InX::Got, Off, &Sym, 0,
+ Sym.IsPreemptible ? R_ADDEND : R_ABS, Target->GotRel);
+}
- // REL type relocations don't have addend fields unlike RELAs, and
- // their addends are stored to the section to which they are applied.
- // So, store addends if we need to.
- //
- // This is ugly -- the difference between REL and RELA should be
- // handled in a better way. It's a TODO.
- if (!Config->IsRela && !Preemptible)
- InX::Got->Relocations.push_back({R_ABS, Target->GotRel, Off, 0, &Sym});
+// Return true if we can define a symbol in the executable that
+// contains the value/function of a symbol defined in a shared
+// library.
+static bool canDefineSymbolInExecutable(Symbol &Sym) {
+ // If the symbol has default visibility the symbol defined in the
+ // executable will preempt it.
+ // Note that we want the visibility of the shared symbol itself, not
+ // the visibility of the symbol in the output file we are producing. That is
+ // why we use Sym.StOther.
+ if ((Sym.StOther & 0x3) == STV_DEFAULT)
+ return true;
+
+ // If we are allowed to break address equality of functions, defining
+ // a plt entry will allow the program to call the function in the
+ // .so, but the .so and the executable will no agree on the address
+ // of the function. Similar logic for objects.
+ return ((Sym.isFunc() && Config->IgnoreFunctionAddressEquality) ||
+ (Sym.isObject() && Config->IgnoreDataAddressEquality));
}
// The reason we have to do this early scan is as follows
@@ -879,129 +809,23 @@ template <class ELFT> static void addGotEntry(Symbol &Sym, bool Preemptible) {
// complicates things for the dynamic linker and means we would have to reserve
// space for the extra PT_LOAD even if we end up not using it.
template <class ELFT, class RelTy>
-static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) {
- OffsetGetter GetOffset(Sec);
-
- // Not all relocations end up in Sec.Relocations, but a lot do.
- Sec.Relocations.reserve(Rels.size());
-
- for (auto I = Rels.begin(), End = Rels.end(); I != End; ++I) {
- const RelTy &Rel = *I;
- Symbol &Sym = Sec.getFile<ELFT>()->getRelocTargetSym(Rel);
- RelType Type = Rel.getType(Config->IsMips64EL);
-
- // Deal with MIPS oddity.
- if (Config->MipsN32Abi)
- Type = getMipsN32RelType(I, End);
-
- // Get an offset in an output section this relocation is applied to.
- uint64_t Offset = GetOffset.get(Rel.r_offset);
- if (Offset == uint64_t(-1))
- continue;
-
- // Skip if the target symbol is an erroneous undefined symbol.
- if (maybeReportUndefined(Sym, Sec, Rel.r_offset))
- continue;
-
- RelExpr Expr =
- Target->getRelExpr(Type, Sym, Sec.Data.begin() + Rel.r_offset);
-
- // Ignore "hint" relocations because they are only markers for relaxation.
- if (isRelExprOneOf<R_HINT, R_NONE>(Expr))
- continue;
-
- // Handle yet another MIPS-ness.
- if (isMipsGprel(Type)) {
- int64_t Addend = computeAddend<ELFT>(Rel, End, Sec, Expr, Sym.isLocal());
- Sec.Relocations.push_back({R_MIPS_GOTREL, Type, Offset, Addend, &Sym});
- continue;
- }
-
- bool Preemptible = Sym.IsPreemptible;
-
- // Strenghten or relax a PLT access.
- //
- // GNU ifunc symbols must be accessed via PLT because their addresses
- // are determined by runtime.
- //
- // On the other hand, if we know that a PLT entry will be resolved within
- // the same ELF module, we can skip PLT access and directly jump to the
- // destination function. For example, if we are linking a main exectuable,
- // all dynamic symbols that can be resolved within the executable will
- // actually be resolved that way at runtime, because the main exectuable
- // is always at the beginning of a search list. We can leverage that fact.
- if (Sym.isGnuIFunc())
- Expr = toPlt(Expr);
- else if (!Preemptible && Expr == R_GOT_PC && !isAbsoluteValue(Sym))
- Expr =
- Target->adjustRelaxExpr(Type, Sec.Data.data() + Rel.r_offset, Expr);
- else if (!Preemptible)
- Expr = fromPlt(Expr);
-
- bool IsConstant =
- isStaticLinkTimeConstant(Expr, Type, Sym, Sec, Rel.r_offset);
-
- Expr = adjustExpr<ELFT>(Sym, Expr, Type, Sec, Rel.r_offset, IsConstant);
- if (errorCount())
- continue;
-
- // This relocation does not require got entry, but it is relative to got and
- // needs it to be created. Here we request for that.
- if (isRelExprOneOf<R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, R_GOTREL,
- R_GOTREL_FROM_END, R_PPC_TOC>(Expr))
- InX::Got->HasGotOffRel = true;
-
- // Read an addend.
- int64_t Addend = computeAddend<ELFT>(Rel, End, Sec, Expr, Sym.isLocal());
-
- // 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)) {
- I += (Processed - 1);
- continue;
- }
-
- // If a relocation needs PLT, we create PLT and GOTPLT slots for the symbol.
- if (needsPlt(Expr) && !Sym.isInPlt()) {
- if (Sym.isGnuIFunc() && !Preemptible)
- addPltEntry<ELFT>(InX::Iplt, InX::IgotPlt, InX::RelaIplt,
- Target->IRelativeRel, Sym, true);
- else
- addPltEntry<ELFT>(InX::Plt, InX::GotPlt, InX::RelaPlt, Target->PltRel,
- Sym, !Preemptible);
- }
-
- // Create a GOT slot if a relocation needs GOT.
- if (needsGot(Expr)) {
- if (Config->EMachine == EM_MIPS) {
- // MIPS ABI has special rules to process GOT entries and doesn't
- // require relocation entries for them. A special case is TLS
- // relocations. In that case dynamic loader applies dynamic
- // relocations to initialize TLS GOT entries.
- // See "Global Offset Table" in Chapter 5 in the following document
- // for detailed description:
- // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
- InX::MipsGot->addEntry(Sym, Addend, Expr);
- if (Sym.isTls() && Sym.IsPreemptible)
- InX::RelaDyn->addReloc({Target->TlsGotRel, InX::MipsGot,
- Sym.getGotOffset(), false, &Sym, 0});
- } else if (!Sym.isInGot()) {
- addGotEntry<ELFT>(Sym, Preemptible);
- }
- }
-
- if (!needsPlt(Expr) && !needsGot(Expr) && Sym.IsPreemptible) {
- // We don't know anything about the finaly symbol. Just ask the dynamic
- // linker to handle the relocation for us.
- if (!Target->isPicRel(Type))
- errorOrWarn(
- "relocation " + toString(Type) +
- " cannot be used against shared object; recompile with -fPIC" +
- getLocation(Sec, Sym, Offset));
+static void processRelocAux(InputSectionBase &Sec, RelExpr Expr, RelType Type,
+ uint64_t Offset, Symbol &Sym, const RelTy &Rel,
+ int64_t Addend) {
+ if (isStaticLinkTimeConstant(Expr, Type, Sym, Sec, Offset)) {
+ Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
+ return;
+ }
+ bool CanWrite = (Sec.Flags & SHF_WRITE) || !Config->ZText;
+ if (CanWrite) {
+ // R_GOT refers to a position in the got, even if the symbol is preemptible.
+ bool IsPreemptibleValue = Sym.IsPreemptible && Expr != R_GOT;
- InX::RelaDyn->addReloc(
- {Target->getDynRel(Type), &Sec, Offset, false, &Sym, Addend});
+ if (!IsPreemptibleValue) {
+ addRelativeReloc(&Sec, Offset, &Sym, Addend, Expr, Type);
+ return;
+ } else if (RelType Rel = Target->getDynRel(Type)) {
+ InX::RelaDyn->addReloc(Rel, &Sec, Offset, &Sym, Addend, R_ADDEND, Type);
// MIPS ABI turns using of GOT and dynamic relocations inside out.
// While regular ABI uses dynamic relocations to fill up GOT entries
@@ -1019,37 +843,210 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) {
// a dynamic relocation.
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf p.4-19
if (Config->EMachine == EM_MIPS)
- InX::MipsGot->addEntry(Sym, Addend, Expr);
- continue;
+ InX::MipsGot->addEntry(*Sec.File, Sym, Addend, Expr);
+ return;
}
+ }
- // The size is not going to change, so we fold it in here.
- if (Expr == R_SIZE)
- Addend += Sym.getSize();
+ // If the relocation is to a weak undef, and we are producing
+ // executable, give up on it and produce a non preemptible 0.
+ if (!Config->Shared && Sym.isUndefWeak()) {
+ Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
+ return;
+ }
- // If the produced value is a constant, we just remember to write it
- // when outputting this section. We also have to do it if the format
- // uses Elf_Rel, since in that case the written value is the addend.
- if (IsConstant) {
- Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
- continue;
+ if (!CanWrite && (Config->Pic && !isRelExpr(Expr))) {
+ error(
+ "can't create dynamic relocation " + toString(Type) + " against " +
+ (Sym.getName().empty() ? "local symbol" : "symbol: " + toString(Sym)) +
+ " in readonly segment; recompile object files with -fPIC "
+ "or pass '-Wl,-z,notext' to allow text relocations in the output" +
+ getLocation(Sec, Sym, Offset));
+ return;
+ }
+
+ // Copy relocations are only possible if we are creating an executable.
+ if (Config->Shared) {
+ errorOrWarn("relocation " + toString(Type) +
+ " cannot be used against symbol " + toString(Sym) +
+ "; recompile with -fPIC" + getLocation(Sec, Sym, Offset));
+ return;
+ }
+
+ // If the symbol is undefined we already reported any relevant errors.
+ if (Sym.isUndefined())
+ return;
+
+ if (!canDefineSymbolInExecutable(Sym)) {
+ error("cannot preempt symbol: " + toString(Sym) +
+ getLocation(Sec, Sym, Offset));
+ return;
+ }
+
+ if (Sym.isObject()) {
+ // Produce a copy relocation.
+ if (auto *SS = dyn_cast<SharedSymbol>(&Sym)) {
+ if (!Config->ZCopyreloc)
+ error("unresolvable relocation " + toString(Type) +
+ " against symbol '" + toString(*SS) +
+ "'; recompile with -fPIC or remove '-z nocopyreloc'" +
+ getLocation(Sec, Sym, Offset));
+ addCopyRelSymbol<ELFT>(*SS);
}
+ Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
+ return;
+ }
- // If the output being produced is position independent, the final value
- // is still not known. In that case we still need some help from the
- // dynamic linker. We can however do better than just copying the incoming
- // relocation. We can process some of it and and just ask the dynamic
- // linker to add the load address.
- if (Config->IsRela) {
- InX::RelaDyn->addReloc(
- {Target->RelativeRel, &Sec, Offset, true, &Sym, Addend});
- } else {
- // In REL, addends are stored to the target section.
- InX::RelaDyn->addReloc(
- {Target->RelativeRel, &Sec, Offset, true, &Sym, 0});
- Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
+ if (Sym.isFunc()) {
+ // This handles a non PIC program call to function in a shared library. In
+ // an ideal world, we could just report an error saying the relocation can
+ // overflow at runtime. In the real world with glibc, crt1.o has a
+ // R_X86_64_PC32 pointing to libc.so.
+ //
+ // The general idea on how to handle such cases is to create a PLT entry and
+ // use that as the function value.
+ //
+ // For the static linking part, we just return a plt expr and everything
+ // else will use the PLT entry as the address.
+ //
+ // The remaining problem is making sure pointer equality still works. We
+ // need the help of the dynamic linker for that. We let it know that we have
+ // a direct reference to a so symbol by creating an undefined symbol with a
+ // non zero st_value. Seeing that, the dynamic linker resolves the symbol to
+ // the value of the symbol we created. This is true even for got entries, so
+ // pointer equality is maintained. To avoid an infinite loop, the only entry
+ // that points to the real function is a dedicated got entry used by the
+ // plt. That is identified by special relocation types (R_X86_64_JUMP_SLOT,
+ // R_386_JMP_SLOT, etc).
+
+ // For position independent executable on i386, the plt entry requires ebx
+ // to be set. This causes two problems:
+ // * If some code has a direct reference to a function, it was probably
+ // compiled without -fPIE/-fPIC and doesn't maintain ebx.
+ // * If a library definition gets preempted to the executable, it will have
+ // the wrong ebx value.
+ if (Config->Pie && Config->EMachine == EM_386)
+ errorOrWarn("symbol '" + toString(Sym) +
+ "' cannot be preempted; recompile with -fPIE" +
+ getLocation(Sec, Sym, Offset));
+ if (!Sym.isInPlt())
+ addPltEntry<ELFT>(InX::Plt, InX::GotPlt, InX::RelaPlt, Target->PltRel,
+ Sym);
+ if (!Sym.isDefined())
+ replaceWithDefined(Sym, InX::Plt, Sym.getPltOffset(), 0);
+ Sym.NeedsPltAddr = true;
+ Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
+ return;
+ }
+
+ errorOrWarn("symbol '" + toString(Sym) + "' has no type" +
+ getLocation(Sec, Sym, Offset));
+}
+
+template <class ELFT, class RelTy>
+static void scanReloc(InputSectionBase &Sec, OffsetGetter &GetOffset, RelTy *&I,
+ RelTy *End) {
+ const RelTy &Rel = *I;
+ Symbol &Sym = Sec.getFile<ELFT>()->getRelocTargetSym(Rel);
+ RelType Type;
+
+ // Deal with MIPS oddity.
+ if (Config->MipsN32Abi) {
+ Type = getMipsN32RelType(I, End);
+ } else {
+ Type = Rel.getType(Config->IsMips64EL);
+ ++I;
+ }
+
+ // Get an offset in an output section this relocation is applied to.
+ uint64_t Offset = GetOffset.get(Rel.r_offset);
+ if (Offset == uint64_t(-1))
+ return;
+
+ // Skip if the target symbol is an erroneous undefined symbol.
+ if (maybeReportUndefined(Sym, Sec, Rel.r_offset))
+ return;
+
+ const uint8_t *RelocatedAddr = Sec.Data.begin() + Rel.r_offset;
+ RelExpr Expr = Target->getRelExpr(Type, Sym, RelocatedAddr);
+
+ // Ignore "hint" relocations because they are only markers for relaxation.
+ if (isRelExprOneOf<R_HINT, R_NONE>(Expr))
+ return;
+
+ // Strenghten or relax relocations.
+ //
+ // GNU ifunc symbols must be accessed via PLT because their addresses
+ // are determined by runtime.
+ //
+ // On the other hand, if we know that a PLT entry will be resolved within
+ // the same ELF module, we can skip PLT access and directly jump to the
+ // destination function. For example, if we are linking a main exectuable,
+ // all dynamic symbols that can be resolved within the executable will
+ // actually be resolved that way at runtime, because the main exectuable
+ // is always at the beginning of a search list. We can leverage that fact.
+ if (Sym.isGnuIFunc())
+ Expr = toPlt(Expr);
+ else if (!Sym.IsPreemptible && Expr == R_GOT_PC && !isAbsoluteValue(Sym))
+ Expr = Target->adjustRelaxExpr(Type, RelocatedAddr, Expr);
+ else if (!Sym.IsPreemptible)
+ Expr = fromPlt(Expr);
+
+ // This relocation does not require got entry, but it is relative to got and
+ // needs it to be created. Here we request for that.
+ if (isRelExprOneOf<R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, R_GOTREL,
+ R_GOTREL_FROM_END, R_PPC_TOC>(Expr))
+ InX::Got->HasGotOffRel = true;
+
+ // Read an addend.
+ int64_t Addend = computeAddend<ELFT>(Rel, End, Sec, Expr, Sym.isLocal());
+
+ // 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)) {
+ I += (Processed - 1);
+ return;
+ }
+
+ // If a relocation needs PLT, we create PLT and GOTPLT slots for the symbol.
+ if (needsPlt(Expr) && !Sym.isInPlt()) {
+ if (Sym.isGnuIFunc() && !Sym.IsPreemptible)
+ addPltEntry<ELFT>(InX::Iplt, InX::IgotPlt, InX::RelaIplt,
+ Target->IRelativeRel, Sym);
+ else
+ addPltEntry<ELFT>(InX::Plt, InX::GotPlt, InX::RelaPlt, Target->PltRel,
+ Sym);
+ }
+
+ // Create a GOT slot if a relocation needs GOT.
+ if (needsGot(Expr)) {
+ if (Config->EMachine == EM_MIPS) {
+ // MIPS ABI has special rules to process GOT entries and doesn't
+ // require relocation entries for them. A special case is TLS
+ // relocations. In that case dynamic loader applies dynamic
+ // relocations to initialize TLS GOT entries.
+ // See "Global Offset Table" in Chapter 5 in the following document
+ // for detailed description:
+ // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+ InX::MipsGot->addEntry(*Sec.File, Sym, Addend, Expr);
+ } else if (!Sym.isInGot()) {
+ addGotEntry<ELFT>(Sym);
}
}
+
+ processRelocAux<ELFT>(Sec, Expr, Type, Offset, Sym, Rel, Addend);
+}
+
+template <class ELFT, class RelTy>
+static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) {
+ OffsetGetter GetOffset(Sec);
+
+ // Not all relocations end up in Sec.Relocations, but a lot do.
+ Sec.Relocations.reserve(Rels.size());
+
+ for (auto I = Rels.begin(), End = Rels.end(); I != End;)
+ scanReloc<ELFT>(Sec, GetOffset, I, End);
}
template <class ELFT> void elf::scanRelocations(InputSectionBase &S) {
@@ -1264,17 +1261,30 @@ ThunkSection *ThunkCreator::getISThunkSec(InputSection *IS) {
//
// We follow a simple but conservative heuristic to place ThunkSections at
// offsets that are multiples of a Target specific branch range.
-// For an InputSectionRange that is smaller than the range, a single
+// For an InputSectionDescription that is smaller than the range, a single
// ThunkSection at the end of the range will do.
+//
+// For an InputSectionDescription that is more than twice the size of the range,
+// we place the last ThunkSection at range bytes from the end of the
+// InputSectionDescription in order to increase the likelihood that the
+// distance from a thunk to its target will be sufficiently small to
+// allow for the creation of a short thunk.
void ThunkCreator::createInitialThunkSections(
ArrayRef<OutputSection *> OutputSections) {
forEachInputSectionDescription(
OutputSections, [&](OutputSection *OS, InputSectionDescription *ISD) {
if (ISD->Sections.empty())
return;
+ uint32_t ISDBegin = ISD->Sections.front()->OutSecOff;
+ uint32_t ISDEnd =
+ ISD->Sections.back()->OutSecOff + ISD->Sections.back()->getSize();
+ uint32_t LastThunkLowerBound = -1;
+ if (ISDEnd - ISDBegin > Target->ThunkSectionSpacing * 2)
+ LastThunkLowerBound = ISDEnd - Target->ThunkSectionSpacing;
+
uint32_t ISLimit;
- uint32_t PrevISLimit = ISD->Sections.front()->OutSecOff;
- uint32_t ThunkUpperBound = PrevISLimit + Target->ThunkSectionSpacing;
+ uint32_t PrevISLimit = ISDBegin;
+ uint32_t ThunkUpperBound = ISDBegin + Target->ThunkSectionSpacing;
for (const InputSection *IS : ISD->Sections) {
ISLimit = IS->OutSecOff + IS->getSize();
@@ -1282,6 +1292,8 @@ void ThunkCreator::createInitialThunkSections(
addThunkSection(OS, ISD, PrevISLimit);
ThunkUpperBound = PrevISLimit + Target->ThunkSectionSpacing;
}
+ if (ISLimit > LastThunkLowerBound)
+ break;
PrevISLimit = ISLimit;
}
addThunkSection(OS, ISD, ISLimit);
@@ -1298,17 +1310,22 @@ ThunkSection *ThunkCreator::addThunkSection(OutputSection *OS,
std::pair<Thunk *, bool> ThunkCreator::getThunk(Symbol &Sym, RelType Type,
uint64_t Src) {
- auto Res = ThunkedSymbols.insert({&Sym, std::vector<Thunk *>()});
- if (!Res.second) {
- // Check existing Thunks for Sym to see if they can be reused
- for (Thunk *ET : Res.first->second)
- if (ET->isCompatibleWith(Type) &&
- Target->inBranchRange(Type, Src, ET->ThunkSym->getVA()))
- return std::make_pair(ET, false);
- }
+ std::vector<Thunk *> *ThunkVec = nullptr;
+ // We use (section, offset) pair to find the thunk position if possible so
+ // that we create only one thunk for aliased symbols or ICFed sections.
+ if (auto *D = dyn_cast<Defined>(&Sym))
+ if (!D->isInPlt() && D->Section)
+ ThunkVec = &ThunkedSymbolsBySection[{D->Section->Repl, D->Value}];
+ if (!ThunkVec)
+ ThunkVec = &ThunkedSymbols[&Sym];
+ // Check existing Thunks for Sym to see if they can be reused
+ for (Thunk *ET : *ThunkVec)
+ if (ET->isCompatibleWith(Type) &&
+ Target->inBranchRange(Type, Src, ET->getThunkTargetSym()->getVA()))
+ return std::make_pair(ET, false);
// No existing compatible Thunk in range, create a new one
Thunk *T = addThunk(Type, Sym);
- Res.first->second.push_back(T);
+ ThunkVec->push_back(T);
return std::make_pair(T, true);
}
@@ -1316,7 +1333,7 @@ std::pair<Thunk *, bool> ThunkCreator::getThunk(Symbol &Sym, RelType Type,
// InputSectionDescription::Sections.
void ThunkCreator::forEachInputSectionDescription(
ArrayRef<OutputSection *> OutputSections,
- std::function<void(OutputSection *, InputSectionDescription *)> Fn) {
+ llvm::function_ref<void(OutputSection *, InputSectionDescription *)> Fn) {
for (OutputSection *OS : OutputSections) {
if (!(OS->Flags & SHF_ALLOC) || !(OS->Flags & SHF_EXECINSTR))
continue;
@@ -1384,7 +1401,7 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) {
OutputSections, [&](OutputSection *OS, InputSectionDescription *ISD) {
for (InputSection *IS : ISD->Sections)
for (Relocation &Rel : IS->Relocations) {
- uint64_t Src = OS->Addr + IS->OutSecOff + Rel.Offset;
+ uint64_t Src = IS->getVA(Rel.Offset);
// If we are a relocation to an existing Thunk, check if it is
// still in range. If not then Rel will be altered to point to its
@@ -1399,7 +1416,6 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) {
bool IsNew;
std::tie(T, IsNew) = getThunk(*Rel.Sym, Rel.Type, Src);
if (IsNew) {
- AddressesChanged = true;
// Find or create a ThunkSection for the new Thunk
ThunkSection *TS;
if (auto *TIS = T->getTargetInputSection())
@@ -1407,13 +1423,18 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) {
else
TS = getISDThunkSec(OS, IS, ISD, Rel.Type, Src);
TS->addThunk(T);
- Thunks[T->ThunkSym] = T;
+ Thunks[T->getThunkTargetSym()] = T;
}
// Redirect relocation to Thunk, we never go via the PLT to a Thunk
- Rel.Sym = T->ThunkSym;
+ Rel.Sym = T->getThunkTargetSym();
Rel.Expr = fromPlt(Rel.Expr);
}
+ for (auto &P : ISD->ThunkSections)
+ AddressesChanged |= P.first->assignOffsets();
});
+ for (auto &P : ThunkedSections)
+ AddressesChanged |= P.second->assignOffsets();
+
// Merge all created synthetic ThunkSections back into OutputSection
mergeThunks(OutputSections);
++Pass;
diff --git a/gnu/llvm/tools/lld/ELF/SymbolTable.cpp b/gnu/llvm/tools/lld/ELF/SymbolTable.cpp
index c3a00bea4aa..1f5a84ec2c7 100644
--- a/gnu/llvm/tools/lld/ELF/SymbolTable.cpp
+++ b/gnu/llvm/tools/lld/ELF/SymbolTable.cpp
@@ -38,7 +38,7 @@ static InputFile *getFirstElf() {
return ObjectFiles[0];
if (!SharedFiles.empty())
return SharedFiles[0];
- return nullptr;
+ return BitcodeFiles[0];
}
// All input object files must be for the same architecture
@@ -82,6 +82,7 @@ template <class ELFT> void SymbolTable::addFile(InputFile *File) {
// Lazy object file
if (auto *F = dyn_cast<LazyObjFile>(File)) {
+ LazyObjFiles.push_back(F);
F->parse<ELFT>();
return;
}
@@ -117,7 +118,7 @@ template <class ELFT> void SymbolTable::addFile(InputFile *File) {
// not in native object file format but in the LLVM bitcode format.
// This function compiles bitcode files into a few big native files
// using LLVM functions and replaces bitcode symbols with the results.
-// Because all bitcode files that consist of a program are passed
+// Because all bitcode files that the program consists of are passed
// to the compiler at once, it can do whole-program optimization.
template <class ELFT> void SymbolTable::addCombinedLTOObject() {
if (BitcodeFiles.empty())
@@ -130,7 +131,10 @@ template <class ELFT> void SymbolTable::addCombinedLTOObject() {
for (InputFile *File : LTO->compile()) {
DenseSet<CachedHashStringRef> DummyGroups;
- cast<ObjFile<ELFT>>(File)->parse(DummyGroups);
+ auto *Obj = cast<ObjFile<ELFT>>(File);
+ Obj->parse(DummyGroups);
+ for (Symbol *Sym : Obj->getGlobalSymbols())
+ Sym->parseSymbolVersion();
ObjectFiles.push_back(File);
}
}
@@ -154,6 +158,12 @@ template <class ELFT> void SymbolTable::addSymbolWrap(StringRef Name) {
Symbol *Sym = find(Name);
if (!Sym)
return;
+
+ // Do not wrap the same symbol twice.
+ for (const WrappedSymbol &S : WrappedSymbols)
+ if (S.Sym == Sym)
+ return;
+
Symbol *Real = addUndefined<ELFT>(Saver.save("__real_" + Name));
Symbol *Wrap = addUndefined<ELFT>(Saver.save("__wrap_" + Name));
WrappedSymbols.push_back({Sym, Real, Wrap});
@@ -186,7 +196,7 @@ void SymbolTable::applySymbolWrap() {
// First, make a copy of __real_sym.
Symbol *Real = nullptr;
if (W.Real->isDefined()) {
- Real = (Symbol *)make<SymbolUnion>();
+ Real = reinterpret_cast<Symbol *>(make<SymbolUnion>());
memcpy(Real, W.Real, sizeof(SymbolUnion));
}
@@ -234,8 +244,7 @@ std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) {
Symbol *Sym;
if (IsNew) {
- Sym = (Symbol *)make<SymbolUnion>();
- Sym->InVersionScript = false;
+ Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
Sym->Visibility = STV_DEFAULT;
Sym->IsUsedInRegularObj = false;
Sym->ExportDynamic = false;
@@ -294,26 +303,88 @@ Symbol *SymbolTable::addUndefined(StringRef Name, uint8_t Binding,
uint8_t Visibility = getVisibility(StOther);
std::tie(S, WasInserted) =
insert(Name, Type, Visibility, CanOmitFromDynSym, File);
+
// An undefined symbol with non default visibility must be satisfied
// in the same DSO.
if (WasInserted || (isa<SharedSymbol>(S) && Visibility != STV_DEFAULT)) {
replaceSymbol<Undefined>(S, File, Name, Binding, StOther, Type);
return S;
}
+
if (S->isShared() || S->isLazy() || (S->isUndefined() && Binding != STB_WEAK))
S->Binding = Binding;
- if (Binding != STB_WEAK) {
+
+ if (!Config->GcSections && Binding != STB_WEAK)
if (auto *SS = dyn_cast<SharedSymbol>(S))
- if (!Config->GcSections)
- SS->getFile<ELFT>().IsNeeded = true;
- }
- if (auto *L = dyn_cast<Lazy>(S)) {
+ SS->getFile<ELFT>().IsNeeded = true;
+
+ if (S->isLazy()) {
// An undefined weak will not fetch archive members. See comment on Lazy in
// Symbols.h for the details.
- if (Binding == STB_WEAK)
- L->Type = Type;
- else if (InputFile *F = L->fetch())
- addFile<ELFT>(F);
+ if (Binding == STB_WEAK) {
+ S->Type = Type;
+ return S;
+ }
+
+ // Do extra check for --warn-backrefs.
+ //
+ // --warn-backrefs is an option to prevent an undefined reference from
+ // fetching an archive member written earlier in the command line. It can be
+ // used to keep compatibility with GNU linkers to some degree.
+ // I'll explain the feature and why you may find it useful in this comment.
+ //
+ // lld's symbol resolution semantics is more relaxed than traditional Unix
+ // linkers. For example,
+ //
+ // ld.lld foo.a bar.o
+ //
+ // succeeds even if bar.o contains an undefined symbol that has to be
+ // resolved by some object file in foo.a. Traditional Unix linkers don't
+ // allow this kind of backward reference, as they visit each file only once
+ // from left to right in the command line while resolving all undefined
+ // symbols at the moment of visiting.
+ //
+ // In the above case, since there's no undefined symbol when a linker visits
+ // foo.a, no files are pulled out from foo.a, and because the linker forgets
+ // about foo.a after visiting, it can't resolve undefined symbols in bar.o
+ // that could have been resolved otherwise.
+ //
+ // That lld accepts more relaxed form means that (besides it'd make more
+ // sense) you can accidentally write a command line or a build file that
+ // works only with lld, even if you have a plan to distribute it to wider
+ // users who may be using GNU linkers. With --warn-backrefs, you can detect
+ // a library order that doesn't work with other Unix linkers.
+ //
+ // The option is also useful to detect cyclic dependencies between static
+ // archives. Again, lld accepts
+ //
+ // ld.lld foo.a bar.a
+ //
+ // even if foo.a and bar.a depend on each other. With --warn-backrefs, it is
+ // handled as an error.
+ //
+ // Here is how the option works. We assign a group ID to each file. A file
+ // with a smaller group ID can pull out object files from an archive file
+ // with an equal or greater group ID. Otherwise, it is a reverse dependency
+ // and an error.
+ //
+ // A file outside --{start,end}-group gets a fresh ID when instantiated. All
+ // files within the same --{start,end}-group get the same group ID. E.g.
+ //
+ // ld.lld A B --start-group C D --end-group E
+ //
+ // A forms group 0. B form group 1. C and D (including their member object
+ // files) form group 2. E forms group 3. I think that you can see how this
+ // group assignment rule simulates the traditional linker's semantics.
+ bool Backref =
+ Config->WarnBackrefs && File && S->File->GroupId < File->GroupId;
+ fetchLazy<ELFT>(S);
+
+ // We don't report backward references to weak symbols as they can be
+ // overridden later.
+ if (Backref && S->Binding != STB_WEAK)
+ warn("backward reference detected: " + Name + " in " + toString(File) +
+ " refers to " + toString(S->File));
}
return S;
}
@@ -381,7 +452,11 @@ Symbol *SymbolTable::addCommon(StringRef N, uint64_t Size, uint32_t Alignment,
bool WasInserted;
std::tie(S, WasInserted) = insert(N, Type, getVisibility(StOther),
/*CanOmitFromDynSym*/ false, &File);
+
int Cmp = compareDefined(S, WasInserted, Binding, N);
+ if (Cmp < 0)
+ return S;
+
if (Cmp > 0) {
auto *Bss = make<BssSection>("COMMON", Size, Alignment);
Bss->File = &File;
@@ -389,45 +464,43 @@ Symbol *SymbolTable::addCommon(StringRef N, uint64_t Size, uint32_t Alignment,
InputSections.push_back(Bss);
replaceSymbol<Defined>(S, &File, N, Binding, StOther, Type, 0, Size, Bss);
- } else if (Cmp == 0) {
- auto *D = cast<Defined>(S);
- auto *Bss = dyn_cast_or_null<BssSection>(D->Section);
- if (!Bss) {
- // Non-common symbols take precedence over common symbols.
- if (Config->WarnCommon)
- warn("common " + S->getName() + " is overridden");
- return S;
- }
+ return S;
+ }
+ auto *D = cast<Defined>(S);
+ auto *Bss = dyn_cast_or_null<BssSection>(D->Section);
+ if (!Bss) {
+ // Non-common symbols take precedence over common symbols.
if (Config->WarnCommon)
- warn("multiple common of " + D->getName());
+ warn("common " + S->getName() + " is overridden");
+ return S;
+ }
- Bss->Alignment = std::max(Bss->Alignment, Alignment);
- if (Size > Bss->Size) {
- D->File = Bss->File = &File;
- D->Size = Bss->Size = Size;
- }
+ if (Config->WarnCommon)
+ warn("multiple common of " + D->getName());
+
+ Bss->Alignment = std::max(Bss->Alignment, Alignment);
+ if (Size > Bss->Size) {
+ D->File = Bss->File = &File;
+ D->Size = Bss->Size = Size;
}
return S;
}
-static void warnOrError(const Twine &Msg) {
- if (Config->AllowMultipleDefinition)
- warn(Msg);
- else
- error(Msg);
-}
-
static void reportDuplicate(Symbol *Sym, InputFile *NewFile) {
- warnOrError("duplicate symbol: " + toString(*Sym) + "\n>>> defined in " +
- toString(Sym->File) + "\n>>> defined in " + toString(NewFile));
+ if (!Config->AllowMultipleDefinition)
+ error("duplicate symbol: " + toString(*Sym) + "\n>>> defined in " +
+ toString(Sym->File) + "\n>>> defined in " + toString(NewFile));
}
-static void reportDuplicate(Symbol *Sym, InputSectionBase *ErrSec,
- uint64_t ErrOffset) {
+static void reportDuplicate(Symbol *Sym, InputFile *NewFile,
+ InputSectionBase *ErrSec, uint64_t ErrOffset) {
+ if (Config->AllowMultipleDefinition)
+ return;
+
Defined *D = cast<Defined>(Sym);
if (!D->Section || !ErrSec) {
- reportDuplicate(Sym, ErrSec ? ErrSec->File : nullptr);
+ reportDuplicate(Sym, NewFile);
return;
}
@@ -451,7 +524,7 @@ static void reportDuplicate(Symbol *Sym, InputSectionBase *ErrSec,
if (!Src2.empty())
Msg += Src2 + "\n>>> ";
Msg += Obj2;
- warnOrError(Msg);
+ error(Msg);
}
Symbol *SymbolTable::addRegular(StringRef Name, uint8_t StOther, uint8_t Type,
@@ -467,7 +540,8 @@ Symbol *SymbolTable::addRegular(StringRef Name, uint8_t StOther, uint8_t Type,
replaceSymbol<Defined>(S, File, Name, Binding, StOther, Type, Value, Size,
Section);
else if (Cmp == 0)
- reportDuplicate(S, dyn_cast_or_null<InputSectionBase>(Section), Value);
+ reportDuplicate(S, File, dyn_cast_or_null<InputSectionBase>(Section),
+ Value);
return S;
}
@@ -488,8 +562,8 @@ void SymbolTable::addShared(StringRef Name, SharedFile<ELFT> &File,
// An undefined symbol with non default visibility must be satisfied
// in the same DSO.
- if (WasInserted || ((S->isUndefined() || S->isLazy()) &&
- S->getVisibility() == STV_DEFAULT)) {
+ if (WasInserted ||
+ ((S->isUndefined() || S->isLazy()) && S->Visibility == STV_DEFAULT)) {
uint8_t Binding = S->Binding;
bool WasUndefined = S->isUndefined();
replaceSymbol<SharedSymbol>(S, File, Name, Sym.getBinding(), Sym.st_other,
@@ -528,85 +602,58 @@ Symbol *SymbolTable::find(StringRef Name) {
return SymVector[It->second];
}
-template <class ELFT>
-Symbol *SymbolTable::addLazyArchive(StringRef Name, ArchiveFile &F,
- const object::Archive::Symbol Sym) {
+// This is used to handle lazy symbols. May replace existent
+// symbol with lazy version or request to Fetch it.
+template <class ELFT, typename LazyT, typename... ArgT>
+static void replaceOrFetchLazy(StringRef Name, InputFile &File,
+ llvm::function_ref<InputFile *()> Fetch,
+ ArgT &&... Arg) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(Name);
+ std::tie(S, WasInserted) = Symtab->insert(Name);
if (WasInserted) {
- replaceSymbol<LazyArchive>(S, F, Sym, Symbol::UnknownType);
- return S;
+ replaceSymbol<LazyT>(S, File, Symbol::UnknownType,
+ std::forward<ArgT>(Arg)...);
+ return;
}
if (!S->isUndefined())
- return S;
+ return;
// An undefined weak will not fetch archive members. See comment on Lazy in
// Symbols.h for the details.
if (S->isWeak()) {
- replaceSymbol<LazyArchive>(S, F, Sym, S->Type);
+ replaceSymbol<LazyT>(S, File, S->Type, std::forward<ArgT>(Arg)...);
S->Binding = STB_WEAK;
- return S;
+ return;
}
- std::pair<MemoryBufferRef, uint64_t> MBInfo = F.getMember(&Sym);
- if (!MBInfo.first.getBuffer().empty())
- addFile<ELFT>(createObjectFile(MBInfo.first, F.getName(), MBInfo.second));
- return S;
+
+ if (InputFile *F = Fetch())
+ Symtab->addFile<ELFT>(F);
}
template <class ELFT>
-void SymbolTable::addLazyObject(StringRef Name, LazyObjFile &Obj) {
- Symbol *S;
- bool WasInserted;
- std::tie(S, WasInserted) = insert(Name);
- if (WasInserted) {
- replaceSymbol<LazyObject>(S, Obj, Name, Symbol::UnknownType);
- return;
- }
- if (!S->isUndefined())
- return;
-
- // See comment for addLazyArchive above.
- if (S->isWeak())
- replaceSymbol<LazyObject>(S, Obj, Name, S->Type);
- else if (InputFile *F = Obj.fetch())
- addFile<ELFT>(F);
-}
-
-// If we already saw this symbol, force loading its file.
-template <class ELFT> void SymbolTable::fetchIfLazy(StringRef Name) {
- if (Symbol *B = find(Name)) {
- // Mark the symbol not to be eliminated by LTO
- // even if it is a bitcode symbol.
- B->IsUsedInRegularObj = true;
- if (auto *L = dyn_cast<Lazy>(B))
- if (InputFile *File = L->fetch())
- addFile<ELFT>(File);
- }
+void SymbolTable::addLazyArchive(StringRef Name, ArchiveFile &F,
+ const object::Archive::Symbol Sym) {
+ replaceOrFetchLazy<ELFT, LazyArchive>(Name, F, [&]() { return F.fetch(Sym); },
+ Sym);
}
-// This function takes care of the case in which shared libraries depend on
-// the user program (not the other way, which is usual). Shared libraries
-// may have undefined symbols, expecting that the user program provides
-// the definitions for them. An example is BSD's __progname symbol.
-// We need to put such symbols to the main program's .dynsym so that
-// shared libraries can find them.
-// Except this, we ignore undefined symbols in DSOs.
-template <class ELFT> void SymbolTable::scanShlibUndefined() {
- for (InputFile *F : SharedFiles) {
- for (StringRef U : cast<SharedFile<ELFT>>(F)->getUndefinedSymbols()) {
- Symbol *Sym = find(U);
- if (!Sym || !Sym->isDefined())
- continue;
- Sym->ExportDynamic = true;
+template <class ELFT>
+void SymbolTable::addLazyObject(StringRef Name, LazyObjFile &Obj) {
+ replaceOrFetchLazy<ELFT, LazyObject>(Name, Obj, [&]() { return Obj.fetch(); },
+ Name);
+}
- // If -dynamic-list is given, the default version is set to
- // VER_NDX_LOCAL, which prevents a symbol to be exported via .dynsym.
- // Set to VER_NDX_GLOBAL so the symbol will be handled as if it were
- // specified by -dynamic-list.
- Sym->VersionId = VER_NDX_GLOBAL;
- }
+template <class ELFT> void SymbolTable::fetchLazy(Symbol *Sym) {
+ if (auto *S = dyn_cast<LazyArchive>(Sym)) {
+ if (InputFile *File = S->fetch())
+ addFile<ELFT>(File);
+ return;
}
+
+ auto *S = cast<LazyObject>(Sym);
+ if (InputFile *File = cast<LazyObjFile>(S->File)->fetch())
+ addFile<ELFT>(File);
}
// Initialize DemangledSyms with a map from demangled symbols to symbol
@@ -705,7 +752,7 @@ void SymbolTable::assignExactVersion(SymbolVersion Ver, uint16_t VersionId,
// Get a list of symbols which we need to assign the version to.
std::vector<Symbol *> Syms = findByVersion(Ver);
if (Syms.empty()) {
- if (Config->NoUndefinedVersion)
+ if (!Config->UndefinedVersion)
error("version script assignment of '" + VersionName + "' to symbol '" +
Ver.Name + "' failed: symbol not defined");
return;
@@ -719,10 +766,10 @@ void SymbolTable::assignExactVersion(SymbolVersion Ver, uint16_t VersionId,
if (Sym->getName().contains('@'))
continue;
- if (Sym->InVersionScript)
- warn("duplicate symbol '" + Ver.Name + "' in version script");
+ if (Sym->VersionId != Config->DefaultSymbolVersion &&
+ Sym->VersionId != VersionId)
+ error("duplicate symbol '" + Ver.Name + "' in version script");
Sym->VersionId = VersionId;
- Sym->InVersionScript = true;
}
}
@@ -770,6 +817,11 @@ void SymbolTable::scanVersionScript() {
Sym->parseSymbolVersion();
}
+template void SymbolTable::addFile<ELF32LE>(InputFile *);
+template void SymbolTable::addFile<ELF32BE>(InputFile *);
+template void SymbolTable::addFile<ELF64LE>(InputFile *);
+template void SymbolTable::addFile<ELF64BE>(InputFile *);
+
template void SymbolTable::addSymbolWrap<ELF32LE>(StringRef);
template void SymbolTable::addSymbolWrap<ELF32BE>(StringRef);
template void SymbolTable::addSymbolWrap<ELF64LE>(StringRef);
@@ -794,16 +846,16 @@ template void SymbolTable::addCombinedLTOObject<ELF32BE>();
template void SymbolTable::addCombinedLTOObject<ELF64LE>();
template void SymbolTable::addCombinedLTOObject<ELF64BE>();
-template Symbol *
+template void
SymbolTable::addLazyArchive<ELF32LE>(StringRef, ArchiveFile &,
const object::Archive::Symbol);
-template Symbol *
+template void
SymbolTable::addLazyArchive<ELF32BE>(StringRef, ArchiveFile &,
const object::Archive::Symbol);
-template Symbol *
+template void
SymbolTable::addLazyArchive<ELF64LE>(StringRef, ArchiveFile &,
const object::Archive::Symbol);
-template Symbol *
+template void
SymbolTable::addLazyArchive<ELF64BE>(StringRef, ArchiveFile &,
const object::Archive::Symbol);
@@ -812,6 +864,11 @@ template void SymbolTable::addLazyObject<ELF32BE>(StringRef, LazyObjFile &);
template void SymbolTable::addLazyObject<ELF64LE>(StringRef, LazyObjFile &);
template void SymbolTable::addLazyObject<ELF64BE>(StringRef, LazyObjFile &);
+template void SymbolTable::fetchLazy<ELF32LE>(Symbol *);
+template void SymbolTable::fetchLazy<ELF32BE>(Symbol *);
+template void SymbolTable::fetchLazy<ELF64LE>(Symbol *);
+template void SymbolTable::fetchLazy<ELF64BE>(Symbol *);
+
template void SymbolTable::addShared<ELF32LE>(StringRef, SharedFile<ELF32LE> &,
const typename ELF32LE::Sym &,
uint32_t Alignment, uint32_t);
@@ -824,13 +881,3 @@ template void SymbolTable::addShared<ELF64LE>(StringRef, SharedFile<ELF64LE> &,
template void SymbolTable::addShared<ELF64BE>(StringRef, SharedFile<ELF64BE> &,
const typename ELF64BE::Sym &,
uint32_t Alignment, uint32_t);
-
-template void SymbolTable::fetchIfLazy<ELF32LE>(StringRef);
-template void SymbolTable::fetchIfLazy<ELF32BE>(StringRef);
-template void SymbolTable::fetchIfLazy<ELF64LE>(StringRef);
-template void SymbolTable::fetchIfLazy<ELF64BE>(StringRef);
-
-template void SymbolTable::scanShlibUndefined<ELF32LE>();
-template void SymbolTable::scanShlibUndefined<ELF32BE>();
-template void SymbolTable::scanShlibUndefined<ELF64LE>();
-template void SymbolTable::scanShlibUndefined<ELF64BE>();
diff --git a/gnu/llvm/tools/lld/ELF/Symbols.cpp b/gnu/llvm/tools/lld/ELF/Symbols.cpp
index 6e0a83c9612..dc0d891af97 100644
--- a/gnu/llvm/tools/lld/ELF/Symbols.cpp
+++ b/gnu/llvm/tools/lld/ELF/Symbols.cpp
@@ -14,7 +14,6 @@
#include "SyntheticSections.h"
#include "Target.h"
#include "Writer.h"
-
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Strings.h"
#include "llvm/ADT/STLExtras.h"
@@ -40,6 +39,7 @@ Defined *ElfSym::GlobalOffsetTable;
Defined *ElfSym::MipsGp;
Defined *ElfSym::MipsGpDisp;
Defined *ElfSym::MipsLocalGp;
+Defined *ElfSym::RelaIpltEnd;
static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) {
switch (Sym.kind()) {
@@ -59,6 +59,7 @@ static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) {
return D.Value;
IS = IS->Repl;
+
uint64_t Offset = D.Value;
// An object in an SHF_MERGE section might be referenced via a
@@ -77,8 +78,6 @@ static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) {
Addend = 0;
}
- const OutputSection *OutSec = IS->getOutputSection();
-
// In the typical case, this is actually very simple and boils
// down to adding together 3 numbers:
// 1. The address of the output section.
@@ -89,7 +88,7 @@ static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) {
// If you understand the data structures involved with this next
// line (and how they get built), then you have a pretty good
// understanding of the linker.
- uint64_t VA = (OutSec ? OutSec->Addr : 0) + IS->getOffset(Offset);
+ uint64_t VA = IS->getVA(Offset);
if (D.isTls() && !Config->Relocatable) {
if (!Out::TlsPhdr)
@@ -99,20 +98,12 @@ static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) {
}
return VA;
}
- case Symbol::SharedKind: {
- auto &SS = cast<SharedSymbol>(Sym);
- if (SS.CopyRelSec)
- return SS.CopyRelSec->getParent()->Addr + SS.CopyRelSec->OutSecOff;
- if (SS.NeedsPltAddr)
- return Sym.getPltVA();
- return 0;
- }
+ case Symbol::SharedKind:
case Symbol::UndefinedKind:
return 0;
case Symbol::LazyArchiveKind:
case Symbol::LazyObjectKind:
- assert(Sym.IsUsedInRegularObj && "lazy symbol reached writer");
- return 0;
+ llvm_unreachable("lazy symbol reached writer");
}
llvm_unreachable("invalid symbol kind");
}
@@ -135,22 +126,26 @@ uint64_t Symbol::getGotPltVA() const {
}
uint64_t Symbol::getGotPltOffset() const {
- return GotPltIndex * Target->GotPltEntrySize;
+ if (IsInIgot)
+ return PltIndex * Target->GotPltEntrySize;
+ return (PltIndex + Target->GotPltHeaderEntriesNum) * Target->GotPltEntrySize;
}
uint64_t Symbol::getPltVA() const {
if (this->IsInIplt)
return InX::Iplt->getVA() + PltIndex * Target->PltEntrySize;
- return InX::Plt->getVA() + Target->PltHeaderSize +
- PltIndex * Target->PltEntrySize;
+ return InX::Plt->getVA() + Target->getPltEntryOffset(PltIndex);
+}
+
+uint64_t Symbol::getPltOffset() const {
+ assert(!this->IsInIplt);
+ return Target->getPltEntryOffset(PltIndex);
}
uint64_t Symbol::getSize() const {
if (const auto *DR = dyn_cast<Defined>(this))
return DR->Size;
- if (const auto *S = dyn_cast<SharedSymbol>(this))
- return S->Size;
- return 0;
+ return cast<SharedSymbol>(this)->Size;
}
OutputSection *Symbol::getOutputSection() const {
@@ -159,13 +154,6 @@ OutputSection *Symbol::getOutputSection() const {
return Sec->Repl->getOutputSection();
return nullptr;
}
-
- if (auto *S = dyn_cast<SharedSymbol>(this)) {
- if (S->CopyRelSec)
- return S->CopyRelSec->getParent();
- return nullptr;
- }
-
return nullptr;
}
@@ -181,7 +169,7 @@ void Symbol::parseSymbolVersion() {
return;
// Truncate the symbol name so that it doesn't include the version string.
- Name = {S.data(), Pos};
+ NameSize = Pos;
// If this is not in this DSO, it is not a definition.
if (!isDefined())
@@ -207,42 +195,24 @@ void Symbol::parseSymbolVersion() {
// It is an error if the specified version is not defined.
// Usually version script is not provided when linking executable,
// but we may still want to override a versioned symbol from DSO,
- // so we do not report error in this case.
- if (Config->Shared)
+ // so we do not report error in this case. We also do not error
+ // if the symbol has a local version as it won't be in the dynamic
+ // symbol table.
+ if (Config->Shared && VersionId != VER_NDX_LOCAL)
error(toString(File) + ": symbol " + S + " has undefined version " +
Verstr);
}
-InputFile *Lazy::fetch() {
- if (auto *S = dyn_cast<LazyArchive>(this))
- return S->fetch();
- return cast<LazyObject>(this)->fetch();
-}
-
-ArchiveFile &LazyArchive::getFile() { return *cast<ArchiveFile>(File); }
-
-InputFile *LazyArchive::fetch() {
- std::pair<MemoryBufferRef, uint64_t> MBInfo = getFile().getMember(&Sym);
-
- // getMember returns an empty buffer if the member was already
- // read from the library.
- if (MBInfo.first.getBuffer().empty())
- return nullptr;
- return createObjectFile(MBInfo.first, getFile().getName(), MBInfo.second);
-}
-
-LazyObjFile &LazyObject::getFile() { return *cast<LazyObjFile>(File); }
-
-InputFile *LazyObject::fetch() { return getFile().fetch(); }
+InputFile *LazyArchive::fetch() { return cast<ArchiveFile>(File)->fetch(Sym); }
uint8_t Symbol::computeBinding() const {
if (Config->Relocatable)
return Binding;
if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED)
return STB_LOCAL;
- if (VersionId == VER_NDX_LOCAL && isDefined())
+ if (VersionId == VER_NDX_LOCAL && isDefined() && !IsPreemptible)
return STB_LOCAL;
- if (Config->NoGnuUnique && Binding == STB_GNU_UNIQUE)
+ if (!Config->GnuUnique && Binding == STB_GNU_UNIQUE)
return STB_GLOBAL;
return Binding;
}
@@ -274,6 +244,27 @@ void elf::printTraceSymbol(Symbol *Sym) {
message(toString(Sym->File) + S + Sym->getName());
}
+void elf::warnUnorderableSymbol(const Symbol *Sym) {
+ if (!Config->WarnSymbolOrdering)
+ return;
+
+ const InputFile *File = Sym->File;
+ auto *D = dyn_cast<Defined>(Sym);
+
+ auto Warn = [&](StringRef S) { warn(toString(File) + S + Sym->getName()); };
+
+ if (Sym->isUndefined())
+ Warn(": unable to order undefined symbol: ");
+ else if (Sym->isShared())
+ Warn(": unable to order shared symbol: ");
+ else if (D && !D->Section)
+ Warn(": unable to order absolute symbol: ");
+ else if (D && isa<OutputSection>(D->Section))
+ Warn(": unable to order synthetic symbol: ");
+ else if (D && !D->Section->Repl->Live)
+ Warn(": unable to order discarded symbol: ");
+}
+
// Returns a symbol for an error message.
std::string lld::toString(const Symbol &B) {
if (Config->Demangle)
diff --git a/gnu/llvm/tools/lld/ELF/Symbols.h b/gnu/llvm/tools/lld/ELF/Symbols.h
index 1e3c0af64ef..6a33f5ebce2 100644
--- a/gnu/llvm/tools/lld/ELF/Symbols.h
+++ b/gnu/llvm/tools/lld/ELF/Symbols.h
@@ -7,8 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// All symbols are handled as SymbolBodies regardless of their types.
-// This file defines various types of SymbolBodies.
+// This file defines various types of Symbols.
//
//===----------------------------------------------------------------------===//
@@ -16,9 +15,8 @@
#define LLD_ELF_SYMBOLS_H
#include "InputSection.h"
-#include "Strings.h"
-
#include "lld/Common/LLVM.h"
+#include "lld/Common/Strings.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/ELF.h"
@@ -34,6 +32,20 @@ template <class ELFT> class ObjFile;
class OutputSection;
template <class ELFT> class SharedFile;
+// This is a StringRef-like container that doesn't run strlen().
+//
+// ELF string tables contain a lot of null-terminated strings. Most of them
+// are not necessary for the linker because they are names of local symbols,
+// and the linker doesn't use local symbol names for name resolution. So, we
+// use this class to represents strings read from string tables.
+struct StringRefZ {
+ StringRefZ(const char *S) : Data(S), Size(-1) {}
+ StringRefZ(StringRef S) : Data(S.data()), Size(S.size()) {}
+
+ const char *Data;
+ const uint32_t Size;
+};
+
// The base class for real symbol classes.
class Symbol {
public:
@@ -47,6 +59,25 @@ public:
Kind kind() const { return static_cast<Kind>(SymbolKind); }
+ // The file from which this symbol was created.
+ InputFile *File;
+
+protected:
+ const char *NameData;
+ mutable uint32_t NameSize;
+
+public:
+ uint32_t DynsymIndex = 0;
+ uint32_t GotIndex = -1;
+ uint32_t PltIndex = -1;
+ uint32_t GlobalDynIndex = -1;
+
+ // This field is a index to the symbol's version definition.
+ uint32_t VerdefIndex = -1;
+
+ // Version definition index.
+ uint16_t VersionId;
+
// Symbol binding. This is not overwritten by replaceSymbol to track
// changes during resolution. In particular:
// - An undefined weak is still weak when it resolves to a shared library.
@@ -54,8 +85,11 @@ public:
// remember it is weak.
uint8_t Binding;
- // Version definition index.
- uint16_t VersionId;
+ // The following fields have the same meaning as the ELF symbol attributes.
+ uint8_t Type; // symbol type
+ uint8_t StOther; // st_other field value
+
+ const uint8_t SymbolKind;
// Symbol visibility. This is the computed minimum visibility of all
// observed non-DSO symbols.
@@ -81,12 +115,6 @@ public:
// True if this symbol is specified by --trace-symbol option.
unsigned Traced : 1;
- // This symbol version was found in a version script.
- unsigned InVersionScript : 1;
-
- // The file from which this symbol was created.
- InputFile *File;
-
bool includeInDynsym() const;
uint8_t computeBinding() const;
bool isWeak() const { return Binding == llvm::ELF::STB_WEAK; }
@@ -100,15 +128,15 @@ public:
return SymbolKind == LazyArchiveKind || SymbolKind == LazyObjectKind;
}
- // True is this is an undefined weak symbol. This only works once
- // all input files have been added.
- bool isUndefWeak() const {
- // See comment on Lazy the details.
- return isWeak() && (isUndefined() || isLazy());
+ // True if this is an undefined weak symbol.
+ bool isUndefWeak() const { return isWeak() && isUndefined(); }
+
+ StringRef getName() const {
+ if (NameSize == (uint32_t)-1)
+ NameSize = strlen(NameData);
+ return {NameData, NameSize};
}
- StringRef getName() const { return Name; }
- uint8_t getVisibility() const { return StOther & 0x3; }
void parseSymbolVersion();
bool isInGot() const { return GotIndex != -1U; }
@@ -121,34 +149,22 @@ public:
uint64_t getGotPltOffset() const;
uint64_t getGotPltVA() const;
uint64_t getPltVA() const;
+ uint64_t getPltOffset() const;
uint64_t getSize() const;
OutputSection *getOutputSection() const;
- uint32_t DynsymIndex = 0;
- uint32_t GotIndex = -1;
- uint32_t GotPltIndex = -1;
- uint32_t PltIndex = -1;
- uint32_t GlobalDynIndex = -1;
-
protected:
Symbol(Kind K, InputFile *File, StringRefZ Name, uint8_t Binding,
uint8_t StOther, uint8_t Type)
- : Binding(Binding), File(File), SymbolKind(K), NeedsPltAddr(false),
- IsInGlobalMipsGot(false), Is32BitMipsGot(false), IsInIplt(false),
- IsInIgot(false), IsPreemptible(false), Used(!Config->GcSections),
- Type(Type), StOther(StOther), Name(Name) {}
-
- const unsigned SymbolKind : 8;
+ : File(File), NameData(Name.Data), NameSize(Name.Size), Binding(Binding),
+ Type(Type), StOther(StOther), SymbolKind(K), NeedsPltAddr(false),
+ IsInIplt(false), IsInIgot(false), IsPreemptible(false),
+ Used(!Config->GcSections), NeedsTocRestore(false) {}
public:
// True the symbol should point to its PLT entry.
// For SharedSymbol only.
unsigned NeedsPltAddr : 1;
- // True if this symbol has an entry in the global part of MIPS GOT.
- unsigned IsInGlobalMipsGot : 1;
-
- // True if this symbol is referenced by 32-bit GOT relocations.
- unsigned Is32BitMipsGot : 1;
// True if this symbol is in the Iplt sub-section of the Plt.
unsigned IsInIplt : 1;
@@ -156,14 +172,15 @@ public:
// True if this symbol is in the Igot sub-section of the .got.plt or .got.
unsigned IsInIgot : 1;
+ // True if this symbol is preemptible at load time.
unsigned IsPreemptible : 1;
// True if an undefined or shared symbol is used from a live section.
unsigned Used : 1;
- // The following fields have the same meaning as the ELF symbol attributes.
- uint8_t Type; // symbol type
- uint8_t StOther; // st_other field value
+ // True if a call to this symbol needs to be followed by a restore of the
+ // PPC64 toc pointer.
+ unsigned NeedsTocRestore : 1;
// The Type field may also have this value. It means that we have not yet seen
// a non-Lazy symbol with this name, so we don't know what its type is. The
@@ -178,9 +195,6 @@ public:
bool isGnuIFunc() const { return Type == llvm::ELF::STT_GNU_IFUNC; }
bool isObject() const { return Type == llvm::ELF::STT_OBJECT; }
bool isFile() const { return Type == llvm::ELF::STT_FILE; }
-
-protected:
- StringRefZ Name;
};
// Represents a symbol that is defined in the current output file.
@@ -214,8 +228,9 @@ public:
SharedSymbol(InputFile &File, StringRef Name, uint8_t Binding,
uint8_t StOther, uint8_t Type, uint64_t Value, uint64_t Size,
uint32_t Alignment, uint32_t VerdefIndex)
- : Symbol(SharedKind, &File, Name, Binding, StOther, Type), Value(Value),
- Size(Size), VerdefIndex(VerdefIndex), Alignment(Alignment) {
+ : Symbol(SharedKind, &File, Name, Binding, StOther, Type),
+ Alignment(Alignment), Value(Value), Size(Size) {
+ this->VerdefIndex = VerdefIndex;
// GNU ifunc is a mechanism to allow user-supplied functions to
// resolve PLT slot values at load-time. This is contrary to the
// regular symbol resolution scheme in which symbols are resolved just
@@ -240,54 +255,36 @@ public:
return *cast<SharedFile<ELFT>>(File);
}
- // If not null, there is a copy relocation to this section.
- InputSection *CopyRelSec = nullptr;
+ uint32_t Alignment;
uint64_t Value; // st_value
uint64_t Size; // st_size
-
- // This field is a index to the symbol's version definition.
- uint32_t VerdefIndex;
-
- uint32_t Alignment;
};
-// This represents a symbol that is not yet in the link, but we know where to
-// find it if needed. If the resolver finds both Undefined and Lazy for the same
-// name, it will ask the Lazy to load a file.
+// LazyArchive and LazyObject represent a symbols that is not yet in the link,
+// but we know where to find it if needed. If the resolver finds both Undefined
+// and Lazy for the same name, it will ask the Lazy to load a file.
//
// A special complication is the handling of weak undefined symbols. They should
// not load a file, but we have to remember we have seen both the weak undefined
// and the lazy. We represent that with a lazy symbol with a weak binding. This
// means that code looking for undefined symbols normally also has to take lazy
// symbols into consideration.
-class Lazy : public Symbol {
-public:
- static bool classof(const Symbol *S) { return S->isLazy(); }
-
- // Returns an object file for this symbol, or a nullptr if the file
- // was already returned.
- InputFile *fetch();
-
-protected:
- Lazy(Kind K, InputFile &File, StringRef Name, uint8_t Type)
- : Symbol(K, &File, Name, llvm::ELF::STB_GLOBAL, llvm::ELF::STV_DEFAULT,
- Type) {}
-};
// This class represents a symbol defined in an archive file. It is
// created from an archive file header, and it knows how to load an
// object file from an archive to replace itself with a defined
// symbol.
-class LazyArchive : public Lazy {
+class LazyArchive : public Symbol {
public:
- LazyArchive(InputFile &File, const llvm::object::Archive::Symbol S,
- uint8_t Type)
- : Lazy(LazyArchiveKind, File, S.getName(), Type), Sym(S) {}
+ LazyArchive(InputFile &File, uint8_t Type,
+ const llvm::object::Archive::Symbol S)
+ : Symbol(LazyArchiveKind, &File, S.getName(), llvm::ELF::STB_GLOBAL,
+ llvm::ELF::STV_DEFAULT, Type),
+ Sym(S) {}
static bool classof(const Symbol *S) { return S->kind() == LazyArchiveKind; }
- ArchiveFile &getFile();
InputFile *fetch();
private:
@@ -296,15 +293,13 @@ private:
// LazyObject symbols represents symbols in object files between
// --start-lib and --end-lib options.
-class LazyObject : public Lazy {
+class LazyObject : public Symbol {
public:
- LazyObject(InputFile &File, StringRef Name, uint8_t Type)
- : Lazy(LazyObjectKind, File, Name, Type) {}
+ LazyObject(InputFile &File, uint8_t Type, StringRef Name)
+ : Symbol(LazyObjectKind, &File, Name, llvm::ELF::STB_GLOBAL,
+ llvm::ELF::STV_DEFAULT, Type) {}
static bool classof(const Symbol *S) { return S->kind() == LazyObjectKind; }
-
- LazyObjFile &getFile();
- InputFile *fetch();
};
// Some linker-generated symbols need to be created as
@@ -337,6 +332,9 @@ struct ElfSym {
static Defined *MipsGp;
static Defined *MipsGpDisp;
static Defined *MipsLocalGp;
+
+ // __rela_iplt_end or __rel_iplt_end
+ static Defined *RelaIpltEnd;
};
// A buffer class that is large enough to hold any Symbol-derived
@@ -354,6 +352,8 @@ void printTraceSymbol(Symbol *Sym);
template <typename T, typename... ArgT>
void replaceSymbol(Symbol *S, ArgT &&... Arg) {
+ static_assert(std::is_trivially_destructible<T>(),
+ "Symbol types must be trivially destructible");
static_assert(sizeof(T) <= sizeof(SymbolUnion), "SymbolUnion too small");
static_assert(alignof(T) <= alignof(SymbolUnion),
"SymbolUnion not aligned enough");
@@ -370,13 +370,14 @@ void replaceSymbol(Symbol *S, ArgT &&... Arg) {
S->ExportDynamic = Sym.ExportDynamic;
S->CanInline = Sym.CanInline;
S->Traced = Sym.Traced;
- S->InVersionScript = Sym.InVersionScript;
// Print out a log message if --trace-symbol was specified.
// This is for debugging.
if (S->Traced)
printTraceSymbol(S);
}
+
+void warnUnorderableSymbol(const Symbol *Sym);
} // namespace elf
std::string toString(const elf::Symbol &B);
diff --git a/gnu/llvm/tools/lld/ELF/SyntheticSections.cpp b/gnu/llvm/tools/lld/ELF/SyntheticSections.cpp
index 023554cb268..475531f0ad1 100644
--- a/gnu/llvm/tools/lld/ELF/SyntheticSections.cpp
+++ b/gnu/llvm/tools/lld/ELF/SyntheticSections.cpp
@@ -20,15 +20,16 @@
#include "InputFiles.h"
#include "LinkerScript.h"
#include "OutputSections.h"
-#include "Strings.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "Target.h"
#include "Writer.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
+#include "lld/Common/Strings.h"
#include "lld/Common/Threads.h"
#include "lld/Common/Version.h"
+#include "llvm/ADT/SetOperations.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
#include "llvm/Object/Decompressor.h"
@@ -47,27 +48,20 @@ using namespace llvm::dwarf;
using namespace llvm::ELF;
using namespace llvm::object;
using namespace llvm::support;
-using namespace llvm::support::endian;
using namespace lld;
using namespace lld::elf;
-constexpr size_t MergeNoTailSection::NumShards;
-
-static void write32(void *Buf, uint32_t Val) {
- endian::write32(Buf, Val, Config->Endianness);
-}
+using llvm::support::endian::read32le;
+using llvm::support::endian::write32le;
+using llvm::support::endian::write64le;
-uint64_t SyntheticSection::getVA() const {
- if (OutputSection *Sec = getParent())
- return Sec->Addr + OutSecOff;
- return 0;
-}
+constexpr size_t MergeNoTailSection::NumShards;
// Returns an LLD version string.
static ArrayRef<uint8_t> getVersion() {
// Check LLD_VERSION first for ease of testing.
- // You can get consitent output by using the environment variable.
+ // You can get consistent output by using the environment variable.
// This is only for testing.
StringRef S = getenv("LLD_VERSION");
if (S.empty())
@@ -192,8 +186,6 @@ MipsOptionsSection<ELFT> *MipsOptionsSection<ELFT>::create() {
auto *Opt = reinterpret_cast<const Elf_Mips_Options *>(D.data());
if (Opt->kind == ODK_REGINFO) {
- if (Config->Relocatable && Opt->getRegInfo().ri_gp_value)
- error(Filename + ": unsupported non-zero ri_gp_value");
Reginfo.ri_gprmask |= Opt->getRegInfo().ri_gprmask;
Sec->getFile<ELFT>()->MipsGp0 = Opt->getRegInfo().ri_gp_value;
break;
@@ -244,10 +236,8 @@ MipsReginfoSection<ELFT> *MipsReginfoSection<ELFT>::create() {
error(toString(Sec->File) + ": invalid size of .reginfo section");
return nullptr;
}
- auto *R = reinterpret_cast<const Elf_Mips_RegInfo *>(Sec->Data.data());
- if (Config->Relocatable && R->ri_gp_value)
- error(toString(Sec->File) + ": unsupported non-zero ri_gp_value");
+ auto *R = reinterpret_cast<const Elf_Mips_RegInfo *>(Sec->Data.data());
Reginfo.ri_gprmask |= R->ri_gprmask;
Sec->getFile<ELFT>()->MipsGp0 = R->ri_gp_value;
};
@@ -266,8 +256,8 @@ InputSection *elf::createInterpSection() {
return Sec;
}
-Symbol *elf::addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value,
- uint64_t Size, InputSectionBase &Section) {
+Defined *elf::addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value,
+ uint64_t Size, InputSectionBase &Section) {
auto *S = make<Defined>(Section.File, Name, STB_LOCAL, STV_DEFAULT, Type,
Value, Size, &Section);
if (InX::SymTab)
@@ -338,8 +328,6 @@ void BuildIdSection::computeHash(
BssSection::BssSection(StringRef Name, uint64_t Size, uint32_t Alignment)
: SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_NOBITS, Alignment, Name) {
this->Bss = true;
- if (OutputSection *Sec = getParent())
- Sec->Alignment = std::max(Sec->Alignment, Alignment);
this->Size = Size;
}
@@ -347,7 +335,7 @@ void BuildIdSection::writeBuildId(ArrayRef<uint8_t> Buf) {
switch (Config->BuildId) {
case BuildIdKind::Fast:
computeHash(Buf, [](uint8_t *Dest, ArrayRef<uint8_t> Arr) {
- write64le(Dest, xxHash64(toStringRef(Arr)));
+ write64le(Dest, xxHash64(Arr));
});
break;
case BuildIdKind::Md5:
@@ -380,15 +368,11 @@ EhFrameSection::EhFrameSection()
// and where their relocations point to.
template <class ELFT, class RelTy>
CieRecord *EhFrameSection::addCie(EhSectionPiece &Cie, ArrayRef<RelTy> Rels) {
- auto *Sec = cast<EhInputSection>(Cie.Sec);
- if (read32(Cie.data().data() + 4, Config->Endianness) != 0)
- fatal(toString(Sec) + ": CIE expected at beginning of .eh_frame");
-
Symbol *Personality = nullptr;
unsigned FirstRelI = Cie.FirstRelocation;
if (FirstRelI != (unsigned)-1)
Personality =
- &Sec->template getFile<ELFT>()->getRelocTargetSym(Rels[FirstRelI]);
+ &Cie.Sec->template getFile<ELFT>()->getRelocTargetSym(Rels[FirstRelI]);
// Search for an existing CIE by CIE contents/relocation target pair.
CieRecord *&Rec = CieMap[{Cie.data(), Personality}];
@@ -433,14 +417,14 @@ bool EhFrameSection::isFdeLive(EhSectionPiece &Fde, ArrayRef<RelTy> Rels) {
// one and associates FDEs to the CIE.
template <class ELFT, class RelTy>
void EhFrameSection::addSectionAux(EhInputSection *Sec, ArrayRef<RelTy> Rels) {
- DenseMap<size_t, CieRecord *> OffsetToCie;
+ OffsetToCie.clear();
for (EhSectionPiece &Piece : Sec->Pieces) {
// The empty record is the end marker.
if (Piece.Size == 4)
return;
size_t Offset = Piece.InputOff;
- uint32_t ID = read32(Piece.data().data() + 4, Config->Endianness);
+ uint32_t ID = read32(Piece.data().data() + 4);
if (ID == 0) {
OffsetToCie[Offset] = addCie<ELFT>(Piece, Rels);
continue;
@@ -468,10 +452,6 @@ template <class ELFT> void EhFrameSection::addSection(InputSectionBase *C) {
for (auto *DS : Sec->DependentSections)
DependentSections.push_back(DS);
- // .eh_frame is a sequence of CIE or FDE records. This function
- // splits it into pieces so that we can call
- // SplitInputSection::getSectionPiece on the section.
- Sec->split<ELFT>();
if (Sec->Pieces.empty())
return;
@@ -494,9 +474,7 @@ static void writeCieFde(uint8_t *Buf, ArrayRef<uint8_t> D) {
}
void EhFrameSection::finalizeContents() {
- if (this->Size)
- return; // Already finalized.
-
+ assert(!this->Size); // Not finalized.
size_t Off = 0;
for (CieRecord *Rec : CieRecords) {
Rec->Cie->OutputOff = Off;
@@ -509,10 +487,10 @@ void EhFrameSection::finalizeContents() {
}
// The LSB standard does not allow a .eh_frame section with zero
- // Call Frame Information records. Therefore add a CIE record length
- // 0 as a terminator if this .eh_frame section is empty.
- if (Off == 0)
- Off = 4;
+ // Call Frame Information records. glibc unwind-dw2-fde.c
+ // classify_object_over_fdes expects there is a CIE record length 0 as a
+ // terminator. Thus we add one unconditionally.
+ Off += 4;
this->Size = Off;
}
@@ -524,25 +502,47 @@ std::vector<EhFrameSection::FdeData> EhFrameSection::getFdeData() const {
uint8_t *Buf = getParent()->Loc + OutSecOff;
std::vector<FdeData> Ret;
+ uint64_t VA = InX::EhFrameHdr->getVA();
for (CieRecord *Rec : CieRecords) {
uint8_t Enc = getFdeEncoding(Rec->Cie);
for (EhSectionPiece *Fde : Rec->Fdes) {
- uint32_t Pc = getFdePc(Buf, Fde->OutputOff, Enc);
- uint32_t FdeVA = getParent()->Addr + Fde->OutputOff;
- Ret.push_back({Pc, FdeVA});
+ uint64_t Pc = getFdePc(Buf, Fde->OutputOff, Enc);
+ uint64_t FdeVA = getParent()->Addr + Fde->OutputOff;
+ if (!isInt<32>(Pc - VA))
+ fatal(toString(Fde->Sec) + ": PC offset is too large: 0x" +
+ Twine::utohexstr(Pc - VA));
+ Ret.push_back({uint32_t(Pc - VA), uint32_t(FdeVA - VA)});
}
}
+
+ // Sort the FDE list by their PC and uniqueify. Usually there is only
+ // one FDE for a PC (i.e. function), but if ICF merges two functions
+ // into one, there can be more than one FDEs pointing to the address.
+ auto Less = [](const FdeData &A, const FdeData &B) {
+ return A.PcRel < B.PcRel;
+ };
+ std::stable_sort(Ret.begin(), Ret.end(), Less);
+ auto Eq = [](const FdeData &A, const FdeData &B) {
+ return A.PcRel == B.PcRel;
+ };
+ Ret.erase(std::unique(Ret.begin(), Ret.end(), Eq), Ret.end());
+
return Ret;
}
static uint64_t readFdeAddr(uint8_t *Buf, int Size) {
switch (Size) {
case DW_EH_PE_udata2:
- return read16(Buf, Config->Endianness);
+ return read16(Buf);
+ case DW_EH_PE_sdata2:
+ return (int16_t)read16(Buf);
case DW_EH_PE_udata4:
- return read32(Buf, Config->Endianness);
+ return read32(Buf);
+ case DW_EH_PE_sdata4:
+ return (int32_t)read32(Buf);
case DW_EH_PE_udata8:
- return read64(Buf, Config->Endianness);
+ case DW_EH_PE_sdata8:
+ return read64(Buf);
case DW_EH_PE_absptr:
return readUint(Buf);
}
@@ -556,7 +556,7 @@ uint64_t EhFrameSection::getFdePc(uint8_t *Buf, size_t FdeOff,
// The starting address to which this FDE applies is
// stored at FDE + 8 byte.
size_t Off = FdeOff + 8;
- uint64_t Addr = readFdeAddr(Buf + Off, Enc & 0x7);
+ uint64_t Addr = readFdeAddr(Buf + Off, Enc & 0xf);
if ((Enc & 0x70) == DW_EH_PE_absptr)
return Addr;
if ((Enc & 0x70) == DW_EH_PE_pcrel)
@@ -589,7 +589,15 @@ void EhFrameSection::writeTo(uint8_t *Buf) {
GotSection::GotSection()
: SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
- Target->GotEntrySize, ".got") {}
+ Target->GotEntrySize, ".got") {
+ // PPC64 saves the ElfSym::GlobalOffsetTable .TOC. as the first entry in the
+ // .got. If there are no references to .TOC. in the symbol table,
+ // ElfSym::GlobalOffsetTable will not be defined and we won't need to save
+ // .TOC. in the .got. When it is defined, we increase NumEntries by the number
+ // of entries used to emit ElfSym::GlobalOffsetTable.
+ if (ElfSym::GlobalOffsetTable && !Target->GotBaseSymInGotPlt)
+ NumEntries += Target->GotHeaderEntriesNum;
+}
void GotSection::addEntry(Symbol &Sym) {
Sym.GotIndex = NumEntries;
@@ -623,196 +631,383 @@ uint64_t GotSection::getGlobalDynOffset(const Symbol &B) const {
return B.GlobalDynIndex * Config->Wordsize;
}
-void GotSection::finalizeContents() { Size = NumEntries * Config->Wordsize; }
+void GotSection::finalizeContents() {
+ Size = NumEntries * Config->Wordsize;
+}
bool GotSection::empty() 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) or there's a symbol that points to a GOT
- // (i.e. _GLOBAL_OFFSET_TABLE_).
- return NumEntries == 0 && !HasGotOffRel && !ElfSym::GlobalOffsetTable;
+ // (i.e. _GLOBAL_OFFSET_TABLE_) that the target defines relative to the .got.
+ return NumEntries == 0 && !HasGotOffRel &&
+ !(ElfSym::GlobalOffsetTable && !Target->GotBaseSymInGotPlt);
}
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);
}
+static uint64_t getMipsPageAddr(uint64_t Addr) {
+ return (Addr + 0x8000) & ~0xffff;
+}
+
+static uint64_t getMipsPageCount(uint64_t Size) {
+ return (Size + 0xfffe) / 0xffff + 1;
+}
+
MipsGotSection::MipsGotSection()
: SyntheticSection(SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL, SHT_PROGBITS, 16,
".got") {}
-void MipsGotSection::addEntry(Symbol &Sym, int64_t Addend, RelExpr Expr) {
- // For "true" local symbols which can be referenced from the same module
- // only compiler creates two instructions for address loading:
- //
- // lw $8, 0($gp) # R_MIPS_GOT16
- // addi $8, $8, 0 # R_MIPS_LO16
- //
- // The first instruction loads high 16 bits of the symbol address while
- // the second adds an offset. That allows to reduce number of required
- // GOT entries because only one global offset table entry is necessary
- // for every 64 KBytes of local data. So for local symbols we need to
- // allocate number of GOT entries to hold all required "page" addresses.
- //
- // All global symbols (hidden and regular) considered by compiler uniformly.
- // It always generates a single `lw` instruction and R_MIPS_GOT16 relocation
- // to load address of the symbol. So for each such symbol we need to
- // allocate dedicated GOT entry to store its address.
- //
- // If a symbol is preemptible we need help of dynamic linker to get its
- // final address. The corresponding GOT entries are allocated in the
- // "global" part of GOT. Entries for non preemptible global symbol allocated
- // in the "local" part of GOT.
- //
- // See "Global Offset Table" in Chapter 5:
- // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+void MipsGotSection::addEntry(InputFile &File, Symbol &Sym, int64_t Addend,
+ RelExpr Expr) {
+ FileGot &G = getGot(File);
if (Expr == R_MIPS_GOT_LOCAL_PAGE) {
- // At this point we do not know final symbol value so to reduce number
- // of allocated GOT entries do the following trick. Save all output
- // sections referenced by GOT relocations. Then later in the `finalize`
- // method calculate number of "pages" required to cover all saved output
- // section and allocate appropriate number of GOT entries.
- PageIndexMap.insert({Sym.getOutputSection(), 0});
- return;
- }
- if (Sym.isTls()) {
- // GOT entries created for MIPS TLS relocations behave like
- // almost GOT entries from other ABIs. They go to the end
- // of the global offset table.
- Sym.GotIndex = TlsEntries.size();
- TlsEntries.push_back(&Sym);
- return;
- }
- auto AddEntry = [&](Symbol &S, uint64_t A, GotEntries &Items) {
- if (S.isInGot() && !A)
- return;
- size_t NewIndex = Items.size();
- if (!EntryIndexMap.insert({{&S, A}, NewIndex}).second)
- return;
- Items.emplace_back(&S, A);
- if (!A)
- S.GotIndex = NewIndex;
- };
- if (Sym.IsPreemptible) {
- // Ignore addends for preemptible symbols. They got single GOT entry anyway.
- AddEntry(Sym, 0, GlobalEntries);
- Sym.IsInGlobalMipsGot = true;
- } else if (Expr == R_MIPS_GOT_OFF32) {
- AddEntry(Sym, Addend, LocalEntries32);
- Sym.Is32BitMipsGot = true;
- } else {
- // Hold local GOT entries accessed via a 16-bit index separately.
- // That allows to write them in the beginning of the GOT and keep
- // their indexes as less as possible to escape relocation's overflow.
- AddEntry(Sym, Addend, LocalEntries);
- }
+ if (const OutputSection *OS = Sym.getOutputSection())
+ G.PagesMap.insert({OS, {}});
+ else
+ G.Local16.insert({{nullptr, getMipsPageAddr(Sym.getVA(Addend))}, 0});
+ } else if (Sym.isTls())
+ G.Tls.insert({&Sym, 0});
+ else if (Sym.IsPreemptible && Expr == R_ABS)
+ G.Relocs.insert({&Sym, 0});
+ else if (Sym.IsPreemptible)
+ G.Global.insert({&Sym, 0});
+ else if (Expr == R_MIPS_GOT_OFF32)
+ G.Local32.insert({{&Sym, Addend}, 0});
+ else
+ G.Local16.insert({{&Sym, Addend}, 0});
}
-bool MipsGotSection::addDynTlsEntry(Symbol &Sym) {
- if (Sym.GlobalDynIndex != -1U)
- return false;
- Sym.GlobalDynIndex = TlsEntries.size();
- // Global Dynamic TLS entries take two GOT slots.
- TlsEntries.push_back(nullptr);
- TlsEntries.push_back(&Sym);
- return true;
+void MipsGotSection::addDynTlsEntry(InputFile &File, Symbol &Sym) {
+ getGot(File).DynTlsSymbols.insert({&Sym, 0});
}
-// Reserves TLS entries for a TLS module ID and a TLS block offset.
-// In total it takes two GOT slots.
-bool MipsGotSection::addTlsIndex() {
- if (TlsIndexOff != uint32_t(-1))
- return false;
- TlsIndexOff = TlsEntries.size() * Config->Wordsize;
- TlsEntries.push_back(nullptr);
- TlsEntries.push_back(nullptr);
- return true;
+void MipsGotSection::addTlsIndex(InputFile &File) {
+ getGot(File).DynTlsSymbols.insert({nullptr, 0});
}
-static uint64_t getMipsPageAddr(uint64_t Addr) {
- return (Addr + 0x8000) & ~0xffff;
+size_t MipsGotSection::FileGot::getEntriesNum() const {
+ return getPageEntriesNum() + Local16.size() + Global.size() + Relocs.size() +
+ Tls.size() + DynTlsSymbols.size() * 2;
}
-static uint64_t getMipsPageCount(uint64_t Size) {
- return (Size + 0xfffe) / 0xffff + 1;
+size_t MipsGotSection::FileGot::getPageEntriesNum() const {
+ size_t Num = 0;
+ for (const std::pair<const OutputSection *, FileGot::PageBlock> &P : PagesMap)
+ Num += P.second.Count;
+ return Num;
}
-uint64_t MipsGotSection::getPageEntryOffset(const Symbol &B,
- int64_t Addend) const {
- const OutputSection *OutSec = B.getOutputSection();
- uint64_t SecAddr = getMipsPageAddr(OutSec->Addr);
- uint64_t SymAddr = getMipsPageAddr(B.getVA(Addend));
- uint64_t Index = PageIndexMap.lookup(OutSec) + (SymAddr - SecAddr) / 0xffff;
- assert(Index < PageEntriesNum);
- return (HeaderEntriesNum + Index) * Config->Wordsize;
+size_t MipsGotSection::FileGot::getIndexedEntriesNum() const {
+ size_t Count = getPageEntriesNum() + Local16.size() + Global.size();
+ // If there are relocation-only entries in the GOT, TLS entries
+ // are allocated after them. TLS entries should be addressable
+ // by 16-bit index so count both reloc-only and TLS entries.
+ if (!Tls.empty() || !DynTlsSymbols.empty())
+ Count += Relocs.size() + Tls.size() + DynTlsSymbols.size() * 2;
+ return Count;
}
-uint64_t MipsGotSection::getSymEntryOffset(const Symbol &B,
- int64_t Addend) const {
- // Calculate offset of the GOT entries block: TLS, global, local.
- uint64_t Index = HeaderEntriesNum + PageEntriesNum;
- if (B.isTls())
- Index += LocalEntries.size() + LocalEntries32.size() + GlobalEntries.size();
- else if (B.IsInGlobalMipsGot)
- Index += LocalEntries.size() + LocalEntries32.size();
- else if (B.Is32BitMipsGot)
- Index += LocalEntries.size();
- // Calculate offset of the GOT entry in the block.
- if (B.isInGot())
- Index += B.GotIndex;
- else {
- auto It = EntryIndexMap.find({&B, Addend});
- assert(It != EntryIndexMap.end());
- Index += It->second;
+MipsGotSection::FileGot &MipsGotSection::getGot(InputFile &F) {
+ if (!F.MipsGotIndex.hasValue()) {
+ Gots.emplace_back();
+ Gots.back().File = &F;
+ F.MipsGotIndex = Gots.size() - 1;
+ }
+ return Gots[*F.MipsGotIndex];
+}
+
+uint64_t MipsGotSection::getPageEntryOffset(const InputFile *F,
+ const Symbol &Sym,
+ int64_t Addend) const {
+ const FileGot &G = Gots[*F->MipsGotIndex];
+ uint64_t Index = 0;
+ if (const OutputSection *OutSec = Sym.getOutputSection()) {
+ uint64_t SecAddr = getMipsPageAddr(OutSec->Addr);
+ uint64_t SymAddr = getMipsPageAddr(Sym.getVA(Addend));
+ Index = G.PagesMap.lookup(OutSec).FirstIndex + (SymAddr - SecAddr) / 0xffff;
+ } else {
+ Index = G.Local16.lookup({nullptr, getMipsPageAddr(Sym.getVA(Addend))});
}
return Index * Config->Wordsize;
}
-uint64_t MipsGotSection::getTlsOffset() const {
- return (getLocalEntriesNum() + GlobalEntries.size()) * Config->Wordsize;
+uint64_t MipsGotSection::getSymEntryOffset(const InputFile *F, const Symbol &S,
+ int64_t Addend) const {
+ const FileGot &G = Gots[*F->MipsGotIndex];
+ Symbol *Sym = const_cast<Symbol *>(&S);
+ if (Sym->isTls())
+ return G.Tls.lookup(Sym) * Config->Wordsize;
+ if (Sym->IsPreemptible)
+ return G.Global.lookup(Sym) * Config->Wordsize;
+ return G.Local16.lookup({Sym, Addend}) * Config->Wordsize;
+}
+
+uint64_t MipsGotSection::getTlsIndexOffset(const InputFile *F) const {
+ const FileGot &G = Gots[*F->MipsGotIndex];
+ return G.DynTlsSymbols.lookup(nullptr) * Config->Wordsize;
}
-uint64_t MipsGotSection::getGlobalDynOffset(const Symbol &B) const {
- return B.GlobalDynIndex * Config->Wordsize;
+uint64_t MipsGotSection::getGlobalDynOffset(const InputFile *F,
+ const Symbol &S) const {
+ const FileGot &G = Gots[*F->MipsGotIndex];
+ Symbol *Sym = const_cast<Symbol *>(&S);
+ return G.DynTlsSymbols.lookup(Sym) * Config->Wordsize;
}
const Symbol *MipsGotSection::getFirstGlobalEntry() const {
- return GlobalEntries.empty() ? nullptr : GlobalEntries.front().first;
+ if (Gots.empty())
+ return nullptr;
+ const FileGot &PrimGot = Gots.front();
+ if (!PrimGot.Global.empty())
+ return PrimGot.Global.front().first;
+ if (!PrimGot.Relocs.empty())
+ return PrimGot.Relocs.front().first;
+ return nullptr;
}
unsigned MipsGotSection::getLocalEntriesNum() const {
- return HeaderEntriesNum + PageEntriesNum + LocalEntries.size() +
- LocalEntries32.size();
+ if (Gots.empty())
+ return HeaderEntriesNum;
+ return HeaderEntriesNum + Gots.front().getPageEntriesNum() +
+ Gots.front().Local16.size();
+}
+
+bool MipsGotSection::tryMergeGots(FileGot &Dst, FileGot &Src, bool IsPrimary) {
+ FileGot Tmp = Dst;
+ set_union(Tmp.PagesMap, Src.PagesMap);
+ set_union(Tmp.Local16, Src.Local16);
+ set_union(Tmp.Global, Src.Global);
+ set_union(Tmp.Relocs, Src.Relocs);
+ set_union(Tmp.Tls, Src.Tls);
+ set_union(Tmp.DynTlsSymbols, Src.DynTlsSymbols);
+
+ size_t Count = IsPrimary ? HeaderEntriesNum : 0;
+ Count += Tmp.getIndexedEntriesNum();
+
+ if (Count * Config->Wordsize > Config->MipsGotSize)
+ return false;
+
+ std::swap(Tmp, Dst);
+ return true;
}
void MipsGotSection::finalizeContents() { updateAllocSize(); }
bool MipsGotSection::updateAllocSize() {
- PageEntriesNum = 0;
- for (std::pair<const OutputSection *, size_t> &P : PageIndexMap) {
- // For each output section referenced by GOT page relocations calculate
- // and save into PageIndexMap an upper bound of MIPS GOT entries required
- // to store page addresses of local symbols. We assume the worst case -
- // each 64kb page of the output section has at least one GOT relocation
- // against it. And take in account the case when the section intersects
- // page boundaries.
- P.second = PageEntriesNum;
- PageEntriesNum += getMipsPageCount(P.first->Size);
- }
- Size = (getLocalEntriesNum() + GlobalEntries.size() + TlsEntries.size()) *
- Config->Wordsize;
+ Size = HeaderEntriesNum * Config->Wordsize;
+ for (const FileGot &G : Gots)
+ Size += G.getEntriesNum() * Config->Wordsize;
return false;
}
+template <class ELFT> void MipsGotSection::build() {
+ if (Gots.empty())
+ return;
+
+ std::vector<FileGot> MergedGots(1);
+
+ // For each GOT move non-preemptible symbols from the `Global`
+ // to `Local16` list. Preemptible symbol might become non-preemptible
+ // one if, for example, it gets a related copy relocation.
+ for (FileGot &Got : Gots) {
+ for (auto &P: Got.Global)
+ if (!P.first->IsPreemptible)
+ Got.Local16.insert({{P.first, 0}, 0});
+ Got.Global.remove_if([&](const std::pair<Symbol *, size_t> &P) {
+ return !P.first->IsPreemptible;
+ });
+ }
+
+ // For each GOT remove "reloc-only" entry if there is "global"
+ // entry for the same symbol. And add local entries which indexed
+ // using 32-bit value at the end of 16-bit entries.
+ for (FileGot &Got : Gots) {
+ Got.Relocs.remove_if([&](const std::pair<Symbol *, size_t> &P) {
+ return Got.Global.count(P.first);
+ });
+ set_union(Got.Local16, Got.Local32);
+ Got.Local32.clear();
+ }
+
+ // Evaluate number of "reloc-only" entries in the resulting GOT.
+ // To do that put all unique "reloc-only" and "global" entries
+ // from all GOTs to the future primary GOT.
+ FileGot *PrimGot = &MergedGots.front();
+ for (FileGot &Got : Gots) {
+ set_union(PrimGot->Relocs, Got.Global);
+ set_union(PrimGot->Relocs, Got.Relocs);
+ Got.Relocs.clear();
+ }
+
+ // Evaluate number of "page" entries in each GOT.
+ for (FileGot &Got : Gots) {
+ for (std::pair<const OutputSection *, FileGot::PageBlock> &P :
+ Got.PagesMap) {
+ const OutputSection *OS = P.first;
+ uint64_t SecSize = 0;
+ for (BaseCommand *Cmd : OS->SectionCommands) {
+ if (auto *ISD = dyn_cast<InputSectionDescription>(Cmd))
+ for (InputSection *IS : ISD->Sections) {
+ uint64_t Off = alignTo(SecSize, IS->Alignment);
+ SecSize = Off + IS->getSize();
+ }
+ }
+ P.second.Count = getMipsPageCount(SecSize);
+ }
+ }
+
+ // Merge GOTs. Try to join as much as possible GOTs but do not exceed
+ // maximum GOT size. At first, try to fill the primary GOT because
+ // the primary GOT can be accessed in the most effective way. If it
+ // is not possible, try to fill the last GOT in the list, and finally
+ // create a new GOT if both attempts failed.
+ for (FileGot &SrcGot : Gots) {
+ InputFile *File = SrcGot.File;
+ if (tryMergeGots(MergedGots.front(), SrcGot, true)) {
+ File->MipsGotIndex = 0;
+ } else {
+ // If this is the first time we failed to merge with the primary GOT,
+ // MergedGots.back() will also be the primary GOT. We must make sure not
+ // to try to merge again with IsPrimary=false, as otherwise, if the
+ // inputs are just right, we could allow the primary GOT to become 1 or 2
+ // words too big due to ignoring the header size.
+ if (MergedGots.size() == 1 ||
+ !tryMergeGots(MergedGots.back(), SrcGot, false)) {
+ MergedGots.emplace_back();
+ std::swap(MergedGots.back(), SrcGot);
+ }
+ File->MipsGotIndex = MergedGots.size() - 1;
+ }
+ }
+ std::swap(Gots, MergedGots);
+
+ // Reduce number of "reloc-only" entries in the primary GOT
+ // by substracting "global" entries exist in the primary GOT.
+ PrimGot = &Gots.front();
+ PrimGot->Relocs.remove_if([&](const std::pair<Symbol *, size_t> &P) {
+ return PrimGot->Global.count(P.first);
+ });
+
+ // Calculate indexes for each GOT entry.
+ size_t Index = HeaderEntriesNum;
+ for (FileGot &Got : Gots) {
+ Got.StartIndex = &Got == PrimGot ? 0 : Index;
+ for (std::pair<const OutputSection *, FileGot::PageBlock> &P :
+ Got.PagesMap) {
+ // For each output section referenced by GOT page relocations calculate
+ // and save into PagesMap an upper bound of MIPS GOT entries required
+ // to store page addresses of local symbols. We assume the worst case -
+ // each 64kb page of the output section has at least one GOT relocation
+ // against it. And take in account the case when the section intersects
+ // page boundaries.
+ P.second.FirstIndex = Index;
+ Index += P.second.Count;
+ }
+ for (auto &P: Got.Local16)
+ P.second = Index++;
+ for (auto &P: Got.Global)
+ P.second = Index++;
+ for (auto &P: Got.Relocs)
+ P.second = Index++;
+ for (auto &P: Got.Tls)
+ P.second = Index++;
+ for (auto &P: Got.DynTlsSymbols) {
+ P.second = Index;
+ Index += 2;
+ }
+ }
+
+ // Update Symbol::GotIndex field to use this
+ // value later in the `sortMipsSymbols` function.
+ for (auto &P : PrimGot->Global)
+ P.first->GotIndex = P.second;
+ for (auto &P : PrimGot->Relocs)
+ P.first->GotIndex = P.second;
+
+ // Create dynamic relocations.
+ for (FileGot &Got : Gots) {
+ // Create dynamic relocations for TLS entries.
+ for (std::pair<Symbol *, size_t> &P : Got.Tls) {
+ Symbol *S = P.first;
+ uint64_t Offset = P.second * Config->Wordsize;
+ if (S->IsPreemptible)
+ InX::RelaDyn->addReloc(Target->TlsGotRel, this, Offset, S);
+ }
+ 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->Pic)
+ continue;
+ InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S);
+ } 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->Pic)
+ continue;
+ InX::RelaDyn->addReloc(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;
+ InX::RelaDyn->addReloc(Target->TlsOffsetRel, this, Offset, S);
+ }
+ }
+
+ // Do not create dynamic relocations for non-TLS
+ // entries in the primary GOT.
+ if (&Got == PrimGot)
+ continue;
+
+ // Dynamic relocations for "global" entries.
+ for (const std::pair<Symbol *, size_t> &P : Got.Global) {
+ uint64_t Offset = P.second * Config->Wordsize;
+ InX::RelaDyn->addReloc(Target->RelativeRel, this, Offset, P.first);
+ }
+ if (!Config->Pic)
+ continue;
+ // Dynamic relocations for "local" entries in case of PIC.
+ for (const std::pair<const OutputSection *, FileGot::PageBlock> &L :
+ Got.PagesMap) {
+ size_t PageCount = L.second.Count;
+ for (size_t PI = 0; PI < PageCount; ++PI) {
+ uint64_t Offset = (L.second.FirstIndex + PI) * Config->Wordsize;
+ InX::RelaDyn->addReloc({Target->RelativeRel, this, Offset, L.first,
+ int64_t(PI * 0x10000)});
+ }
+ }
+ for (const std::pair<GotEntry, size_t> &P : Got.Local16) {
+ uint64_t Offset = P.second * Config->Wordsize;
+ InX::RelaDyn->addReloc({Target->RelativeRel, this, Offset, true,
+ P.first.first, P.first.second});
+ }
+ }
+}
+
bool MipsGotSection::empty() const {
// We add the .got section to the result for dynamic MIPS target because
// its address and properties are mentioned in the .dynamic section.
return Config->Relocatable;
}
-uint64_t MipsGotSection::getGp() const { return ElfSym::MipsGp->getVA(0); }
+uint64_t MipsGotSection::getGp(const InputFile *F) const {
+ // For files without related GOT or files refer a primary GOT
+ // returns "common" _gp value. For secondary GOTs calculate
+ // individual _gp values.
+ if (!F || !F->MipsGotIndex.hasValue() || *F->MipsGotIndex == 0)
+ return ElfSym::MipsGp->getVA(0);
+ return getVA() + Gots[*F->MipsGotIndex].StartIndex * Config->Wordsize +
+ 0x7ff0;
+}
void MipsGotSection::writeTo(uint8_t *Buf) {
// Set the MSB of the second GOT slot. This is not required by any
@@ -830,59 +1025,67 @@ void MipsGotSection::writeTo(uint8_t *Buf) {
// keep doing this for now. We really need to revisit this to see
// if we had to do this.
writeUint(Buf + Config->Wordsize, (uint64_t)1 << (Config->Wordsize * 8 - 1));
- Buf += HeaderEntriesNum * Config->Wordsize;
- // Write 'page address' entries to the local part of the GOT.
- for (std::pair<const OutputSection *, size_t> &L : PageIndexMap) {
- size_t PageCount = getMipsPageCount(L.first->Size);
- uint64_t FirstPageAddr = getMipsPageAddr(L.first->Addr);
- for (size_t PI = 0; PI < PageCount; ++PI) {
- uint8_t *Entry = Buf + (L.second + PI) * Config->Wordsize;
- writeUint(Entry, FirstPageAddr + PI * 0x10000);
- }
- }
- Buf += PageEntriesNum * Config->Wordsize;
- auto AddEntry = [&](const GotEntry &SA) {
- uint8_t *Entry = Buf;
- Buf += Config->Wordsize;
- const Symbol *Sym = SA.first;
- uint64_t VA = Sym->getVA(SA.second);
- if (Sym->StOther & STO_MIPS_MICROMIPS)
- VA |= 1;
- writeUint(Entry, VA);
- };
- std::for_each(std::begin(LocalEntries), std::end(LocalEntries), AddEntry);
- std::for_each(std::begin(LocalEntries32), std::end(LocalEntries32), AddEntry);
- std::for_each(std::begin(GlobalEntries), std::end(GlobalEntries), AddEntry);
- // Initialize TLS-related GOT entries. If the 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
- if (TlsIndexOff != -1U && !Config->Pic)
- writeUint(Buf + TlsIndexOff, 1);
- for (const Symbol *B : TlsEntries) {
- if (!B || B->IsPreemptible)
- continue;
- uint64_t VA = B->getVA();
- if (B->GotIndex != -1U) {
- uint8_t *Entry = Buf + B->GotIndex * Config->Wordsize;
- writeUint(Entry, VA - 0x7000);
+ for (const FileGot &G : Gots) {
+ auto Write = [&](size_t I, const Symbol *S, int64_t A) {
+ uint64_t VA = A;
+ if (S) {
+ VA = S->getVA(A);
+ if (S->StOther & STO_MIPS_MICROMIPS)
+ VA |= 1;
+ }
+ writeUint(Buf + I * Config->Wordsize, VA);
+ };
+ // Write 'page address' entries to the local part of the GOT.
+ for (const std::pair<const OutputSection *, FileGot::PageBlock> &L :
+ G.PagesMap) {
+ size_t PageCount = L.second.Count;
+ uint64_t FirstPageAddr = getMipsPageAddr(L.first->Addr);
+ for (size_t PI = 0; PI < PageCount; ++PI)
+ Write(L.second.FirstIndex + PI, nullptr, FirstPageAddr + PI * 0x10000);
}
- if (B->GlobalDynIndex != -1U) {
- uint8_t *Entry = Buf + B->GlobalDynIndex * Config->Wordsize;
- writeUint(Entry, 1);
- Entry += Config->Wordsize;
- writeUint(Entry, VA - 0x8000);
+ // Local, global, TLS, reloc-only entries.
+ // 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
+ 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
+ // will be done by REL32 dynamic relocations.
+ if (&G == &Gots.front())
+ for (const std::pair<const Symbol *, size_t> &P : G.Global)
+ Write(P.second, P.first, 0);
+ 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);
+ for (const std::pair<Symbol *, size_t> &P : G.DynTlsSymbols) {
+ if (P.first == nullptr && !Config->Pic)
+ Write(P.second, nullptr, 1);
+ else if (P.first && !P.first->IsPreemptible) {
+ // If we are emitting PIC code 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->Pic)
+ Write(P.second, nullptr, 1);
+ Write(P.second + 1, P.first, -0x8000);
+ }
}
}
}
+// On PowerPC the .plt section is used to hold the table of function addresses
+// instead of the .got.plt, and the type is SHT_NOBITS similar to a .bss
+// section. I don't know why we have a BSS style type for the section but it is
+// consitent across both 64-bit PowerPC ABIs as well as the 32-bit PowerPC ABI.
GotPltSection::GotPltSection()
- : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
- Target->GotPltEntrySize, ".got.plt") {}
+ : SyntheticSection(SHF_ALLOC | SHF_WRITE,
+ Config->EMachine == EM_PPC64 ? SHT_NOBITS : SHT_PROGBITS,
+ Target->GotPltEntrySize,
+ Config->EMachine == EM_PPC64 ? ".plt" : ".got.plt") {}
void GotPltSection::addEntry(Symbol &Sym) {
- Sym.GotPltIndex = Target->GotPltHeaderEntriesNum + Entries.size();
+ assert(Sym.PltIndex == Entries.size());
Entries.push_back(&Sym);
}
@@ -900,16 +1103,37 @@ void GotPltSection::writeTo(uint8_t *Buf) {
}
}
-// On ARM the IgotPltSection is part of the GotSection, on other Targets it is
-// part of the .got.plt
+bool GotPltSection::empty() const {
+ // We need to emit a GOT.PLT even if it's empty if there's a symbol that
+ // references the _GLOBAL_OFFSET_TABLE_ and the Target defines the symbol
+ // relative to the .got.plt section.
+ return Entries.empty() &&
+ !(ElfSym::GlobalOffsetTable && Target->GotBaseSymInGotPlt);
+}
+
+static StringRef getIgotPltName() {
+ // On ARM the IgotPltSection is part of the GotSection.
+ if (Config->EMachine == EM_ARM)
+ return ".got";
+
+ // On PowerPC64 the GotPltSection is renamed to '.plt' so the IgotPltSection
+ // needs to be named the same.
+ if (Config->EMachine == EM_PPC64)
+ return ".plt";
+
+ return ".got.plt";
+}
+
+// On PowerPC64 the GotPltSection type is SHT_NOBITS so we have to follow suit
+// with the IgotPltSection.
IgotPltSection::IgotPltSection()
- : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
- Target->GotPltEntrySize,
- Config->EMachine == EM_ARM ? ".got" : ".got.plt") {}
+ : SyntheticSection(SHF_ALLOC | SHF_WRITE,
+ Config->EMachine == EM_PPC64 ? SHT_NOBITS : SHT_PROGBITS,
+ Target->GotPltEntrySize, getIgotPltName()) {}
void IgotPltSection::addEntry(Symbol &Sym) {
Sym.IsInIgot = true;
- Sym.GotPltIndex = Entries.size();
+ assert(Sym.PltIndex == Entries.size());
Entries.push_back(&Sym);
}
@@ -1005,8 +1229,14 @@ void DynamicSection<ELFT>::addInt(int32_t Tag, uint64_t Val) {
template <class ELFT>
void DynamicSection<ELFT>::addInSec(int32_t Tag, InputSection *Sec) {
+ Entries.push_back({Tag, [=] { return Sec->getVA(0); }});
+}
+
+template <class ELFT>
+void DynamicSection<ELFT>::addInSecRelative(int32_t Tag, InputSection *Sec) {
+ size_t TagOffset = Entries.size() * Entsize;
Entries.push_back(
- {Tag, [=] { return Sec->getParent()->Addr + Sec->OutSecOff; }});
+ {Tag, [=] { return Sec->getVA(0) - (getVA() + TagOffset); }});
}
template <class ELFT>
@@ -1036,6 +1266,8 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
DtFlags |= DF_SYMBOLIC;
if (Config->ZInitfirst)
DtFlags1 |= DF_1_INITFIRST;
+ if (Config->ZInterpose)
+ DtFlags1 |= DF_1_INTERPOSE;
if (Config->ZNodelete)
DtFlags1 |= DF_1_NODELETE;
if (Config->ZNodlopen)
@@ -1048,6 +1280,8 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
DtFlags |= DF_ORIGIN;
DtFlags1 |= DF_1_ORIGIN;
}
+ if (!Config->ZText)
+ DtFlags |= DF_TEXTREL;
if (DtFlags)
addInt(DT_FLAGS, DtFlags);
@@ -1083,6 +1317,14 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
addInt(IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels);
}
}
+ if (InX::RelrDyn && !InX::RelrDyn->Relocs.empty()) {
+ addInSec(Config->UseAndroidRelrTags ? DT_ANDROID_RELR : DT_RELR,
+ InX::RelrDyn);
+ addSize(Config->UseAndroidRelrTags ? DT_ANDROID_RELRSZ : DT_RELRSZ,
+ InX::RelrDyn->getParent());
+ addInt(Config->UseAndroidRelrTags ? DT_ANDROID_RELRENT : DT_RELRENT,
+ sizeof(Elf_Relr));
+ }
// .rel[a].plt section usually consists of two parts, containing plt and
// iplt relocations. It is possible to have only iplt relocations in the
// output. In that case RelaPlt is empty and have zero offset, the same offset
@@ -1162,8 +1404,23 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
else
addInt(DT_MIPS_GOTSYM, InX::DynSymTab->getNumSymbols());
addInSec(DT_PLTGOT, InX::MipsGot);
- if (InX::MipsRldMap)
- addInSec(DT_MIPS_RLD_MAP, InX::MipsRldMap);
+ if (InX::MipsRldMap) {
+ if (!Config->Pie)
+ addInSec(DT_MIPS_RLD_MAP, InX::MipsRldMap);
+ // Store the offset to the .rld_map section
+ // relative to the address of the tag.
+ addInSecRelative(DT_MIPS_RLD_MAP_REL, InX::MipsRldMap);
+ }
+ }
+
+ // Glink dynamic tag is required by the V2 abi if the plt section isn't empty.
+ if (Config->EMachine == EM_PPC64 && !InX::Plt->empty()) {
+ // The Glink tag points to 32 bytes before the first lazy symbol resolution
+ // stub, which starts directly after the header.
+ Entries.push_back({DT_PPC64_GLINK, [=] {
+ unsigned Offset = Target->PltHeaderSize - 32;
+ return InX::Plt->getVA(0) + Offset;
+ }});
}
addInt(DT_NULL, 0);
@@ -1183,13 +1440,16 @@ template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) {
}
uint64_t DynamicReloc::getOffset() const {
- return InputSec->getOutputSection()->Addr + InputSec->getOffset(OffsetInSec);
+ return InputSec->getVA(OffsetInSec);
}
-int64_t DynamicReloc::getAddend() const {
+int64_t DynamicReloc::computeAddend() const {
if (UseSymVA)
return Sym->getVA(Addend);
- return Addend;
+ if (!OutputSec)
+ return Addend;
+ // See the comment in the DynamicReloc ctor.
+ return getMipsPageAddr(OutputSec->Addr) + Addend;
}
uint32_t DynamicReloc::getSymIndex() const {
@@ -1204,6 +1464,23 @@ RelocationBaseSection::RelocationBaseSection(StringRef Name, uint32_t Type,
: SyntheticSection(SHF_ALLOC, Type, Config->Wordsize, Name),
DynamicTag(DynamicTag), SizeDynamicTag(SizeDynamicTag) {}
+void RelocationBaseSection::addReloc(RelType DynType, InputSectionBase *IS,
+ uint64_t OffsetInSec, Symbol *Sym) {
+ addReloc({DynType, IS, OffsetInSec, false, Sym, 0});
+}
+
+void RelocationBaseSection::addReloc(RelType DynType,
+ InputSectionBase *InputSec,
+ uint64_t OffsetInSec, Symbol *Sym,
+ int64_t Addend, RelExpr Expr,
+ RelType Type) {
+ // 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});
+}
+
void RelocationBaseSection::addReloc(const DynamicReloc &Reloc) {
if (Reloc.Type == Target->RelativeRel)
++NumRelativeRelocs;
@@ -1220,23 +1497,17 @@ void RelocationBaseSection::finalizeContents() {
getParent()->Link = Link;
}
+RelrBaseSection::RelrBaseSection()
+ : SyntheticSection(SHF_ALLOC,
+ Config->UseAndroidRelrTags ? SHT_ANDROID_RELR : SHT_RELR,
+ Config->Wordsize, ".relr.dyn") {}
+
template <class ELFT>
static void encodeDynamicReloc(typename ELFT::Rela *P,
const DynamicReloc &Rel) {
if (Config->IsRela)
- P->r_addend = Rel.getAddend();
+ P->r_addend = Rel.computeAddend();
P->r_offset = Rel.getOffset();
- if (Config->EMachine == EM_MIPS && Rel.getInputSec() == InX::MipsGot)
- // The MIPS GOT section contains dynamic relocations that correspond to TLS
- // entries. These entries are placed after the global and local sections of
- // the GOT. At the point when we create these relocations, the size of the
- // global and local sections is unknown, so the offset that we store in the
- // TLS entry's DynamicReloc is relative to the start of the TLS section of
- // the GOT, rather than being relative to the start of the GOT. This line of
- // code adds the size of the global and local sections to the virtual
- // address computed by getOffset() in order to adjust it into the TLS
- // section.
- P->r_offset += InX::MipsGot->getTlsOffset();
P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->IsMips64EL);
}
@@ -1249,32 +1520,22 @@ RelocationSection<ELFT>::RelocationSection(StringRef Name, bool Sort)
this->Entsize = Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
}
-template <class ELFT, class RelTy>
-static bool compRelocations(const RelTy &A, const RelTy &B) {
- bool AIsRel = A.getType(Config->IsMips64EL) == Target->RelativeRel;
- bool BIsRel = B.getType(Config->IsMips64EL) == Target->RelativeRel;
+static bool compRelocations(const DynamicReloc &A, const DynamicReloc &B) {
+ bool AIsRel = A.Type == Target->RelativeRel;
+ bool BIsRel = B.Type == Target->RelativeRel;
if (AIsRel != BIsRel)
return AIsRel;
-
- return A.getSymbol(Config->IsMips64EL) < B.getSymbol(Config->IsMips64EL);
+ return A.getSymIndex() < B.getSymIndex();
}
template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
- uint8_t *BufBegin = Buf;
+ if (Sort)
+ std::stable_sort(Relocs.begin(), Relocs.end(), compRelocations);
+
for (const DynamicReloc &Rel : Relocs) {
encodeDynamicReloc<ELFT>(reinterpret_cast<Elf_Rela *>(Buf), Rel);
Buf += Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
}
-
- if (Sort) {
- if (Config->IsRela)
- std::stable_sort((Elf_Rela *)BufBegin,
- (Elf_Rela *)BufBegin + Relocs.size(),
- compRelocations<ELFT, Elf_Rela>);
- else
- std::stable_sort((Elf_Rel *)BufBegin, (Elf_Rel *)BufBegin + Relocs.size(),
- compRelocations<ELFT, Elf_Rel>);
- }
}
template <class ELFT> unsigned RelocationSection<ELFT>::getRelocOffset() {
@@ -1362,10 +1623,10 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() {
NonRelatives.push_back(R);
}
- std::sort(Relatives.begin(), Relatives.end(),
- [](const Elf_Rel &A, const Elf_Rel &B) {
- return A.r_offset < B.r_offset;
- });
+ llvm::sort(Relatives.begin(), Relatives.end(),
+ [](const Elf_Rel &A, const Elf_Rel &B) {
+ return A.r_offset < B.r_offset;
+ });
// Try to find groups of relative relocations which are spaced one word
// apart from one another. These generally correspond to vtable entries. The
@@ -1443,10 +1704,10 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() {
}
// Finally the non-relative relocations.
- std::sort(NonRelatives.begin(), NonRelatives.end(),
- [](const Elf_Rela &A, const Elf_Rela &B) {
- return A.r_offset < B.r_offset;
- });
+ llvm::sort(NonRelatives.begin(), NonRelatives.end(),
+ [](const Elf_Rela &A, const Elf_Rela &B) {
+ return A.r_offset < B.r_offset;
+ });
if (!NonRelatives.empty()) {
Add(NonRelatives.size());
Add(HasAddendIfRela);
@@ -1469,6 +1730,97 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() {
return RelocData.size() != OldSize;
}
+template <class ELFT> RelrSection<ELFT>::RelrSection() {
+ this->Entsize = Config->Wordsize;
+}
+
+template <class ELFT> bool RelrSection<ELFT>::updateAllocSize() {
+ // This function computes the contents of an SHT_RELR packed relocation
+ // section.
+ //
+ // Proposal for adding SHT_RELR sections to generic-abi is here:
+ // https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg
+ //
+ // The encoded sequence of Elf64_Relr entries in a SHT_RELR section looks
+ // like [ AAAAAAAA BBBBBBB1 BBBBBBB1 ... AAAAAAAA BBBBBB1 ... ]
+ //
+ // i.e. start with an address, followed by any number of bitmaps. The address
+ // entry encodes 1 relocation. The subsequent bitmap entries encode up to 63
+ // relocations each, at subsequent offsets following the last address entry.
+ //
+ // The bitmap entries must have 1 in the least significant bit. The assumption
+ // here is that an address cannot have 1 in lsb. Odd addresses are not
+ // supported.
+ //
+ // Excluding the least significant bit in the bitmap, each non-zero bit in
+ // the bitmap represents a relocation to be applied to a corresponding machine
+ // word that follows the base address word. The second least significant bit
+ // represents the machine word immediately following the initial address, and
+ // each bit that follows represents the next word, in linear order. As such,
+ // a single bitmap can encode up to 31 relocations in a 32-bit object, and
+ // 63 relocations in a 64-bit object.
+ //
+ // This encoding has a couple of interesting properties:
+ // 1. Looking at any entry, it is clear whether it's an address or a bitmap:
+ // even means address, odd means bitmap.
+ // 2. Just a simple list of addresses is a valid encoding.
+
+ size_t OldSize = RelrRelocs.size();
+ RelrRelocs.clear();
+
+ // Same as Config->Wordsize but faster because this is a compile-time
+ // constant.
+ const size_t Wordsize = sizeof(typename ELFT::uint);
+
+ // Number of bits to use for the relocation offsets bitmap.
+ // Must be either 63 or 31.
+ const size_t NBits = Wordsize * 8 - 1;
+
+ // Get offsets for all relative relocations and sort them.
+ std::vector<uint64_t> Offsets;
+ for (const RelativeReloc &Rel : Relocs)
+ Offsets.push_back(Rel.getOffset());
+ llvm::sort(Offsets.begin(), Offsets.end());
+
+ // For each leading relocation, find following ones that can be folded
+ // as a bitmap and fold them.
+ for (size_t I = 0, E = Offsets.size(); I < E;) {
+ // Add a leading relocation.
+ RelrRelocs.push_back(Elf_Relr(Offsets[I]));
+ uint64_t Base = Offsets[I] + Wordsize;
+ ++I;
+
+ // Find foldable relocations to construct bitmaps.
+ while (I < E) {
+ uint64_t Bitmap = 0;
+
+ while (I < E) {
+ uint64_t Delta = Offsets[I] - Base;
+
+ // If it is too far, it cannot be folded.
+ if (Delta >= NBits * Wordsize)
+ break;
+
+ // If it is not a multiple of wordsize away, it cannot be folded.
+ if (Delta % Wordsize)
+ break;
+
+ // Fold it.
+ Bitmap |= 1ULL << (Delta / Wordsize);
+ ++I;
+ }
+
+ if (!Bitmap)
+ break;
+
+ RelrRelocs.push_back(Elf_Relr((Bitmap << 1) | 1));
+ Base += NBits * Wordsize;
+ }
+ }
+
+ return RelrRelocs.size() != OldSize;
+}
+
SymbolTableBaseSection::SymbolTableBaseSection(StringTableSection &StrTabSec)
: SyntheticSection(StrTabSec.isDynamic() ? (uint64_t)SHF_ALLOC : 0,
StrTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB,
@@ -1484,50 +1836,70 @@ SymbolTableBaseSection::SymbolTableBaseSection(StringTableSection &StrTabSec)
static bool sortMipsSymbols(const SymbolTableEntry &L,
const SymbolTableEntry &R) {
// Sort entries related to non-local preemptible symbols by GOT indexes.
- // All other entries go to the first part of GOT in arbitrary order.
- bool LIsInLocalGot = !L.Sym->IsInGlobalMipsGot;
- bool RIsInLocalGot = !R.Sym->IsInGlobalMipsGot;
- if (LIsInLocalGot || RIsInLocalGot)
- return !RIsInLocalGot;
- return L.Sym->GotIndex < R.Sym->GotIndex;
+ // All other entries go to the beginning of a dynsym in arbitrary order.
+ if (L.Sym->isInGot() && R.Sym->isInGot())
+ return L.Sym->GotIndex < R.Sym->GotIndex;
+ if (!L.Sym->isInGot() && !R.Sym->isInGot())
+ return false;
+ return !L.Sym->isInGot();
}
void SymbolTableBaseSection::finalizeContents() {
getParent()->Link = StrTabSec.getParent()->SectionIndex;
+ if (this->Type != SHT_DYNSYM)
+ return;
+
// If it is a .dynsym, there should be no local symbols, but we need
// to do a few things for the dynamic linker.
- if (this->Type == SHT_DYNSYM) {
- // Section's Info field has the index of the first non-local symbol.
- // Because the first symbol entry is a null entry, 1 is the first.
- getParent()->Info = 1;
-
- if (InX::GnuHashTab) {
- // NB: It also sorts Symbols to meet the GNU hash table requirements.
- InX::GnuHashTab->addSymbols(Symbols);
- } else if (Config->EMachine == EM_MIPS) {
- std::stable_sort(Symbols.begin(), Symbols.end(), sortMipsSymbols);
- }
- size_t I = 0;
- for (const SymbolTableEntry &S : Symbols) S.Sym->DynsymIndex = ++I;
- return;
+ // Section's Info field has the index of the first non-local symbol.
+ // Because the first symbol entry is a null entry, 1 is the first.
+ getParent()->Info = 1;
+
+ if (InX::GnuHashTab) {
+ // NB: It also sorts Symbols to meet the GNU hash table requirements.
+ InX::GnuHashTab->addSymbols(Symbols);
+ } else if (Config->EMachine == EM_MIPS) {
+ std::stable_sort(Symbols.begin(), Symbols.end(), sortMipsSymbols);
}
+
+ size_t I = 0;
+ for (const SymbolTableEntry &S : Symbols)
+ S.Sym->DynsymIndex = ++I;
}
// The ELF spec requires that all local symbols precede global symbols, so we
// sort symbol entries in this function. (For .dynsym, we don't do that because
// symbols for dynamic linking are inherently all globals.)
+//
+// Aside from above, we put local symbols in groups starting with the STT_FILE
+// symbol. That is convenient for purpose of identifying where are local symbols
+// coming from.
void SymbolTableBaseSection::postThunkContents() {
- if (this->Type == SHT_DYNSYM)
- return;
- // move all local symbols before global symbols.
- auto It = std::stable_partition(
+ assert(this->Type == SHT_SYMTAB);
+
+ // Move all local symbols before global symbols.
+ auto E = std::stable_partition(
Symbols.begin(), Symbols.end(), [](const SymbolTableEntry &S) {
return S.Sym->isLocal() || S.Sym->computeBinding() == STB_LOCAL;
});
- size_t NumLocals = It - Symbols.begin();
+ size_t NumLocals = E - Symbols.begin();
getParent()->Info = NumLocals + 1;
+
+ // We want to group the local symbols by file. For that we rebuild the local
+ // part of the symbols vector. We do not need to care about the STT_FILE
+ // symbols, they are already naturally placed first in each group. That
+ // happens because STT_FILE is always the first symbol in the object and hence
+ // precede all other local symbols we add for a file.
+ MapVector<InputFile *, std::vector<SymbolTableEntry>> Arr;
+ for (const SymbolTableEntry &S : llvm::make_range(Symbols.begin(), E))
+ Arr[S.Sym->File].push_back(S);
+
+ auto I = Symbols.begin();
+ for (std::pair<InputFile *, std::vector<SymbolTableEntry>> &P : Arr)
+ for (SymbolTableEntry &Entry : P.second)
+ *I++ = Entry;
}
void SymbolTableBaseSection::addSymbol(Symbol *B) {
@@ -1565,6 +1937,23 @@ SymbolTableSection<ELFT>::SymbolTableSection(StringTableSection &StrTabSec)
this->Entsize = sizeof(Elf_Sym);
}
+static BssSection *getCommonSec(Symbol *Sym) {
+ if (!Config->DefineCommon)
+ if (auto *D = dyn_cast<Defined>(Sym))
+ return dyn_cast_or_null<BssSection>(D->Section);
+ return nullptr;
+}
+
+static uint32_t getSymSectionIndex(Symbol *Sym) {
+ if (getCommonSec(Sym))
+ return SHN_COMMON;
+ if (!isa<Defined>(Sym) || Sym->NeedsPltAddr)
+ return SHN_UNDEF;
+ if (const OutputSection *OS = Sym->getOutputSection())
+ return OS->SectionIndex >= SHN_LORESERVE ? SHN_XINDEX : OS->SectionIndex;
+ return SHN_ABS;
+}
+
// Write the internal symbol table contents to the output symbol table.
template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
// The first entry is a null entry as per the ELF spec.
@@ -1586,20 +1975,7 @@ template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
}
ESym->st_name = Ent.StrTabOffset;
-
- // Set a section index.
- BssSection *CommonSec = nullptr;
- if (!Config->DefineCommon)
- if (auto *D = dyn_cast<Defined>(Sym))
- CommonSec = dyn_cast_or_null<BssSection>(D->Section);
- if (CommonSec)
- ESym->st_shndx = SHN_COMMON;
- else if (const OutputSection *OutSec = Sym->getOutputSection())
- ESym->st_shndx = OutSec->SectionIndex;
- else if (isa<Defined>(Sym))
- ESym->st_shndx = SHN_ABS;
- else
- ESym->st_shndx = SHN_UNDEF;
+ ESym->st_shndx = getSymSectionIndex(Ent.Sym);
// Copy symbol size if it is a defined symbol. st_size is not significant
// for undefined symbols, so whether copying it or not is up to us if that's
@@ -1614,7 +1990,7 @@ template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
// st_value is usually an address of a symbol, but that has a
// special meaining for uninstantiated common symbols (this can
// occur if -r is given).
- if (CommonSec)
+ if (BssSection *CommonSec = getCommonSec(Ent.Sym))
ESym->st_value = CommonSec->Alignment;
else
ESym->st_value = Sym->getVA();
@@ -1635,9 +2011,11 @@ template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
ESym->st_other |= STO_MIPS_PLT;
if (isMicroMips()) {
// Set STO_MIPS_MICROMIPS flag and less-significant bit for
- // defined microMIPS symbols and shared symbols with PLT record.
- if ((Sym->isDefined() && (Sym->StOther & STO_MIPS_MICROMIPS)) ||
- (Sym->isShared() && Sym->NeedsPltAddr)) {
+ // a defined microMIPS symbol and symbol should point to its
+ // PLT entry (in case of microMIPS, PLT entries always contain
+ // microMIPS code).
+ if (Sym->isDefined() &&
+ ((Sym->StOther & STO_MIPS_MICROMIPS) || Sym->NeedsPltAddr)) {
if (StrTabSec.isDynamic())
ESym->st_value |= 1;
ESym->st_other |= STO_MIPS_MICROMIPS;
@@ -1652,6 +2030,44 @@ template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
}
}
+SymtabShndxSection::SymtabShndxSection()
+ : SyntheticSection(0, SHT_SYMTAB_SHNDX, 4, ".symtab_shndxr") {
+ this->Entsize = 4;
+}
+
+void SymtabShndxSection::writeTo(uint8_t *Buf) {
+ // We write an array of 32 bit values, where each value has 1:1 association
+ // with an entry in .symtab. If the corresponding entry contains SHN_XINDEX,
+ // we need to write actual index, otherwise, we must write SHN_UNDEF(0).
+ Buf += 4; // Ignore .symtab[0] entry.
+ for (const SymbolTableEntry &Entry : InX::SymTab->getSymbols()) {
+ if (getSymSectionIndex(Entry.Sym) == SHN_XINDEX)
+ write32(Buf, Entry.Sym->getOutputSection()->SectionIndex);
+ Buf += 4;
+ }
+}
+
+bool SymtabShndxSection::empty() const {
+ // SHT_SYMTAB can hold symbols with section indices values up to
+ // SHN_LORESERVE. If we need more, we want to use extension SHT_SYMTAB_SHNDX
+ // section. Problem is that we reveal the final section indices a bit too
+ // late, and we do not know them here. For simplicity, we just always create
+ // a .symtab_shndxr section when the amount of output sections is huge.
+ size_t Size = 0;
+ for (BaseCommand *Base : Script->SectionCommands)
+ if (isa<OutputSection>(Base))
+ ++Size;
+ return Size < SHN_LORESERVE;
+}
+
+void SymtabShndxSection::finalizeContents() {
+ getParent()->Link = InX::SymTab->getParent()->SectionIndex;
+}
+
+size_t SymtabShndxSection::getSize() const {
+ return InX::SymTab->getNumSymbols() * 4;
+}
+
// .hash and .gnu.hash sections contain on-disk hash tables that map
// symbol names to their dynamic symbol table indices. Their purpose
// is to help the dynamic linker resolve symbols quickly. If ELF files
@@ -1690,12 +2106,14 @@ GnuHashTableSection::GnuHashTableSection()
void GnuHashTableSection::finalizeContents() {
getParent()->Link = InX::DynSymTab->getParent()->SectionIndex;
- // Computes bloom filter size in word size. We want to allocate 8
+ // Computes bloom filter size in word size. We want to allocate 12
// bits for each symbol. It must be a power of two.
- if (Symbols.empty())
+ if (Symbols.empty()) {
MaskWords = 1;
- else
- MaskWords = NextPowerOf2((Symbols.size() - 1) / Config->Wordsize);
+ } else {
+ uint64_t NumBits = Symbols.size() * 12;
+ MaskWords = NextPowerOf2(NumBits / (Config->Wordsize * 8));
+ }
Size = 16; // Header
Size += Config->Wordsize * MaskWords; // Bloom filter
@@ -1713,7 +2131,7 @@ void GnuHashTableSection::writeTo(uint8_t *Buf) {
write32(Buf, NBuckets);
write32(Buf + 4, InX::DynSymTab->getNumSymbols() - Symbols.size());
write32(Buf + 8, MaskWords);
- write32(Buf + 12, getShift2());
+ write32(Buf + 12, Shift2);
Buf += 16;
// Write a bloom filter and a hash table.
@@ -1730,12 +2148,12 @@ void GnuHashTableSection::writeTo(uint8_t *Buf) {
// [1] Ulrich Drepper (2011), "How To Write Shared Libraries" (Ver. 4.1.2),
// p.9, https://www.akkadia.org/drepper/dsohowto.pdf
void GnuHashTableSection::writeBloomFilter(uint8_t *Buf) {
- const unsigned C = Config->Wordsize * 8;
+ unsigned C = Config->Is64 ? 64 : 32;
for (const Entry &Sym : Symbols) {
size_t I = (Sym.Hash / C) & (MaskWords - 1);
uint64_t Val = readUint(Buf + I * Config->Wordsize);
Val |= uint64_t(1) << (Sym.Hash % C);
- Val |= uint64_t(1) << ((Sym.Hash >> getShift2()) % C);
+ Val |= uint64_t(1) << ((Sym.Hash >> Shift2) % C);
writeUint(Buf + I * Config->Wordsize, Val);
}
}
@@ -1777,21 +2195,23 @@ void GnuHashTableSection::addSymbols(std::vector<SymbolTableEntry> &V) {
// its type correctly.
std::vector<SymbolTableEntry>::iterator Mid =
std::stable_partition(V.begin(), V.end(), [](const SymbolTableEntry &S) {
- // Shared symbols that this executable preempts are special. The dynamic
- // linker has to look them up, so they have to be in the hash table.
- if (auto *SS = dyn_cast<SharedSymbol>(S.Sym))
- return SS->CopyRelSec == nullptr && !SS->NeedsPltAddr;
return !S.Sym->isDefined();
});
- if (Mid == V.end())
- return;
// We chose load factor 4 for the on-disk hash table. For each hash
// collision, the dynamic linker will compare a uint32_t hash value.
- // Since the integer comparison is quite fast, we believe we can make
- // the load factor even larger. 4 is just a conservative choice.
+ // Since the integer comparison is quite fast, we believe we can
+ // make the load factor even larger. 4 is just a conservative choice.
+ //
+ // Note that we don't want to create a zero-sized hash table because
+ // Android loader as of 2018 doesn't like a .gnu.hash containing such
+ // table. If that's the case, we create a hash table with one unused
+ // dummy slot.
NBuckets = std::max<size_t>((V.end() - Mid) / 4, 1);
+ if (Mid == V.end())
+ return;
+
for (SymbolTableEntry &Ent : llvm::make_range(Mid, V.end())) {
Symbol *B = Ent.Sym;
uint32_t Hash = hashGnu(B->getName());
@@ -1847,9 +2267,12 @@ void HashTableSection::writeTo(uint8_t *Buf) {
}
}
-PltSection::PltSection(size_t S)
- : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, ".plt"),
- HeaderSize(S) {
+// On PowerPC64 the lazy symbol resolvers go into the `global linkage table`
+// in the .glink section, rather then the typical .plt section.
+PltSection::PltSection(bool IsIplt)
+ : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16,
+ Config->EMachine == EM_PPC64 ? ".glink" : ".plt"),
+ HeaderSize(IsIplt ? 0 : Target->PltHeaderSize), IsIplt(IsIplt) {
// The PLT needs to be writable on SPARC as the dynamic linker will
// modify the instructions in the PLT entries.
if (Config->EMachine == EM_SPARCV9)
@@ -1859,7 +2282,7 @@ PltSection::PltSection(size_t S)
void PltSection::writeTo(uint8_t *Buf) {
// At beginning of PLT but not the IPLT, we have code to call the dynamic
// linker to resolve dynsyms at runtime. Write such code.
- if (HeaderSize != 0)
+ if (!IsIplt)
Target->writePltHeader(Buf);
size_t Off = HeaderSize;
// The IPlt is immediately after the Plt, account for this in RelOff
@@ -1878,7 +2301,7 @@ void PltSection::writeTo(uint8_t *Buf) {
template <class ELFT> void PltSection::addEntry(Symbol &Sym) {
Sym.PltIndex = Entries.size();
RelocationBaseSection *PltRelocSection = InX::RelaPlt;
- if (HeaderSize == 0) {
+ if (IsIplt) {
PltRelocSection = InX::RelaIplt;
Sym.IsInIplt = true;
}
@@ -1895,7 +2318,7 @@ size_t PltSection::getSize() const {
// example ARM uses mapping symbols to aid disassembly
void PltSection::addSymbols() {
// The PLT may have symbols defined for the Header, the IPLT has no header
- if (HeaderSize != 0)
+ if (!IsIplt)
Target->addPltHeaderSymbols(*this);
size_t Off = HeaderSize;
for (size_t I = 0; I < Entries.size(); ++I) {
@@ -1905,7 +2328,7 @@ void PltSection::addSymbols() {
}
unsigned PltSection::getPltRelocOff() const {
- return (HeaderSize == 0) ? InX::Plt->getSize() : 0;
+ return IsIplt ? InX::Plt->getSize() : 0;
}
// The string hash function for .gdb_index.
@@ -1916,16 +2339,48 @@ static uint32_t computeGdbHash(StringRef S) {
return H;
}
-static std::vector<GdbIndexChunk::CuEntry> readCuList(DWARFContext &Dwarf) {
- std::vector<GdbIndexChunk::CuEntry> Ret;
+GdbIndexSection::GdbIndexSection()
+ : SyntheticSection(0, SHT_PROGBITS, 1, ".gdb_index") {}
+
+// Returns the desired size of an on-disk hash table for a .gdb_index section.
+// There's a tradeoff between size and collision rate. We aim 75% utilization.
+size_t GdbIndexSection::computeSymtabSize() const {
+ return std::max<size_t>(NextPowerOf2(Symbols.size() * 4 / 3), 1024);
+}
+
+// Compute the output section size.
+void GdbIndexSection::initOutputSize() {
+ Size = sizeof(GdbIndexHeader) + computeSymtabSize() * 8;
+
+ for (GdbChunk &Chunk : Chunks)
+ Size += Chunk.CompilationUnits.size() * 16 + Chunk.AddressAreas.size() * 20;
+
+ // Add the constant pool size if exists.
+ if (!Symbols.empty()) {
+ GdbSymbol &Sym = Symbols.back();
+ Size += Sym.NameOff + Sym.Name.size() + 1;
+ }
+}
+
+static std::vector<InputSection *> getDebugInfoSections() {
+ std::vector<InputSection *> Ret;
+ for (InputSectionBase *S : InputSections)
+ if (InputSection *IS = dyn_cast<InputSection>(S))
+ if (IS->Name == ".debug_info")
+ Ret.push_back(IS);
+ return Ret;
+}
+
+static std::vector<GdbIndexSection::CuEntry> readCuList(DWARFContext &Dwarf) {
+ std::vector<GdbIndexSection::CuEntry> Ret;
for (std::unique_ptr<DWARFCompileUnit> &Cu : Dwarf.compile_units())
Ret.push_back({Cu->getOffset(), Cu->getLength() + 4});
return Ret;
}
-static std::vector<GdbIndexChunk::AddressEntry>
+static std::vector<GdbIndexSection::AddressEntry>
readAddressAreas(DWARFContext &Dwarf, InputSection *Sec) {
- std::vector<GdbIndexChunk::AddressEntry> Ret;
+ std::vector<GdbIndexSection::AddressEntry> Ret;
uint32_t CuIdx = 0;
for (std::unique_ptr<DWARFCompileUnit> &Cu : Dwarf.compile_units()) {
@@ -1949,218 +2404,192 @@ readAddressAreas(DWARFContext &Dwarf, InputSection *Sec) {
return Ret;
}
-static std::vector<GdbIndexChunk::NameTypeEntry>
-readPubNamesAndTypes(DWARFContext &Dwarf) {
+static std::vector<GdbIndexSection::NameTypeEntry>
+readPubNamesAndTypes(DWARFContext &Dwarf, uint32_t Idx) {
StringRef Sec1 = Dwarf.getDWARFObj().getGnuPubNamesSection();
StringRef Sec2 = Dwarf.getDWARFObj().getGnuPubTypesSection();
- std::vector<GdbIndexChunk::NameTypeEntry> Ret;
+ std::vector<GdbIndexSection::NameTypeEntry> Ret;
for (StringRef Sec : {Sec1, Sec2}) {
DWARFDebugPubTable Table(Sec, Config->IsLE, true);
- for (const DWARFDebugPubTable::Set &Set : Table.getData()) {
- for (const DWARFDebugPubTable::Entry &Ent : Set.Entries) {
- CachedHashStringRef S(Ent.Name, computeGdbHash(Ent.Name));
- Ret.push_back({S, Ent.Descriptor.toBits()});
- }
- }
+ for (const DWARFDebugPubTable::Set &Set : Table.getData())
+ for (const DWARFDebugPubTable::Entry &Ent : Set.Entries)
+ Ret.push_back({{Ent.Name, computeGdbHash(Ent.Name)},
+ (Ent.Descriptor.toBits() << 24) | Idx});
}
return Ret;
}
-static std::vector<InputSection *> getDebugInfoSections() {
- std::vector<InputSection *> Ret;
- for (InputSectionBase *S : InputSections)
- if (InputSection *IS = dyn_cast<InputSection>(S))
- if (IS->Name == ".debug_info")
- Ret.push_back(IS);
- return Ret;
-}
+// Create a list of symbols from a given list of symbol names and types
+// by uniquifying them by name.
+static std::vector<GdbIndexSection::GdbSymbol>
+createSymbols(ArrayRef<std::vector<GdbIndexSection::NameTypeEntry>> NameTypes) {
+ typedef GdbIndexSection::GdbSymbol GdbSymbol;
+ typedef GdbIndexSection::NameTypeEntry NameTypeEntry;
-void GdbIndexSection::fixCuIndex() {
- uint32_t Idx = 0;
- for (GdbIndexChunk &Chunk : Chunks) {
- for (GdbIndexChunk::AddressEntry &Ent : Chunk.AddressAreas)
- Ent.CuIndex += Idx;
- Idx += Chunk.CompilationUnits.size();
- }
-}
+ // The number of symbols we will handle in this function is of the order
+ // of millions for very large executables, so we use multi-threading to
+ // speed it up.
+ size_t NumShards = 32;
+ size_t Concurrency = 1;
+ if (ThreadsEnabled)
+ Concurrency =
+ std::min<size_t>(PowerOf2Floor(hardware_concurrency()), NumShards);
-std::vector<std::vector<uint32_t>> GdbIndexSection::createCuVectors() {
- std::vector<std::vector<uint32_t>> Ret;
- uint32_t Idx = 0;
- uint32_t Off = 0;
+ // A sharded map to uniquify symbols by name.
+ std::vector<DenseMap<CachedHashStringRef, size_t>> Map(NumShards);
+ size_t Shift = 32 - countTrailingZeros(NumShards);
- for (GdbIndexChunk &Chunk : Chunks) {
- for (GdbIndexChunk::NameTypeEntry &Ent : Chunk.NamesAndTypes) {
- GdbSymbol *&Sym = Symbols[Ent.Name];
- if (!Sym) {
- Sym = make<GdbSymbol>(GdbSymbol{Ent.Name.hash(), Off, Ret.size()});
- Off += Ent.Name.size() + 1;
- Ret.push_back({});
- }
+ // Instantiate GdbSymbols while uniqufying them by name.
+ std::vector<std::vector<GdbSymbol>> Symbols(NumShards);
+ parallelForEachN(0, Concurrency, [&](size_t ThreadId) {
+ for (ArrayRef<NameTypeEntry> Entries : NameTypes) {
+ for (const NameTypeEntry &Ent : Entries) {
+ size_t ShardId = Ent.Name.hash() >> Shift;
+ if ((ShardId & (Concurrency - 1)) != ThreadId)
+ continue;
+
+ size_t &Idx = Map[ShardId][Ent.Name];
+ if (Idx) {
+ Symbols[ShardId][Idx - 1].CuVector.push_back(Ent.Type);
+ continue;
+ }
- // gcc 5.4.1 produces a buggy .debug_gnu_pubnames that contains
- // duplicate entries, so we want to dedup them.
- std::vector<uint32_t> &Vec = Ret[Sym->CuVectorIndex];
- uint32_t Val = (Ent.Type << 24) | Idx;
- if (Vec.empty() || Vec.back() != Val)
- Vec.push_back(Val);
+ Idx = Symbols[ShardId].size() + 1;
+ Symbols[ShardId].push_back({Ent.Name, {Ent.Type}, 0, 0});
+ }
}
- Idx += Chunk.CompilationUnits.size();
+ });
+
+ size_t NumSymbols = 0;
+ for (ArrayRef<GdbSymbol> V : Symbols)
+ NumSymbols += V.size();
+
+ // The return type is a flattened vector, so we'll copy each vector
+ // contents to Ret.
+ std::vector<GdbSymbol> Ret;
+ Ret.reserve(NumSymbols);
+ for (std::vector<GdbSymbol> &Vec : Symbols)
+ for (GdbSymbol &Sym : Vec)
+ Ret.push_back(std::move(Sym));
+
+ // CU vectors and symbol names are adjacent in the output file.
+ // We can compute their offsets in the output file now.
+ size_t Off = 0;
+ for (GdbSymbol &Sym : Ret) {
+ Sym.CuVectorOff = Off;
+ Off += (Sym.CuVector.size() + 1) * 4;
+ }
+ for (GdbSymbol &Sym : Ret) {
+ Sym.NameOff = Off;
+ Off += Sym.Name.size() + 1;
}
- StringPoolSize = Off;
return Ret;
}
-template <class ELFT> GdbIndexSection *elf::createGdbIndex() {
- // Gather debug info to create a .gdb_index section.
+// Returns a newly-created .gdb_index section.
+template <class ELFT> GdbIndexSection *GdbIndexSection::create() {
std::vector<InputSection *> Sections = getDebugInfoSections();
- std::vector<GdbIndexChunk> Chunks(Sections.size());
-
- parallelForEachN(0, Chunks.size(), [&](size_t I) {
- ObjFile<ELFT> *File = Sections[I]->getFile<ELFT>();
- DWARFContext Dwarf(make_unique<LLDDwarfObj<ELFT>>(File));
-
- Chunks[I].DebugInfoSec = Sections[I];
- Chunks[I].CompilationUnits = readCuList(Dwarf);
- Chunks[I].AddressAreas = readAddressAreas(Dwarf, Sections[I]);
- Chunks[I].NamesAndTypes = readPubNamesAndTypes(Dwarf);
- });
// .debug_gnu_pub{names,types} are useless in executables.
// They are present in input object files solely for creating
- // a .gdb_index. So we can remove it from the output.
+ // a .gdb_index. So we can remove them from the output.
for (InputSectionBase *S : InputSections)
if (S->Name == ".debug_gnu_pubnames" || S->Name == ".debug_gnu_pubtypes")
S->Live = false;
- // Create a .gdb_index and returns it.
- return make<GdbIndexSection>(std::move(Chunks));
-}
+ std::vector<GdbChunk> Chunks(Sections.size());
+ std::vector<std::vector<NameTypeEntry>> NameTypes(Sections.size());
-static size_t getCuSize(ArrayRef<GdbIndexChunk> Arr) {
- size_t Ret = 0;
- for (const GdbIndexChunk &D : Arr)
- Ret += D.CompilationUnits.size();
- return Ret;
-}
-
-static size_t getAddressAreaSize(ArrayRef<GdbIndexChunk> Arr) {
- size_t Ret = 0;
- for (const GdbIndexChunk &D : Arr)
- Ret += D.AddressAreas.size();
- return Ret;
-}
-
-std::vector<GdbSymbol *> GdbIndexSection::createGdbSymtab() {
- uint32_t Size = NextPowerOf2(Symbols.size() * 4 / 3);
- if (Size < 1024)
- Size = 1024;
-
- uint32_t Mask = Size - 1;
- std::vector<GdbSymbol *> Ret(Size);
+ parallelForEachN(0, Sections.size(), [&](size_t I) {
+ ObjFile<ELFT> *File = Sections[I]->getFile<ELFT>();
+ DWARFContext Dwarf(make_unique<LLDDwarfObj<ELFT>>(File));
- for (auto &KV : Symbols) {
- GdbSymbol *Sym = KV.second;
- uint32_t I = Sym->NameHash & Mask;
- uint32_t Step = ((Sym->NameHash * 17) & Mask) | 1;
+ Chunks[I].Sec = Sections[I];
+ Chunks[I].CompilationUnits = readCuList(Dwarf);
+ Chunks[I].AddressAreas = readAddressAreas(Dwarf, Sections[I]);
+ NameTypes[I] = readPubNamesAndTypes(Dwarf, I);
+ });
- while (Ret[I])
- I = (I + Step) & Mask;
- Ret[I] = Sym;
- }
+ auto *Ret = make<GdbIndexSection>();
+ Ret->Chunks = std::move(Chunks);
+ Ret->Symbols = createSymbols(NameTypes);
+ Ret->initOutputSize();
return Ret;
}
-GdbIndexSection::GdbIndexSection(std::vector<GdbIndexChunk> &&C)
- : SyntheticSection(0, SHT_PROGBITS, 1, ".gdb_index"), Chunks(std::move(C)) {
- fixCuIndex();
- CuVectors = createCuVectors();
- GdbSymtab = createGdbSymtab();
-
- // Compute offsets early to know the section size.
- // Each chunk size needs to be in sync with what we write in writeTo.
- CuTypesOffset = CuListOffset + getCuSize(Chunks) * 16;
- SymtabOffset = CuTypesOffset + getAddressAreaSize(Chunks) * 20;
- ConstantPoolOffset = SymtabOffset + GdbSymtab.size() * 8;
-
- size_t Off = 0;
- for (ArrayRef<uint32_t> Vec : CuVectors) {
- CuVectorOffsets.push_back(Off);
- Off += (Vec.size() + 1) * 4;
- }
- StringPoolOffset = ConstantPoolOffset + Off;
-}
-
-size_t GdbIndexSection::getSize() const {
- return StringPoolOffset + StringPoolSize;
-}
-
void GdbIndexSection::writeTo(uint8_t *Buf) {
- // Write the section header.
- write32le(Buf, 7);
- write32le(Buf + 4, CuListOffset);
- write32le(Buf + 8, CuTypesOffset);
- write32le(Buf + 12, CuTypesOffset);
- write32le(Buf + 16, SymtabOffset);
- write32le(Buf + 20, ConstantPoolOffset);
- Buf += 24;
+ // Write the header.
+ auto *Hdr = reinterpret_cast<GdbIndexHeader *>(Buf);
+ uint8_t *Start = Buf;
+ Hdr->Version = 7;
+ Buf += sizeof(*Hdr);
// Write the CU list.
- for (GdbIndexChunk &D : Chunks) {
- for (GdbIndexChunk::CuEntry &Cu : D.CompilationUnits) {
- write64le(Buf, D.DebugInfoSec->OutSecOff + Cu.CuOffset);
+ Hdr->CuListOff = Buf - Start;
+ for (GdbChunk &Chunk : Chunks) {
+ for (CuEntry &Cu : Chunk.CompilationUnits) {
+ write64le(Buf, Chunk.Sec->OutSecOff + Cu.CuOffset);
write64le(Buf + 8, Cu.CuLength);
Buf += 16;
}
}
// Write the address area.
- for (GdbIndexChunk &D : Chunks) {
- for (GdbIndexChunk::AddressEntry &E : D.AddressAreas) {
- uint64_t BaseAddr =
- E.Section->getParent()->Addr + E.Section->getOffset(0);
+ Hdr->CuTypesOff = Buf - Start;
+ Hdr->AddressAreaOff = Buf - Start;
+ uint32_t CuOff = 0;
+ for (GdbChunk &Chunk : Chunks) {
+ for (AddressEntry &E : Chunk.AddressAreas) {
+ uint64_t BaseAddr = E.Section->getVA(0);
write64le(Buf, BaseAddr + E.LowAddress);
write64le(Buf + 8, BaseAddr + E.HighAddress);
- write32le(Buf + 16, E.CuIndex);
+ write32le(Buf + 16, E.CuIndex + CuOff);
Buf += 20;
}
+ CuOff += Chunk.CompilationUnits.size();
}
- // Write the symbol table.
- for (GdbSymbol *Sym : GdbSymtab) {
- if (Sym) {
- write32le(Buf, Sym->NameOffset + StringPoolOffset - ConstantPoolOffset);
- write32le(Buf + 4, CuVectorOffsets[Sym->CuVectorIndex]);
- }
- Buf += 8;
+ // Write the on-disk open-addressing hash table containing symbols.
+ Hdr->SymtabOff = Buf - Start;
+ size_t SymtabSize = computeSymtabSize();
+ uint32_t Mask = SymtabSize - 1;
+
+ for (GdbSymbol &Sym : Symbols) {
+ uint32_t H = Sym.Name.hash();
+ uint32_t I = H & Mask;
+ uint32_t Step = ((H * 17) & Mask) | 1;
+
+ while (read32le(Buf + I * 8))
+ I = (I + Step) & Mask;
+
+ write32le(Buf + I * 8, Sym.NameOff);
+ write32le(Buf + I * 8 + 4, Sym.CuVectorOff);
}
+ Buf += SymtabSize * 8;
+
+ // Write the string pool.
+ Hdr->ConstantPoolOff = Buf - Start;
+ for (GdbSymbol &Sym : Symbols)
+ memcpy(Buf + Sym.NameOff, Sym.Name.data(), Sym.Name.size());
+
// Write the CU vectors.
- for (ArrayRef<uint32_t> Vec : CuVectors) {
- write32le(Buf, Vec.size());
+ for (GdbSymbol &Sym : Symbols) {
+ write32le(Buf, Sym.CuVector.size());
Buf += 4;
- for (uint32_t Val : Vec) {
+ for (uint32_t Val : Sym.CuVector) {
write32le(Buf, Val);
Buf += 4;
}
}
-
- // Write the string pool.
- for (auto &KV : Symbols) {
- CachedHashStringRef S = KV.first;
- GdbSymbol *Sym = KV.second;
- size_t Off = Sym->NameOffset;
- memcpy(Buf + Off, S.val().data(), S.size());
- Buf[Off + S.size()] = '\0';
- }
}
bool GdbIndexSection::empty() const { return !Out::DebugInfo; }
EhFrameHeader::EhFrameHeader()
- : SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 1, ".eh_frame_hdr") {}
+ : SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 4, ".eh_frame_hdr") {}
// .eh_frame_hdr contains a binary search table of pointers to FDEs.
// Each entry of the search table consists of two values,
@@ -2171,14 +2600,6 @@ void EhFrameHeader::writeTo(uint8_t *Buf) {
std::vector<FdeData> Fdes = InX::EhFrame->getFdeData();
- // Sort the FDE list by their PC and uniqueify. Usually there is only
- // one FDE for a PC (i.e. function), but if ICF merges two functions
- // into one, there can be more than one FDEs pointing to the address.
- auto Less = [](const FdeData &A, const FdeData &B) { return A.Pc < B.Pc; };
- std::stable_sort(Fdes.begin(), Fdes.end(), Less);
- auto Eq = [](const FdeData &A, const FdeData &B) { return A.Pc == B.Pc; };
- Fdes.erase(std::unique(Fdes.begin(), Fdes.end(), Eq), Fdes.end());
-
Buf[0] = 1;
Buf[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4;
Buf[2] = DW_EH_PE_udata4;
@@ -2187,10 +2608,9 @@ void EhFrameHeader::writeTo(uint8_t *Buf) {
write32(Buf + 8, Fdes.size());
Buf += 12;
- uint64_t VA = this->getVA();
for (FdeData &Fde : Fdes) {
- write32(Buf, Fde.Pc - VA);
- write32(Buf + 4, Fde.FdeVA - VA);
+ write32(Buf, Fde.PcRel);
+ write32(Buf + 4, Fde.FdeVARel);
Buf += 8;
}
}
@@ -2300,11 +2720,9 @@ VersionNeedSection<ELFT>::VersionNeedSection()
NextIndex = getVerDefNum() + 1;
}
-template <class ELFT>
-void VersionNeedSection<ELFT>::addSymbol(SharedSymbol *SS) {
- SharedFile<ELFT> &File = SS->getFile<ELFT>();
- const typename ELFT::Verdef *Ver = File.Verdefs[SS->VerdefIndex];
- if (!Ver) {
+template <class ELFT> void VersionNeedSection<ELFT>::addSymbol(Symbol *SS) {
+ auto &File = cast<SharedFile<ELFT>>(*SS->File);
+ if (SS->VerdefIndex == VER_NDX_GLOBAL) {
SS->VersionId = VER_NDX_GLOBAL;
return;
}
@@ -2314,7 +2732,9 @@ void VersionNeedSection<ELFT>::addSymbol(SharedSymbol *SS) {
// for the soname.
if (File.VerdefMap.empty())
Needed.push_back({&File, InX::DynStrTab->addString(File.SoName)});
+ const typename ELFT::Verdef *Ver = File.Verdefs[SS->VerdefIndex];
typename SharedFile<ELFT>::NeededVer &NV = File.VerdefMap[Ver];
+
// If we don't already know that we need an Elf_Vernaux for this Elf_Verdef,
// prepare to create one by allocating a version identifier and creating a
// dynstr entry for the version name.
@@ -2478,11 +2898,20 @@ static MergeSyntheticSection *createMergeSynthetic(StringRef Name,
return make<MergeNoTailSection>(Name, Type, Flags, Alignment);
}
-// Debug sections may be compressed by zlib. Uncompress if exists.
+// Debug sections may be compressed by zlib. Decompress if exists.
void elf::decompressSections() {
+ parallelForEach(InputSections,
+ [](InputSectionBase *Sec) { Sec->maybeDecompress(); });
+}
+
+template <class ELFT> void elf::splitSections() {
+ // splitIntoPieces needs to be called on each MergeInputSection
+ // before calling finalizeContents().
parallelForEach(InputSections, [](InputSectionBase *Sec) {
- if (Sec->Live)
- Sec->maybeUncompress();
+ if (auto *S = dyn_cast<MergeInputSection>(Sec))
+ S->splitIntoPieces();
+ else if (auto *Eh = dyn_cast<EhInputSection>(Sec))
+ Eh->split<ELFT>();
});
}
@@ -2494,14 +2923,6 @@ void elf::decompressSections() {
// that it replaces. It then finalizes each synthetic section in order
// to compute an output offset for each piece of each input section.
void elf::mergeSections() {
- // splitIntoPieces needs to be called on each MergeInputSection
- // before calling finalizeContents(). Do that first.
- parallelForEach(InputSections, [](InputSectionBase *Sec) {
- if (Sec->Live)
- if (auto *S = dyn_cast<MergeInputSection>(Sec))
- S->splitIntoPieces();
- });
-
std::vector<MergeSyntheticSection *> MergeSections;
for (InputSectionBase *&S : InputSections) {
MergeInputSection *MS = dyn_cast<MergeInputSection>(S);
@@ -2510,8 +2931,10 @@ void elf::mergeSections() {
// We do not want to handle sections that are not alive, so just remove
// them instead of trying to merge.
- if (!MS->Live)
+ if (!MS->Live) {
+ S = nullptr;
continue;
+ }
StringRef OutsecName = getOutputSectionName(MS);
uint32_t Alignment = MS->Alignment;
@@ -2565,8 +2988,7 @@ ARMExidxSentinelSection::ARMExidxSentinelSection()
// address described by any other table entry.
void ARMExidxSentinelSection::writeTo(uint8_t *Buf) {
assert(Highest);
- uint64_t S =
- Highest->getParent()->Addr + Highest->getOffset(Highest->getSize());
+ uint64_t S = Highest->getVA(Highest->getSize());
uint64_t P = getVA();
Target->relocateOne(Buf, R_ARM_PREL31, S - P);
write32le(Buf + 4, 1);
@@ -2574,18 +2996,16 @@ void ARMExidxSentinelSection::writeTo(uint8_t *Buf) {
// The sentinel has to be removed if there are no other .ARM.exidx entries.
bool ARMExidxSentinelSection::empty() const {
- OutputSection *OS = getParent();
- if (!OS)
- return false;
-
- for (auto *B : OS->SectionCommands)
- if (auto *ISD = dyn_cast<InputSectionDescription>(B))
- for (auto *S : ISD->Sections)
- if (!isa<ARMExidxSentinelSection>(S))
- return false;
+ for (InputSection *IS : getInputSections(getParent()))
+ if (!isa<ARMExidxSentinelSection>(IS))
+ return false;
return true;
}
+bool ARMExidxSentinelSection::classof(const SectionBase *D) {
+ return D->kind() == InputSectionBase::Synthetic && D->Type == SHT_ARM_EXIDX;
+}
+
ThunkSection::ThunkSection(OutputSection *OS, uint64_t Off)
: SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS,
Config->Wordsize, ".text.thunk") {
@@ -2594,16 +3014,13 @@ ThunkSection::ThunkSection(OutputSection *OS, uint64_t Off)
}
void ThunkSection::addThunk(Thunk *T) {
- uint64_t Off = alignTo(Size, T->Alignment);
- T->Offset = Off;
Thunks.push_back(T);
T->addSymbols(*this);
- Size = Off + T->size();
}
void ThunkSection::writeTo(uint8_t *Buf) {
- for (const Thunk *T : Thunks)
- T->writeTo(Buf + T->Offset, *this);
+ for (Thunk *T : Thunks)
+ T->writeTo(Buf + T->Offset);
}
InputSection *ThunkSection::getTargetInputSection() const {
@@ -2613,6 +3030,20 @@ InputSection *ThunkSection::getTargetInputSection() const {
return T->getTargetInputSection();
}
+bool ThunkSection::assignOffsets() {
+ uint64_t Off = 0;
+ for (Thunk *T : Thunks) {
+ Off = alignTo(Off, T->Alignment);
+ T->setOffset(Off);
+ uint32_t Size = T->size();
+ T->getThunkTargetSym()->Size = Size;
+ Off += Size;
+ }
+ bool Changed = Off != Size;
+ Size = Off;
+ return Changed;
+}
+
InputSection *InX::ARMAttributes;
BssSection *InX::Bss;
BssSection *InX::BssRelRo;
@@ -2634,16 +3065,23 @@ MipsRldMapSection *InX::MipsRldMap;
PltSection *InX::Plt;
PltSection *InX::Iplt;
RelocationBaseSection *InX::RelaDyn;
+RelrBaseSection *InX::RelrDyn;
RelocationBaseSection *InX::RelaPlt;
RelocationBaseSection *InX::RelaIplt;
StringTableSection *InX::ShStrTab;
StringTableSection *InX::StrTab;
SymbolTableBaseSection *InX::SymTab;
+SymtabShndxSection *InX::SymTabShndx;
+
+template GdbIndexSection *GdbIndexSection::create<ELF32LE>();
+template GdbIndexSection *GdbIndexSection::create<ELF32BE>();
+template GdbIndexSection *GdbIndexSection::create<ELF64LE>();
+template GdbIndexSection *GdbIndexSection::create<ELF64BE>();
-template GdbIndexSection *elf::createGdbIndex<ELF32LE>();
-template GdbIndexSection *elf::createGdbIndex<ELF32BE>();
-template GdbIndexSection *elf::createGdbIndex<ELF64LE>();
-template GdbIndexSection *elf::createGdbIndex<ELF64BE>();
+template void elf::splitSections<ELF32LE>();
+template void elf::splitSections<ELF32BE>();
+template void elf::splitSections<ELF64LE>();
+template void elf::splitSections<ELF64BE>();
template void EhFrameSection::addSection<ELF32LE>(InputSectionBase *);
template void EhFrameSection::addSection<ELF32BE>(InputSectionBase *);
@@ -2655,6 +3093,11 @@ template void PltSection::addEntry<ELF32BE>(Symbol &Sym);
template void PltSection::addEntry<ELF64LE>(Symbol &Sym);
template void PltSection::addEntry<ELF64BE>(Symbol &Sym);
+template void MipsGotSection::build<ELF32LE>();
+template void MipsGotSection::build<ELF32BE>();
+template void MipsGotSection::build<ELF64LE>();
+template void MipsGotSection::build<ELF64BE>();
+
template class elf::MipsAbiFlagsSection<ELF32LE>;
template class elf::MipsAbiFlagsSection<ELF32BE>;
template class elf::MipsAbiFlagsSection<ELF64LE>;
@@ -2685,6 +3128,11 @@ template class elf::AndroidPackedRelocationSection<ELF32BE>;
template class elf::AndroidPackedRelocationSection<ELF64LE>;
template class elf::AndroidPackedRelocationSection<ELF64BE>;
+template class elf::RelrSection<ELF32LE>;
+template class elf::RelrSection<ELF32BE>;
+template class elf::RelrSection<ELF64LE>;
+template class elf::RelrSection<ELF64BE>;
+
template class elf::SymbolTableSection<ELF32LE>;
template class elf::SymbolTableSection<ELF32BE>;
template class elf::SymbolTableSection<ELF64LE>;
diff --git a/gnu/llvm/tools/lld/ELF/Writer.cpp b/gnu/llvm/tools/lld/ELF/Writer.cpp
index 058aa178771..ccff0c58333 100644
--- a/gnu/llvm/tools/lld/ELF/Writer.cpp
+++ b/gnu/llvm/tools/lld/ELF/Writer.cpp
@@ -9,18 +9,19 @@
#include "Writer.h"
#include "AArch64ErrataFix.h"
+#include "CallGraphSort.h"
#include "Config.h"
#include "Filesystem.h"
#include "LinkerScript.h"
#include "MapFile.h"
#include "OutputSections.h"
#include "Relocations.h"
-#include "Strings.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "lld/Common/Memory.h"
+#include "lld/Common/Strings.h"
#include "lld/Common/Threads.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSwitch.h"
@@ -49,7 +50,7 @@ public:
private:
void copyLocalSymbols();
void addSectionSymbols();
- void forEachRelSec(std::function<void(InputSectionBase &)> Fn);
+ void forEachRelSec(llvm::function_ref<void(InputSectionBase &)> Fn);
void sortSections();
void resolveShfLinkOrder();
void sortInputSections();
@@ -62,6 +63,7 @@ private:
void assignFileOffsets();
void assignFileOffsetsBinary();
void setPhdrs();
+ void checkSections();
void fixSectionAlignments();
void openFile();
void writeTrapInstr();
@@ -81,40 +83,49 @@ private:
uint64_t FileSize;
uint64_t SectionHeaderOff;
-
- bool HasGotBaseSym = false;
};
} // anonymous namespace
-StringRef elf::getOutputSectionName(InputSectionBase *S) {
- // ".zdebug_" is a prefix for ZLIB-compressed sections.
- // Because we decompressed input sections, we want to remove 'z'.
- if (S->Name.startswith(".zdebug_"))
- return Saver.save("." + S->Name.substr(2));
+static bool isSectionPrefix(StringRef Prefix, StringRef Name) {
+ return Name.startswith(Prefix) || Name == Prefix.drop_back();
+}
+StringRef elf::getOutputSectionName(const InputSectionBase *S) {
if (Config->Relocatable)
return S->Name;
// This is for --emit-relocs. If .text.foo is emitted as .text.bar, we want
// to emit .rela.text.foo as .rela.text.bar for consistency (this is not
// technically required, but not doing it is odd). This code guarantees that.
- if ((S->Type == SHT_REL || S->Type == SHT_RELA) &&
- !isa<SyntheticSection>(S)) {
- OutputSection *Out =
- cast<InputSection>(S)->getRelocatedSection()->getOutputSection();
- if (S->Type == SHT_RELA)
- return Saver.save(".rela" + Out->Name);
- return Saver.save(".rel" + Out->Name);
+ if (auto *IS = dyn_cast<InputSection>(S)) {
+ if (InputSectionBase *Rel = IS->getRelocatedSection()) {
+ OutputSection *Out = Rel->getOutputSection();
+ if (S->Type == SHT_RELA)
+ return Saver.save(".rela" + Out->Name);
+ return Saver.save(".rel" + Out->Name);
+ }
}
+ // This check is for -z keep-text-section-prefix. This option separates text
+ // sections with prefix ".text.hot", ".text.unlikely", ".text.startup" or
+ // ".text.exit".
+ // When enabled, this allows identifying the hot code region (.text.hot) in
+ // the final binary which can be selectively mapped to huge pages or mlocked,
+ // for instance.
+ if (Config->ZKeepTextSectionPrefix)
+ for (StringRef V :
+ {".text.hot.", ".text.unlikely.", ".text.startup.", ".text.exit."}) {
+ if (isSectionPrefix(V, S->Name))
+ return V.drop_back();
+ }
+
for (StringRef V :
{".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.rel.ro.",
".bss.", ".init_array.", ".fini_array.", ".ctors.", ".dtors.", ".tbss.",
".gcc_except_table.", ".tdata.", ".ARM.exidx.", ".ARM.extab.",
- ".openbsd.randomdata."}) {
- StringRef Prefix = V.drop_back();
- if (S->Name.startswith(V) || S->Name == Prefix)
- return Prefix;
+ ".openbsd.randomdata."}) {
+ if (isSectionPrefix(V, S->Name))
+ return V.drop_back();
}
// CommonSection is identified as "COMMON" in linker scripts.
@@ -195,21 +206,30 @@ void elf::addReservedSymbols() {
Symtab->addAbsolute("__gnu_local_gp", STV_HIDDEN, STB_GLOBAL);
}
+ // The Power Architecture 64-bit v2 ABI defines a TableOfContents (TOC) which
+ // combines the typical ELF GOT with the small data sections. It commonly
+ // includes .got .toc .sdata .sbss. The .TOC. symbol replaces both
+ // _GLOBAL_OFFSET_TABLE_ and _SDA_BASE_ from the 32-bit ABI. It is used to
+ // represent the TOC base which is offset by 0x8000 bytes from the start of
+ // the .got section.
ElfSym::GlobalOffsetTable = addOptionalRegular(
- "_GLOBAL_OFFSET_TABLE_", Out::ElfHeader, Target->GotBaseSymOff);
+ (Config->EMachine == EM_PPC64) ? ".TOC." : "_GLOBAL_OFFSET_TABLE_",
+ Out::ElfHeader, Target->GotBaseSymOff);
// __ehdr_start is the location of ELF file headers. Note that we define
// this symbol unconditionally even when using a linker script, which
// differs from the behavior implemented by GNU linker which only define
// this symbol if ELF headers are in the memory mapped segment.
+ addOptionalRegular("__ehdr_start", Out::ElfHeader, 0, STV_HIDDEN);
+
// __executable_start is not documented, but the expectation of at
- // least the android libc is that it points to the elf header too.
+ // least the Android libc is that it points to the ELF header.
+ addOptionalRegular("__executable_start", Out::ElfHeader, 0, STV_HIDDEN);
+
// __dso_handle symbol is passed to cxa_finalize as a marker to identify
// each DSO. The address of the symbol doesn't matter as long as they are
// different in different DSOs, so we chose the start address of the DSO.
- for (const char *Name :
- {"__ehdr_start", "__executable_start", "__dso_handle"})
- addOptionalRegular(Name, Out::ElfHeader, 0, STV_HIDDEN);
+ addOptionalRegular("__dso_handle", Out::ElfHeader, 0, STV_HIDDEN);
// If linker script do layout we do not need to create any standart symbols.
if (Script->HasSectionsCommand)
@@ -269,6 +289,7 @@ template <class ELFT> static void createSyntheticSections() {
if (Config->Strip != StripPolicy::All) {
InX::StrTab = make<StringTableSection>(".strtab", false);
InX::SymTab = make<SymbolTableSection<ELFT>>(*InX::StrTab);
+ InX::SymTabShndx = make<SymtabShndxSection>();
}
if (Config->BuildId != BuildIdKind::None) {
@@ -282,10 +303,9 @@ template <class ELFT> static void createSyntheticSections() {
// If there is a SECTIONS command and a .data.rel.ro section name use name
// .data.rel.ro.bss so that we match in the .data.rel.ro output section.
// This makes sure our relro is contiguous.
- bool HasDataRelRo =
- Script->HasSectionsCommand && findSection(".data.rel.ro");
- InX::BssRelRo = make<BssSection>(
- HasDataRelRo ? ".data.rel.ro.bss" : ".bss.rel.ro", 0, 1);
+ bool HasDataRelRo = Script->HasSectionsCommand && findSection(".data.rel.ro");
+ InX::BssRelRo =
+ make<BssSection>(HasDataRelRo ? ".data.rel.ro.bss" : ".bss.rel.ro", 0, 1);
Add(InX::BssRelRo);
// Add MIPS-specific sections.
@@ -332,6 +352,11 @@ template <class ELFT> static void createSyntheticSections() {
Add(InX::RelaDyn);
}
+ if (Config->RelrPackDynRelocs) {
+ InX::RelrDyn = make<RelrSection<ELFT>>();
+ Add(InX::RelrDyn);
+ }
+
// Add .got. MIPS' .got is so different from the other archs,
// it has its own class.
if (Config->EMachine == EM_MIPS) {
@@ -348,7 +373,7 @@ template <class ELFT> static void createSyntheticSections() {
Add(InX::IgotPlt);
if (Config->GdbIndex) {
- InX::GdbIndex = createGdbIndex<ELFT>();
+ InX::GdbIndex = GdbIndexSection::create<ELFT>();
Add(InX::GdbIndex);
}
@@ -371,9 +396,9 @@ template <class ELFT> static void createSyntheticSections() {
false /*Sort*/);
Add(InX::RelaIplt);
- InX::Plt = make<PltSection>(Target->PltHeaderSize);
+ InX::Plt = make<PltSection>(false);
Add(InX::Plt);
- InX::Iplt = make<PltSection>(0);
+ InX::Iplt = make<PltSection>(true);
Add(InX::Iplt);
if (!Config->Relocatable) {
@@ -387,6 +412,8 @@ template <class ELFT> static void createSyntheticSections() {
if (InX::SymTab)
Add(InX::SymTab);
+ if (InX::SymTabShndx)
+ Add(InX::SymTabShndx);
Add(InX::ShStrTab);
if (InX::StrTab)
Add(InX::StrTab);
@@ -456,6 +483,9 @@ template <class ELFT> void Writer<ELFT>::run() {
Sec->Addr = 0;
}
+ if (Config->CheckSections)
+ checkSections();
+
// It does not make sense try to open the file if we have error already.
if (errorCount())
return;
@@ -478,8 +508,9 @@ template <class ELFT> void Writer<ELFT>::run() {
if (errorCount())
return;
- // Handle -Map option.
+ // Handle -Map and -cref options.
writeMapFile();
+ writeCrossReferenceTable();
if (errorCount())
return;
@@ -492,10 +523,6 @@ static bool shouldKeepInSymtab(SectionBase *Sec, StringRef SymName,
if (B.isSection())
return false;
- // If sym references a section in a discarded group, don't keep it.
- if (Sec == &InputSection::Discarded)
- return false;
-
if (Config->Discard == DiscardPolicy::None)
return true;
@@ -640,6 +667,9 @@ static bool isRelroSection(const OutputSection *Sec) {
if (InX::Got && Sec == InX::Got->getParent())
return true;
+ if (Sec->Name.equals(".toc"))
+ return true;
+
// .got.plt contains pointers to external function symbols. They are
// by default resolved lazily, so we usually cannot put it into RELRO.
// However, if "-z now" is given, the lazy symbol resolution is
@@ -675,20 +705,22 @@ static bool isRelroSection(const OutputSection *Sec) {
// * It is easy to check if a give branch was taken.
// * It is easy two see how similar two ranks are (see getRankProximity).
enum RankFlags {
- RF_NOT_ADDR_SET = 1 << 16,
- RF_NOT_INTERP = 1 << 15,
- RF_NOT_ALLOC = 1 << 14,
- RF_WRITE = 1 << 13,
- RF_EXEC_WRITE = 1 << 12,
- RF_EXEC = 1 << 11,
- RF_NON_TLS_BSS = 1 << 10,
- RF_NON_TLS_BSS_RO = 1 << 9,
- RF_NOT_TLS = 1 << 8,
- RF_BSS = 1 << 7,
+ RF_NOT_ADDR_SET = 1 << 18,
+ RF_NOT_INTERP = 1 << 17,
+ RF_NOT_ALLOC = 1 << 16,
+ RF_WRITE = 1 << 15,
+ RF_EXEC_WRITE = 1 << 14,
+ RF_EXEC = 1 << 13,
+ RF_RODATA = 1 << 12,
+ RF_NON_TLS_BSS = 1 << 11,
+ RF_NON_TLS_BSS_RO = 1 << 10,
+ RF_NOT_TLS = 1 << 9,
+ RF_BSS = 1 << 8,
+ RF_NOTE = 1 << 7,
RF_PPC_NOT_TOCBSS = 1 << 6,
- RF_PPC_OPD = 1 << 5,
- RF_PPC_TOCL = 1 << 4,
- RF_PPC_TOC = 1 << 3,
+ RF_PPC_TOCL = 1 << 5,
+ RF_PPC_TOC = 1 << 4,
+ RF_PPC_GOT = 1 << 3,
RF_PPC_BRANCH_LT = 1 << 2,
RF_MIPS_GPREL = 1 << 1,
RF_MIPS_NOT_GOT = 1 << 0
@@ -719,8 +751,7 @@ static unsigned getSectionRank(const OutputSection *Sec) {
// considerations:
// * Read-only sections come first such that they go in the
// PT_LOAD covering the program headers at the start of the file.
- // * Read-only, executable sections come next, unless the
- // -no-rosegment option is used.
+ // * Read-only, executable sections come next.
// * Writable, executable sections follow such that .plt on
// architectures where it needs to be writable will be placed
// between .text and .data.
@@ -732,11 +763,16 @@ static unsigned getSectionRank(const OutputSection *Sec) {
if (IsExec) {
if (IsWrite)
Rank |= RF_EXEC_WRITE;
- else if (!Config->SingleRoRx)
+ else
Rank |= RF_EXEC;
- } else {
- if (IsWrite)
- Rank |= RF_WRITE;
+ } else if (IsWrite) {
+ Rank |= RF_WRITE;
+ } else if (Sec->Type == SHT_PROGBITS) {
+ // Make non-executable and non-writable PROGBITS sections (e.g .rodata
+ // .eh_frame) closer to .text. They likely contain PC or GOT relative
+ // relocations and there could be relocation overflow if other huge sections
+ // (.dynstr .dynsym) were placed in between.
+ Rank |= RF_RODATA;
}
// If we got here we know that both A and B are in the same PT_LOAD.
@@ -772,6 +808,12 @@ static unsigned getSectionRank(const OutputSection *Sec) {
if (IsNoBits)
Rank |= RF_BSS;
+ // We create a NOTE segment for contiguous .note sections, so make
+ // them contigous if there are more than one .note section with the
+ // same attributes.
+ if (Sec->Type == SHT_NOTE)
+ Rank |= RF_NOTE;
+
// Some architectures have additional ordering restrictions for sections
// within the same PT_LOAD.
if (Config->EMachine == EM_PPC64) {
@@ -785,18 +827,19 @@ static unsigned getSectionRank(const OutputSection *Sec) {
if (Name != ".tocbss")
Rank |= RF_PPC_NOT_TOCBSS;
- if (Name == ".opd")
- Rank |= RF_PPC_OPD;
-
if (Name == ".toc1")
Rank |= RF_PPC_TOCL;
if (Name == ".toc")
Rank |= RF_PPC_TOC;
+ if (Name == ".got")
+ Rank |= RF_PPC_GOT;
+
if (Name == ".branch_lt")
Rank |= RF_PPC_BRANCH_LT;
}
+
if (Config->EMachine == EM_MIPS) {
// All sections with SHF_MIPS_GPREL flag should be grouped together
// because data in these sections is addressable with a gp relative address.
@@ -828,8 +871,6 @@ void PhdrEntry::add(OutputSection *Sec) {
p_align = std::max(p_align, Sec->Alignment);
if (p_type == PT_LOAD)
Sec->PtLoad = this;
- if (Sec->LMAExpr)
- ASectionHasLMA = true;
}
// The beginning and the ending of .rel[a].plt section are marked
@@ -839,17 +880,19 @@ 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->Static)
+ if (Config->Relocatable || needsInterpSection())
return;
StringRef S = Config->IsRela ? "__rela_iplt_start" : "__rel_iplt_start";
addOptionalRegular(S, InX::RelaIplt, 0, STV_HIDDEN, STB_WEAK);
S = Config->IsRela ? "__rela_iplt_end" : "__rel_iplt_end";
- addOptionalRegular(S, InX::RelaIplt, -1, STV_HIDDEN, STB_WEAK);
+ ElfSym::RelaIpltEnd =
+ addOptionalRegular(S, InX::RelaIplt, 0, STV_HIDDEN, STB_WEAK);
}
template <class ELFT>
-void Writer<ELFT>::forEachRelSec(std::function<void(InputSectionBase &)> Fn) {
+void Writer<ELFT>::forEachRelSec(
+ llvm::function_ref<void(InputSectionBase &)> Fn) {
// Scan all relocations. Each relocation goes through a series
// of tests to determine if it needs special treatment, such as
// creating GOT, PLT, copy relocations, etc.
@@ -869,14 +912,18 @@ void Writer<ELFT>::forEachRelSec(std::function<void(InputSectionBase &)> Fn) {
// defining these symbols explicitly in the linker script.
template <class ELFT> void Writer<ELFT>::setReservedSymbolSections() {
if (ElfSym::GlobalOffsetTable) {
- // The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention to
- // be at some offset from the base of the .got section, usually 0 or the end
- // of the .got
- InputSection *GotSection = InX::MipsGot ? cast<InputSection>(InX::MipsGot)
- : cast<InputSection>(InX::Got);
+ // The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention usually
+ // to the start of the .got or .got.plt section.
+ InputSection *GotSection = InX::GotPlt;
+ if (!Target->GotBaseSymInGotPlt)
+ GotSection = InX::MipsGot ? cast<InputSection>(InX::MipsGot)
+ : cast<InputSection>(InX::Got);
ElfSym::GlobalOffsetTable->Section = GotSection;
}
+ if (ElfSym::RelaIpltEnd)
+ ElfSym::RelaIpltEnd->Value = InX::RelaIplt->getSize();
+
PhdrEntry *Last = nullptr;
PhdrEntry *LastRO = nullptr;
@@ -949,8 +996,7 @@ static int getRankProximityAux(OutputSection *A, OutputSection *B) {
static int getRankProximity(OutputSection *A, BaseCommand *B) {
if (auto *Sec = dyn_cast<OutputSection>(B))
- if (Sec->Live)
- return getRankProximityAux(A, Sec);
+ return getRankProximityAux(A, Sec);
return -1;
}
@@ -969,11 +1015,9 @@ static int getRankProximity(OutputSection *A, BaseCommand *B) {
// rw_sec : { *(rw_sec) }
// would mean that the RW PT_LOAD would become unaligned.
static bool shouldSkip(BaseCommand *Cmd) {
- if (isa<OutputSection>(Cmd))
- return false;
if (auto *Assign = dyn_cast<SymbolAssignment>(Cmd))
return Assign->Name != ".";
- return true;
+ return false;
}
// We want to place orphan sections so that they share as much
@@ -996,20 +1040,16 @@ findOrphanPos(std::vector<BaseCommand *>::iterator B,
int Proximity = getRankProximity(Sec, *I);
for (; I != E; ++I) {
auto *CurSec = dyn_cast<OutputSection>(*I);
- if (!CurSec || !CurSec->Live)
+ if (!CurSec)
continue;
if (getRankProximity(Sec, CurSec) != Proximity ||
Sec->SortRank < CurSec->SortRank)
break;
}
- auto IsLiveSection = [](BaseCommand *Cmd) {
- auto *OS = dyn_cast<OutputSection>(Cmd);
- return OS && OS->Live;
- };
-
+ auto IsOutputSec = [](BaseCommand *Cmd) { return isa<OutputSection>(Cmd); };
auto J = std::find_if(llvm::make_reverse_iterator(I),
- llvm::make_reverse_iterator(B), IsLiveSection);
+ llvm::make_reverse_iterator(B), IsOutputSec);
I = J.base();
// As a special case, if the orphan section is the last section, put
@@ -1017,7 +1057,7 @@ findOrphanPos(std::vector<BaseCommand *>::iterator B,
// This matches bfd's behavior and is convenient when the linker script fully
// specifies the start of the file, but doesn't care about the end (the non
// alloc sections for example).
- auto NextSec = std::find_if(I, E, IsLiveSection);
+ auto NextSec = std::find_if(I, E, IsOutputSec);
if (NextSec == E)
return E;
@@ -1026,32 +1066,172 @@ findOrphanPos(std::vector<BaseCommand *>::iterator B,
return I;
}
-// If no layout was provided by linker script, we want to apply default
-// sorting for special input sections and handle --symbol-ordering-file.
-template <class ELFT> void Writer<ELFT>::sortInputSections() {
- assert(!Script->HasSectionsCommand);
+// Builds section order for handling --symbol-ordering-file.
+static DenseMap<const InputSectionBase *, int> buildSectionOrder() {
+ DenseMap<const InputSectionBase *, int> SectionOrder;
+ // Use the rarely used option -call-graph-ordering-file to sort sections.
+ if (!Config->CallGraphProfile.empty())
+ return computeCallGraphProfileOrder();
- // Sort input sections by priority using the list provided
- // by --symbol-ordering-file.
- DenseMap<SectionBase *, int> Order = buildSectionOrder();
- if (!Order.empty())
- for (BaseCommand *Base : Script->SectionCommands)
- if (auto *Sec = dyn_cast<OutputSection>(Base))
- if (Sec->Live)
- Sec->sort([&](InputSectionBase *S) { return Order.lookup(S); });
+ if (Config->SymbolOrderingFile.empty())
+ return SectionOrder;
+
+ struct SymbolOrderEntry {
+ int Priority;
+ bool Present;
+ };
+
+ // Build a map from symbols to their priorities. Symbols that didn't
+ // appear in the symbol ordering file have the lowest priority 0.
+ // All explicitly mentioned symbols have negative (higher) priorities.
+ DenseMap<StringRef, SymbolOrderEntry> SymbolOrder;
+ int Priority = -Config->SymbolOrderingFile.size();
+ for (StringRef S : Config->SymbolOrderingFile)
+ SymbolOrder.insert({S, {Priority++, false}});
+
+ // Build a map from sections to their priorities.
+ auto AddSym = [&](Symbol &Sym) {
+ auto It = SymbolOrder.find(Sym.getName());
+ if (It == SymbolOrder.end())
+ return;
+ SymbolOrderEntry &Ent = It->second;
+ Ent.Present = true;
+
+ warnUnorderableSymbol(&Sym);
+
+ if (auto *D = dyn_cast<Defined>(&Sym)) {
+ if (auto *Sec = dyn_cast_or_null<InputSectionBase>(D->Section)) {
+ int &Priority = SectionOrder[cast<InputSectionBase>(Sec->Repl)];
+ Priority = std::min(Priority, Ent.Priority);
+ }
+ }
+ };
+ // We want both global and local symbols. We get the global ones from the
+ // symbol table and iterate the object files for the local ones.
+ for (Symbol *Sym : Symtab->getSymbols())
+ if (!Sym->isLazy())
+ AddSym(*Sym);
+ for (InputFile *File : ObjectFiles)
+ for (Symbol *Sym : File->getSymbols())
+ if (Sym->isLocal())
+ AddSym(*Sym);
+
+ if (Config->WarnSymbolOrdering)
+ for (auto OrderEntry : SymbolOrder)
+ if (!OrderEntry.second.Present)
+ warn("symbol ordering file: no such symbol: " + OrderEntry.first);
+
+ return SectionOrder;
+}
+
+// Sorts the sections in ISD according to the provided section order.
+static void
+sortISDBySectionOrder(InputSectionDescription *ISD,
+ const DenseMap<const InputSectionBase *, int> &Order) {
+ std::vector<InputSection *> UnorderedSections;
+ std::vector<std::pair<InputSection *, int>> OrderedSections;
+ uint64_t UnorderedSize = 0;
+
+ for (InputSection *IS : ISD->Sections) {
+ auto I = Order.find(IS);
+ if (I == Order.end()) {
+ UnorderedSections.push_back(IS);
+ UnorderedSize += IS->getSize();
+ continue;
+ }
+ OrderedSections.push_back({IS, I->second});
+ }
+ llvm::sort(
+ OrderedSections.begin(), OrderedSections.end(),
+ [&](std::pair<InputSection *, int> A, std::pair<InputSection *, int> B) {
+ return A.second < B.second;
+ });
+
+ // Find an insertion point for the ordered section list in the unordered
+ // section list. On targets with limited-range branches, this is the mid-point
+ // of the unordered section list. This decreases the likelihood that a range
+ // extension thunk will be needed to enter or exit the ordered region. If the
+ // ordered section list is a list of hot functions, we can generally expect
+ // the ordered functions to be called more often than the unordered functions,
+ // making it more likely that any particular call will be within range, and
+ // therefore reducing the number of thunks required.
+ //
+ // For example, imagine that you have 8MB of hot code and 32MB of cold code.
+ // If the layout is:
+ //
+ // 8MB hot
+ // 32MB cold
+ //
+ // only the first 8-16MB of the cold code (depending on which hot function it
+ // is actually calling) can call the hot code without a range extension thunk.
+ // However, if we use this layout:
+ //
+ // 16MB cold
+ // 8MB hot
+ // 16MB cold
+ //
+ // both the last 8-16MB of the first block of cold code and the first 8-16MB
+ // of the second block of cold code can call the hot code without a thunk. So
+ // we effectively double the amount of code that could potentially call into
+ // the hot code without a thunk.
+ size_t InsPt = 0;
+ if (Target->ThunkSectionSpacing && !OrderedSections.empty()) {
+ uint64_t UnorderedPos = 0;
+ for (; InsPt != UnorderedSections.size(); ++InsPt) {
+ UnorderedPos += UnorderedSections[InsPt]->getSize();
+ if (UnorderedPos > UnorderedSize / 2)
+ break;
+ }
+ }
+
+ ISD->Sections.clear();
+ for (InputSection *IS : makeArrayRef(UnorderedSections).slice(0, InsPt))
+ ISD->Sections.push_back(IS);
+ for (std::pair<InputSection *, int> P : OrderedSections)
+ ISD->Sections.push_back(P.first);
+ for (InputSection *IS : makeArrayRef(UnorderedSections).slice(InsPt))
+ ISD->Sections.push_back(IS);
+}
+
+static void sortSection(OutputSection *Sec,
+ const DenseMap<const InputSectionBase *, int> &Order) {
+ StringRef Name = Sec->Name;
// Sort input sections by section name suffixes for
// __attribute__((init_priority(N))).
- if (OutputSection *Sec = findSection(".init_array"))
- Sec->sortInitFini();
- if (OutputSection *Sec = findSection(".fini_array"))
- Sec->sortInitFini();
+ if (Name == ".init_array" || Name == ".fini_array") {
+ if (!Script->HasSectionsCommand)
+ Sec->sortInitFini();
+ return;
+ }
// Sort input sections by the special rule for .ctors and .dtors.
- if (OutputSection *Sec = findSection(".ctors"))
- Sec->sortCtorsDtors();
- if (OutputSection *Sec = findSection(".dtors"))
- Sec->sortCtorsDtors();
+ if (Name == ".ctors" || Name == ".dtors") {
+ if (!Script->HasSectionsCommand)
+ Sec->sortCtorsDtors();
+ return;
+ }
+
+ // Never sort these.
+ if (Name == ".init" || Name == ".fini")
+ return;
+
+ // Sort input sections by priority using the list provided
+ // by --symbol-ordering-file.
+ if (!Order.empty())
+ for (BaseCommand *B : Sec->SectionCommands)
+ if (auto *ISD = dyn_cast<InputSectionDescription>(B))
+ sortISDBySectionOrder(ISD, Order);
+}
+
+// If no layout was provided by linker script, we want to apply default
+// sorting for special input sections. This also handles --symbol-ordering-file.
+template <class ELFT> void Writer<ELFT>::sortInputSections() {
+ // Build the order once since it is expensive.
+ DenseMap<const InputSectionBase *, int> Order = buildSectionOrder();
+ for (BaseCommand *Base : Script->SectionCommands)
+ if (auto *Sec = dyn_cast<OutputSection>(Base))
+ sortSection(Sec, Order);
}
template <class ELFT> void Writer<ELFT>::sortSections() {
@@ -1062,22 +1242,29 @@ template <class ELFT> void Writer<ELFT>::sortSections() {
if (Config->Relocatable)
return;
- for (BaseCommand *Base : Script->SectionCommands)
- if (auto *Sec = dyn_cast<OutputSection>(Base))
- Sec->SortRank = getSectionRank(Sec);
+ sortInputSections();
- if (!Script->HasSectionsCommand) {
- sortInputSections();
+ for (BaseCommand *Base : Script->SectionCommands) {
+ auto *OS = dyn_cast<OutputSection>(Base);
+ if (!OS)
+ continue;
+ OS->SortRank = getSectionRank(OS);
+
+ // We want to assign rude approximation values to OutSecOff fields
+ // to know the relative order of the input sections. We use it for
+ // sorting SHF_LINK_ORDER sections. See resolveShfLinkOrder().
+ uint64_t I = 0;
+ for (InputSection *Sec : getInputSections(OS))
+ Sec->OutSecOff = I++;
+ }
+ if (!Script->HasSectionsCommand) {
// We know that all the OutputSections are contiguous in this case.
- auto E = Script->SectionCommands.end();
- auto I = Script->SectionCommands.begin();
auto IsSection = [](BaseCommand *Base) { return isa<OutputSection>(Base); };
- I = std::find_if(I, E, IsSection);
- E = std::find_if(llvm::make_reverse_iterator(E),
- llvm::make_reverse_iterator(I), IsSection)
- .base();
- std::stable_sort(I, E, compareSections);
+ std::stable_sort(
+ llvm::find_if(Script->SectionCommands, IsSection),
+ llvm::find_if(llvm::reverse(Script->SectionCommands), IsSection).base(),
+ compareSections);
return;
}
@@ -1108,7 +1295,7 @@ template <class ELFT> void Writer<ELFT>::sortSections() {
// The way we define an order then is:
// * Sort only the orphan sections. They are in the end right now.
// * Move each orphan section to its preferred position. We try
- // to put each section in the last position where it it can share
+ // to put each section in the last position where it can share
// a PT_LOAD.
//
// There is some ambiguity as to where exactly a new entry should be
@@ -1124,7 +1311,7 @@ template <class ELFT> void Writer<ELFT>::sortSections() {
auto E = Script->SectionCommands.end();
auto NonScriptI = std::find_if(I, E, [](BaseCommand *Base) {
if (auto *Sec = dyn_cast<OutputSection>(Base))
- return Sec->Live && Sec->SectionIndex == INT_MAX;
+ return Sec->SectionIndex == UINT32_MAX;
return false;
});
@@ -1199,8 +1386,7 @@ static bool isDuplicateArmExidxSec(InputSection *Prev, InputSection *Cur) {
};
// Get the last table Entry from the previous .ARM.exidx section.
- const ExidxEntry &PrevEntry = *reinterpret_cast<const ExidxEntry *>(
- Prev->Data.data() + Prev->getSize() - sizeof(ExidxEntry));
+ const ExidxEntry &PrevEntry = Prev->getDataAs<ExidxEntry>().back();
if (IsExtabRef(PrevEntry.Unwind))
return false;
@@ -1212,14 +1398,7 @@ static bool isDuplicateArmExidxSec(InputSection *Prev, InputSection *Cur) {
// consecutive identical entries are rare and the effort to check that they
// are identical is high.
- if (isa<SyntheticSection>(Cur))
- // Exidx sentinel section has implicit EXIDX_CANTUNWIND;
- return PrevEntry.Unwind == 0x1;
-
- ArrayRef<const ExidxEntry> Entries(
- reinterpret_cast<const ExidxEntry *>(Cur->Data.data()),
- Cur->getSize() / sizeof(ExidxEntry));
- for (const ExidxEntry &Entry : Entries)
+ for (const ExidxEntry Entry : Cur->getDataAs<ExidxEntry>())
if (IsExtabRef(Entry.Unwind) || Entry.Unwind != PrevEntry.Unwind)
return false;
// All table entries in this .ARM.exidx Section can be merged into the
@@ -1249,13 +1428,12 @@ template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() {
if (!Config->Relocatable && Config->EMachine == EM_ARM &&
Sec->Type == SHT_ARM_EXIDX) {
- if (!Sections.empty() && isa<ARMExidxSentinelSection>(Sections.back())) {
+ if (auto *Sentinel = dyn_cast<ARMExidxSentinelSection>(Sections.back())) {
assert(Sections.size() >= 2 &&
"We should create a sentinel section only if there are "
"alive regular exidx sections.");
// The last executable section is required to fill the sentinel.
// Remember it here so that we don't have to find it again.
- auto *Sentinel = cast<ARMExidxSentinelSection>(Sections.back());
Sentinel->Highest = Sections[Sections.size() - 2]->getLinkOrderDep();
}
@@ -1266,16 +1444,13 @@ template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() {
// previous one. This does not require any rewriting of InputSection
// contents but misses opportunities for fine grained deduplication
// where only a subset of the InputSection contents can be merged.
- int Cur = 1;
- int Prev = 0;
+ size_t Prev = 0;
// The last one is a sentinel entry which should not be removed.
- int N = Sections.size() - 1;
- while (Cur < N) {
- if (isDuplicateArmExidxSec(Sections[Prev], Sections[Cur]))
- Sections[Cur] = nullptr;
+ for (size_t I = 1; I < Sections.size() - 1; ++I) {
+ if (isDuplicateArmExidxSec(Sections[Prev], Sections[I]))
+ Sections[I] = nullptr;
else
- Prev = Cur;
- ++Cur;
+ Prev = I;
}
}
}
@@ -1286,14 +1461,12 @@ template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() {
// Remove the Sections we marked as duplicate earlier.
for (BaseCommand *Base : Sec->SectionCommands)
if (auto *ISD = dyn_cast<InputSectionDescription>(Base))
- ISD->Sections.erase(
- std::remove(ISD->Sections.begin(), ISD->Sections.end(), nullptr),
- ISD->Sections.end());
+ llvm::erase_if(ISD->Sections, [](InputSection *IS) { return !IS; });
}
}
static void applySynthetic(const std::vector<SyntheticSection *> &Sections,
- std::function<void(SyntheticSection *)> Fn) {
+ llvm::function_ref<void(SyntheticSection *)> Fn) {
for (SyntheticSection *SS : Sections)
if (SS && SS->getParent() && !SS->empty())
Fn(SS);
@@ -1320,27 +1493,15 @@ static void removeUnusedSyntheticSections() {
if (!SS)
return;
OutputSection *OS = SS->getParent();
- if (!SS->empty() || !OS)
+ if (!OS || !SS->empty())
continue;
- std::vector<BaseCommand *>::iterator Empty = OS->SectionCommands.end();
- for (auto I = OS->SectionCommands.begin(), E = OS->SectionCommands.end();
- I != E; ++I) {
- BaseCommand *B = *I;
- if (auto *ISD = dyn_cast<InputSectionDescription>(B)) {
+ // If we reach here, then SS is an unused synthetic section and we want to
+ // remove it from corresponding input section description of output section.
+ for (BaseCommand *B : OS->SectionCommands)
+ if (auto *ISD = dyn_cast<InputSectionDescription>(B))
llvm::erase_if(ISD->Sections,
[=](InputSection *IS) { return IS == SS; });
- if (ISD->Sections.empty())
- Empty = I;
- }
- }
- if (Empty != OS->SectionCommands.end())
- OS->SectionCommands.erase(Empty);
-
- // If there are no other sections in the output section, remove it from the
- // output.
- if (OS->SectionCommands.empty())
- OS->Live = false;
}
}
@@ -1432,9 +1593,9 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
if (InX::DynSymTab && Sym->includeInDynsym()) {
InX::DynSymTab->addSymbol(Sym);
- if (auto *SS = dyn_cast<SharedSymbol>(Sym))
- if (cast<SharedFile<ELFT>>(Sym->File)->IsNeeded)
- In<ELFT>::VerNeed->addSymbol(SS);
+ if (auto *File = dyn_cast_or_null<SharedFile<ELFT>>(Sym->File))
+ if (File->IsNeeded && !Sym->isUndefined())
+ In<ELFT>::VerNeed->addSymbol(Sym);
}
}
@@ -1442,10 +1603,12 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
if (errorCount())
return;
+ if (InX::MipsGot)
+ InX::MipsGot->build<ELFT>();
+
removeUnusedSyntheticSections();
sortSections();
- Script->removeEmptyCommands();
// Now that we have the final list, create a list of all the
// OutputSections for convenience.
@@ -1453,6 +1616,15 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
if (auto *Sec = dyn_cast<OutputSection>(Base))
OutputSections.push_back(Sec);
+ // Ensure data sections are not mixed with executable sections when
+ // -execute-only is used.
+ if (Config->ExecuteOnly)
+ for (OutputSection *OS : OutputSections)
+ if (OS->Flags & SHF_EXECINSTR)
+ for (InputSection *IS : getInputSections(OS))
+ if (!(IS->Flags & SHF_EXECINSTR))
+ error("-execute-only does not support intermingling data and code");
+
// Prefer command line supplied address over other constraints.
for (OutputSection *Sec : OutputSections) {
auto I = Config->SectionStartMap.find(Sec->Name);
@@ -1461,7 +1633,7 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
}
// This is a bit of a hack. A value of 0 means undef, so we set it
- // to 1 t make __ehdr_start defined. The section number is not
+ // to 1 to make __ehdr_start defined. The section number is not
// particularly relevant.
Out::ElfHeader->SectionIndex = 1;
@@ -1487,12 +1659,13 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// Dynamic section must be the last one in this list and dynamic
// symbol table section (DynSymTab) must be the first one.
applySynthetic(
- {InX::DynSymTab, InX::Bss, InX::BssRelRo, InX::GnuHashTab,
- InX::HashTab, InX::SymTab, InX::ShStrTab, InX::StrTab,
- In<ELFT>::VerDef, InX::DynStrTab, InX::Got, InX::MipsGot,
- InX::IgotPlt, InX::GotPlt, InX::RelaDyn, InX::RelaIplt,
- InX::RelaPlt, InX::Plt, InX::Iplt, InX::EhFrameHdr,
- In<ELFT>::VerSym, In<ELFT>::VerNeed, InX::Dynamic},
+ {InX::DynSymTab, InX::Bss, InX::BssRelRo, InX::GnuHashTab,
+ InX::HashTab, InX::SymTab, InX::SymTabShndx, InX::ShStrTab,
+ InX::StrTab, In<ELFT>::VerDef, InX::DynStrTab, InX::Got,
+ InX::MipsGot, InX::IgotPlt, InX::GotPlt, InX::RelaDyn,
+ InX::RelrDyn, InX::RelaIplt, InX::RelaPlt, InX::Plt,
+ InX::Iplt, InX::EhFrameHdr, In<ELFT>::VerSym, In<ELFT>::VerNeed,
+ InX::Dynamic},
[](SyntheticSection *SS) { SS->finalizeContents(); });
if (!Script->HasSectionsCommand && !Config->Relocatable)
@@ -1504,10 +1677,11 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// Some architectures need to generate content that depends on the address
// of InputSections. For example some architectures use small displacements
- // for jump instructions that is is the linker's responsibility for creating
+ // for jump instructions that is the linker's responsibility for creating
// range extension thunks for. As the generation of the content may also
// alter InputSection addresses we must converge to a fixed point.
- if (Target->NeedsThunks || Config->AndroidPackDynRelocs) {
+ if (Target->NeedsThunks || Config->AndroidPackDynRelocs ||
+ Config->RelrPackDynRelocs) {
ThunkCreator TC;
AArch64Err843419Patcher A64P;
bool Changed;
@@ -1524,34 +1698,48 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
if (InX::MipsGot)
InX::MipsGot->updateAllocSize();
Changed |= InX::RelaDyn->updateAllocSize();
+ if (InX::RelrDyn)
+ Changed |= InX::RelrDyn->updateAllocSize();
} while (Changed);
}
+ // createThunks may have added local symbols to the static symbol table
+ applySynthetic({InX::SymTab},
+ [](SyntheticSection *SS) { SS->postThunkContents(); });
+
// Fill other section headers. The dynamic table is finalized
// at the end because some tags like RELSZ depend on result
// of finalizing other sections.
for (OutputSection *Sec : OutputSections)
Sec->finalize<ELFT>();
-
- // createThunks may have added local symbols to the static symbol table
- applySynthetic({InX::SymTab},
- [](SyntheticSection *SS) { SS->postThunkContents(); });
}
// The linker is expected to define SECNAME_start and SECNAME_end
// symbols for a few sections. This function defines them.
template <class ELFT> void Writer<ELFT>::addStartEndSymbols() {
- auto Define = [&](StringRef Start, StringRef End, OutputSection *OS) {
- // These symbols resolve to the image base if the section does not exist.
- // A special value -1 indicates end of the section.
+ // If a section does not exist, there's ambiguity as to how we
+ // define _start and _end symbols for an init/fini section. Since
+ // the loader assume that the symbols are always defined, we need to
+ // always define them. But what value? The loader iterates over all
+ // pointers between _start and _end to run global ctors/dtors, so if
+ // the section is empty, their symbol values don't actually matter
+ // as long as _start and _end point to the same location.
+ //
+ // That said, we don't want to set the symbols to 0 (which is
+ // probably the simplest value) because that could cause some
+ // program to fail to link due to relocation overflow, if their
+ // program text is above 2 GiB. We use the address of the .text
+ // section instead to prevent that failure.
+ OutputSection *Default = findSection(".text");
+ if (!Default)
+ Default = Out::ElfHeader;
+ auto Define = [=](StringRef Start, StringRef End, OutputSection *OS) {
if (OS) {
addOptionalRegular(Start, OS, 0);
addOptionalRegular(End, OS, -1);
} else {
- if (Config->Pic)
- OS = Out::ElfHeader;
- addOptionalRegular(Start, OS, 0);
- addOptionalRegular(End, OS, 0);
+ addOptionalRegular(Start, Default, 0);
+ addOptionalRegular(End, Default, 0);
}
};
@@ -1573,12 +1761,12 @@ void Writer<ELFT>::addStartStopSymbols(OutputSection *Sec) {
StringRef S = Sec->Name;
if (!isValidCIdentifier(S))
return;
- addOptionalRegular(Saver.save("__start_" + S), Sec, 0, STV_DEFAULT);
- addOptionalRegular(Saver.save("__stop_" + S), Sec, -1, STV_DEFAULT);
+ addOptionalRegular(Saver.save("__start_" + S), Sec, 0, STV_PROTECTED);
+ addOptionalRegular(Saver.save("__stop_" + S), Sec, -1, STV_PROTECTED);
}
static bool needsPtLoad(OutputSection *Sec) {
- if (!(Sec->Flags & SHF_ALLOC))
+ if (!(Sec->Flags & SHF_ALLOC) || Sec->Noload)
return false;
// Don't allocate VA space for TLS NOBITS sections. The PT_TLS PHDR is
@@ -1596,6 +1784,8 @@ static bool needsPtLoad(OutputSection *Sec) {
static uint64_t computeFlags(uint64_t Flags) {
if (Config->Omagic)
return PF_R | PF_W | PF_X;
+ if (Config->ExecuteOnly && (Flags & PF_X))
+ return Flags & ~PF_R;
if (Config->SingleRoRx && !(Flags & PF_W))
return Flags | PF_X;
return Flags;
@@ -1634,10 +1824,14 @@ template <class ELFT> std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs() {
// Segments are contiguous memory regions that has the same attributes
// (e.g. executable or writable). There is one phdr for each segment.
// Therefore, we need to create a new phdr when the next section has
- // different flags or is loaded at a discontiguous address using AT linker
- // script command.
+ // different flags or is loaded at a discontiguous address or memory
+ // region using AT or AT> linker script command, respectively. At the same
+ // time, we don't want to create a separate load segment for the headers,
+ // even if the first output section has an AT or AT> attribute.
uint64_t NewFlags = computeFlags(Sec->getPhdrFlags());
- if ((Sec->LMAExpr && Load->ASectionHasLMA) ||
+ if (((Sec->LMAExpr ||
+ (Sec->LMARegion && (Sec->LMARegion != Load->FirstSec->LMARegion))) &&
+ Load->LastSec != Out::ProgramHeaders) ||
Sec->MemRegion != Load->FirstSec->MemRegion || Flags != NewFlags) {
Load = AddHdr(PT_LOAD, NewFlags);
@@ -1700,11 +1894,9 @@ template <class ELFT> std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs() {
// pages for the stack non-executable. If you really want an executable
// stack, you can pass -z execstack, but that's not recommended for
// security reasons.
- unsigned Perm;
+ unsigned Perm = PF_R | PF_W;
if (Config->ZExecstack)
- Perm = PF_R | PF_W | PF_X;
- else
- Perm = PF_R | PF_W;
+ Perm |= PF_X;
AddHdr(PT_GNU_STACK, Perm)->p_memsz = Config->ZStackSize;
// PT_OPENBSD_WXNEEDED is a OpenBSD-specific header to mark the executable
@@ -1717,7 +1909,7 @@ template <class ELFT> std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs() {
// Create one PT_NOTE per a group of contiguous .note sections.
PhdrEntry *Note = nullptr;
for (OutputSection *Sec : OutputSections) {
- if (Sec->Type == SHT_NOTE) {
+ if (Sec->Type == SHT_NOTE && (Sec->Flags & SHF_ALLOC)) {
if (!Note || Sec->LMAExpr)
Note = AddHdr(PT_NOTE, PF_R);
Note->add(Sec);
@@ -1822,6 +2014,12 @@ template <class ELFT> void Writer<ELFT>::assignFileOffsetsBinary() {
FileSize = alignTo(Off, Config->Wordsize);
}
+static std::string rangeToString(uint64_t Addr, uint64_t Len) {
+ if (Len == 0)
+ return "<empty range at 0x" + utohexstr(Addr) + ">";
+ return "[0x" + utohexstr(Addr) + ", 0x" + utohexstr(Addr + Len - 1) + "]";
+}
+
// Assign file offsets to output sections.
template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
uint64_t Off = 0;
@@ -1846,6 +2044,24 @@ template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
SectionHeaderOff = alignTo(Off, Config->Wordsize);
FileSize = SectionHeaderOff + (OutputSections.size() + 1) * sizeof(Elf_Shdr);
+
+ // Our logic assumes that sections have rising VA within the same segment.
+ // With use of linker scripts it is possible to violate this rule and get file
+ // offset overlaps or overflows. That should never happen with a valid script
+ // which does not move the location counter backwards and usually scripts do
+ // not do that. Unfortunately, there are apps in the wild, for example, Linux
+ // kernel, which control segment distribution explicitly and move the counter
+ // backwards, so we have to allow doing that to support linking them. We
+ // perform non-critical checks for overlaps in checkSectionOverlap(), but here
+ // we want to prevent file size overflows because it would crash the linker.
+ for (OutputSection *Sec : OutputSections) {
+ if (Sec->Type == SHT_NOBITS)
+ continue;
+ if ((Sec->Offset > FileSize) || (Sec->Offset + Sec->Size > FileSize))
+ error("unable to place section " + Sec->Name + " at file offset " +
+ rangeToString(Sec->Offset, Sec->Offset + Sec->Size) +
+ "; check your linker script for overflows");
+ }
}
// Finalize the program headers. We call this function after we assign
@@ -1884,6 +2100,97 @@ template <class ELFT> void Writer<ELFT>::setPhdrs() {
}
}
+// A helper struct for checkSectionOverlap.
+namespace {
+struct SectionOffset {
+ OutputSection *Sec;
+ uint64_t Offset;
+};
+} // namespace
+
+// Check whether sections overlap for a specific address range (file offsets,
+// load and virtual adresses).
+static void checkOverlap(StringRef Name, std::vector<SectionOffset> &Sections,
+ bool IsVirtualAddr) {
+ llvm::sort(Sections.begin(), Sections.end(),
+ [=](const SectionOffset &A, const SectionOffset &B) {
+ return A.Offset < B.Offset;
+ });
+
+ // Finding overlap is easy given a vector is sorted by start position.
+ // If an element starts before the end of the previous element, they overlap.
+ for (size_t I = 1, End = Sections.size(); I < End; ++I) {
+ SectionOffset A = Sections[I - 1];
+ SectionOffset B = Sections[I];
+ if (B.Offset >= A.Offset + A.Sec->Size)
+ continue;
+
+ // If both sections are in OVERLAY we allow the overlapping of virtual
+ // addresses, because it is what OVERLAY was designed for.
+ if (IsVirtualAddr && A.Sec->InOverlay && B.Sec->InOverlay)
+ continue;
+
+ errorOrWarn("section " + A.Sec->Name + " " + Name +
+ " range overlaps with " + B.Sec->Name + "\n>>> " + A.Sec->Name +
+ " range is " + rangeToString(A.Offset, A.Sec->Size) + "\n>>> " +
+ B.Sec->Name + " range is " +
+ rangeToString(B.Offset, B.Sec->Size));
+ }
+}
+
+// Check for overlapping sections and address overflows.
+//
+// In this function we check that none of the output sections have overlapping
+// file offsets. For SHF_ALLOC sections we also check that the load address
+// ranges and the virtual address ranges don't overlap
+template <class ELFT> void Writer<ELFT>::checkSections() {
+ // First, check that section's VAs fit in available address space for target.
+ for (OutputSection *OS : OutputSections)
+ if ((OS->Addr + OS->Size < OS->Addr) ||
+ (!ELFT::Is64Bits && OS->Addr + OS->Size > UINT32_MAX))
+ errorOrWarn("section " + OS->Name + " at 0x" + utohexstr(OS->Addr) +
+ " of size 0x" + utohexstr(OS->Size) +
+ " exceeds available address space");
+
+ // Check for overlapping file offsets. In this case we need to skip any
+ // section marked as SHT_NOBITS. These sections don't actually occupy space in
+ // the file so Sec->Offset + Sec->Size can overlap with others. If --oformat
+ // binary is specified only add SHF_ALLOC sections are added to the output
+ // file so we skip any non-allocated sections in that case.
+ std::vector<SectionOffset> FileOffs;
+ for (OutputSection *Sec : OutputSections)
+ if (0 < Sec->Size && Sec->Type != SHT_NOBITS &&
+ (!Config->OFormatBinary || (Sec->Flags & SHF_ALLOC)))
+ FileOffs.push_back({Sec, Sec->Offset});
+ checkOverlap("file", FileOffs, false);
+
+ // When linking with -r there is no need to check for overlapping virtual/load
+ // addresses since those addresses will only be assigned when the final
+ // executable/shared object is created.
+ if (Config->Relocatable)
+ return;
+
+ // Checking for overlapping virtual and load addresses only needs to take
+ // into account SHF_ALLOC sections since others will not be loaded.
+ // Furthermore, we also need to skip SHF_TLS sections since these will be
+ // mapped to other addresses at runtime and can therefore have overlapping
+ // ranges in the file.
+ std::vector<SectionOffset> VMAs;
+ for (OutputSection *Sec : OutputSections)
+ if (0 < Sec->Size && (Sec->Flags & SHF_ALLOC) && !(Sec->Flags & SHF_TLS))
+ VMAs.push_back({Sec, Sec->Addr});
+ checkOverlap("virtual address", VMAs, true);
+
+ // Finally, check that the load addresses don't overlap. This will usually be
+ // the same as the virtual addresses but can be different when using a linker
+ // script with AT().
+ std::vector<SectionOffset> LMAs;
+ for (OutputSection *Sec : OutputSections)
+ if (0 < Sec->Size && (Sec->Flags & SHF_ALLOC) && !(Sec->Flags & SHF_TLS))
+ LMAs.push_back({Sec, Sec->getLMA()});
+ checkOverlap("load address", LMAs, false);
+}
+
// The entry point address is chosen in the following ways.
//
// 1. the '-e' entry command-line option;
@@ -1925,8 +2232,20 @@ static uint16_t getELFType() {
return ET_EXEC;
}
+static uint8_t getAbiVersion() {
+ // MIPS non-PIC executable gets ABI version 1.
+ if (Config->EMachine == EM_MIPS && getELFType() == ET_EXEC &&
+ (Config->EFlags & (EF_MIPS_PIC | EF_MIPS_CPIC)) == EF_MIPS_CPIC)
+ return 1;
+ return 0;
+}
+
template <class ELFT> void Writer<ELFT>::writeHeader() {
uint8_t *Buf = Buffer->getBufferStart();
+ // For executable segments, the trap instructions are written before writing
+ // the header. Setting Elf header bytes to zero ensures that any unused bytes
+ // in header are zero-cleared, instead of having trap instructions.
+ memset(Buf, 0, sizeof(Elf_Ehdr));
memcpy(Buf, "\177ELF", 4);
// Write the ELF header.
@@ -1935,6 +2254,7 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
EHdr->e_ident[EI_DATA] = Config->IsLE ? ELFDATA2LSB : ELFDATA2MSB;
EHdr->e_ident[EI_VERSION] = EV_CURRENT;
EHdr->e_ident[EI_OSABI] = Config->OSABI;
+ EHdr->e_ident[EI_ABIVERSION] = getAbiVersion();
EHdr->e_type = getELFType();
EHdr->e_machine = Config->EMachine;
EHdr->e_version = EV_CURRENT;
@@ -1944,8 +2264,6 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
EHdr->e_ehsize = sizeof(Elf_Ehdr);
EHdr->e_phnum = Phdrs.size();
EHdr->e_shentsize = sizeof(Elf_Shdr);
- EHdr->e_shnum = OutputSections.size() + 1;
- EHdr->e_shstrndx = InX::ShStrTab->getParent()->SectionIndex;
if (!Config->Relocatable) {
EHdr->e_phoff = sizeof(Elf_Ehdr);
@@ -1966,8 +2284,30 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
++HBuf;
}
- // Write the section header table. Note that the first table entry is null.
+ // Write the section header table.
+ //
+ // The ELF header can only store numbers up to SHN_LORESERVE in the e_shnum
+ // and e_shstrndx fields. When the value of one of these fields exceeds
+ // SHN_LORESERVE ELF requires us to put sentinel values in the ELF header and
+ // use fields in the section header at index 0 to store
+ // the value. The sentinel values and fields are:
+ // e_shnum = 0, SHdrs[0].sh_size = number of sections.
+ // e_shstrndx = SHN_XINDEX, SHdrs[0].sh_link = .shstrtab section index.
auto *SHdrs = reinterpret_cast<Elf_Shdr *>(Buf + EHdr->e_shoff);
+ size_t Num = OutputSections.size() + 1;
+ if (Num >= SHN_LORESERVE)
+ SHdrs->sh_size = Num;
+ else
+ EHdr->e_shnum = Num;
+
+ uint32_t StrTabIndex = InX::ShStrTab->getParent()->SectionIndex;
+ if (StrTabIndex >= SHN_LORESERVE) {
+ SHdrs->sh_link = StrTabIndex;
+ EHdr->e_shstrndx = SHN_XINDEX;
+ } else {
+ EHdr->e_shstrndx = StrTabIndex;
+ }
+
for (OutputSection *Sec : OutputSections)
Sec->writeHeaderTo<ELFT>(++SHdrs);
}
@@ -2038,14 +2378,6 @@ template <class ELFT> void Writer<ELFT>::writeTrapInstr() {
template <class ELFT> void Writer<ELFT>::writeSections() {
uint8_t *Buf = Buffer->getBufferStart();
- // PPC64 needs to process relocations in the .opd section
- // before processing relocations in code-containing sections.
- if (auto *OpdCmd = findSection(".opd")) {
- Out::Opd = OpdCmd;
- Out::OpdBuf = Buf + Out::Opd->Offset;
- OpdCmd->template writeTo<ELFT>(Buf + Out::Opd->Offset);
- }
-
OutputSection *EhFrameHdr = nullptr;
if (InX::EhFrameHdr && !InX::EhFrameHdr->empty())
EhFrameHdr = InX::EhFrameHdr->getParent();
@@ -2058,8 +2390,7 @@ template <class ELFT> void Writer<ELFT>::writeSections() {
Sec->writeTo<ELFT>(Buf + Sec->Offset);
for (OutputSection *Sec : OutputSections)
- if (Sec != Out::Opd && Sec != EhFrameHdr && Sec->Type != SHT_REL &&
- Sec->Type != SHT_RELA)
+ if (Sec != EhFrameHdr && Sec->Type != SHT_REL && Sec->Type != SHT_RELA)
Sec->writeTo<ELFT>(Buf + Sec->Offset);
// The .eh_frame_hdr depends on .eh_frame section contents, therefore
diff --git a/gnu/llvm/tools/lld/docs/ld.lld.1 b/gnu/llvm/tools/lld/docs/ld.lld.1
index 64e3e2dc624..98fc3a34bd1 100644
--- a/gnu/llvm/tools/lld/docs/ld.lld.1
+++ b/gnu/llvm/tools/lld/docs/ld.lld.1
@@ -3,7 +3,7 @@
.\"
.\" This man page documents only lld's ELF linking support, obtained originally
.\" from FreeBSD.
-.Dd February 9, 2018
+.Dd September 14, 2018
.Dt LD.LLD 1
.Os
.Sh NAME
@@ -30,22 +30,24 @@ These options are available:
.It Fl -allow-multiple-definition
Do not error if a symbol is defined multiple times.
The first definition will be used.
+.It Fl -apply-dynamic-relocs
+Apply link-time values for dynamic relocations.
.It Fl -as-needed
Only set
.Dv DT_NEEDED
for shared libraries if used.
-.It Fl -auxiliary Ar value
+.It Fl -auxiliary Ns = Ns Ar value
Set the
.Dv DT_AUXILIARY
field to the specified name.
-.It Fl -Bdynamic
+.It Fl -Bdynamic , Fl -dy
Link against shared libraries.
-.It Fl -Bstatic
+.It Fl -Bstatic , Fl -static , Fl -dn
Do not link against shared libraries.
-.It Fl -Bsymbolic-functions
-Bind defined function symbols locally.
.It Fl -Bsymbolic
Bind defined symbols locally.
+.It Fl -Bsymbolic-functions
+Bind defined function symbols locally.
.It Fl -build-id Ns = Ns Ar value
Generate a build ID note.
.Ar value
@@ -93,7 +95,9 @@ may be
.Cm none
or
.Cm zlib .
-.It Fl -define-common
+.It Fl -cref
+Output cross reference table.
+.It Fl -define-common , Fl d
Assign space to common symbols.
.It Fl -defsym Ns = Ns Ar symbol Ns = Ns Ar expression
Define a symbol alias.
@@ -107,13 +111,13 @@ or
Demangle symbol names.
.It Fl -disable-new-dtags
Disable new dynamic tags.
-.It Fl -discard-all
+.It Fl -discard-all , Fl x
Delete all local symbols.
-.It Fl -discard-locals
+.It Fl -discard-locals , Fl X
Delete temporary local symbols.
.It Fl -discard-none
Keep all symbols in the symbol table.
-.It Fl -dynamic-linker Ar value
+.It Fl -dynamic-linker Ns = Ns Ar value
Specify the dynamic linker to be used for a dynamically linked executable.
This is recorded in an ELF segment of type
.Dv PT_INTERP .
@@ -126,7 +130,7 @@ Request creation of
section and
.Dv PT_GNU_EH_FRAME
segment header.
-.It Fl -emit-relocs
+.It Fl -emit-relocs , Fl q
Generate relocations in the output.
.It Fl -enable-new-dtags
Enable new dynamic tags.
@@ -142,21 +146,21 @@ A value of zero indicates that there is no limit.
Report unresolved symbols as errors.
.It Fl -exclude-libs Ns = Ns Ar value
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
-Put symbols in the dynamic symbol table.
.It Fl -fatal-warnings
Treat warnings as errors.
-.It Fl -filter Ns = Ns Ar value
+.It Fl -filter Ns = Ns Ar value , Fl F Ar value
Set the
.Dv DT_FILTER
field to the specified value.
.It Fl -fini Ns = Ns Ar symbol
Specify a finalizer function.
-.It Fl -format Ns = Ns Ar input-format
+.It Fl -format Ns = Ns Ar input-format , Fl b Ar input-format
Specify the format of the inputs following this option.
.Ar input-format
may be one of
@@ -187,6 +191,8 @@ is the default.
Print a help message.
.It Fl -icf Ns = Ns Cm all
Enable identical code folding.
+.It Fl -icf Ns = Ns Cm safe
+Enable safe identical code folding.
.It Fl -icf Ns = Ns Cm none
Disable identical code folding.
.It Fl -image-base Ns = Ns Ar value
@@ -194,25 +200,29 @@ Set the base address to
.Ar value .
.It Fl -init Ns = Ns Ar symbol
Specify an initializer function.
+.It Fl -keep-unique Ns = Ns Ar symbol
+Do not fold
+.Ar symbol
+during ICF.
+.It Fl l Ar libName, Fl -library Ns = Ns Ar libName
+Root name of library to use.
+.It Fl L Ar dir , Fl -library-path Ns = Ns Ar dir
+Add a directory to the library search path.
.It Fl -lto-aa-pipeline Ns = Ns Ar value
AA pipeline to run during LTO.
Used in conjunction with
.Fl -lto-newpm-passes .
.It Fl -lto-newpm-passes Ns = Ns Ar value
Passes to run during LTO.
-.It Fl -lto-O Ar opt-level
+.It Fl -lto-O Ns Ar opt-level
Optimization level for LTO.
.It Fl -lto-partitions Ns = Ns Ar value
Number of LTO codegen partitions.
-.It Fl L Ar dir
-Add a directory to the library search path.
-.It Fl l Ar libName
-Root name of library to use.
-.It Fl -Map Ns = Ns Ar file
-Print a link map to
-.Ar file .
.It Fl m Ar value
Set target emulation.
+.It Fl -Map Ns = Ns Ar file , Fl M Ar file
+Print a link map to
+.Ar file .
.It Fl -no-as-needed
Always set
.Dv DT_NEEDED
@@ -241,26 +251,18 @@ Report version scripts that refer undefined symbols.
Report unresolved symbols even if the linker is creating a shared library.
.It Fl -no-whole-archive
Restores the default behavior of loading archive members.
-.It Fl -noinhibit-exec
-Retain the executable output file whenever it is still usable.
.It Fl -no-pie
Do not create a position independent executable.
+.It Fl -noinhibit-exec
+Retain the executable output file whenever it is still usable.
.It Fl -nostdlib
Only search directories specified on the command line.
-.It Fl -oformat Ar format
-Specify the format for the output object file.
-The only supported
-.Ar format
-is
-.Cm binary ,
-which produces output with no ELF header.
-.It Fl -omagic
-Set the text and data sections to be readable and writable.
-.It Fl -opt-remarks-filename Ar file
-Write optimization remarks in YAML format to
-.Ar file .
-.It Fl -opt-remarks-with-hotness
-Include hotness information in the optimization remarks file.
+.It Fl o Ar path
+Write the output executable, library, or object to
+.Ar path .
+If not specified,
+.Dv a.out
+is used as a default.
.It Fl O Ns Ar value
Optimize output file size.
.Ar value
@@ -277,25 +279,42 @@ Enable string tail merging.
.Pp
.Fl O Ns Cm 1
is the default.
-.It Fl o Ar path
-Write the output executable, library, or object to
-.Ar path .
-If not specified,
-.Dv a.out
-is used as a default.
+.It Fl -oformat Ns = Ns Ar format
+Specify the format for the output object file.
+The only supported
+.Ar format
+is
+.Cm binary ,
+which produces output with no ELF header.
+.It Fl -omagic , Fl N
+Set the text and data sections to be readable and writable.
+.It Fl -opt-remarks-filename Ar file
+Write optimization remarks in YAML format to
+.Ar file .
+.It Fl -opt-remarks-with-hotness
+Include hotness information in the optimization remarks file.
.It Fl -pie
Create a position independent executable.
.It Fl -print-gc-sections
List removed unused sections.
.It Fl -print-map
Print a link map to the standard output.
-.It Fl -relocatable
+.It Fl -push-state
+Save the current state of
+.Fl -as-needed ,
+.Fl -static ,
+and
+.Fl -while-archive.
+.It Fl -pop-state
+Undo the effect of
+.Fl -push-state.
+.It Fl -relocatable , Fl r
Create relocatable object file.
.It Fl -reproduce Ns = Ns Ar value
Dump linker invocation and input files for debugging.
.It Fl -retain-symbols-file Ns = Ns Ar file
Retain only the symbols listed in the file.
-.It Fl -rpath Ns = Ns Ar value
+.It Fl -rpath Ns = Ns Ar value , Fl R Ar value
Add a
.Dv DT_RUNPATH
to the output.
@@ -305,14 +324,14 @@ The supported values are
.Cm windows
and
.Cm posix .
-.It Fl -script Ns = Ns Ar file
+.It Fl -script Ns = Ns Ar file , Fl T Ar file
Read linker script from
.Ar file .
-.It Fl -section-start Ar section Ns = Ns Ar address
+.It Fl -section-start Ns = Ns Ar section Ns = Ns Ar address
Set address of section.
-.It Fl -shared
+.It Fl -shared , Fl -Bsharable
Build a shared object.
-.It Fl -soname Ns = Ns Ar value
+.It Fl -soname Ns = Ns Ar value , Fl h Ar value
Set
.Dv DT_SONAME
to
@@ -322,11 +341,11 @@ Specifies sections sorting rule when linkerscript is used.
.It Fl -start-lib
Start a grouping of objects that should be treated as if they were together
in an archive.
-.It Fl -strip-all
+.It Fl -strip-all , Fl s
Strip all symbols.
-.It Fl -strip-debug
+.It Fl -strip-debug , Fl S
Strip debugging information.
-.It Fl -symbol-ordering-file Ar file
+.It Fl -symbol-ordering-file Ns = Ns Ar file
Lay out sections in the order specified by
.Ar file .
.It Fl -sysroot Ns = Ns Ar value
@@ -365,42 +384,46 @@ Same as
with
.Li .data
as the sectionname.
+.It Fl -Ttext Ns = Ns Ar value
+Same as
+.Fl -section-start
+with
+.Li .text
+as the sectionname.
.It Fl -thinlto-cache-dir Ns = Ns Ar value
Path to ThinLTO cached object file directory.
-.It Fl -thinlto-cache-policy Ar value
+.It Fl -thinlto-cache-policy Ns = Ns Ar value
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 -trace-symbol Ns = Ns Ar symbol
-Trace references to
-.Ar symbol .
.It Fl -trace
Print the names of the input files.
-.It Fl -Ttext Ns = Ns Ar value
-Same as
-.Fl -section-start
-with
-.Li .text
-as the sectionname.
-.It Fl -undefined Ns = Ns Ar symbol
+.It Fl -trace-symbol Ns = Ns Ar symbol , Fl y Ar symbol
+Trace references to
+.Ar symbol .
+.It Fl -undefined Ns = Ns Ar symbol , Fl u Ar symbol
Force
.Ar symbol
to be an undefined symbol during linking.
.It Fl -unresolved-symbols Ns = Ns Ar value
Determine how to handle unresolved symbols.
+.It Fl v
+Display the version number and proceed with linking if object files are
+specified.
+.It Fl V , Fl -version
+Display the version number and exit.
.It Fl -verbose
Verbose mode.
.It Fl -version-script Ns = Ns Ar file
Read version script from
.Ar file .
-.It Fl V , Fl -version
-Display the version number and exit.
-.It Fl v
-Display the version number and proceed with linking if object files are
-specified.
+.It Fl -warn-backrefs
+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-common
Warn about duplicate common symbols.
.It Fl -warn-unresolved-symbols
@@ -417,6 +440,16 @@ Make the main stack executable.
Stack permissions are recorded in the
.Dv PT_GNU_STACK
segment.
+.It Cm initfirst
+Sets the
+.Dv DF_1_INITFIRST
+flag to indicate the module should be initialized first.
+.It Cm interpose
+Set the
+.Dv DF_1_INTERPOSE
+flag to indicate to the runtime linker that the object is an interposer.
+During symbol resolution interposers are searched after the application
+but before other dependencies.
.It Cm muldefs
Do not error if a symbol is defined multiple times.
The first definition will be used.
@@ -525,3 +558,8 @@ may produce different results compared to traditional linkers.
In practice, large bodies of third party software have been linked with
.Nm
without material issues.
+.Pp
+The
+.Fl -warn-backrefs
+option may be used to identify a linker invocation that may be incompatible
+with traditional Unix-like linker behavior.
diff --git a/gnu/llvm/tools/lld/tools/lld/lld.cpp b/gnu/llvm/tools/lld/tools/lld/lld.cpp
index 01aae99e757..e84a94cc3f5 100644
--- a/gnu/llvm/tools/lld/tools/lld/lld.cpp
+++ b/gnu/llvm/tools/lld/tools/lld/lld.cpp
@@ -7,12 +7,22 @@
//
//===----------------------------------------------------------------------===//
//
-// This is the entry point to the lld driver. This is a thin wrapper which
-// dispatches to the given platform specific driver.
+// This file contains the main function of the lld executable. The main
+// function is a thin wrapper which dispatches to the platform specific
+// driver.
//
-// If there is -flavor option, it is dispatched according to the arguments.
-// If the flavor parameter is not present, then it is dispatched according
-// to argv[0].
+// lld is a single executable that contains four different linkers for ELF,
+// COFF, WebAssembly and Mach-O. The main function dispatches according to
+// argv[0] (i.e. command name). The most common name for each target is shown
+// below:
+//
+// - ld.lld: ELF (Unix)
+// - ld64: Mach-O (macOS)
+// - lld-link: COFF (Windows)
+// - ld-wasm: WebAssembly
+//
+// lld can be invoked as "lld" along with "-flavor" option. This is for
+// backward compatibility and not recommended.
//
//===----------------------------------------------------------------------===//
@@ -20,10 +30,9 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Twine.h"
-#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/Path.h"
-#include "llvm/Support/PrettyStackTrace.h"
-#include "llvm/Support/Signals.h"
+#include <cstdlib>
using namespace lld;
using namespace llvm;
@@ -104,13 +113,18 @@ static Flavor parseFlavor(std::vector<const char *> &V) {
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) {
- // Standard set up, so program fails gracefully.
- sys::PrintStackTraceOnErrorSignal(Argv[0]);
- PrettyStackTraceProgram StackPrinter(Argc, Argv);
- llvm_shutdown_obj Shutdown;
+ InitLLVM X(Argc, Argv);
std::vector<const char *> Args(Argv, Argv + Argc);
switch (parseFlavor(Args)) {
@@ -119,17 +133,18 @@ int main(int Argc, const char **Argv) {
if (isPETarget(Args))
return !mingw::link(Args);
#endif
- return !elf::link(Args, true);
+ return !elf::link(Args, canExitEarly());
#ifndef __OpenBSD__
case WinLink:
- return !coff::link(Args, true);
+ return !coff::link(Args, canExitEarly());
case Darwin:
- return !mach_o::link(Args);
+ return !mach_o::link(Args, canExitEarly());
case Wasm:
- return !wasm::link(Args, true);
+ return !wasm::link(Args, canExitEarly());
#endif
default:
die("lld is a generic driver.\n"
- "Invoke ld.lld (Unix), ld (macOS) or lld-link (Windows) instead.");
+ "Invoke ld.lld (Unix), ld64.lld (macOS), lld-link (Windows), wasm-lld"
+ " (WebAssembly) instead");
}
}