summaryrefslogtreecommitdiff
path: root/gnu/llvm/tools/lld
diff options
context:
space:
mode:
authorPatrick Wildt <patrick@cvs.openbsd.org>2017-10-04 20:51:30 +0000
committerPatrick Wildt <patrick@cvs.openbsd.org>2017-10-04 20:51:30 +0000
commitd46291b91182428a0bc2c850c95991c82421fbdd (patch)
tree0a9bdef38d98f04ef4c1bb2c4a982261d120dbd9 /gnu/llvm/tools/lld
parentce4942c67154008535160eec8b913fb008038b6b (diff)
Merge LLVM 5.0.0 release.
Diffstat (limited to 'gnu/llvm/tools/lld')
-rw-r--r--gnu/llvm/tools/lld/ELF/Config.h103
-rw-r--r--gnu/llvm/tools/lld/ELF/Driver.cpp673
-rw-r--r--gnu/llvm/tools/lld/ELF/DriverUtils.cpp27
-rw-r--r--gnu/llvm/tools/lld/ELF/Options.td90
-rw-r--r--gnu/llvm/tools/lld/ELF/OutputSections.cpp715
-rw-r--r--gnu/llvm/tools/lld/ELF/SymbolTable.cpp304
-rw-r--r--gnu/llvm/tools/lld/ELF/Symbols.cpp290
-rw-r--r--gnu/llvm/tools/lld/ELF/SyntheticSections.cpp1937
-rw-r--r--gnu/llvm/tools/lld/tools/lld/lld.cpp8
9 files changed, 2273 insertions, 1874 deletions
diff --git a/gnu/llvm/tools/lld/ELF/Config.h b/gnu/llvm/tools/lld/ELF/Config.h
index f58e3e5715b..23627dd812d 100644
--- a/gnu/llvm/tools/lld/ELF/Config.h
+++ b/gnu/llvm/tools/lld/ELF/Config.h
@@ -13,7 +13,10 @@
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
-#include "llvm/Support/ELF.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Support/CachePruning.h"
+#include "llvm/Support/CodeGen.h"
+#include "llvm/Support/Endian.h"
#include <vector>
@@ -34,14 +37,14 @@ enum ELFKind {
// For --build-id.
enum class BuildIdKind { None, Fast, Md5, Sha1, Hexstring, Uuid };
-// For --discard-{all,locals,none} and --retain-symbols-file.
-enum class DiscardPolicy { Default, All, Locals, RetainFile, None };
+// For --discard-{all,locals,none}.
+enum class DiscardPolicy { Default, All, Locals, None };
// For --strip-{all,debug}.
enum class StripPolicy { None, All, Debug };
// For --unresolved-symbols.
-enum class UnresolvedPolicy { NoUndef, ReportError, Warn, Ignore };
+enum class UnresolvedPolicy { ReportError, Warn, WarnAll, Ignore, IgnoreAll };
// For --sort-section and linkerscript sorting rules.
enum class SortSectionPolicy { Default, None, Alignment, Name, Priority };
@@ -58,11 +61,16 @@ struct SymbolVersion {
// This struct contains symbols version definition that
// can be found in version script if it is used for link.
struct VersionDefinition {
- VersionDefinition(llvm::StringRef Name, uint16_t Id) : Name(Name), Id(Id) {}
llvm::StringRef Name;
- uint16_t Id;
+ uint16_t Id = 0;
std::vector<SymbolVersion> Globals;
- size_t NameOff; // Offset in string table.
+ size_t NameOff = 0; // Offset in the string table
+};
+
+// Structure for mapping renamed symbols
+struct RenamedSymbol {
+ Symbol *Target;
+ uint8_t OriginalBinding;
};
// This struct contains the global configuration for the linker.
@@ -72,6 +80,7 @@ struct VersionDefinition {
struct Configuration {
InputFile *FirstElf = nullptr;
uint8_t OSABI = 0;
+ llvm::CachePruningPolicy ThinLTOCachePolicy;
llvm::StringMap<uint64_t> SectionStartMap;
llvm::StringRef DynamicLinker;
llvm::StringRef Entry;
@@ -80,52 +89,57 @@ struct Configuration {
llvm::StringRef Init;
llvm::StringRef LTOAAPipeline;
llvm::StringRef LTONewPmPasses;
+ llvm::StringRef MapFile;
llvm::StringRef OutputFile;
+ llvm::StringRef OptRemarksFilename;
llvm::StringRef SoName;
llvm::StringRef Sysroot;
- llvm::StringSet<> RetainSymbolsFile;
- std::string RPath;
+ llvm::StringRef ThinLTOCacheDir;
+ 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;
std::vector<llvm::StringRef> SymbolOrderingFile;
std::vector<llvm::StringRef> Undefined;
std::vector<SymbolVersion> VersionScriptGlobals;
std::vector<SymbolVersion> VersionScriptLocals;
std::vector<uint8_t> BuildIdVector;
+ llvm::MapVector<Symbol *, RenamedSymbol> RenamedSymbols;
bool AllowMultipleDefinition;
bool AsNeeded = false;
bool Bsymbolic;
bool BsymbolicFunctions;
bool ColorDiagnostics = false;
+ bool CompressDebugSections;
bool DefineCommon;
bool Demangle = true;
bool DisableVerify;
bool EhFrameHdr;
+ bool EmitRelocs;
bool EnableNewDtags;
bool ExportDynamic;
bool FatalWarnings;
bool GcSections;
bool GdbIndex;
- bool GnuHash = false;
+ bool GnuHash;
bool ICF;
- bool Mips64EL = false;
bool MipsN32Abi = false;
bool NoGnuUnique;
bool NoUndefinedVersion;
bool Nostdlib;
bool OFormatBinary;
- bool OMagic;
- bool Pic;
+ bool Omagic;
+ bool OptRemarksWithHotness;
bool Pie;
bool PrintGcSections;
- bool Rela;
bool Relocatable;
bool SaveTemps;
bool SingleRoRx;
bool Shared;
bool Static = false;
- bool SysvHash = true;
+ bool SysvHash;
bool Target1Rel;
bool Threads;
bool Trace;
@@ -134,18 +148,21 @@ struct Configuration {
bool WarnMissingEntry;
bool ZCombreloc;
bool ZExecstack;
+ bool ZNocopyreloc;
bool ZNodelete;
bool ZNodlopen;
bool ZNow;
bool ZOrigin;
bool ZRelro;
+ bool ZRodynamic;
+ bool ZText;
bool ExitEarly;
bool ZWxneeded;
DiscardPolicy Discard;
SortSectionPolicy SortSection;
- StripPolicy Strip = StripPolicy::None;
+ StripPolicy Strip;
UnresolvedPolicy UnresolvedSymbols;
- Target2Policy Target2 = Target2Policy::GotRel;
+ Target2Policy Target2;
BuildIdKind BuildId = BuildIdKind::None;
ELFKind EKind = ELFNoneKind;
uint16_t DefaultSymbolVersion = llvm::ELF::VER_NDX_GLOBAL;
@@ -158,6 +175,58 @@ struct Configuration {
unsigned LTOO;
unsigned Optimize;
unsigned ThinLTOJobs;
+
+ // The following config options do not directly correspond to any
+ // particualr command line options.
+
+ // True if we need to pass through relocations in input files to the
+ // output file. Usually false because we consume relocations.
+ bool CopyRelocs;
+
+ // True if the target is ELF64. False if ELF32.
+ bool Is64;
+
+ // True if the target is little-endian. False if big-endian.
+ bool IsLE;
+
+ // endianness::little if IsLE is true. endianness::big otherwise.
+ llvm::support::endianness Endianness;
+
+ // True if the target is the little-endian MIPS64.
+ //
+ // The reason why we have this variable only for the MIPS is because
+ // we use this often. Some ELF headers for MIPS64EL are in a
+ // mixed-endian (which is horrible and I'd say that's a serious spec
+ // bug), and we need to know whether we are reading MIPS ELF files or
+ // not in various places.
+ //
+ // (Note that MIPS64EL is not a typo for MIPS64LE. This is the official
+ // name whatever that means. A fun hypothesis is that "EL" is short for
+ // little-endian written in the little-endian order, but I don't know
+ // if that's true.)
+ bool IsMips64EL;
+
+ // The ELF spec defines two types of relocation table entries, RELA and
+ // REL. RELA is a triplet of (offset, info, addend) while REL is a
+ // tuple of (offset, info). Addends for REL are implicit and read from
+ // the location where the relocations are applied. So, REL is more
+ // compact than RELA but requires a bit of more work to process.
+ //
+ // (From the linker writer's view, this distinction is not necessary.
+ // If the ELF had chosen whichever and sticked with it, it would have
+ // been easier to write code to process relocations, but it's too late
+ // to change the spec.)
+ //
+ // Each ABI defines its relocation type. IsRela is true if target
+ // uses RELA. As far as we know, all 64-bit ABIs are using RELA. A
+ // few 32-bit ABIs are using RELA too.
+ bool IsRela;
+
+ // True if we are creating position-independent code.
+ bool Pic;
+
+ // 4 for ELF32, 8 for ELF64.
+ int Wordsize;
};
// The only instance of Configuration struct.
diff --git a/gnu/llvm/tools/lld/ELF/Driver.cpp b/gnu/llvm/tools/lld/ELF/Driver.cpp
index 99253313c35..a069bd637e7 100644
--- a/gnu/llvm/tools/lld/ELF/Driver.cpp
+++ b/gnu/llvm/tools/lld/ELF/Driver.cpp
@@ -6,17 +6,37 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
+//
+// The driver drives the entire linking process. It is responsible for
+// parsing command line options and doing whatever it is instructed to do.
+//
+// One notable thing in the LLD's driver when compared to other linkers is
+// that the LLD's driver is agnostic on the host operating system.
+// Other linkers usually have implicit default values (such as a dynamic
+// linker path or library paths) for each host OS.
+//
+// I don't think implicit default values are useful because they are
+// usually explicitly specified by the compiler driver. They can even
+// be harmful when you are doing cross-linking. Therefore, in LLD, we
+// simply trust the compiler driver to pass all required options and
+// don't try to make effort on our side.
+//
+//===----------------------------------------------------------------------===//
#include "Driver.h"
#include "Config.h"
#include "Error.h"
+#include "Filesystem.h"
#include "ICF.h"
#include "InputFiles.h"
#include "InputSection.h"
#include "LinkerScript.h"
#include "Memory.h"
+#include "OutputSections.h"
+#include "ScriptParser.h"
#include "Strings.h"
#include "SymbolTable.h"
+#include "SyntheticSections.h"
#include "Target.h"
#include "Threads.h"
#include "Writer.h"
@@ -24,8 +44,8 @@
#include "lld/Driver/Driver.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
-#include "llvm/Object/Decompressor.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Compression.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/TarWriter.h"
#include "llvm/Support/TargetSelect.h"
@@ -48,16 +68,19 @@ BumpPtrAllocator elf::BAlloc;
StringSaver elf::Saver{BAlloc};
std::vector<SpecificAllocBase *> elf::SpecificAllocBase::Instances;
+static void setConfigs();
+
bool elf::link(ArrayRef<const char *> Args, bool CanExitEarly,
raw_ostream &Error) {
ErrorCount = 0;
ErrorOS = &Error;
- Argv0 = Args[0];
+ InputSections.clear();
Tar = nullptr;
Config = make<Configuration>();
Driver = make<LinkerDriver>();
- ScriptConfig = make<ScriptConfiguration>();
+ Script = make<LinkerScript>();
+ Config->Argv = {Args.begin(), Args.end()};
Driver->main(Args, CanExitEarly);
freeArena();
@@ -76,12 +99,10 @@ 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})
- .Case("armelf_linux_eabi", {ELF32LEKind, EM_ARM})
+ .Cases("armelf", "armelf_linux_eabi", {ELF32LEKind, EM_ARM})
.Case("elf32_x86_64", {ELF32LEKind, EM_X86_64})
- .Case("elf32btsmip", {ELF32BEKind, EM_MIPS})
- .Case("elf32ltsmip", {ELF32LEKind, EM_MIPS})
- .Case("elf32btsmipn32", {ELF32BEKind, EM_MIPS})
- .Case("elf32ltsmipn32", {ELF32LEKind, EM_MIPS})
+ .Cases("elf32btsmip", "elf32btsmipn32", {ELF32BEKind, EM_MIPS})
+ .Cases("elf32ltsmip", "elf32ltsmipn32", {ELF32LEKind, EM_MIPS})
.Case("elf32ppc", {ELF32BEKind, EM_PPC})
.Case("elf64btsmip", {ELF64BEKind, EM_MIPS})
.Case("elf64ltsmip", {ELF64LEKind, EM_MIPS})
@@ -102,13 +123,13 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef Emul) {
// Returns slices of MB by parsing MB as an archive file.
// Each slice consists of a member file in the archive.
-std::vector<MemoryBufferRef>
-LinkerDriver::getArchiveMembers(MemoryBufferRef MB) {
+std::vector<std::pair<MemoryBufferRef, uint64_t>> static getArchiveMembers(
+ MemoryBufferRef MB) {
std::unique_ptr<Archive> File =
check(Archive::create(MB),
MB.getBufferIdentifier() + ": failed to parse archive");
- std::vector<MemoryBufferRef> V;
+ std::vector<std::pair<MemoryBufferRef, uint64_t>> V;
Error Err = Error::success();
for (const ErrorOr<Archive::Child> &COrErr : File->children(Err)) {
Archive::Child C =
@@ -118,7 +139,7 @@ LinkerDriver::getArchiveMembers(MemoryBufferRef MB) {
check(C.getMemoryBufferRef(),
MB.getBufferIdentifier() +
": could not get the buffer for a child of the archive");
- V.push_back(MBRef);
+ V.push_back(std::make_pair(MBRef, C.getChildOffset()));
}
if (Err)
fatal(MB.getBufferIdentifier() + ": Archive::children failed: " +
@@ -131,9 +152,8 @@ LinkerDriver::getArchiveMembers(MemoryBufferRef MB) {
return V;
}
-// Opens and parses a file. Path has to be resolved already.
-// Newly created memory buffers are owned by this driver.
-void LinkerDriver::addFile(StringRef Path) {
+// Opens a file and create a file object. Path has to be resolved already.
+void LinkerDriver::addFile(StringRef Path, bool WithLOption) {
using namespace sys::fs;
Optional<MemoryBufferRef> Buffer = readFile(Path);
@@ -150,24 +170,53 @@ void LinkerDriver::addFile(StringRef Path) {
case file_magic::unknown:
readLinkerScript(MBRef);
return;
- case file_magic::archive:
+ case file_magic::archive: {
+ // Handle -whole-archive.
if (InWholeArchive) {
- for (MemoryBufferRef MB : getArchiveMembers(MBRef))
- Files.push_back(createObjectFile(MB, Path));
+ for (const auto &P : getArchiveMembers(MBRef))
+ Files.push_back(createObjectFile(P.first, Path, P.second));
return;
}
- Files.push_back(make<ArchiveFile>(MBRef));
+
+ std::unique_ptr<Archive> File =
+ check(Archive::create(MBRef), Path + ": failed to parse archive");
+
+ // If an archive file has no symbol table, it is likely that a user
+ // is attempting LTO and using a default ar command that doesn't
+ // understand the LLVM bitcode file. It is a pretty common error, so
+ // we'll handle it as if it had a symbol table.
+ if (!File->isEmpty() && !File->hasSymbolTable()) {
+ for (const auto &P : getArchiveMembers(MBRef))
+ Files.push_back(make<LazyObjectFile>(P.first, Path, P.second));
+ return;
+ }
+
+ // Handle the regular case.
+ Files.push_back(make<ArchiveFile>(std::move(File)));
return;
+ }
case file_magic::elf_shared_object:
if (Config->Relocatable) {
error("attempted static link of dynamic object " + Path);
return;
}
- Files.push_back(createSharedFile(MBRef));
+
+ // DSOs usually have DT_SONAME tags in their ELF headers, and the
+ // sonames are used to identify DSOs. But if they are missing,
+ // they are identified by filenames. We don't know whether the new
+ // file has a DT_SONAME or not because we haven't parsed it yet.
+ // Here, we set the default soname for the file because we might
+ // need it later.
+ //
+ // If a file was specified by -lfoo, the directory part is not
+ // significant, as a user did not specify it. This behavior is
+ // compatible with GNU.
+ Files.push_back(
+ createSharedFile(MBRef, WithLOption ? path::filename(Path) : Path));
return;
default:
if (InLib)
- Files.push_back(make<LazyObjectFile>(MBRef));
+ Files.push_back(make<LazyObjectFile>(MBRef, "", 0));
else
Files.push_back(createObjectFile(MBRef));
}
@@ -176,7 +225,7 @@ void LinkerDriver::addFile(StringRef Path) {
// Add a given library by searching it from input search paths.
void LinkerDriver::addLibrary(StringRef Name) {
if (Optional<std::string> Path = searchLibrary(Name))
- addFile(*Path);
+ addFile(*Path, /*WithLOption=*/true);
else
error("unable to find library -l" + Name);
}
@@ -210,6 +259,12 @@ static void checkOptions(opt::InputArgList &Args) {
if (Config->Pie && Config->Shared)
error("-shared and -pie may not be used together");
+ if (!Config->Shared && !Config->FilterList.empty())
+ error("-F may not be used without -shared");
+
+ if (!Config->Shared && !Config->AuxiliaryList.empty())
+ error("-f may not be used without -shared");
+
if (Config->Relocatable) {
if (Config->Shared)
error("-r and -shared may not be used together");
@@ -222,18 +277,11 @@ static void checkOptions(opt::InputArgList &Args) {
}
}
-static StringRef getString(opt::InputArgList &Args, unsigned Key,
- StringRef Default = "") {
- if (auto *Arg = Args.getLastArg(Key))
- return Arg->getValue();
- return Default;
-}
-
static int getInteger(opt::InputArgList &Args, unsigned Key, int Default) {
int V = Default;
if (auto *Arg = Args.getLastArg(Key)) {
StringRef S = Arg->getValue();
- if (S.getAsInteger(10, V))
+ if (!to_integer(S, V, 10))
error(Arg->getSpelling() + ": number expected, but got " + S);
}
return V;
@@ -255,13 +303,11 @@ static bool hasZOption(opt::InputArgList &Args, StringRef Key) {
static uint64_t getZOptionValue(opt::InputArgList &Args, StringRef Key,
uint64_t Default) {
for (auto *Arg : Args.filtered(OPT_z)) {
- StringRef Value = Arg->getValue();
- size_t Pos = Value.find("=");
- if (Pos != StringRef::npos && Key == Value.substr(0, Pos)) {
- Value = Value.substr(Pos + 1);
- uint64_t Result;
- if (Value.getAsInteger(0, Result))
- error("invalid " + Key + ": " + Value);
+ std::pair<StringRef, StringRef> KV = StringRef(Arg->getValue()).split('=');
+ if (KV.first == Key) {
+ uint64_t Result = Default;
+ if (!to_integer(KV.second, Result))
+ error("invalid " + Key + ": " + KV.second);
return Result;
}
}
@@ -296,8 +342,8 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) {
// lot of "configure" scripts out there that are generated by old version
// of Libtool. We cannot convince every software developer to migrate to
// the latest version and re-generate scripts. So we have this hack.
- if (Args.hasArg(OPT_version) || Args.hasArg(OPT_v))
- outs() << getLLDVersion() << " (compatible with GNU linkers)\n";
+ if (Args.hasArg(OPT_v) || Args.hasArg(OPT_version))
+ message(getLLDVersion() + " (compatible with GNU linkers)");
// ld.bfd always exits after printing out the version string.
// ld.gold proceeds if a given option is -v. Because gold's behavior
@@ -327,6 +373,7 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) {
initLLVM(Args);
createFiles(Args);
inferMachineType();
+ setConfigs();
checkOptions(Args);
if (ErrorCount)
return;
@@ -349,36 +396,76 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) {
}
}
-static UnresolvedPolicy getUnresolvedSymbolOption(opt::InputArgList &Args) {
+static bool getArg(opt::InputArgList &Args, unsigned K1, unsigned K2,
+ bool Default) {
+ if (auto *Arg = Args.getLastArg(K1, K2))
+ return Arg->getOption().getID() == K1;
+ return Default;
+}
+
+static std::vector<StringRef> getArgs(opt::InputArgList &Args, int Id) {
+ std::vector<StringRef> V;
+ for (auto *Arg : Args.filtered(Id))
+ V.push_back(Arg->getValue());
+ return V;
+}
+
+static std::string getRpath(opt::InputArgList &Args) {
+ std::vector<StringRef> V = getArgs(Args, OPT_rpath);
+ return llvm::join(V.begin(), V.end(), ":");
+}
+
+// Determines what we should do if there are remaining unresolved
+// symbols after the name resolution.
+static UnresolvedPolicy getUnresolvedSymbolPolicy(opt::InputArgList &Args) {
+ // -noinhibit-exec or -r imply some default values.
if (Args.hasArg(OPT_noinhibit_exec))
- return UnresolvedPolicy::Warn;
- if (Args.hasArg(OPT_no_undefined) || hasZOption(Args, "defs"))
- return UnresolvedPolicy::NoUndef;
- if (Config->Relocatable)
- return UnresolvedPolicy::Ignore;
+ return UnresolvedPolicy::WarnAll;
+ if (Args.hasArg(OPT_relocatable))
+ return UnresolvedPolicy::IgnoreAll;
- if (auto *Arg = Args.getLastArg(OPT_unresolved_symbols)) {
- StringRef S = Arg->getValue();
- if (S == "ignore-all" || S == "ignore-in-object-files")
- return UnresolvedPolicy::Ignore;
- if (S == "ignore-in-shared-libs" || S == "report-all")
- return UnresolvedPolicy::ReportError;
- error("unknown --unresolved-symbols value: " + S);
+ UnresolvedPolicy ErrorOrWarn = getArg(Args, OPT_error_unresolved_symbols,
+ OPT_warn_unresolved_symbols, true)
+ ? UnresolvedPolicy::ReportError
+ : UnresolvedPolicy::Warn;
+
+ // Process the last of -unresolved-symbols, -no-undefined or -z defs.
+ for (auto *Arg : llvm::reverse(Args)) {
+ switch (Arg->getOption().getID()) {
+ case OPT_unresolved_symbols: {
+ StringRef S = Arg->getValue();
+ if (S == "ignore-all" || S == "ignore-in-object-files")
+ return UnresolvedPolicy::Ignore;
+ if (S == "ignore-in-shared-libs" || S == "report-all")
+ return ErrorOrWarn;
+ error("unknown --unresolved-symbols value: " + S);
+ continue;
+ }
+ case OPT_no_undefined:
+ return ErrorOrWarn;
+ case OPT_z:
+ if (StringRef(Arg->getValue()) == "defs")
+ return ErrorOrWarn;
+ continue;
+ }
}
- return UnresolvedPolicy::ReportError;
+
+ // -shared implies -unresolved-symbols=ignore-all because missing
+ // symbols are likely to be resolved at runtime using other DSOs.
+ if (Config->Shared)
+ return UnresolvedPolicy::Ignore;
+ return ErrorOrWarn;
}
-static Target2Policy getTarget2Option(opt::InputArgList &Args) {
- if (auto *Arg = Args.getLastArg(OPT_target2)) {
- StringRef S = Arg->getValue();
- if (S == "rel")
- return Target2Policy::Rel;
- if (S == "abs")
- return Target2Policy::Abs;
- if (S == "got-rel")
- return Target2Policy::GotRel;
- error("unknown --target2 option: " + S);
- }
+static Target2Policy getTarget2(opt::InputArgList &Args) {
+ StringRef S = Args.getLastArgValue(OPT_target2, "got-rel");
+ if (S == "rel")
+ return Target2Policy::Rel;
+ if (S == "abs")
+ return Target2Policy::Abs;
+ if (S == "got-rel")
+ return Target2Policy::GotRel;
+ error("unknown --target2 option: " + S);
return Target2Policy::GotRel;
}
@@ -392,16 +479,10 @@ static bool isOutputFormatBinary(opt::InputArgList &Args) {
return false;
}
-static bool getArg(opt::InputArgList &Args, unsigned K1, unsigned K2,
- bool Default) {
- if (auto *Arg = Args.getLastArg(K1, K2))
- return Arg->getOption().getID() == K1;
- return Default;
-}
-
-static DiscardPolicy getDiscardOption(opt::InputArgList &Args) {
- if (Config->Relocatable)
+static DiscardPolicy getDiscard(opt::InputArgList &Args) {
+ if (Args.hasArg(OPT_relocatable))
return DiscardPolicy::None;
+
auto *Arg =
Args.getLastArg(OPT_discard_all, OPT_discard_locals, OPT_discard_none);
if (!Arg)
@@ -413,20 +494,30 @@ static DiscardPolicy getDiscardOption(opt::InputArgList &Args) {
return DiscardPolicy::None;
}
-static StripPolicy getStripOption(opt::InputArgList &Args) {
- if (auto *Arg = Args.getLastArg(OPT_strip_all, OPT_strip_debug)) {
- if (Arg->getOption().getID() == OPT_strip_all)
- return StripPolicy::All;
- return StripPolicy::Debug;
- }
- return StripPolicy::None;
+static StringRef getDynamicLinker(opt::InputArgList &Args) {
+ auto *Arg = Args.getLastArg(OPT_dynamic_linker, OPT_no_dynamic_linker);
+ if (!Arg || Arg->getOption().getID() == OPT_no_dynamic_linker)
+ return "";
+ return Arg->getValue();
+}
+
+static StripPolicy getStrip(opt::InputArgList &Args) {
+ if (Args.hasArg(OPT_relocatable))
+ return StripPolicy::None;
+
+ auto *Arg = Args.getLastArg(OPT_strip_all, OPT_strip_debug);
+ if (!Arg)
+ return StripPolicy::None;
+ if (Arg->getOption().getID() == OPT_strip_all)
+ return StripPolicy::All;
+ return StripPolicy::Debug;
}
static uint64_t parseSectionAddress(StringRef S, opt::Arg *Arg) {
uint64_t VA = 0;
if (S.startswith("0x"))
S = S.drop_front(2);
- if (S.getAsInteger(16, VA))
+ if (!to_integer(S, VA, 16))
error("invalid argument: " + toString(Arg));
return VA;
}
@@ -449,8 +540,8 @@ static StringMap<uint64_t> getSectionStartMap(opt::InputArgList &Args) {
return Ret;
}
-static SortSectionPolicy getSortKind(opt::InputArgList &Args) {
- StringRef S = getString(Args, OPT_sort_section);
+static SortSectionPolicy getSortSection(opt::InputArgList &Args) {
+ StringRef S = Args.getLastArgValue(OPT_sort_section);
if (S == "alignment")
return SortSectionPolicy::Alignment;
if (S == "name")
@@ -460,6 +551,44 @@ static SortSectionPolicy getSortKind(opt::InputArgList &Args) {
return SortSectionPolicy::Default;
}
+static std::pair<bool, bool> getHashStyle(opt::InputArgList &Args) {
+ StringRef S = Args.getLastArgValue(OPT_hash_style, "sysv");
+ if (S == "sysv")
+ return {true, false};
+ if (S == "gnu")
+ return {false, true};
+ if (S != "both")
+ error("unknown -hash-style: " + S);
+ return {true, true};
+}
+
+// Parse --build-id or --build-id=<style>. We handle "tree" as a
+// synonym for "sha1" because all our hash functions including
+// -build-id=sha1 are actually tree hashes for performance reasons.
+static std::pair<BuildIdKind, std::vector<uint8_t>>
+getBuildId(opt::InputArgList &Args) {
+ auto *Arg = Args.getLastArg(OPT_build_id, OPT_build_id_eq);
+ if (!Arg)
+ return {BuildIdKind::None, {}};
+
+ if (Arg->getOption().getID() == OPT_build_id)
+ return {BuildIdKind::Fast, {}};
+
+ StringRef S = Arg->getValue();
+ if (S == "md5")
+ return {BuildIdKind::Md5, {}};
+ if (S == "sha1" || S == "tree")
+ return {BuildIdKind::Sha1, {}};
+ if (S == "uuid")
+ return {BuildIdKind::Uuid, {}};
+ if (S.startswith("0x"))
+ return {BuildIdKind::Hexstring, parseHex(S.substr(2))};
+
+ if (S != "none")
+ error("unknown --build-id style: " + S);
+ return {BuildIdKind::None, {}};
+}
+
static std::vector<StringRef> getLines(MemoryBufferRef MB) {
SmallVector<StringRef, 0> Arr;
MB.getBuffer().split(Arr, '\n');
@@ -473,42 +602,58 @@ static std::vector<StringRef> getLines(MemoryBufferRef MB) {
return Ret;
}
+static bool getCompressDebugSections(opt::InputArgList &Args) {
+ StringRef S = Args.getLastArgValue(OPT_compress_debug_sections, "none");
+ if (S == "none")
+ return false;
+ if (S != "zlib")
+ error("unknown --compress-debug-sections value: " + S);
+ if (!zlib::isAvailable())
+ error("--compress-debug-sections: zlib is not available");
+ return true;
+}
+
// Initializes Config members by the command line options.
void LinkerDriver::readConfigs(opt::InputArgList &Args) {
- for (auto *Arg : Args.filtered(OPT_L))
- Config->SearchPaths.push_back(Arg->getValue());
-
- std::vector<StringRef> RPaths;
- for (auto *Arg : Args.filtered(OPT_rpath))
- RPaths.push_back(Arg->getValue());
- if (!RPaths.empty())
- Config->RPath = llvm::join(RPaths.begin(), RPaths.end(), ":");
-
- if (auto *Arg = Args.getLastArg(OPT_m)) {
- // Parse ELF{32,64}{LE,BE} and CPU type.
- StringRef S = Arg->getValue();
- std::tie(Config->EKind, Config->EMachine, Config->OSABI) =
- parseEmulation(S);
- Config->MipsN32Abi = (S == "elf32btsmipn32" || S == "elf32ltsmipn32");
- Config->Emulation = S;
- }
-
Config->AllowMultipleDefinition = Args.hasArg(OPT_allow_multiple_definition);
+ Config->AuxiliaryList = getArgs(Args, OPT_auxiliary);
Config->Bsymbolic = Args.hasArg(OPT_Bsymbolic);
Config->BsymbolicFunctions = Args.hasArg(OPT_Bsymbolic_functions);
+ Config->CompressDebugSections = getCompressDebugSections(Args);
+ Config->DefineCommon = getArg(Args, OPT_define_common, OPT_no_define_common,
+ !Args.hasArg(OPT_relocatable));
Config->Demangle = getArg(Args, OPT_demangle, OPT_no_demangle, true);
Config->DisableVerify = Args.hasArg(OPT_disable_verify);
+ Config->Discard = getDiscard(Args);
+ Config->DynamicLinker = getDynamicLinker(Args);
Config->EhFrameHdr = Args.hasArg(OPT_eh_frame_hdr);
+ Config->EmitRelocs = Args.hasArg(OPT_emit_relocs);
Config->EnableNewDtags = !Args.hasArg(OPT_disable_new_dtags);
- Config->ExportDynamic = Args.hasArg(OPT_export_dynamic);
- Config->FatalWarnings = Args.hasArg(OPT_fatal_warnings);
+ Config->Entry = Args.getLastArgValue(OPT_entry);
+ Config->ExportDynamic =
+ getArg(Args, OPT_export_dynamic, OPT_no_export_dynamic, false);
+ Config->FatalWarnings =
+ getArg(Args, OPT_fatal_warnings, OPT_no_fatal_warnings, false);
+ Config->FilterList = getArgs(Args, OPT_filter);
+ Config->Fini = Args.getLastArgValue(OPT_fini, "_fini");
Config->GcSections = getArg(Args, OPT_gc_sections, OPT_no_gc_sections, false);
Config->GdbIndex = Args.hasArg(OPT_gdb_index);
- Config->ICF = Args.hasArg(OPT_icf);
+ Config->ICF = getArg(Args, OPT_icf_all, OPT_icf_none, false);
+ Config->Init = Args.getLastArgValue(OPT_init, "_init");
+ Config->LTOAAPipeline = Args.getLastArgValue(OPT_lto_aa_pipeline);
+ Config->LTONewPmPasses = Args.getLastArgValue(OPT_lto_newpm_passes);
+ Config->LTOO = getInteger(Args, OPT_lto_O, 2);
+ Config->LTOPartitions = getInteger(Args, OPT_lto_partitions, 1);
+ Config->MapFile = Args.getLastArgValue(OPT_Map);
Config->NoGnuUnique = Args.hasArg(OPT_no_gnu_unique);
Config->NoUndefinedVersion = Args.hasArg(OPT_no_undefined_version);
Config->Nostdlib = Args.hasArg(OPT_nostdlib);
- Config->OMagic = Args.hasArg(OPT_omagic);
+ Config->OFormatBinary = isOutputFormatBinary(Args);
+ Config->Omagic = Args.hasArg(OPT_omagic);
+ Config->OptRemarksFilename = Args.getLastArgValue(OPT_opt_remarks_filename);
+ Config->OptRemarksWithHotness = Args.hasArg(OPT_opt_remarks_with_hotness);
+ Config->Optimize = getInteger(Args, OPT_O, 1);
+ Config->OutputFile = Args.getLastArgValue(OPT_o);
#ifdef __OpenBSD__
Config->Pie = getArg(Args, OPT_pie, OPT_nopie,
!Args.hasArg(OPT_shared) && !Args.hasArg(OPT_relocatable));
@@ -516,137 +661,111 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
Config->Pie = getArg(Args, OPT_pie, OPT_nopie, false);
#endif
Config->PrintGcSections = Args.hasArg(OPT_print_gc_sections);
+ Config->Rpath = getRpath(Args);
Config->Relocatable = Args.hasArg(OPT_relocatable);
- Config->DefineCommon = getArg(Args, OPT_define_common, OPT_no_define_common,
- !Config->Relocatable);
- Config->Discard = getDiscardOption(Args);
Config->SaveTemps = Args.hasArg(OPT_save_temps);
- Config->SingleRoRx = Args.hasArg(OPT_no_rosegment);
+ Config->SearchPaths = getArgs(Args, OPT_L);
+ Config->SectionStartMap = getSectionStartMap(Args);
Config->Shared = Args.hasArg(OPT_shared);
+ Config->SingleRoRx = Args.hasArg(OPT_no_rosegment);
+ Config->SoName = Args.getLastArgValue(OPT_soname);
+ Config->SortSection = getSortSection(Args);
+ Config->Strip = getStrip(Args);
+ Config->Sysroot = Args.getLastArgValue(OPT_sysroot);
Config->Target1Rel = getArg(Args, OPT_target1_rel, OPT_target1_abs, false);
+ Config->Target2 = getTarget2(Args);
+ Config->ThinLTOCacheDir = Args.getLastArgValue(OPT_thinlto_cache_dir);
+ Config->ThinLTOCachePolicy = check(
+ parseCachePruningPolicy(Args.getLastArgValue(OPT_thinlto_cache_policy)),
+ "--thinlto-cache-policy: invalid cache policy");
+ Config->ThinLTOJobs = getInteger(Args, OPT_thinlto_jobs, -1u);
Config->Threads = getArg(Args, OPT_threads, OPT_no_threads, true);
Config->Trace = Args.hasArg(OPT_trace);
+ Config->Undefined = getArgs(Args, OPT_undefined);
+ Config->UnresolvedSymbols = getUnresolvedSymbolPolicy(Args);
Config->Verbose = Args.hasArg(OPT_verbose);
Config->WarnCommon = Args.hasArg(OPT_warn_common);
-
- Config->DynamicLinker = getString(Args, OPT_dynamic_linker);
- Config->Entry = getString(Args, OPT_entry);
- Config->Fini = getString(Args, OPT_fini, "_fini");
- Config->Init = getString(Args, OPT_init, "_init");
- Config->LTOAAPipeline = getString(Args, OPT_lto_aa_pipeline);
- Config->LTONewPmPasses = getString(Args, OPT_lto_newpm_passes);
- Config->OutputFile = getString(Args, OPT_o);
- Config->SoName = getString(Args, OPT_soname);
- Config->Sysroot = getString(Args, OPT_sysroot);
-
- Config->Optimize = getInteger(Args, OPT_O, 1);
- Config->LTOO = getInteger(Args, OPT_lto_O, 2);
- if (Config->LTOO > 3)
- error("invalid optimization level for LTO: " + getString(Args, OPT_lto_O));
- Config->LTOPartitions = getInteger(Args, OPT_lto_partitions, 1);
- if (Config->LTOPartitions == 0)
- error("--lto-partitions: number of threads must be > 0");
- Config->ThinLTOJobs = getInteger(Args, OPT_thinlto_jobs, -1u);
- if (Config->ThinLTOJobs == 0)
- error("--thinlto-jobs: number of threads must be > 0");
-
Config->ZCombreloc = !hasZOption(Args, "nocombreloc");
Config->ZExecstack = hasZOption(Args, "execstack");
+ Config->ZNocopyreloc = hasZOption(Args, "nocopyreloc");
Config->ZNodelete = hasZOption(Args, "nodelete");
Config->ZNodlopen = hasZOption(Args, "nodlopen");
Config->ZNow = hasZOption(Args, "now");
Config->ZOrigin = hasZOption(Args, "origin");
Config->ZRelro = !hasZOption(Args, "norelro");
- Config->ZStackSize = getZOptionValue(Args, "stack-size", -1);
+ Config->ZRodynamic = hasZOption(Args, "rodynamic");
+ Config->ZStackSize = getZOptionValue(Args, "stack-size", 0);
+ Config->ZText = !hasZOption(Args, "notext");
Config->ZWxneeded = hasZOption(Args, "wxneeded");
- Config->OFormatBinary = isOutputFormatBinary(Args);
- Config->SectionStartMap = getSectionStartMap(Args);
- Config->SortSection = getSortKind(Args);
- Config->Target2 = getTarget2Option(Args);
- Config->UnresolvedSymbols = getUnresolvedSymbolOption(Args);
+ if (Config->LTOO > 3)
+ error("invalid optimization level for LTO: " +
+ Args.getLastArgValue(OPT_lto_O));
+ if (Config->LTOPartitions == 0)
+ error("--lto-partitions: number of threads must be > 0");
+ if (Config->ThinLTOJobs == 0)
+ error("--thinlto-jobs: number of threads must be > 0");
+
+ if (auto *Arg = Args.getLastArg(OPT_m)) {
+ // Parse ELF{32,64}{LE,BE} and CPU type.
+ StringRef S = Arg->getValue();
+ std::tie(Config->EKind, Config->EMachine, Config->OSABI) =
+ parseEmulation(S);
+ Config->MipsN32Abi = (S == "elf32btsmipn32" || S == "elf32ltsmipn32");
+ Config->Emulation = S;
+ }
+
+ if (Args.hasArg(OPT_print_map))
+ Config->MapFile = "-";
// --omagic is an option to create old-fashioned executables in which
// .text segments are writable. Today, the option is still in use to
// create special-purpose programs such as boot loaders. It doesn't
// make sense to create PT_GNU_RELRO for such executables.
- if (Config->OMagic)
+ if (Config->Omagic)
Config->ZRelro = false;
- if (!Config->Relocatable)
- Config->Strip = getStripOption(Args);
-
- // Config->Pic is true if we are generating position-independent code.
- Config->Pic = Config->Pie || Config->Shared;
-
- if (auto *Arg = Args.getLastArg(OPT_hash_style)) {
- StringRef S = Arg->getValue();
- if (S == "gnu") {
- Config->GnuHash = true;
- Config->SysvHash = false;
- } else if (S == "both") {
- Config->GnuHash = true;
- } else if (S != "sysv")
- error("unknown hash style: " + S);
- }
-
- // Parse --build-id or --build-id=<style>.
- if (Args.hasArg(OPT_build_id))
- Config->BuildId = BuildIdKind::Fast;
- if (auto *Arg = Args.getLastArg(OPT_build_id_eq)) {
- StringRef S = Arg->getValue();
- if (S == "md5") {
- Config->BuildId = BuildIdKind::Md5;
- } else if (S == "sha1" || S == "tree") {
- Config->BuildId = BuildIdKind::Sha1;
- } else if (S == "uuid") {
- Config->BuildId = BuildIdKind::Uuid;
- } else if (S == "none") {
- Config->BuildId = BuildIdKind::None;
- } else if (S.startswith("0x")) {
- Config->BuildId = BuildIdKind::Hexstring;
- Config->BuildIdVector = parseHex(S.substr(2));
- } else {
- error("unknown --build-id style: " + S);
- }
- }
-
- for (auto *Arg : Args.filtered(OPT_auxiliary))
- Config->AuxiliaryList.push_back(Arg->getValue());
- if (!Config->Shared && !Config->AuxiliaryList.empty())
- error("-f may not be used without -shared");
-
- for (auto *Arg : Args.filtered(OPT_undefined))
- Config->Undefined.push_back(Arg->getValue());
-
- if (auto *Arg = Args.getLastArg(OPT_dynamic_list))
- if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
- readDynamicList(*Buffer);
+ std::tie(Config->SysvHash, Config->GnuHash) = getHashStyle(Args);
+ std::tie(Config->BuildId, Config->BuildIdVector) = getBuildId(Args);
if (auto *Arg = Args.getLastArg(OPT_symbol_ordering_file))
if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
Config->SymbolOrderingFile = getLines(*Buffer);
- // If --retain-symbol-file is used, we'll retail only the symbols listed in
+ // If --retain-symbol-file is used, we'll keep only the symbols listed in
// the file and discard all others.
if (auto *Arg = Args.getLastArg(OPT_retain_symbols_file)) {
- Config->Discard = DiscardPolicy::RetainFile;
+ Config->DefaultSymbolVersion = VER_NDX_LOCAL;
if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
for (StringRef S : getLines(*Buffer))
- Config->RetainSymbolsFile.insert(S);
+ Config->VersionScriptGlobals.push_back(
+ {S, /*IsExternCpp*/ false, /*HasWildcard*/ false});
}
- for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol))
- Config->VersionScriptGlobals.push_back(
- {Arg->getValue(), /*IsExternCpp*/ false, /*HasWildcard*/ false});
-
- // Dynamic lists are a simplified linker script that doesn't need the
- // "global:" and implicitly ends with a "local:*". Set the variables needed to
- // simulate that.
- if (Args.hasArg(OPT_dynamic_list) || Args.hasArg(OPT_export_dynamic_symbol)) {
- Config->ExportDynamic = true;
- if (!Config->Shared)
- Config->DefaultSymbolVersion = VER_NDX_LOCAL;
+ bool HasExportDynamic =
+ getArg(Args, OPT_export_dynamic, OPT_no_export_dynamic, false);
+
+ // Parses -dynamic-list and -export-dynamic-symbol. They make some
+ // symbols private. Note that -export-dynamic takes precedence over them
+ // as it says all symbols should be exported.
+ if (!HasExportDynamic) {
+ for (auto *Arg : Args.filtered(OPT_dynamic_list))
+ if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
+ readDynamicList(*Buffer);
+
+ for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol))
+ Config->VersionScriptGlobals.push_back(
+ {Arg->getValue(), /*IsExternCpp*/ false, /*HasWildcard*/ false});
+
+ // Dynamic lists are a simplified linker script that doesn't need the
+ // "global:" and implicitly ends with a "local:*". Set the variables
+ // needed to simulate that.
+ if (Args.hasArg(OPT_dynamic_list) ||
+ Args.hasArg(OPT_export_dynamic_symbol)) {
+ Config->ExportDynamic = true;
+ if (!Config->Shared)
+ Config->DefaultSymbolVersion = VER_NDX_LOCAL;
+ }
}
if (auto *Arg = Args.getLastArg(OPT_version_script))
@@ -654,6 +773,29 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
readVersionScript(*Buffer);
}
+// 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() {
+ 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;
+}
+
// Returns a value of "-format" option.
static bool getBinaryOption(StringRef S) {
if (S == "binary")
@@ -672,7 +814,7 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) {
addLibrary(Arg->getValue());
break;
case OPT_INPUT:
- addFile(Arg->getValue());
+ addFile(Arg->getValue(), /*WithLOption=*/false);
break;
case OPT_alias_script_T:
case OPT_script:
@@ -751,7 +893,7 @@ static uint64_t getImageBase(opt::InputArgList &Args) {
StringRef S = Arg->getValue();
uint64_t V;
- if (S.getAsInteger(0, V)) {
+ if (!to_integer(S, V)) {
error("-image-base: number expected, but got " + S);
return 0;
}
@@ -760,18 +902,63 @@ static uint64_t getImageBase(opt::InputArgList &Args) {
return V;
}
+// Parses --defsym=alias option.
+static std::vector<std::pair<StringRef, StringRef>>
+getDefsym(opt::InputArgList &Args) {
+ std::vector<std::pair<StringRef, StringRef>> Ret;
+ for (auto *Arg : Args.filtered(OPT_defsym)) {
+ StringRef From;
+ StringRef To;
+ std::tie(From, To) = StringRef(Arg->getValue()).split('=');
+ if (!isValidCIdentifier(To))
+ error("--defsym: symbol name expected, but got " + To);
+ Ret.push_back({From, To});
+ }
+ return Ret;
+}
+
+// Parses `--exclude-libs=lib,lib,...`.
+// The library names may be delimited by commas or colons.
+static DenseSet<StringRef> getExcludeLibs(opt::InputArgList &Args) {
+ DenseSet<StringRef> Ret;
+ for (auto *Arg : Args.filtered(OPT_exclude_libs)) {
+ StringRef S = Arg->getValue();
+ for (;;) {
+ size_t Pos = S.find_first_of(",:");
+ if (Pos == StringRef::npos)
+ break;
+ Ret.insert(S.substr(0, Pos));
+ S = S.substr(Pos + 1);
+ }
+ Ret.insert(S);
+ }
+ return Ret;
+}
+
+// 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.
+// A special library name "ALL" means all archive files.
+//
+// This is not a popular option, but some programs such as bionic libc use it.
+static void excludeLibs(opt::InputArgList &Args, ArrayRef<InputFile *> Files) {
+ DenseSet<StringRef> Libs = getExcludeLibs(Args);
+ bool All = Libs.count("ALL");
+
+ for (InputFile *File : Files)
+ if (auto *F = dyn_cast<ArchiveFile>(File))
+ if (All || Libs.count(path::filename(F->getName())))
+ for (Symbol *Sym : F->getSymbols())
+ Sym->VersionId = VER_NDX_LOCAL;
+}
+
// 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) {
SymbolTable<ELFT> Symtab;
elf::Symtab<ELFT>::X = &Symtab;
- Target = createTarget();
- ScriptBase = Script<ELFT>::X = make<LinkerScript<ELFT>>();
+ Target = getTarget();
- Config->Rela =
- ELFT::Is64Bits || Config->EMachine == EM_X86_64 || Config->MipsN32Abi;
- Config->Mips64EL =
- (Config->EMachine == EM_MIPS && Config->EKind == ELF64LEKind);
Config->MaxPageSize = getMaxPageSize(Args);
Config->ImageBase = getImageBase(Args);
@@ -779,6 +966,16 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
if (Config->OutputFile.empty())
Config->OutputFile = "a.out";
+ // Fail early if the output file or map file is not writable. If a user has a
+ // long link, e.g. due to a large LTO link, they do not wish to run it and
+ // find that it failed because there was a mistake in their command-line.
+ if (auto E = tryCreateFile(Config->OutputFile))
+ error("cannot open output file " + Config->OutputFile + ": " + E.message());
+ if (auto E = tryCreateFile(Config->MapFile))
+ error("cannot open map file " + Config->MapFile + ": " + E.message());
+ if (ErrorCount)
+ return;
+
// Use default entry point name if no name was given via the command
// line nor linker scripts. For some reason, MIPS entry point name is
// different from others.
@@ -806,46 +1003,64 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
if (ErrorCount)
return;
+ // Handle the `--undefined <sym>` options.
Symtab.scanUndefinedFlags();
+
+ // Handle undefined symbols in DSOs.
Symtab.scanShlibUndefined();
+
+ // Handle the -exclude-libs option.
+ if (Args.hasArg(OPT_exclude_libs))
+ excludeLibs(Args, Files);
+
+ // Apply version scripts.
Symtab.scanVersionScript();
+ // Create wrapped symbols for -wrap option.
+ for (auto *Arg : Args.filtered(OPT_wrap))
+ Symtab.addSymbolWrap(Arg->getValue());
+
+ // Create alias symbols for -defsym option.
+ for (std::pair<StringRef, StringRef> &Def : getDefsym(Args))
+ Symtab.addSymbolAlias(Def.first, Def.second);
+
Symtab.addCombinedLTOObject();
if (ErrorCount)
return;
- for (auto *Arg : Args.filtered(OPT_wrap))
- Symtab.wrap(Arg->getValue());
+ // Some symbols (such as __ehdr_start) are defined lazily only when there
+ // are undefined symbols for them, so we add these to trigger that logic.
+ for (StringRef Sym : Script->Opt.ReferencedSymbols)
+ Symtab.addUndefined(Sym);
+
+ // Apply symbol renames for -wrap and -defsym
+ Symtab.applySymbolRenames();
// Now that we have a complete list of input files.
// Beyond this point, no new files are added.
// Aggregate all input sections into one place.
for (elf::ObjectFile<ELFT> *F : Symtab.getObjectFiles())
- for (InputSectionBase<ELFT> *S : F->getSections())
- if (S && S != &InputSection<ELFT>::Discarded)
- Symtab.Sections.push_back(S);
+ for (InputSectionBase *S : F->getSections())
+ if (S && S != &InputSection::Discarded)
+ InputSections.push_back(S);
for (BinaryFile *F : Symtab.getBinaryFiles())
- for (InputSectionData *S : F->getSections())
- Symtab.Sections.push_back(cast<InputSection<ELFT>>(S));
+ for (InputSectionBase *S : F->getSections())
+ InputSections.push_back(cast<InputSection>(S));
- // Do size optimizations: garbage collection and identical code folding.
+ // This adds a .comment section containing a version string. We have to add it
+ // before decompressAndMergeSections because the .comment section is a
+ // mergeable section.
+ if (!Config->Relocatable)
+ InputSections.push_back(createCommentSection<ELFT>());
+
+ // Do size optimizations: garbage collection, merging of SHF_MERGE sections
+ // and identical code folding.
if (Config->GcSections)
markLive<ELFT>();
+ decompressAndMergeSections();
if (Config->ICF)
doIcf<ELFT>();
- // MergeInputSection::splitIntoPieces needs to be called before
- // any call of MergeInputSection::getOffset. Do that.
- forEach(Symtab.Sections.begin(), Symtab.Sections.end(),
- [](InputSectionBase<ELFT> *S) {
- if (!S->Live)
- return;
- if (Decompressor::isCompressedELFSection(S->Flags, S->Name))
- S->uncompress();
- if (auto *MS = dyn_cast<MergeInputSection<ELFT>>(S))
- MS->splitIntoPieces();
- });
-
// 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 36b4052d72a..2f7d16b2505 100644
--- a/gnu/llvm/tools/lld/ELF/DriverUtils.cpp
+++ b/gnu/llvm/tools/lld/ELF/DriverUtils.cpp
@@ -16,7 +16,6 @@
#include "Driver.h"
#include "Error.h"
#include "Memory.h"
-#include "ScriptParser.h"
#include "lld/Config/Version.h"
#include "lld/Core/Reproduce.h"
#include "llvm/ADT/Optional.h"
@@ -43,9 +42,9 @@ using namespace lld::elf;
// Create table mapping all options defined in Options.td
static const opt::OptTable::Info OptInfo[] = {
-#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X6, X7, X8, X9, X10) \
- {X1, X2, X9, X10, OPT_##ID, opt::Option::KIND##Class, \
- X8, X7, OPT_##GROUP, OPT_##ALIAS, X6},
+#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \
+ {X1, X2, X10, X11, OPT_##ID, opt::Option::KIND##Class, \
+ X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12},
#include "Options.inc"
#undef OPTION
};
@@ -54,8 +53,6 @@ ELFOptTable::ELFOptTable() : OptTable(OptInfo) {}
// Parse -color-diagnostics={auto,always,never} or -no-color-diagnostics.
static bool getColorDiagnostics(opt::InputArgList &Args) {
- bool Default = (ErrorOS == &errs() && Process::StandardErrHasColors());
-
auto *Arg = Args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq,
OPT_no_color_diagnostics);
if (!Arg)
@@ -67,7 +64,7 @@ static bool getColorDiagnostics(opt::InputArgList &Args) {
StringRef S = Arg->getValue();
if (S == "auto")
- return Default;
+ return ErrorOS->has_colors();
if (S == "always")
return true;
if (S != "never")
@@ -129,10 +126,11 @@ void elf::printHelp(const char *Argv0) {
// 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-powerpc "
- << "elf32-tradbigmips elf32-tradlittlemips elf32-x86-64 "
- << "elf64-amdgpu elf64-littleaarch64 elf64-powerpc "
- << "elf64-tradbigmips elf64-tradlittlemips elf64-x86-64\n";
+ << "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";
}
// Reconstructs command line arguments so that so that you can re-run
@@ -149,6 +147,13 @@ std::string elf::createResponseFile(const opt::InputArgList &Args) {
case OPT_INPUT:
OS << quote(rewritePath(Arg->getValue())) << "\n";
break;
+ case OPT_o:
+ // If -o path contains directories, "lld @response.txt" will likely
+ // fail because the archive we are creating doesn't contain empty
+ // directories for the output path (-o doesn't create directories).
+ // Strip directories to prevent the issue.
+ OS << "-o " << quote(sys::path::filename(Arg->getValue())) << "\n";
+ break;
case OPT_L:
case OPT_dynamic_list:
case OPT_rpath:
diff --git a/gnu/llvm/tools/lld/ELF/Options.td b/gnu/llvm/tools/lld/ELF/Options.td
index 77ed4c7e466..1400a206bdf 100644
--- a/gnu/llvm/tools/lld/ELF/Options.td
+++ b/gnu/llvm/tools/lld/ELF/Options.td
@@ -22,6 +22,11 @@ def build_id: F<"build-id">, HelpText<"Generate build ID note">;
def build_id_eq: J<"build-id=">, HelpText<"Generate build ID note">;
+def compress_debug_sections : J<"compress-debug-sections=">,
+ HelpText<"Compress DWARF debug sections">;
+
+def defsym: J<"defsym=">, HelpText<"Define a symbol alias">;
+
def L: JoinedOrSeparate<["-"], "L">, MetaVarName<"<dir>">,
HelpText<"Add a directory to the library search path">;
@@ -48,6 +53,8 @@ def color_diagnostics_eq: J<"color-diagnostics=">,
def define_common: F<"define-common">,
HelpText<"Assign space to common symbols">;
+def demangle: F<"demangle">, HelpText<"Demangle symbol names">;
+
def disable_new_dtags: F<"disable-new-dtags">,
HelpText<"Disable new dynamic tags">;
@@ -68,6 +75,8 @@ def dynamic_list: S<"dynamic-list">,
def eh_frame_hdr: F<"eh-frame-hdr">,
HelpText<"Request creation of .eh_frame_hdr section and PT_GNU_EH_FRAME segment header">;
+def emit_relocs: F<"emit-relocs">, HelpText<"Generate relocations in output">;
+
def enable_new_dtags: F<"enable-new-dtags">,
HelpText<"Enable new dynamic tags">;
@@ -80,6 +89,12 @@ def entry: S<"entry">, MetaVarName<"<entry>">,
def error_limit: S<"error-limit">,
HelpText<"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">;
+
+def exclude_libs: S<"exclude-libs">,
+ HelpText<"Exclude static libraries from automatic export">;
+
def export_dynamic: F<"export-dynamic">,
HelpText<"Put symbols in the dynamic symbol table">;
@@ -89,6 +104,8 @@ def export_dynamic_symbol: S<"export-dynamic-symbol">,
def fatal_warnings: F<"fatal-warnings">,
HelpText<"Treat warnings as errors">;
+def filter: J<"filter=">, HelpText<"Set DT_FILTER field to the specified name">;
+
def fini: S<"fini">, MetaVarName<"<symbol>">,
HelpText<"Specify a finalizer function">;
@@ -109,7 +126,9 @@ def hash_style: S<"hash-style">,
def help: F<"help">, HelpText<"Print option help">;
-def icf: F<"icf=all">, HelpText<"Enable identical code folding">;
+def icf_all: F<"icf=all">, HelpText<"Enable identical code folding">;
+
+def icf_none: F<"icf=none">, HelpText<"Disable identical code folding">;
def image_base : J<"image-base=">, HelpText<"Set the base address">;
@@ -124,6 +143,8 @@ def lto_O: J<"lto-O">, MetaVarName<"<opt-level>">,
def m: JoinedOrSeparate<["-"], "m">, HelpText<"Set target emulation">;
+def Map: JS<"Map">, HelpText<"Print a link map to the specified file">;
+
def nostdlib: F<"nostdlib">,
HelpText<"Only search directories specified on the command line">;
@@ -139,6 +160,12 @@ def no_define_common: F<"no-define-common">,
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_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">;
@@ -170,7 +197,7 @@ def o: JoinedOrSeparate<["-"], "o">, MetaVarName<"<path>">,
def oformat: Separate<["--"], "oformat">, MetaVarName<"<format>">,
HelpText<"Specify the binary format for the output object file">;
-def omagic: F<"omagic">, MetaVarName<"<magic>">,
+def omagic: Flag<["--"], "omagic">, MetaVarName<"<magic>">,
HelpText<"Set the text and data sections to be readable and writable">;
def pie: F<"pie">, HelpText<"Create a position independent executable">;
@@ -178,6 +205,9 @@ def pie: F<"pie">, HelpText<"Create a position independent executable">;
def print_gc_sections: F<"print-gc-sections">,
HelpText<"List removed unused sections">;
+def print_map: F<"print-map">,
+ HelpText<"Print a link map to the standard output">;
+
def reproduce: S<"reproduce">,
HelpText<"Dump linker invocation and input files for debugging">;
@@ -221,7 +251,7 @@ def threads: F<"threads">, HelpText<"Run the linker multi-threaded">;
def trace: F<"trace">, HelpText<"Print the names of the input files">;
-def trace_symbol : J<"trace-symbol=">, HelpText<"Trace references to symbols">;
+def trace_symbol : S<"trace-symbol">, HelpText<"Trace references to symbols">;
def undefined: S<"undefined">,
HelpText<"Force undefined symbol during linking">;
@@ -244,6 +274,9 @@ def version_script: S<"version-script">,
def warn_common: F<"warn-common">,
HelpText<"Warn about duplicate common symbols">;
+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">;
@@ -264,25 +297,32 @@ def alias_L__library_path: J<"library-path=">, Alias<L>;
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_defsym: S<"defsym">, Alias<defsym>;
def alias_discard_all_x: Flag<["-"], "x">, Alias<discard_all>;
def alias_discard_locals_X: Flag<["-"], "X">, Alias<discard_locals>;
def alias_dynamic_list: J<"dynamic-list=">, Alias<dynamic_list>;
+def alias_emit_relocs: Flag<["-"], "q">, Alias<emit_relocs>;
def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias<entry>;
def alias_entry_entry: J<"entry=">, Alias<entry>;
def alias_error_limit: J<"error-limit=">, Alias<error_limit>;
+def alias_exclude_libs: J<"exclude-libs=">, Alias<exclude_libs>;
def alias_export_dynamic_E: Flag<["-"], "E">, Alias<export_dynamic>;
def alias_export_dynamic_symbol: J<"export-dynamic-symbol=">,
Alias<export_dynamic_symbol>;
+def alias_filter: Separate<["-"], "F">, Alias<filter>;
def alias_fini_fini: J<"fini=">, Alias<fini>;
def alias_format_b: S<"b">, Alias<format>;
def alias_hash_style_hash_style: J<"hash-style=">, Alias<hash_style>;
def alias_init_init: J<"init=">, Alias<init>;
def alias_l__library: J<"library=">, Alias<l>;
+def alias_Map_eq: J<"Map=">, Alias<Map>;
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_reproduce_eq: J<"reproduce=">, Alias<reproduce>;
def alias_retain_symbols_file: S<"retain-symbols-file">, Alias<retain_symbols_file>;
def alias_rpath_R: JoinedOrSeparate<["-"], "R">, Alias<rpath>;
def alias_rpath_rpath: J<"rpath=">, Alias<rpath>;
@@ -297,12 +337,14 @@ def alias_strip_debug_S: Flag<["-"], "S">, Alias<strip_debug>;
def alias_Tbss: J<"Tbss=">, Alias<Tbss>;
def alias_Tdata: J<"Tdata=">, Alias<Tdata>;
def alias_trace: Flag<["-"], "t">, Alias<trace>;
+def trace_trace_symbol_eq : J<"trace-symbol=">, Alias<trace_symbol>;
def alias_trace_symbol_y : JoinedOrSeparate<["-"], "y">, Alias<trace_symbol>;
def alias_Ttext: J<"Ttext=">, Alias<Ttext>;
def alias_Ttext_segment: S<"Ttext-segment">, Alias<Ttext>;
def alias_Ttext_segment_eq: J<"Ttext-segment=">, Alias<Ttext>;
def alias_undefined_eq: J<"undefined=">, Alias<undefined>;
def alias_undefined_u: JoinedOrSeparate<["-"], "u">, Alias<undefined>;
+def alias_version_script_eq: J<"version-script=">, Alias<version_script>;
def alias_version_V: Flag<["-"], "V">, Alias<version>;
def alias_wrap_wrap: J<"wrap=">, Alias<wrap>;
@@ -314,6 +356,26 @@ def end_group_paren: Flag<["-"], ")">;
def start_group: F<"start-group">;
def start_group_paren: Flag<["-"], "(">;
+// 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_newpm_passes: J<"lto-newpm-passes=">,
+ HelpText<"Passes to run during LTO">;
+def lto_partitions: J<"lto-partitions=">,
+ HelpText<"Number of LTO codegen partitions">;
+def disable_verify: F<"disable-verify">;
+def mllvm: S<"mllvm">;
+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">;
+def save_temps: F<"save-temps">;
+def thinlto_cache_dir: J<"thinlto-cache-dir=">,
+ HelpText<"Path to ThinLTO cached object file directory">;
+def thinlto_cache_policy: S<"thinlto-cache-policy">,
+ HelpText<"Pruning policy for the ThinLTO cache">;
+def thinlto_jobs: J<"thinlto-jobs=">, HelpText<"Number of ThinLTO jobs">;
+
// 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
@@ -329,17 +391,13 @@ def plugin_opt_eq: J<"plugin-opt=">;
// Options listed below are silently ignored for now for compatibility.
def allow_shlib_undefined: F<"allow-shlib-undefined">;
def cref: Flag<["--"], "cref">;
-def demangle: F<"demangle">;
def detect_odr_violations: F<"detect-odr-violations">;
def g: Flag<["-"], "g">;
-def M: Flag<["-"], "M">;
-def Map: JS<"Map">;
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">,
Alias<no_add_needed>;
-def no_dynamic_linker: F<"no-dynamic-linker">;
-def no_fatal_warnings: F<"no-fatal-warnings">;
+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">;
@@ -354,19 +412,3 @@ def EL : F<"EL">;
def G: JoinedOrSeparate<["-"], "G">;
def Qy : F<"Qy">;
-// Aliases for ignored options
-def alias_Map_eq: J<"Map=">, Alias<Map>;
-def alias_version_script_version_script: J<"version-script=">,
- Alias<version_script>;
-
-// 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_newpm_passes: J<"lto-newpm-passes=">,
- HelpText<"Passes to run during LTO">;
-def lto_partitions: J<"lto-partitions=">,
- HelpText<"Number of LTO codegen partitions">;
-def disable_verify: F<"disable-verify">;
-def mllvm: S<"mllvm">;
-def save_temps: F<"save-temps">;
-def thinlto_jobs: J<"thinlto-jobs=">, HelpText<"Number of ThinLTO jobs">;
diff --git a/gnu/llvm/tools/lld/ELF/OutputSections.cpp b/gnu/llvm/tools/lld/ELF/OutputSections.cpp
index edcc0f186b3..abe54816586 100644
--- a/gnu/llvm/tools/lld/ELF/OutputSections.cpp
+++ b/gnu/llvm/tools/lld/ELF/OutputSections.cpp
@@ -9,7 +9,6 @@
#include "OutputSections.h"
#include "Config.h"
-#include "EhFrame.h"
#include "LinkerScript.h"
#include "Memory.h"
#include "Strings.h"
@@ -17,7 +16,7 @@
#include "SyntheticSections.h"
#include "Target.h"
#include "Threads.h"
-#include "llvm/Support/Dwarf.h"
+#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/SHA1.h"
@@ -31,15 +30,21 @@ using namespace llvm::ELF;
using namespace lld;
using namespace lld::elf;
-OutputSectionBase::OutputSectionBase(StringRef Name, uint32_t Type,
- uint64_t Flags)
- : Name(Name) {
- this->Type = Type;
- this->Flags = Flags;
- this->Addralign = 1;
-}
-
-uint32_t OutputSectionBase::getPhdrFlags() const {
+uint8_t Out::First;
+OutputSection *Out::Opd;
+uint8_t *Out::OpdBuf;
+PhdrEntry *Out::TlsPhdr;
+OutputSection *Out::DebugInfo;
+OutputSection *Out::ElfHeader;
+OutputSection *Out::ProgramHeaders;
+OutputSection *Out::PreinitArray;
+OutputSection *Out::InitArray;
+OutputSection *Out::FiniArray;
+
+std::vector<OutputSection *> elf::OutputSections;
+std::vector<OutputSectionCommand *> elf::OutputSectionCommands;
+
+uint32_t OutputSection::getPhdrFlags() const {
uint32_t Ret = PF_R;
if (Flags & SHF_WRITE)
Ret |= PF_W;
@@ -49,9 +54,9 @@ uint32_t OutputSectionBase::getPhdrFlags() const {
}
template <class ELFT>
-void OutputSectionBase::writeHeaderTo(typename ELFT::Shdr *Shdr) {
+void OutputSection::writeHeaderTo(typename ELFT::Shdr *Shdr) {
Shdr->sh_entsize = Entsize;
- Shdr->sh_addralign = Addralign;
+ Shdr->sh_addralign = Alignment;
Shdr->sh_type = Type;
Shdr->sh_offset = Offset;
Shdr->sh_flags = Flags;
@@ -62,490 +67,41 @@ void OutputSectionBase::writeHeaderTo(typename ELFT::Shdr *Shdr) {
Shdr->sh_name = ShName;
}
-template <class ELFT> static uint64_t getEntsize(uint32_t Type) {
- switch (Type) {
- case SHT_RELA:
- return sizeof(typename ELFT::Rela);
- case SHT_REL:
- return sizeof(typename ELFT::Rel);
- case SHT_MIPS_REGINFO:
- return sizeof(Elf_Mips_RegInfo<ELFT>);
- case SHT_MIPS_OPTIONS:
- return sizeof(Elf_Mips_Options<ELFT>) + sizeof(Elf_Mips_RegInfo<ELFT>);
- case SHT_MIPS_ABIFLAGS:
- return sizeof(Elf_Mips_ABIFlags<ELFT>);
- default:
- return 0;
- }
-}
+OutputSection::OutputSection(StringRef Name, uint32_t Type, uint64_t Flags)
+ : SectionBase(Output, Name, Flags, /*Entsize*/ 0, /*Alignment*/ 1, Type,
+ /*Info*/ 0,
+ /*Link*/ 0),
+ SectionIndex(INT_MAX) {}
-template <class ELFT>
-OutputSection<ELFT>::OutputSection(StringRef Name, uint32_t Type, uintX_t Flags)
- : OutputSectionBase(Name, Type, Flags) {
- this->Entsize = getEntsize<ELFT>(Type);
-}
-
-template <typename ELFT>
-static bool compareByFilePosition(InputSection<ELFT> *A,
- InputSection<ELFT> *B) {
- // Synthetic doesn't have link order dependecy, stable_sort will keep it last
- if (A->kind() == InputSectionData::Synthetic ||
- B->kind() == InputSectionData::Synthetic)
- return false;
- auto *LA = cast<InputSection<ELFT>>(A->getLinkOrderDep());
- auto *LB = cast<InputSection<ELFT>>(B->getLinkOrderDep());
- OutputSectionBase *AOut = LA->OutSec;
- OutputSectionBase *BOut = LB->OutSec;
- if (AOut != BOut)
- return AOut->SectionIndex < BOut->SectionIndex;
- return LA->OutSecOff < LB->OutSecOff;
+static uint64_t updateOffset(uint64_t Off, InputSection *S) {
+ Off = alignTo(Off, S->Alignment);
+ S->OutSecOff = Off;
+ return Off + S->getSize();
}
-template <class ELFT> void OutputSection<ELFT>::finalize() {
- if ((this->Flags & SHF_LINK_ORDER) && !this->Sections.empty()) {
- std::sort(Sections.begin(), Sections.end(), compareByFilePosition<ELFT>);
- Size = 0;
- assignOffsets();
-
- // We must preserve the link order dependency of sections with the
- // SHF_LINK_ORDER flag. The dependency is indicated by the sh_link field. We
- // need to translate the InputSection sh_link to the OutputSection sh_link,
- // all InputSections in the OutputSection have the same dependency.
- if (auto *D = this->Sections.front()->getLinkOrderDep())
- this->Link = D->OutSec->SectionIndex;
- }
-
- uint32_t Type = this->Type;
- if (!Config->Relocatable || (Type != SHT_RELA && Type != SHT_REL))
- return;
-
- this->Link = In<ELFT>::SymTab->OutSec->SectionIndex;
- // sh_info for SHT_REL[A] sections should contain the section header index of
- // the section to which the relocation applies.
- InputSectionBase<ELFT> *S = Sections[0]->getRelocatedSection();
- this->Info = S->OutSec->SectionIndex;
-}
-
-template <class ELFT>
-void OutputSection<ELFT>::addSection(InputSectionData *C) {
- assert(C->Live);
- auto *S = cast<InputSection<ELFT>>(C);
+void OutputSection::addSection(InputSection *S) {
+ assert(S->Live);
Sections.push_back(S);
- S->OutSec = this;
+ S->Parent = this;
this->updateAlignment(S->Alignment);
- // Keep sh_entsize value of the input section to be able to perform merging
- // later during a final linking using the generated relocatable object.
- if (Config->Relocatable && (S->Flags & SHF_MERGE))
- this->Entsize = S->Entsize;
-}
-
-// This function is called after we sort input sections
-// and scan relocations to setup sections' offsets.
-template <class ELFT> void OutputSection<ELFT>::assignOffsets() {
- uintX_t Off = this->Size;
- for (InputSection<ELFT> *S : Sections) {
- Off = alignTo(Off, S->Alignment);
- S->OutSecOff = Off;
- Off += S->getSize();
- }
- this->Size = Off;
-}
-
-template <class ELFT>
-void OutputSection<ELFT>::sort(
- std::function<int(InputSection<ELFT> *S)> Order) {
- typedef std::pair<unsigned, InputSection<ELFT> *> Pair;
- auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; };
-
- std::vector<Pair> V;
- for (InputSection<ELFT> *S : Sections)
- V.push_back({Order(S), S});
- std::stable_sort(V.begin(), V.end(), Comp);
- Sections.clear();
- for (Pair &P : V)
- Sections.push_back(P.second);
-}
-
-// 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
-// because the compiler keeps the original initialization order in a
-// translation unit and we need to respect that.
-// For more detail, read the section of the GCC's manual about init_priority.
-template <class ELFT> void OutputSection<ELFT>::sortInitFini() {
- // Sort sections by priority.
- sort([](InputSection<ELFT> *S) { return getPriority(S->Name); });
-}
-
-// Returns true if S matches /Filename.?\.o$/.
-static bool isCrtBeginEnd(StringRef S, StringRef Filename) {
- if (!S.endswith(".o"))
- return false;
- S = S.drop_back(2);
- if (S.endswith(Filename))
- return true;
- return !S.empty() && S.drop_back().endswith(Filename);
-}
-
-static bool isCrtbegin(StringRef S) { return isCrtBeginEnd(S, "crtbegin"); }
-static bool isCrtend(StringRef S) { return isCrtBeginEnd(S, "crtend"); }
-
-// .ctors and .dtors are sorted by this priority from highest to lowest.
-//
-// 1. The section was contained in crtbegin (crtbegin contains
-// some sentinel value in its .ctors and .dtors so that the runtime
-// can find the beginning of the sections.)
-//
-// 2. The section has an optional priority value in the form of ".ctors.N"
-// or ".dtors.N" where N is a number. Unlike .{init,fini}_array,
-// they are compared as string rather than number.
-//
-// 3. The section is just ".ctors" or ".dtors".
-//
-// 4. The section was contained in crtend, which contains an end marker.
-//
-// In an ideal world, we don't need this function because .init_array and
-// .ctors are duplicate features (and .init_array is newer.) However, there
-// are too many real-world use cases of .ctors, so we had no choice to
-// support that with this rather ad-hoc semantics.
-template <class ELFT>
-static bool compCtors(const InputSection<ELFT> *A,
- const InputSection<ELFT> *B) {
- bool BeginA = isCrtbegin(A->getFile()->getName());
- bool BeginB = isCrtbegin(B->getFile()->getName());
- if (BeginA != BeginB)
- return BeginA;
- bool EndA = isCrtend(A->getFile()->getName());
- bool EndB = isCrtend(B->getFile()->getName());
- if (EndA != EndB)
- return EndB;
- StringRef X = A->Name;
- StringRef Y = B->Name;
- assert(X.startswith(".ctors") || X.startswith(".dtors"));
- 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;
-}
-
-// Sorts input sections by the special rules for .ctors and .dtors.
-// Unfortunately, the rules are different from the one for .{init,fini}_array.
-// Read the comment above.
-template <class ELFT> void OutputSection<ELFT>::sortCtorsDtors() {
- std::stable_sort(Sections.begin(), Sections.end(), compCtors<ELFT>);
-}
-
-// Fill [Buf, Buf + Size) with Filler. Filler is written in big
-// endian order. This is used for linker script "=fillexp" command.
-void fill(uint8_t *Buf, size_t Size, uint32_t Filler) {
- uint8_t V[4];
- write32be(V, Filler);
- size_t I = 0;
- for (; I + 4 < Size; I += 4)
- memcpy(Buf + I, V, 4);
- memcpy(Buf + I, V, Size - I);
-}
-
-template <class ELFT> void OutputSection<ELFT>::writeTo(uint8_t *Buf) {
- Loc = Buf;
- if (uint32_t Filler = Script<ELFT>::X->getFiller(this->Name))
- fill(Buf, this->Size, Filler);
-
- auto Fn = [=](InputSection<ELFT> *IS) { IS->writeTo(Buf); };
- forEach(Sections.begin(), Sections.end(), Fn);
-
- // Linker scripts may have BYTE()-family commands with which you
- // can write arbitrary bytes to the output. Process them if any.
- Script<ELFT>::X->writeDataBytes(this->Name, Buf);
-}
-
-template <class ELFT>
-EhOutputSection<ELFT>::EhOutputSection()
- : OutputSectionBase(".eh_frame", SHT_PROGBITS, SHF_ALLOC) {}
-
-// Search for an existing CIE record or create a new one.
-// CIE records from input object files are uniquified by their contents
-// and where their relocations point to.
-template <class ELFT>
-template <class RelTy>
-CieRecord *EhOutputSection<ELFT>::addCie(EhSectionPiece &Piece,
- ArrayRef<RelTy> Rels) {
- auto *Sec = cast<EhInputSection<ELFT>>(Piece.ID);
- const endianness E = ELFT::TargetEndianness;
- if (read32<E>(Piece.data().data() + 4) != 0)
- fatal(toString(Sec) + ": CIE expected at beginning of .eh_frame");
-
- SymbolBody *Personality = nullptr;
- unsigned FirstRelI = Piece.FirstRelocation;
- if (FirstRelI != (unsigned)-1)
- Personality = &Sec->getFile()->getRelocTargetSym(Rels[FirstRelI]);
-
- // Search for an existing CIE by CIE contents/relocation target pair.
- CieRecord *Cie = &CieMap[{Piece.data(), Personality}];
-
- // If not found, create a new one.
- if (Cie->Piece == nullptr) {
- Cie->Piece = &Piece;
- Cies.push_back(Cie);
- }
- return Cie;
-}
-
-// There is one FDE per function. Returns true if a given FDE
-// points to a live function.
-template <class ELFT>
-template <class RelTy>
-bool EhOutputSection<ELFT>::isFdeLive(EhSectionPiece &Piece,
- ArrayRef<RelTy> Rels) {
- auto *Sec = cast<EhInputSection<ELFT>>(Piece.ID);
- unsigned FirstRelI = Piece.FirstRelocation;
- if (FirstRelI == (unsigned)-1)
- fatal(toString(Sec) + ": FDE doesn't reference another section");
- const RelTy &Rel = Rels[FirstRelI];
- SymbolBody &B = Sec->getFile()->getRelocTargetSym(Rel);
- auto *D = dyn_cast<DefinedRegular<ELFT>>(&B);
- if (!D || !D->Section)
- return false;
- InputSectionBase<ELFT> *Target = D->Section->Repl;
- return Target && Target->Live;
-}
-
-// .eh_frame is a sequence of CIE or FDE records. In general, there
-// is one CIE record per input object file which is followed by
-// a list of FDEs. This function searches an existing CIE or create a new
-// one and associates FDEs to the CIE.
-template <class ELFT>
-template <class RelTy>
-void EhOutputSection<ELFT>::addSectionAux(EhInputSection<ELFT> *Sec,
- ArrayRef<RelTy> Rels) {
- const endianness E = ELFT::TargetEndianness;
-
- DenseMap<size_t, CieRecord *> OffsetToCie;
- 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<E>(Piece.data().data() + 4);
- if (ID == 0) {
- OffsetToCie[Offset] = addCie(Piece, Rels);
- continue;
- }
-
- uint32_t CieOffset = Offset + 4 - ID;
- CieRecord *Cie = OffsetToCie[CieOffset];
- if (!Cie)
- fatal(toString(Sec) + ": invalid CIE reference");
-
- if (!isFdeLive(Piece, Rels))
- continue;
- Cie->FdePieces.push_back(&Piece);
- NumFdes++;
- }
-}
-
-template <class ELFT>
-void EhOutputSection<ELFT>::addSection(InputSectionData *C) {
- auto *Sec = cast<EhInputSection<ELFT>>(C);
- Sec->OutSec = this;
- this->updateAlignment(Sec->Alignment);
- Sections.push_back(Sec);
-
- // .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();
- if (Sec->Pieces.empty())
- return;
-
- if (Sec->NumRelocations) {
- if (Sec->AreRelocsRela)
- addSectionAux(Sec, Sec->relas());
- else
- addSectionAux(Sec, Sec->rels());
- return;
- }
- addSectionAux(Sec, makeArrayRef<Elf_Rela>(nullptr, nullptr));
-}
-
-template <class ELFT>
-static void writeCieFde(uint8_t *Buf, ArrayRef<uint8_t> D) {
- memcpy(Buf, D.data(), D.size());
- // Fix the size field. -4 since size does not include the size field itself.
- const endianness E = ELFT::TargetEndianness;
- write32<E>(Buf, alignTo(D.size(), sizeof(typename ELFT::uint)) - 4);
-}
-
-template <class ELFT> void EhOutputSection<ELFT>::finalize() {
- if (this->Size)
- return; // Already finalized.
-
- size_t Off = 0;
- for (CieRecord *Cie : Cies) {
- Cie->Piece->OutputOff = Off;
- Off += alignTo(Cie->Piece->size(), sizeof(uintX_t));
-
- for (EhSectionPiece *Fde : Cie->FdePieces) {
- Fde->OutputOff = Off;
- Off += alignTo(Fde->size(), sizeof(uintX_t));
- }
- }
- this->Size = Off + 4;
-}
-
-template <class ELFT> static uint64_t readFdeAddr(uint8_t *Buf, int Size) {
- const endianness E = ELFT::TargetEndianness;
- switch (Size) {
- case DW_EH_PE_udata2:
- return read16<E>(Buf);
- case DW_EH_PE_udata4:
- return read32<E>(Buf);
- case DW_EH_PE_udata8:
- return read64<E>(Buf);
- case DW_EH_PE_absptr:
- if (ELFT::Is64Bits)
- return read64<E>(Buf);
- return read32<E>(Buf);
- }
- fatal("unknown FDE size encoding");
-}
-
-// Returns the VA to which a given FDE (on a mmap'ed buffer) is applied to.
-// We need it to create .eh_frame_hdr section.
-template <class ELFT>
-typename ELFT::uint EhOutputSection<ELFT>::getFdePc(uint8_t *Buf, size_t FdeOff,
- uint8_t Enc) {
- // The starting address to which this FDE applies is
- // stored at FDE + 8 byte.
- size_t Off = FdeOff + 8;
- uint64_t Addr = readFdeAddr<ELFT>(Buf + Off, Enc & 0x7);
- if ((Enc & 0x70) == DW_EH_PE_absptr)
- return Addr;
- if ((Enc & 0x70) == DW_EH_PE_pcrel)
- return Addr + this->Addr + Off;
- fatal("unknown FDE size relative encoding");
-}
-
-template <class ELFT> void EhOutputSection<ELFT>::writeTo(uint8_t *Buf) {
- const endianness E = ELFT::TargetEndianness;
- for (CieRecord *Cie : Cies) {
- size_t CieOffset = Cie->Piece->OutputOff;
- writeCieFde<ELFT>(Buf + CieOffset, Cie->Piece->data());
-
- for (EhSectionPiece *Fde : Cie->FdePieces) {
- size_t Off = Fde->OutputOff;
- writeCieFde<ELFT>(Buf + Off, Fde->data());
-
- // FDE's second word should have the offset to an associated CIE.
- // Write it.
- write32<E>(Buf + Off + 4, Off + 4 - CieOffset);
- }
- }
-
- for (EhInputSection<ELFT> *S : Sections)
- S->relocate(Buf, nullptr);
-
- // Construct .eh_frame_hdr. .eh_frame_hdr is a binary search table
- // to get a FDE from an address to which FDE is applied. So here
- // we obtain two addresses and pass them to EhFrameHdr object.
- if (In<ELFT>::EhFrameHdr) {
- for (CieRecord *Cie : Cies) {
- uint8_t Enc = getFdeEncoding<ELFT>(Cie->Piece);
- for (SectionPiece *Fde : Cie->FdePieces) {
- uintX_t Pc = getFdePc(Buf, Fde->OutputOff, Enc);
- uintX_t FdeVA = this->Addr + Fde->OutputOff;
- In<ELFT>::EhFrameHdr->addFde(Pc, FdeVA);
- }
- }
- }
-}
-
-template <class ELFT>
-MergeOutputSection<ELFT>::MergeOutputSection(StringRef Name, uint32_t Type,
- uintX_t Flags, uintX_t Alignment)
- : OutputSectionBase(Name, Type, Flags),
- Builder(StringTableBuilder::RAW, Alignment) {}
-
-template <class ELFT> void MergeOutputSection<ELFT>::writeTo(uint8_t *Buf) {
- Builder.write(Buf);
-}
-
-template <class ELFT>
-void MergeOutputSection<ELFT>::addSection(InputSectionData *C) {
- auto *Sec = cast<MergeInputSection<ELFT>>(C);
- Sec->OutSec = this;
- this->updateAlignment(Sec->Alignment);
- this->Entsize = Sec->Entsize;
- Sections.push_back(Sec);
-}
-
-template <class ELFT> bool MergeOutputSection<ELFT>::shouldTailMerge() const {
- return (this->Flags & SHF_STRINGS) && Config->Optimize >= 2;
-}
-
-template <class ELFT> void MergeOutputSection<ELFT>::finalizeTailMerge() {
- // Add all string pieces to the string table builder to create section
- // contents.
- for (MergeInputSection<ELFT> *Sec : Sections)
- for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
- if (Sec->Pieces[I].Live)
- Builder.add(Sec->getData(I));
-
- // Fix the string table content. After this, the contents will never change.
- Builder.finalize();
- this->Size = Builder.getSize();
-
- // finalize() fixed tail-optimized strings, so we can now get
- // offsets of strings. Get an offset for each string and save it
- // to a corresponding StringPiece for easy access.
- for (MergeInputSection<ELFT> *Sec : Sections)
- for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
- if (Sec->Pieces[I].Live)
- Sec->Pieces[I].OutputOff = Builder.getOffset(Sec->getData(I));
-}
-
-template <class ELFT> void MergeOutputSection<ELFT>::finalizeNoTailMerge() {
- // Add all string pieces to the string table builder to create section
- // contents. Because we are not tail-optimizing, offsets of strings are
- // fixed when they are added to the builder (string table builder contains
- // a hash table from strings to offsets).
- for (MergeInputSection<ELFT> *Sec : Sections)
- for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
- if (Sec->Pieces[I].Live)
- Sec->Pieces[I].OutputOff = Builder.add(Sec->getData(I));
-
- Builder.finalizeInOrder();
- this->Size = Builder.getSize();
-}
+ // The actual offsets will be computed by assignAddresses. For now, use
+ // crude approximation so that it is at least easy for other code to know the
+ // section order. It is also used to calculate the output section size early
+ // for compressed debug sections.
+ this->Size = updateOffset(Size, S);
-template <class ELFT> void MergeOutputSection<ELFT>::finalize() {
- if (shouldTailMerge())
- finalizeTailMerge();
- else
- finalizeNoTailMerge();
+ // If this section contains a table of fixed-size entries, sh_entsize
+ // holds the element size. Consequently, if this contains two or more
+ // input sections, all of them must have the same sh_entsize. However,
+ // you can put different types of input sections into one output
+ // sectin by using linker scripts. I don't know what to do here.
+ // Probably we sholuld handle that as an error. But for now we just
+ // pick the largest sh_entsize.
+ this->Entsize = std::max(this->Entsize, S->Entsize);
}
-template <class ELFT>
-static typename ELFT::uint getOutFlags(InputSectionBase<ELFT> *S) {
- return S->Flags & ~SHF_GROUP & ~SHF_COMPRESSED;
-}
-
-namespace llvm {
-template <> struct DenseMapInfo<lld::elf::SectionKey> {
- static lld::elf::SectionKey getEmptyKey();
- static lld::elf::SectionKey getTombstoneKey();
- static unsigned getHashValue(const lld::elf::SectionKey &Val);
- static bool isEqual(const lld::elf::SectionKey &LHS,
- const lld::elf::SectionKey &RHS);
-};
-}
-
-template <class ELFT>
-static SectionKey createKey(InputSectionBase<ELFT> *C, StringRef OutsecName) {
+static SectionKey createKey(InputSectionBase *C, StringRef OutsecName) {
// The ELF spec just says
// ----------------------------------------------------------------
// In the first phase, input sections that match in name, type and
@@ -588,81 +144,109 @@ static SectionKey createKey(InputSectionBase<ELFT> *C, StringRef OutsecName) {
//
// Given the above issues, we instead merge sections by name and error on
// incompatible types and flags.
- //
- // The exception being SHF_MERGE, where we create different output sections
- // for each alignment. This makes each output section simple. In case of
- // relocatable object generation we do not try to perform merging and treat
- // SHF_MERGE sections as regular ones, but also create different output
- // sections for them to allow merging at final linking stage.
- //
- // Fortunately, creating symbols in the middle of a merge section is not
- // supported by bfd or gold, so the SHF_MERGE exception should not cause
- // problems with most linker scripts.
- typedef typename ELFT::uint uintX_t;
- uintX_t Flags = C->Flags & (SHF_MERGE | SHF_STRINGS);
-
- uintX_t Alignment = 0;
- if (isa<MergeInputSection<ELFT>>(C) ||
- (Config->Relocatable && (C->Flags & SHF_MERGE)))
- Alignment = std::max<uintX_t>(C->Alignment, C->Entsize);
+ uint32_t Alignment = 0;
+ uint64_t Flags = 0;
+ if (Config->Relocatable && (C->Flags & SHF_MERGE)) {
+ Alignment = std::max<uint64_t>(C->Alignment, C->Entsize);
+ Flags = C->Flags & (SHF_MERGE | SHF_STRINGS);
+ }
return SectionKey{OutsecName, Flags, Alignment};
}
-template <class ELFT> OutputSectionFactory<ELFT>::OutputSectionFactory() {}
+OutputSectionFactory::OutputSectionFactory() {}
-template <class ELFT> OutputSectionFactory<ELFT>::~OutputSectionFactory() {}
+static uint64_t getIncompatibleFlags(uint64_t Flags) {
+ return Flags & (SHF_ALLOC | SHF_TLS);
+}
-template <class ELFT>
-std::pair<OutputSectionBase *, bool>
-OutputSectionFactory<ELFT>::create(InputSectionBase<ELFT> *C,
- StringRef OutsecName) {
- SectionKey Key = createKey(C, OutsecName);
- return create(Key, C);
+// We allow sections of types listed below to merged into a
+// single progbits section. This is typically done by linker
+// scripts. Merging nobits and progbits will force disk space
+// to be allocated for nobits sections. Other ones don't require
+// any special treatment on top of progbits, so there doesn't
+// seem to be a harm in merging them.
+static bool canMergeToProgbits(unsigned Type) {
+ return Type == SHT_NOBITS || Type == SHT_PROGBITS || Type == SHT_INIT_ARRAY ||
+ Type == SHT_PREINIT_ARRAY || Type == SHT_FINI_ARRAY ||
+ Type == SHT_NOTE;
}
-static uint64_t getIncompatibleFlags(uint64_t Flags) {
- return Flags & (SHF_ALLOC | SHF_TLS);
+void elf::reportDiscarded(InputSectionBase *IS) {
+ if (!Config->PrintGcSections)
+ return;
+ message("removing unused section from '" + IS->Name + "' in file '" +
+ IS->File->getName() + "'");
+}
+
+void OutputSectionFactory::addInputSec(InputSectionBase *IS,
+ StringRef OutsecName) {
+ // Sections with the SHT_GROUP attribute reach here only when the - r option
+ // is given. Such sections define "section groups", and InputFiles.cpp has
+ // dedup'ed section groups by their signatures. For the -r, we want to pass
+ // through all SHT_GROUP sections without merging them because merging them
+ // creates broken section contents.
+ if (IS->Type == SHT_GROUP) {
+ OutputSection *Out = nullptr;
+ addInputSec(IS, OutsecName, Out);
+ return;
+ }
+
+ // Imagine .zed : { *(.foo) *(.bar) } script. Both foo and bar may have
+ // relocation sections .rela.foo and .rela.bar for example. Most tools do
+ // not allow multiple REL[A] sections for output section. Hence we
+ // should combine these relocation sections into single output.
+ // We skip synthetic sections because it can be .rela.dyn/.rela.plt or any
+ // other REL[A] sections created by linker itself.
+ if (!isa<SyntheticSection>(IS) &&
+ (IS->Type == SHT_REL || IS->Type == SHT_RELA)) {
+ auto *Sec = cast<InputSection>(IS);
+ OutputSection *Out = Sec->getRelocatedSection()->getOutputSection();
+ addInputSec(IS, OutsecName, Out->RelocationSection);
+ return;
+ }
+
+ SectionKey Key = createKey(IS, OutsecName);
+ OutputSection *&Sec = Map[Key];
+ addInputSec(IS, OutsecName, Sec);
}
-template <class ELFT>
-std::pair<OutputSectionBase *, bool>
-OutputSectionFactory<ELFT>::create(const SectionKey &Key,
- InputSectionBase<ELFT> *C) {
- uintX_t Flags = getOutFlags(C);
- OutputSectionBase *&Sec = Map[Key];
- if (Sec) {
- if (getIncompatibleFlags(Sec->Flags) != getIncompatibleFlags(C->Flags))
- error("Section has flags incompatible with others with the same name " +
- toString(C));
- // Convert notbits to progbits if they are mixed. This happens is some
- // linker scripts.
- if (Sec->Type == SHT_NOBITS && C->Type == SHT_PROGBITS)
- Sec->Type = SHT_PROGBITS;
- if (Sec->Type != C->Type &&
- !(Sec->Type == SHT_PROGBITS && C->Type == SHT_NOBITS))
- error("Section has different type from others with the same name " +
- toString(C));
- Sec->Flags |= Flags;
- return {Sec, false};
+void OutputSectionFactory::addInputSec(InputSectionBase *IS,
+ StringRef OutsecName,
+ OutputSection *&Sec) {
+ if (!IS->Live) {
+ reportDiscarded(IS);
+ return;
}
- uint32_t Type = C->Type;
- switch (C->kind()) {
- case InputSectionBase<ELFT>::Regular:
- case InputSectionBase<ELFT>::Synthetic:
- Sec = make<OutputSection<ELFT>>(Key.Name, Type, Flags);
- break;
- case InputSectionBase<ELFT>::EHFrame:
- return {Out<ELFT>::EhFrame, false};
- case InputSectionBase<ELFT>::Merge:
- Sec = make<MergeOutputSection<ELFT>>(Key.Name, Type, Flags, Key.Alignment);
- break;
+ if (Sec) {
+ if (getIncompatibleFlags(Sec->Flags) != getIncompatibleFlags(IS->Flags))
+ error("incompatible section flags for " + Sec->Name + "\n>>> " +
+ toString(IS) + ": 0x" + utohexstr(IS->Flags) +
+ "\n>>> output section " + Sec->Name + ": 0x" +
+ utohexstr(Sec->Flags));
+ if (Sec->Type != IS->Type) {
+ if (canMergeToProgbits(Sec->Type) && canMergeToProgbits(IS->Type))
+ Sec->Type = SHT_PROGBITS;
+ else
+ error("section type mismatch for " + IS->Name + "\n>>> " +
+ toString(IS) + ": " +
+ getELFSectionTypeName(Config->EMachine, IS->Type) +
+ "\n>>> output section " + Sec->Name + ": " +
+ getELFSectionTypeName(Config->EMachine, Sec->Type));
+ }
+ Sec->Flags |= IS->Flags;
+ } else {
+ Sec = make<OutputSection>(OutsecName, IS->Type, IS->Flags);
+ OutputSections.push_back(Sec);
}
- return {Sec, true};
+
+ Sec->addSection(cast<InputSection>(IS));
}
+OutputSectionFactory::~OutputSectionFactory() {}
+
SectionKey DenseMapInfo<SectionKey>::getEmptyKey() {
return SectionKey{DenseMapInfo<StringRef>::getEmptyKey(), 0, 0};
}
@@ -681,32 +265,13 @@ bool DenseMapInfo<SectionKey>::isEqual(const SectionKey &LHS,
LHS.Flags == RHS.Flags && LHS.Alignment == RHS.Alignment;
}
-namespace lld {
-namespace elf {
-
-template void OutputSectionBase::writeHeaderTo<ELF32LE>(ELF32LE::Shdr *Shdr);
-template void OutputSectionBase::writeHeaderTo<ELF32BE>(ELF32BE::Shdr *Shdr);
-template void OutputSectionBase::writeHeaderTo<ELF64LE>(ELF64LE::Shdr *Shdr);
-template void OutputSectionBase::writeHeaderTo<ELF64BE>(ELF64BE::Shdr *Shdr);
-
-template class OutputSection<ELF32LE>;
-template class OutputSection<ELF32BE>;
-template class OutputSection<ELF64LE>;
-template class OutputSection<ELF64BE>;
-
-template class EhOutputSection<ELF32LE>;
-template class EhOutputSection<ELF32BE>;
-template class EhOutputSection<ELF64LE>;
-template class EhOutputSection<ELF64BE>;
-
-template class MergeOutputSection<ELF32LE>;
-template class MergeOutputSection<ELF32BE>;
-template class MergeOutputSection<ELF64LE>;
-template class MergeOutputSection<ELF64BE>;
-
-template class OutputSectionFactory<ELF32LE>;
-template class OutputSectionFactory<ELF32BE>;
-template class OutputSectionFactory<ELF64LE>;
-template class OutputSectionFactory<ELF64BE>;
-}
+uint64_t elf::getHeaderSize() {
+ if (Config->OFormatBinary)
+ return 0;
+ return Out::ElfHeader->Size + Out::ProgramHeaders->Size;
}
+
+template void OutputSection::writeHeaderTo<ELF32LE>(ELF32LE::Shdr *Shdr);
+template void OutputSection::writeHeaderTo<ELF32BE>(ELF32BE::Shdr *Shdr);
+template void OutputSection::writeHeaderTo<ELF64LE>(ELF64LE::Shdr *Shdr);
+template void OutputSection::writeHeaderTo<ELF64BE>(ELF64BE::Shdr *Shdr);
diff --git a/gnu/llvm/tools/lld/ELF/SymbolTable.cpp b/gnu/llvm/tools/lld/ELF/SymbolTable.cpp
index deecd8d74f4..b9817ba9d2d 100644
--- a/gnu/llvm/tools/lld/ELF/SymbolTable.cpp
+++ b/gnu/llvm/tools/lld/ELF/SymbolTable.cpp
@@ -52,6 +52,9 @@ template <class ELFT> static bool isCompatible(InputFile *F) {
// Add symbols in File to the symbol table.
template <class ELFT> void SymbolTable<ELFT>::addFile(InputFile *File) {
+ if (!Config->FirstElf && isa<ELFFileBase<ELFT>>(File))
+ Config->FirstElf = File;
+
if (!isCompatible<ELFT>(File))
return;
@@ -75,13 +78,13 @@ template <class ELFT> void SymbolTable<ELFT>::addFile(InputFile *File) {
}
if (Config->Trace)
- outs() << toString(File) << "\n";
+ message(toString(File));
// .so file
if (auto *F = dyn_cast<SharedFile<ELFT>>(File)) {
// DSOs are uniquified not by filename but by soname.
F->parseSoName();
- if (ErrorCount || !SoNames.insert(F->getSoName()).second)
+ if (ErrorCount || !SoNames.insert(F->SoName).second)
return;
SharedFiles.push_back(F);
F->parseRest();
@@ -115,7 +118,7 @@ template <class ELFT> void SymbolTable<ELFT>::addCombinedLTOObject() {
// Compile bitcode files and replace bitcode symbols.
LTO.reset(new BitcodeCompiler);
for (BitcodeFile *F : BitcodeFiles)
- LTO->add<ELFT>(*F);
+ LTO->add(*F);
for (InputFile *File : LTO->compile()) {
ObjectFile<ELFT> *Obj = cast<ObjectFile<ELFT>>(File);
@@ -126,19 +129,19 @@ template <class ELFT> void SymbolTable<ELFT>::addCombinedLTOObject() {
}
template <class ELFT>
-DefinedRegular<ELFT> *SymbolTable<ELFT>::addAbsolute(StringRef Name,
- uint8_t Visibility,
- uint8_t Binding) {
+DefinedRegular *SymbolTable<ELFT>::addAbsolute(StringRef Name,
+ uint8_t Visibility,
+ uint8_t Binding) {
Symbol *Sym =
addRegular(Name, Visibility, STT_NOTYPE, 0, 0, Binding, nullptr, nullptr);
- return cast<DefinedRegular<ELFT>>(Sym->body());
+ return cast<DefinedRegular>(Sym->body());
}
// Add Name as an "ignored" symbol. An ignored symbol is a regular
// linker-synthesized defined symbol, but is only defined if needed.
template <class ELFT>
-DefinedRegular<ELFT> *SymbolTable<ELFT>::addIgnored(StringRef Name,
- uint8_t Visibility) {
+DefinedRegular *SymbolTable<ELFT>::addIgnored(StringRef Name,
+ uint8_t Visibility) {
SymbolBody *S = find(Name);
if (!S || S->isInCurrentDSO())
return nullptr;
@@ -159,7 +162,7 @@ template <class ELFT> void SymbolTable<ELFT>::trace(StringRef Name) {
// Rename SYM as __wrap_SYM. The original symbol is preserved as __real_SYM.
// Used to implement --wrap.
-template <class ELFT> void SymbolTable<ELFT>::wrap(StringRef Name) {
+template <class ELFT> void SymbolTable<ELFT>::addSymbolWrap(StringRef Name) {
SymbolBody *B = find(Name);
if (!B)
return;
@@ -167,11 +170,40 @@ template <class ELFT> void SymbolTable<ELFT>::wrap(StringRef Name) {
Symbol *Real = addUndefined(Saver.save("__real_" + Name));
Symbol *Wrap = addUndefined(Saver.save("__wrap_" + Name));
- // We rename symbols by replacing the old symbol's SymbolBody with the new
- // symbol's SymbolBody. This causes all SymbolBody pointers referring to the
- // old symbol to instead refer to the new symbol.
- memcpy(Real->Body.buffer, Sym->Body.buffer, sizeof(Sym->Body));
- memcpy(Sym->Body.buffer, Wrap->Body.buffer, sizeof(Wrap->Body));
+ // Tell LTO not to eliminate this symbol
+ Wrap->IsUsedInRegularObj = true;
+
+ Config->RenamedSymbols[Real] = {Sym, Real->Binding};
+ Config->RenamedSymbols[Sym] = {Wrap, Sym->Binding};
+}
+
+// Creates alias for symbol. Used to implement --defsym=ALIAS=SYM.
+template <class ELFT>
+void SymbolTable<ELFT>::addSymbolAlias(StringRef Alias, StringRef Name) {
+ SymbolBody *B = find(Name);
+ if (!B) {
+ error("-defsym: undefined symbol: " + Name);
+ return;
+ }
+ Symbol *Sym = B->symbol();
+ Symbol *AliasSym = addUndefined(Alias);
+
+ // Tell LTO not to eliminate this symbol
+ Sym->IsUsedInRegularObj = true;
+ Config->RenamedSymbols[AliasSym] = {Sym, AliasSym->Binding};
+}
+
+// Apply symbol renames created by -wrap and -defsym. The renames are created
+// before LTO in addSymbolWrap() and addSymbolAlias() to have a chance to inform
+// LTO (if LTO is running) not to include these symbols in IPO. Now that the
+// symbols are finalized, we can perform the replacement.
+template <class ELFT> void SymbolTable<ELFT>::applySymbolRenames() {
+ for (auto &KV : Config->RenamedSymbols) {
+ Symbol *Dst = KV.first;
+ Symbol *Src = KV.second.Target;
+ Dst->body()->copy(Src->body());
+ Dst->Binding = KV.second.OriginalBinding;
+ }
}
static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) {
@@ -185,6 +217,12 @@ static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) {
// Find an existing symbol or create and insert a new one.
template <class ELFT>
std::pair<Symbol *, bool> SymbolTable<ELFT>::insert(StringRef Name) {
+ // <name>@@<version> means the symbol is the default version. In that
+ // case <name>@@<version> will be used to resolve references to <name>.
+ size_t Pos = Name.find("@@");
+ if (Pos != StringRef::npos)
+ Name = Name.take_front(Pos);
+
auto P = Symtab.insert(
{CachedHashStringRef(Name), SymIndex((int)SymVector.size(), false)});
SymIndex &V = P.first->second;
@@ -197,7 +235,7 @@ std::pair<Symbol *, bool> SymbolTable<ELFT>::insert(StringRef Name) {
Symbol *Sym;
if (IsNew) {
- Sym = new (BAlloc) Symbol;
+ Sym = make<Symbol>();
Sym->InVersionScript = false;
Sym->Binding = STB_WEAK;
Sym->Visibility = STV_DEFAULT;
@@ -212,13 +250,6 @@ std::pair<Symbol *, bool> SymbolTable<ELFT>::insert(StringRef Name) {
return {Sym, IsNew};
}
-// Construct a string in the form of "Sym in File1 and File2".
-// Used to construct an error message.
-static std::string conflictMsg(SymbolBody *Existing, InputFile *NewFile) {
- return "'" + toString(*Existing) + "' in " + toString(Existing->File) +
- " and " + toString(NewFile);
-}
-
// Find an existing symbol or create and insert a new one, then apply the given
// attributes.
template <class ELFT>
@@ -232,13 +263,19 @@ SymbolTable<ELFT>::insert(StringRef Name, uint8_t Type, uint8_t Visibility,
// Merge in the new symbol's visibility.
S->Visibility = getMinVisibility(S->Visibility, Visibility);
+
if (!CanOmitFromDynSym && (Config->Shared || Config->ExportDynamic))
S->ExportDynamic = true;
+
if (IsUsedInRegularObj)
S->IsUsedInRegularObj = true;
+
if (!WasInserted && S->body()->Type != SymbolBody::UnknownType &&
- ((Type == STT_TLS) != S->body()->isTls()))
- error("TLS attribute mismatch for symbol " + conflictMsg(S->body(), File));
+ ((Type == STT_TLS) != S->body()->isTls())) {
+ error("TLS attribute mismatch: " + toString(*S->body()) +
+ "\n>>> defined in " + toString(S->body()->File) +
+ "\n>>> defined in " + toString(File));
+ }
return {S, WasInserted};
}
@@ -258,18 +295,23 @@ Symbol *SymbolTable<ELFT>::addUndefined(StringRef Name, bool IsLocal,
InputFile *File) {
Symbol *S;
bool WasInserted;
+ uint8_t Visibility = getVisibility(StOther);
std::tie(S, WasInserted) =
- insert(Name, Type, getVisibility(StOther), CanOmitFromDynSym, File);
- if (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->body()) && Visibility != STV_DEFAULT)) {
S->Binding = Binding;
- replaceBody<Undefined<ELFT>>(S, Name, IsLocal, StOther, Type, File);
+ replaceBody<Undefined>(S, Name, IsLocal, StOther, Type, File);
return S;
}
if (Binding != STB_WEAK) {
- if (S->body()->isShared() || S->body()->isLazy())
+ SymbolBody *B = S->body();
+ if (B->isShared() || B->isLazy() || B->isUndefined())
S->Binding = Binding;
- if (auto *SS = dyn_cast<SharedSymbol<ELFT>>(S->body()))
- SS->file()->IsUsed = true;
+ if (auto *SS = dyn_cast<SharedSymbol>(B))
+ cast<SharedFile<ELFT>>(SS->File)->IsUsed = true;
}
if (auto *L = dyn_cast<Lazy>(S->body())) {
// An undefined weak will not fetch archive members, but we have to remember
@@ -282,15 +324,36 @@ Symbol *SymbolTable<ELFT>::addUndefined(StringRef Name, bool IsLocal,
return S;
}
+// Using .symver foo,foo@@VER unfortunately creates two symbols: foo and
+// foo@@VER. We want to effectively ignore foo, so give precedence to
+// foo@@VER.
+// FIXME: If users can transition to using
+// .symver foo,foo@@@VER
+// we can delete this hack.
+static int compareVersion(Symbol *S, StringRef Name) {
+ if (Name.find("@@") != StringRef::npos &&
+ S->body()->getName().find("@@") == StringRef::npos)
+ return 1;
+ if (Name.find("@@") == StringRef::npos &&
+ S->body()->getName().find("@@") != StringRef::npos)
+ return -1;
+ return 0;
+}
+
// We have a new defined symbol with the specified binding. Return 1 if the new
// symbol should win, -1 if the new symbol should lose, or 0 if both symbols are
// strong defined symbols.
-static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding) {
+static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding,
+ StringRef Name) {
if (WasInserted)
return 1;
SymbolBody *Body = S->body();
- if (Body->isLazy() || !Body->isInCurrentDSO())
+ if (!Body->isInCurrentDSO())
return 1;
+
+ if (int R = compareVersion(S, Name))
+ return R;
+
if (Binding == STB_WEAK)
return -1;
if (S->isWeak())
@@ -303,8 +366,9 @@ static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding) {
// is a conflict. If the new symbol wins, also update the binding.
template <typename ELFT>
static int compareDefinedNonCommon(Symbol *S, bool WasInserted, uint8_t Binding,
- bool IsAbsolute, typename ELFT::uint Value) {
- if (int Cmp = compareDefined(S, WasInserted, Binding)) {
+ bool IsAbsolute, typename ELFT::uint Value,
+ StringRef Name) {
+ if (int Cmp = compareDefined(S, WasInserted, Binding, Name)) {
if (Cmp > 0)
S->Binding = Binding;
return Cmp;
@@ -315,7 +379,7 @@ static int compareDefinedNonCommon(Symbol *S, bool WasInserted, uint8_t Binding,
if (Config->WarnCommon)
warn("common " + S->body()->getName() + " is overridden");
return 1;
- } else if (auto *R = dyn_cast<DefinedRegular<ELFT>>(B)) {
+ } else if (auto *R = dyn_cast<DefinedRegular>(B)) {
if (R->Section == nullptr && Binding == STB_GLOBAL && IsAbsolute &&
R->Value == Value)
return -1;
@@ -325,14 +389,14 @@ static int compareDefinedNonCommon(Symbol *S, bool WasInserted, uint8_t Binding,
template <class ELFT>
Symbol *SymbolTable<ELFT>::addCommon(StringRef N, uint64_t Size,
- uint64_t Alignment, uint8_t Binding,
+ uint32_t Alignment, uint8_t Binding,
uint8_t StOther, uint8_t Type,
InputFile *File) {
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(N, Type, getVisibility(StOther),
/*CanOmitFromDynSym*/ false, File);
- int Cmp = compareDefined(S, WasInserted, Binding);
+ int Cmp = compareDefined(S, WasInserted, Binding, N);
if (Cmp > 0) {
S->Binding = Binding;
replaceBody<DefinedCommon>(S, N, Size, Alignment, StOther, Type, File);
@@ -355,73 +419,72 @@ Symbol *SymbolTable<ELFT>::addCommon(StringRef N, uint64_t Size,
return S;
}
-static void print(const Twine &Msg) {
+static void warnOrError(const Twine &Msg) {
if (Config->AllowMultipleDefinition)
warn(Msg);
else
error(Msg);
}
-static void reportDuplicate(SymbolBody *Existing, InputFile *NewFile) {
- print("duplicate symbol " + conflictMsg(Existing, NewFile));
+static void reportDuplicate(SymbolBody *Sym, InputFile *NewFile) {
+ warnOrError("duplicate symbol: " + toString(*Sym) + "\n>>> defined in " +
+ toString(Sym->File) + "\n>>> defined in " + toString(NewFile));
}
template <class ELFT>
-static void reportDuplicate(SymbolBody *Existing,
- InputSectionBase<ELFT> *ErrSec,
+static void reportDuplicate(SymbolBody *Sym, InputSectionBase *ErrSec,
typename ELFT::uint ErrOffset) {
- DefinedRegular<ELFT> *D = dyn_cast<DefinedRegular<ELFT>>(Existing);
+ DefinedRegular *D = dyn_cast<DefinedRegular>(Sym);
if (!D || !D->Section || !ErrSec) {
- reportDuplicate(Existing, ErrSec ? ErrSec->getFile() : nullptr);
+ reportDuplicate(Sym, ErrSec ? ErrSec->getFile<ELFT>() : nullptr);
return;
}
- std::string OldLoc = D->Section->getLocation(D->Value);
- std::string NewLoc = ErrSec->getLocation(ErrOffset);
-
- print(NewLoc + ": duplicate symbol '" + toString(*Existing) + "'");
- print(OldLoc + ": previous definition was here");
+ // Construct and print an error message in the form of:
+ //
+ // ld.lld: error: duplicate symbol: foo
+ // >>> defined at bar.c:30
+ // >>> bar.o (/home/alice/src/bar.o)
+ // >>> defined at baz.c:563
+ // >>> baz.o in archive libbaz.a
+ auto *Sec1 = cast<InputSectionBase>(D->Section);
+ std::string Src1 = Sec1->getSrcMsg<ELFT>(D->Value);
+ std::string Obj1 = Sec1->getObjMsg<ELFT>(D->Value);
+ std::string Src2 = ErrSec->getSrcMsg<ELFT>(ErrOffset);
+ std::string Obj2 = ErrSec->getObjMsg<ELFT>(ErrOffset);
+
+ std::string Msg = "duplicate symbol: " + toString(*Sym) + "\n>>> defined at ";
+ if (!Src1.empty())
+ Msg += Src1 + "\n>>> ";
+ Msg += Obj1 + "\n>>> defined at ";
+ if (!Src2.empty())
+ Msg += Src2 + "\n>>> ";
+ Msg += Obj2;
+ warnOrError(Msg);
}
template <typename ELFT>
Symbol *SymbolTable<ELFT>::addRegular(StringRef Name, uint8_t StOther,
- uint8_t Type, uintX_t Value, uintX_t Size,
- uint8_t Binding,
- InputSectionBase<ELFT> *Section,
- InputFile *File) {
+ uint8_t Type, uint64_t Value,
+ uint64_t Size, uint8_t Binding,
+ SectionBase *Section, InputFile *File) {
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name, Type, getVisibility(StOther),
/*CanOmitFromDynSym*/ false, File);
int Cmp = compareDefinedNonCommon<ELFT>(S, WasInserted, Binding,
- Section == nullptr, Value);
+ Section == nullptr, Value, Name);
if (Cmp > 0)
- replaceBody<DefinedRegular<ELFT>>(S, Name, /*IsLocal=*/false, StOther, Type,
- Value, Size, Section, File);
+ replaceBody<DefinedRegular>(S, Name, /*IsLocal=*/false, StOther, Type,
+ Value, Size, Section, File);
else if (Cmp == 0)
- reportDuplicate(S->body(), Section, Value);
+ reportDuplicate<ELFT>(S->body(),
+ dyn_cast_or_null<InputSectionBase>(Section), Value);
return S;
}
template <typename ELFT>
-Symbol *SymbolTable<ELFT>::addSynthetic(StringRef N,
- const OutputSectionBase *Section,
- uintX_t Value, uint8_t StOther) {
- Symbol *S;
- bool WasInserted;
- std::tie(S, WasInserted) = insert(N, STT_NOTYPE, getVisibility(StOther),
- /*CanOmitFromDynSym*/ false, nullptr);
- int Cmp = compareDefinedNonCommon<ELFT>(S, WasInserted, STB_GLOBAL,
- /*IsAbsolute*/ false, /*Value*/ 0);
- if (Cmp > 0)
- replaceBody<DefinedSynthetic>(S, N, Value, Section);
- else if (Cmp == 0)
- reportDuplicate(S->body(), nullptr);
- return S;
-}
-
-template <typename ELFT>
-void SymbolTable<ELFT>::addShared(SharedFile<ELFT> *F, StringRef Name,
+void SymbolTable<ELFT>::addShared(SharedFile<ELFT> *File, StringRef Name,
const Elf_Sym &Sym,
const typename ELFT::Verdef *Verdef) {
// DSO symbols do not affect visibility in the output, so we pass STV_DEFAULT
@@ -429,15 +492,21 @@ void SymbolTable<ELFT>::addShared(SharedFile<ELFT> *F, StringRef Name,
// unchanged.
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) =
- insert(Name, Sym.getType(), STV_DEFAULT, /*CanOmitFromDynSym*/ true, F);
+ std::tie(S, WasInserted) = insert(Name, Sym.getType(), STV_DEFAULT,
+ /*CanOmitFromDynSym*/ true, File);
// Make sure we preempt DSO symbols with default visibility.
if (Sym.getVisibility() == STV_DEFAULT)
S->ExportDynamic = true;
- if (WasInserted || isa<Undefined<ELFT>>(S->body())) {
- replaceBody<SharedSymbol<ELFT>>(S, F, Name, Sym, Verdef);
+
+ SymbolBody *Body = S->body();
+ // An undefined symbol with non default visibility must be satisfied
+ // in the same DSO.
+ if (WasInserted ||
+ (isa<Undefined>(Body) && Body->getVisibility() == STV_DEFAULT)) {
+ replaceBody<SharedSymbol>(S, File, Name, Sym.st_other, Sym.getType(), &Sym,
+ Verdef);
if (!S->isWeak())
- F->IsUsed = true;
+ File->IsUsed = true;
}
}
@@ -450,10 +519,10 @@ Symbol *SymbolTable<ELFT>::addBitcode(StringRef Name, uint8_t Binding,
std::tie(S, WasInserted) =
insert(Name, Type, getVisibility(StOther), CanOmitFromDynSym, F);
int Cmp = compareDefinedNonCommon<ELFT>(S, WasInserted, Binding,
- /*IsAbs*/ false, /*Value*/ 0);
+ /*IsAbs*/ false, /*Value*/ 0, Name);
if (Cmp > 0)
- replaceBody<DefinedRegular<ELFT>>(S, Name, /*IsLocal=*/false, StOther, Type,
- 0, 0, nullptr, F);
+ replaceBody<DefinedRegular>(S, Name, /*IsLocal=*/false, StOther, Type, 0, 0,
+ nullptr, F);
else if (Cmp == 0)
reportDuplicate(S->body(), F);
return S;
@@ -478,18 +547,18 @@ SymbolBody *SymbolTable<ELFT>::findInCurrentDSO(StringRef Name) {
}
template <class ELFT>
-void SymbolTable<ELFT>::addLazyArchive(ArchiveFile *F,
- const object::Archive::Symbol Sym) {
+Symbol *SymbolTable<ELFT>::addLazyArchive(ArchiveFile *F,
+ const object::Archive::Symbol Sym) {
Symbol *S;
bool WasInserted;
StringRef Name = Sym.getName();
std::tie(S, WasInserted) = insert(Name);
if (WasInserted) {
replaceBody<LazyArchive>(S, *F, Sym, SymbolBody::UnknownType);
- return;
+ return S;
}
if (!S->body()->isUndefined())
- return;
+ return S;
// Weak undefined symbols should not fetch members from archives. If we were
// to keep old symbol we would not know that an archive member was available
@@ -500,11 +569,12 @@ void SymbolTable<ELFT>::addLazyArchive(ArchiveFile *F,
// to preserve its type. FIXME: Move the Type field to Symbol.
if (S->isWeak()) {
replaceBody<LazyArchive>(S, *F, Sym, S->body()->Type);
- return;
+ return S;
}
std::pair<MemoryBufferRef, uint64_t> MBInfo = F->getMember(&Sym);
if (!MBInfo.first.getBuffer().empty())
addFile(createObjectFile(MBInfo.first, F->getName(), MBInfo.second));
+ return S;
}
template <class ELFT>
@@ -520,13 +590,10 @@ void SymbolTable<ELFT>::addLazyObject(StringRef Name, LazyObjectFile &Obj) {
return;
// See comment for addLazyArchive above.
- if (S->isWeak()) {
+ if (S->isWeak())
replaceBody<LazyObject>(S, Name, Obj, S->body()->Type);
- } else {
- MemoryBufferRef MBRef = Obj.getBuffer();
- if (!MBRef.getBuffer().empty())
- addFile(createObjectFile(MBRef));
- }
+ else if (InputFile *F = Obj.fetch())
+ addFile(F);
}
// Process undefined (-u) flags by loading lazy symbols named by those flags.
@@ -545,11 +612,20 @@ template <class ELFT> void SymbolTable<ELFT>::scanUndefinedFlags() {
// shared libraries can find them.
// Except this, we ignore undefined symbols in DSOs.
template <class ELFT> void SymbolTable<ELFT>::scanShlibUndefined() {
- for (SharedFile<ELFT> *File : SharedFiles)
- for (StringRef U : File->getUndefinedSymbols())
- if (SymbolBody *Sym = find(U))
- if (Sym->isDefined())
- Sym->symbol()->ExportDynamic = true;
+ for (SharedFile<ELFT> *File : SharedFiles) {
+ for (StringRef U : File->getUndefinedSymbols()) {
+ SymbolBody *Sym = find(U);
+ if (!Sym || !Sym->isDefined())
+ continue;
+ Sym->symbol()->ExportDynamic = true;
+
+ // 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->symbol()->VersionId = VER_NDX_GLOBAL;
+ }
+ }
}
// Initialize DemangledSyms with a map from demangled symbols to symbol
@@ -630,7 +706,8 @@ template <class ELFT> void SymbolTable<ELFT>::handleAnonymousVersion() {
// Set symbol versions to symbols. This function handles patterns
// containing no wildcard characters.
template <class ELFT>
-void SymbolTable<ELFT>::assignExactVersion(SymbolVersion Ver, uint16_t VersionId,
+void SymbolTable<ELFT>::assignExactVersion(SymbolVersion Ver,
+ uint16_t VersionId,
StringRef VersionName) {
if (Ver.HasWildcard)
return;
@@ -646,6 +723,12 @@ void SymbolTable<ELFT>::assignExactVersion(SymbolVersion Ver, uint16_t VersionId
// Assign the version.
for (SymbolBody *B : Syms) {
+ // Skip symbols containing version info because symbol versions
+ // specified by symbol names take precedence over version scripts.
+ // See parseSymbolVersion().
+ if (B->getName().find('@') != StringRef::npos)
+ continue;
+
Symbol *Sym = B->symbol();
if (Sym->InVersionScript)
warn("duplicate symbol '" + Ver.Name + "' in version script");
@@ -659,12 +742,11 @@ void SymbolTable<ELFT>::assignWildcardVersion(SymbolVersion Ver,
uint16_t VersionId) {
if (!Ver.HasWildcard)
return;
- std::vector<SymbolBody *> Syms = findAllByVersion(Ver);
// Exact matching takes precendence over fuzzy matching,
// so we set a version to a symbol only if no version has been assigned
// to the symbol. This behavior is compatible with GNU.
- for (SymbolBody *B : Syms)
+ for (SymbolBody *B : findAllByVersion(Ver))
if (B->symbol()->VersionId == Config->DefaultSymbolVersion)
B->symbol()->VersionId = VersionId;
}
@@ -672,19 +754,9 @@ void SymbolTable<ELFT>::assignWildcardVersion(SymbolVersion Ver,
// This function processes version scripts by updating VersionId
// member of symbols.
template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() {
- // Symbol themselves might know their versions because symbols
- // can contain versions in the form of <name>@<version>.
- // Let them parse their names.
- if (!Config->VersionDefinitions.empty())
- for (Symbol *Sym : SymVector)
- Sym->body()->parseSymbolVersion();
-
// Handle edge cases first.
handleAnonymousVersion();
- if (Config->VersionDefinitions.empty())
- return;
-
// Now we have version definitions, so we need to set version ids to symbols.
// Each version definition has a glob pattern, and all symbols that match
// with the pattern get that version.
@@ -702,6 +774,12 @@ template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() {
for (VersionDefinition &V : llvm::reverse(Config->VersionDefinitions))
for (SymbolVersion &Ver : V.Globals)
assignWildcardVersion(Ver, V.Id);
+
+ // Symbol themselves might know their versions because symbols
+ // can contain versions in the form of <name>@<version>.
+ // Let them parse and update their names to exclude version suffix.
+ for (Symbol *Sym : SymVector)
+ Sym->body()->parseSymbolVersion();
}
template class elf::SymbolTable<ELF32LE>;
diff --git a/gnu/llvm/tools/lld/ELF/Symbols.cpp b/gnu/llvm/tools/lld/ELF/Symbols.cpp
index 43af44ec4b8..c69007e781a 100644
--- a/gnu/llvm/tools/lld/ELF/Symbols.cpp
+++ b/gnu/llvm/tools/lld/ELF/Symbols.cpp
@@ -28,62 +28,90 @@ using namespace llvm::ELF;
using namespace lld;
using namespace lld::elf;
-template <class ELFT>
-static typename ELFT::uint getSymVA(const SymbolBody &Body,
- typename ELFT::uint &Addend) {
- typedef typename ELFT::uint uintX_t;
-
+DefinedRegular *ElfSym::Bss;
+DefinedRegular *ElfSym::Etext1;
+DefinedRegular *ElfSym::Etext2;
+DefinedRegular *ElfSym::Edata1;
+DefinedRegular *ElfSym::Edata2;
+DefinedRegular *ElfSym::End1;
+DefinedRegular *ElfSym::End2;
+DefinedRegular *ElfSym::GlobalOffsetTable;
+DefinedRegular *ElfSym::MipsGp;
+DefinedRegular *ElfSym::MipsGpDisp;
+DefinedRegular *ElfSym::MipsLocalGp;
+
+static uint64_t getSymVA(const SymbolBody &Body, int64_t &Addend) {
switch (Body.kind()) {
- case SymbolBody::DefinedSyntheticKind: {
- auto &D = cast<DefinedSynthetic>(Body);
- const OutputSectionBase *Sec = D.Section;
- if (!Sec)
- return D.Value;
- if (D.Value == uintX_t(-1))
- return Sec->Addr + Sec->Size;
- return Sec->Addr + D.Value;
- }
case SymbolBody::DefinedRegularKind: {
- auto &D = cast<DefinedRegular<ELFT>>(Body);
- InputSectionBase<ELFT> *IS = D.Section;
+ auto &D = cast<DefinedRegular>(Body);
+ SectionBase *IS = D.Section;
+ if (auto *ISB = dyn_cast_or_null<InputSectionBase>(IS))
+ IS = ISB->Repl;
// According to the ELF spec reference to a local symbol from outside
// the group are not allowed. Unfortunately .eh_frame breaks that rule
// and must be treated specially. For now we just replace the symbol with
// 0.
- if (IS == &InputSection<ELFT>::Discarded)
+ if (IS == &InputSection::Discarded)
return 0;
// This is an absolute symbol.
if (!IS)
return D.Value;
- uintX_t Offset = D.Value;
+ uint64_t Offset = D.Value;
+
+ // An object in an SHF_MERGE section might be referenced via a
+ // section symbol (as a hack for reducing the number of local
+ // symbols).
+ // Depending on the addend, the reference via a section symbol
+ // refers to a different object in the merge section.
+ // Since the objects in the merge section are not necessarily
+ // contiguous in the output, the addend can thus affect the final
+ // VA in a non-linear way.
+ // To make this work, we incorporate the addend into the section
+ // offset (and zero out the addend for later processing) so that
+ // we find the right object in the section.
if (D.isSection()) {
Offset += Addend;
Addend = 0;
}
- uintX_t VA = (IS->OutSec ? IS->OutSec->Addr : 0) + IS->getOffset(Offset);
+
+ 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.
+ // 2. The offset of the input section within the output section.
+ // 3. The offset within the input section (this addition happens
+ // inside InputSection::getOffset).
+ //
+ // 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);
+
if (D.isTls() && !Config->Relocatable) {
- if (!Out<ELFT>::TlsPhdr)
+ if (!Out::TlsPhdr)
fatal(toString(D.File) +
- " has a STT_TLS symbol but doesn't have a PT_TLS section");
- return VA - Out<ELFT>::TlsPhdr->p_vaddr;
+ " has an STT_TLS symbol but doesn't have an SHF_TLS section");
+ return VA - Out::TlsPhdr->p_vaddr;
}
return VA;
}
case SymbolBody::DefinedCommonKind:
if (!Config->DefineCommon)
return 0;
- return In<ELFT>::Common->OutSec->Addr + In<ELFT>::Common->OutSecOff +
+ return InX::Common->getParent()->Addr + InX::Common->OutSecOff +
cast<DefinedCommon>(Body).Offset;
case SymbolBody::SharedKind: {
- auto &SS = cast<SharedSymbol<ELFT>>(Body);
- if (!SS.NeedsCopyOrPltAddr)
- return 0;
- if (SS.isFunc())
- return Body.getPltVA<ELFT>();
- return SS.getBssSectionForCopy()->Addr + SS.CopyOffset;
+ auto &SS = cast<SharedSymbol>(Body);
+ if (SS.NeedsCopy)
+ return SS.CopyRelSec->getParent()->Addr + SS.CopyRelSec->OutSecOff +
+ SS.CopyRelSecOff;
+ if (SS.NeedsPltAddr)
+ return Body.getPltVA();
+ return 0;
}
case SymbolBody::UndefinedKind:
return 0;
@@ -97,10 +125,9 @@ static typename ELFT::uint getSymVA(const SymbolBody &Body,
SymbolBody::SymbolBody(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther,
uint8_t Type)
- : SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(IsLocal),
+ : SymbolKind(K), NeedsCopy(false), NeedsPltAddr(false), IsLocal(IsLocal),
IsInGlobalMipsGot(false), Is32BitMipsGot(false), IsInIplt(false),
- IsInIgot(false), CopyIsInBssRelRo(false), Type(Type), StOther(StOther),
- Name(Name) {}
+ IsInIgot(false), Type(Type), StOther(StOther), Name(Name) {}
// Returns true if a symbol can be replaced at load-time by a symbol
// with the same name defined in other ELF executable or DSO.
@@ -112,7 +139,7 @@ bool SymbolBody::isPreemptible() const {
// symbols with copy relocations (which resolve to .bss) or preempt plt
// entries (which resolve to that plt entry).
if (isShared())
- return !NeedsCopyOrPltAddr;
+ return !NeedsCopy && !NeedsPltAddr;
// That's all that can be preempted in a non-DSO.
if (!Config->Shared)
@@ -132,65 +159,76 @@ bool SymbolBody::isPreemptible() const {
return true;
}
-template <class ELFT> bool SymbolBody::hasThunk() const {
- if (auto *DR = dyn_cast<DefinedRegular<ELFT>>(this))
- return DR->ThunkData != nullptr;
- if (auto *S = dyn_cast<SharedSymbol<ELFT>>(this))
- return S->ThunkData != nullptr;
- return false;
+// Overwrites all attributes with Other's so that this symbol becomes
+// an alias to Other. This is useful for handling some options such as
+// --wrap.
+void SymbolBody::copy(SymbolBody *Other) {
+ memcpy(symbol()->Body.buffer, Other->symbol()->Body.buffer,
+ sizeof(Symbol::Body));
}
-template <class ELFT>
-typename ELFT::uint SymbolBody::getVA(typename ELFT::uint Addend) const {
- typename ELFT::uint OutVA = getSymVA<ELFT>(*this, Addend);
+uint64_t SymbolBody::getVA(int64_t Addend) const {
+ uint64_t OutVA = getSymVA(*this, Addend);
return OutVA + Addend;
}
-template <class ELFT> typename ELFT::uint SymbolBody::getGotVA() const {
- return In<ELFT>::Got->getVA() + getGotOffset<ELFT>();
+uint64_t SymbolBody::getGotVA() const {
+ return InX::Got->getVA() + getGotOffset();
}
-template <class ELFT> typename ELFT::uint SymbolBody::getGotOffset() const {
+uint64_t SymbolBody::getGotOffset() const {
return GotIndex * Target->GotEntrySize;
}
-template <class ELFT> typename ELFT::uint SymbolBody::getGotPltVA() const {
+uint64_t SymbolBody::getGotPltVA() const {
if (this->IsInIgot)
- return In<ELFT>::IgotPlt->getVA() + getGotPltOffset<ELFT>();
- return In<ELFT>::GotPlt->getVA() + getGotPltOffset<ELFT>();
+ return InX::IgotPlt->getVA() + getGotPltOffset();
+ return InX::GotPlt->getVA() + getGotPltOffset();
}
-template <class ELFT> typename ELFT::uint SymbolBody::getGotPltOffset() const {
+uint64_t SymbolBody::getGotPltOffset() const {
return GotPltIndex * Target->GotPltEntrySize;
}
-template <class ELFT> typename ELFT::uint SymbolBody::getPltVA() const {
+uint64_t SymbolBody::getPltVA() const {
if (this->IsInIplt)
- return In<ELFT>::Iplt->getVA() + PltIndex * Target->PltEntrySize;
- return In<ELFT>::Plt->getVA() + Target->PltHeaderSize +
+ return InX::Iplt->getVA() + PltIndex * Target->PltEntrySize;
+ return InX::Plt->getVA() + Target->PltHeaderSize +
PltIndex * Target->PltEntrySize;
}
-template <class ELFT> typename ELFT::uint SymbolBody::getThunkVA() const {
- if (const auto *DR = dyn_cast<DefinedRegular<ELFT>>(this))
- return DR->ThunkData->getVA();
- if (const auto *S = dyn_cast<SharedSymbol<ELFT>>(this))
- return S->ThunkData->getVA();
- if (const auto *S = dyn_cast<Undefined<ELFT>>(this))
- return S->ThunkData->getVA();
- fatal("getThunkVA() not supported for Symbol class\n");
-}
-
template <class ELFT> typename ELFT::uint SymbolBody::getSize() const {
if (const auto *C = dyn_cast<DefinedCommon>(this))
return C->Size;
- if (const auto *DR = dyn_cast<DefinedRegular<ELFT>>(this))
+ if (const auto *DR = dyn_cast<DefinedRegular>(this))
return DR->Size;
- if (const auto *S = dyn_cast<SharedSymbol<ELFT>>(this))
- return S->Sym.st_size;
+ if (const auto *S = dyn_cast<SharedSymbol>(this))
+ return S->getSize<ELFT>();
return 0;
}
+OutputSection *SymbolBody::getOutputSection() const {
+ if (auto *S = dyn_cast<DefinedRegular>(this)) {
+ if (S->Section)
+ return S->Section->getOutputSection();
+ return nullptr;
+ }
+
+ if (auto *S = dyn_cast<SharedSymbol>(this)) {
+ if (S->NeedsCopy)
+ return S->CopyRelSec->getParent();
+ return nullptr;
+ }
+
+ if (isa<DefinedCommon>(this)) {
+ if (Config->DefineCommon)
+ return InX::Common->getParent();
+ return nullptr;
+ }
+
+ return nullptr;
+}
+
// If a symbol name contains '@', the characters after that is
// a symbol version name. This function parses that.
void SymbolBody::parseSymbolVersion() {
@@ -227,34 +265,36 @@ void SymbolBody::parseSymbolVersion() {
}
// It is an error if the specified version is not defined.
- error(toString(File) + ": symbol " + S + " has undefined version " + Verstr);
+ // 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)
+ error(toString(File) + ": symbol " + S + " has undefined version " +
+ Verstr);
}
Defined::Defined(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther,
uint8_t Type)
: SymbolBody(K, Name, IsLocal, StOther, Type) {}
-template <class ELFT> bool DefinedRegular<ELFT>::isMipsPIC() const {
+template <class ELFT> bool DefinedRegular::isMipsPIC() const {
+ typedef typename ELFT::Ehdr Elf_Ehdr;
if (!Section || !isFunc())
return false;
+
+ auto *Sec = cast<InputSectionBase>(Section);
+ const Elf_Ehdr *Hdr = Sec->template getFile<ELFT>()->getObj().getHeader();
return (this->StOther & STO_MIPS_MIPS16) == STO_MIPS_PIC ||
- (Section->getFile()->getObj().getHeader()->e_flags & EF_MIPS_PIC);
+ (Hdr->e_flags & EF_MIPS_PIC);
}
-template <typename ELFT>
-Undefined<ELFT>::Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther,
- uint8_t Type, InputFile *File)
+Undefined::Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther,
+ uint8_t Type, InputFile *File)
: SymbolBody(SymbolBody::UndefinedKind, Name, IsLocal, StOther, Type) {
this->File = File;
}
-template <typename ELFT>
-OutputSection<ELFT> *SharedSymbol<ELFT>::getBssSectionForCopy() const {
- assert(needsCopy());
- return CopyIsInBssRelRo ? Out<ELFT>::BssRelRo : Out<ELFT>::Bss;
-}
-
-DefinedCommon::DefinedCommon(StringRef Name, uint64_t Size, uint64_t Alignment,
+DefinedCommon::DefinedCommon(StringRef Name, uint64_t Size, uint32_t Alignment,
uint8_t StOther, uint8_t Type, InputFile *File)
: Defined(SymbolBody::DefinedCommonKind, Name, /*IsLocal=*/false, StOther,
Type),
@@ -262,6 +302,17 @@ DefinedCommon::DefinedCommon(StringRef Name, uint64_t Size, uint64_t Alignment,
this->File = File;
}
+// If a shared symbol is referred via a copy relocation, its alignment
+// becomes part of the ABI. This function returns a symbol alignment.
+// Because symbols don't have alignment attributes, we need to infer that.
+template <class ELFT> uint32_t SharedSymbol::getAlignment() const {
+ auto *File = cast<SharedFile<ELFT>>(this->File);
+ uint32_t SecAlign = File->getSection(getSym<ELFT>())->sh_addralign;
+ uint64_t SymValue = getSym<ELFT>().st_value;
+ uint32_t SymAlign = uint32_t(1) << countTrailingZeros(SymValue);
+ return std::min(SecAlign, SymAlign);
+}
+
InputFile *Lazy::fetch() {
if (auto *S = dyn_cast<LazyArchive>(this))
return S->fetch();
@@ -289,20 +340,14 @@ InputFile *LazyArchive::fetch() {
return createObjectFile(MBInfo.first, file()->getName(), MBInfo.second);
}
-InputFile *LazyObject::fetch() {
- MemoryBufferRef MBRef = file()->getBuffer();
- if (MBRef.getBuffer().empty())
- return nullptr;
- return createObjectFile(MBRef);
-}
+InputFile *LazyObject::fetch() { return file()->fetch(); }
uint8_t Symbol::computeBinding() const {
if (Config->Relocatable)
return Binding;
if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED)
return STB_LOCAL;
- const SymbolBody *Body = body();
- if (VersionId == VER_NDX_LOCAL && Body->isInCurrentDSO())
+ if (VersionId == VER_NDX_LOCAL && body()->isInCurrentDSO())
return STB_LOCAL;
if (Config->NoGnuUnique && Binding == STB_GNU_UNIQUE)
return STB_GLOBAL;
@@ -319,15 +364,15 @@ bool Symbol::includeInDynsym() const {
// Print out a log message for --trace-symbol.
void elf::printTraceSymbol(Symbol *Sym) {
SymbolBody *B = Sym->body();
- outs() << toString(B->File);
-
+ std::string S;
if (B->isUndefined())
- outs() << ": reference to ";
+ S = ": reference to ";
else if (B->isCommon())
- outs() << ": common definition of ";
+ S = ": common definition of ";
else
- outs() << ": definition of ";
- outs() << B->getName() << "\n";
+ S = ": definition of ";
+
+ message(toString(B->File) + S + B->getName());
}
// Returns a symbol for an error message.
@@ -338,62 +383,17 @@ std::string lld::toString(const SymbolBody &B) {
return B.getName();
}
-template bool SymbolBody::hasThunk<ELF32LE>() const;
-template bool SymbolBody::hasThunk<ELF32BE>() const;
-template bool SymbolBody::hasThunk<ELF64LE>() const;
-template bool SymbolBody::hasThunk<ELF64BE>() const;
-
-template uint32_t SymbolBody::template getVA<ELF32LE>(uint32_t) const;
-template uint32_t SymbolBody::template getVA<ELF32BE>(uint32_t) const;
-template uint64_t SymbolBody::template getVA<ELF64LE>(uint64_t) const;
-template uint64_t SymbolBody::template getVA<ELF64BE>(uint64_t) const;
-
-template uint32_t SymbolBody::template getGotVA<ELF32LE>() const;
-template uint32_t SymbolBody::template getGotVA<ELF32BE>() const;
-template uint64_t SymbolBody::template getGotVA<ELF64LE>() const;
-template uint64_t SymbolBody::template getGotVA<ELF64BE>() const;
-
-template uint32_t SymbolBody::template getGotOffset<ELF32LE>() const;
-template uint32_t SymbolBody::template getGotOffset<ELF32BE>() const;
-template uint64_t SymbolBody::template getGotOffset<ELF64LE>() const;
-template uint64_t SymbolBody::template getGotOffset<ELF64BE>() const;
-
-template uint32_t SymbolBody::template getGotPltVA<ELF32LE>() const;
-template uint32_t SymbolBody::template getGotPltVA<ELF32BE>() const;
-template uint64_t SymbolBody::template getGotPltVA<ELF64LE>() const;
-template uint64_t SymbolBody::template getGotPltVA<ELF64BE>() const;
-
-template uint32_t SymbolBody::template getThunkVA<ELF32LE>() const;
-template uint32_t SymbolBody::template getThunkVA<ELF32BE>() const;
-template uint64_t SymbolBody::template getThunkVA<ELF64LE>() const;
-template uint64_t SymbolBody::template getThunkVA<ELF64BE>() const;
-
-template uint32_t SymbolBody::template getGotPltOffset<ELF32LE>() const;
-template uint32_t SymbolBody::template getGotPltOffset<ELF32BE>() const;
-template uint64_t SymbolBody::template getGotPltOffset<ELF64LE>() const;
-template uint64_t SymbolBody::template getGotPltOffset<ELF64BE>() const;
-
-template uint32_t SymbolBody::template getPltVA<ELF32LE>() const;
-template uint32_t SymbolBody::template getPltVA<ELF32BE>() const;
-template uint64_t SymbolBody::template getPltVA<ELF64LE>() const;
-template uint64_t SymbolBody::template getPltVA<ELF64BE>() const;
-
template uint32_t SymbolBody::template getSize<ELF32LE>() const;
template uint32_t SymbolBody::template getSize<ELF32BE>() const;
template uint64_t SymbolBody::template getSize<ELF64LE>() const;
template uint64_t SymbolBody::template getSize<ELF64BE>() const;
-template class elf::Undefined<ELF32LE>;
-template class elf::Undefined<ELF32BE>;
-template class elf::Undefined<ELF64LE>;
-template class elf::Undefined<ELF64BE>;
-
-template class elf::SharedSymbol<ELF32LE>;
-template class elf::SharedSymbol<ELF32BE>;
-template class elf::SharedSymbol<ELF64LE>;
-template class elf::SharedSymbol<ELF64BE>;
+template bool DefinedRegular::template isMipsPIC<ELF32LE>() const;
+template bool DefinedRegular::template isMipsPIC<ELF32BE>() const;
+template bool DefinedRegular::template isMipsPIC<ELF64LE>() const;
+template bool DefinedRegular::template isMipsPIC<ELF64BE>() const;
-template class elf::DefinedRegular<ELF32LE>;
-template class elf::DefinedRegular<ELF32BE>;
-template class elf::DefinedRegular<ELF64LE>;
-template class elf::DefinedRegular<ELF64BE>;
+template uint32_t SharedSymbol::template getAlignment<ELF32LE>() const;
+template uint32_t SharedSymbol::template getAlignment<ELF32BE>() const;
+template uint32_t SharedSymbol::template getAlignment<ELF64LE>() const;
+template uint32_t SharedSymbol::template getAlignment<ELF64BE>() const;
diff --git a/gnu/llvm/tools/lld/ELF/SyntheticSections.cpp b/gnu/llvm/tools/lld/ELF/SyntheticSections.cpp
index d1b6755ab2c..4bbec4ab34b 100644
--- a/gnu/llvm/tools/lld/ELF/SyntheticSections.cpp
+++ b/gnu/llvm/tools/lld/ELF/SyntheticSections.cpp
@@ -27,7 +27,10 @@
#include "Threads.h"
#include "Writer.h"
#include "lld/Config/Version.h"
-#include "llvm/Support/Dwarf.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
+#include "llvm/Object/Decompressor.h"
+#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/RandomNumberGenerator.h"
@@ -45,6 +48,12 @@ using namespace llvm::support::endian;
using namespace lld;
using namespace lld::elf;
+uint64_t SyntheticSection::getVA() const {
+ if (OutputSection *Sec = getParent())
+ return Sec->Addr + OutSecOff;
+ return 0;
+}
+
template <class ELFT> static std::vector<DefinedCommon *> getCommonSymbols() {
std::vector<DefinedCommon *> V;
for (Symbol *S : Symtab<ELFT>::X->getSymbols())
@@ -54,35 +63,24 @@ template <class ELFT> static std::vector<DefinedCommon *> getCommonSymbols() {
}
// Find all common symbols and allocate space for them.
-template <class ELFT> InputSection<ELFT> *elf::createCommonSection() {
- auto *Ret = make<InputSection<ELFT>>(SHF_ALLOC | SHF_WRITE, SHT_NOBITS, 1,
- ArrayRef<uint8_t>(), "COMMON");
- Ret->Live = true;
-
+template <class ELFT> InputSection *elf::createCommonSection() {
if (!Config->DefineCommon)
- return Ret;
+ return nullptr;
// Sort the common symbols by alignment as an heuristic to pack them better.
std::vector<DefinedCommon *> Syms = getCommonSymbols<ELFT>();
+ if (Syms.empty())
+ return nullptr;
+
std::stable_sort(Syms.begin(), Syms.end(),
[](const DefinedCommon *A, const DefinedCommon *B) {
return A->Alignment > B->Alignment;
});
- // Assign offsets to symbols.
- size_t Size = 0;
- size_t Alignment = 1;
- for (DefinedCommon *Sym : Syms) {
- Alignment = std::max<size_t>(Alignment, Sym->Alignment);
- Size = alignTo(Size, Sym->Alignment);
-
- // Compute symbol offset relative to beginning of input section.
- Sym->Offset = Size;
- Size += Sym->Size;
- }
- Ret->Alignment = Alignment;
- Ret->Data = makeArrayRef<uint8_t>(nullptr, Size);
- return Ret;
+ BssSection *Sec = make<BssSection>("COMMON");
+ for (DefinedCommon *Sym : Syms)
+ Sym->Offset = Sec->reserveSpace(Sym->Size, Sym->Alignment);
+ return Sec;
}
// Returns an LLD version string.
@@ -100,16 +98,17 @@ static ArrayRef<uint8_t> getVersion() {
// Creates a .comment section containing LLD version info.
// With this feature, you can identify LLD-generated binaries easily
-// by "objdump -s -j .comment <file>".
+// by "readelf --string-dump .comment <file>".
// The returned object is a mergeable string section.
-template <class ELFT> MergeInputSection<ELFT> *elf::createCommentSection() {
+template <class ELFT> MergeInputSection *elf::createCommentSection() {
typename ELFT::Shdr Hdr = {};
Hdr.sh_flags = SHF_MERGE | SHF_STRINGS;
Hdr.sh_type = SHT_PROGBITS;
Hdr.sh_entsize = 1;
Hdr.sh_addralign = 1;
- auto *Ret = make<MergeInputSection<ELFT>>(/*file=*/nullptr, &Hdr, ".comment");
+ auto *Ret =
+ make<MergeInputSection>((ObjectFile<ELFT> *)nullptr, &Hdr, ".comment");
Ret->Data = getVersion();
Ret->splitIntoPieces();
return Ret;
@@ -118,8 +117,10 @@ template <class ELFT> MergeInputSection<ELFT> *elf::createCommentSection() {
// .MIPS.abiflags section.
template <class ELFT>
MipsAbiFlagsSection<ELFT>::MipsAbiFlagsSection(Elf_Mips_ABIFlags Flags)
- : SyntheticSection<ELFT>(SHF_ALLOC, SHT_MIPS_ABIFLAGS, 8, ".MIPS.abiflags"),
- Flags(Flags) {}
+ : SyntheticSection(SHF_ALLOC, SHT_MIPS_ABIFLAGS, 8, ".MIPS.abiflags"),
+ Flags(Flags) {
+ this->Entsize = sizeof(Elf_Mips_ABIFlags);
+}
template <class ELFT> void MipsAbiFlagsSection<ELFT>::writeTo(uint8_t *Buf) {
memcpy(Buf, &Flags, sizeof(Flags));
@@ -130,13 +131,13 @@ MipsAbiFlagsSection<ELFT> *MipsAbiFlagsSection<ELFT>::create() {
Elf_Mips_ABIFlags Flags = {};
bool Create = false;
- for (InputSectionBase<ELFT> *Sec : Symtab<ELFT>::X->Sections) {
- if (!Sec->Live || Sec->Type != SHT_MIPS_ABIFLAGS)
+ for (InputSectionBase *Sec : InputSections) {
+ if (Sec->Type != SHT_MIPS_ABIFLAGS)
continue;
Sec->Live = false;
Create = true;
- std::string Filename = toString(Sec->getFile());
+ std::string Filename = toString(Sec->getFile<ELFT>());
const size_t Size = Sec->Data.size();
// Older version of BFD (such as the default FreeBSD linker) concatenate
// .MIPS.abiflags instead of merging. To allow for this case (or potential
@@ -175,8 +176,10 @@ MipsAbiFlagsSection<ELFT> *MipsAbiFlagsSection<ELFT>::create() {
// .MIPS.options section.
template <class ELFT>
MipsOptionsSection<ELFT>::MipsOptionsSection(Elf_Mips_RegInfo Reginfo)
- : SyntheticSection<ELFT>(SHF_ALLOC, SHT_MIPS_OPTIONS, 8, ".MIPS.options"),
- Reginfo(Reginfo) {}
+ : SyntheticSection(SHF_ALLOC, SHT_MIPS_OPTIONS, 8, ".MIPS.options"),
+ Reginfo(Reginfo) {
+ this->Entsize = sizeof(Elf_Mips_Options) + sizeof(Elf_Mips_RegInfo);
+}
template <class ELFT> void MipsOptionsSection<ELFT>::writeTo(uint8_t *Buf) {
auto *Options = reinterpret_cast<Elf_Mips_Options *>(Buf);
@@ -184,7 +187,7 @@ template <class ELFT> void MipsOptionsSection<ELFT>::writeTo(uint8_t *Buf) {
Options->size = getSize();
if (!Config->Relocatable)
- Reginfo.ri_gp_value = In<ELFT>::MipsGot->getGp();
+ Reginfo.ri_gp_value = InX::MipsGot->getGp();
memcpy(Buf + sizeof(Elf_Mips_Options), &Reginfo, sizeof(Reginfo));
}
@@ -197,13 +200,13 @@ MipsOptionsSection<ELFT> *MipsOptionsSection<ELFT>::create() {
Elf_Mips_RegInfo Reginfo = {};
bool Create = false;
- for (InputSectionBase<ELFT> *Sec : Symtab<ELFT>::X->Sections) {
- if (!Sec->Live || Sec->Type != SHT_MIPS_OPTIONS)
+ for (InputSectionBase *Sec : InputSections) {
+ if (Sec->Type != SHT_MIPS_OPTIONS)
continue;
Sec->Live = false;
Create = true;
- std::string Filename = toString(Sec->getFile());
+ std::string Filename = toString(Sec->getFile<ELFT>());
ArrayRef<uint8_t> D = Sec->Data;
while (!D.empty()) {
@@ -217,7 +220,7 @@ MipsOptionsSection<ELFT> *MipsOptionsSection<ELFT>::create() {
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()->MipsGp0 = Opt->getRegInfo().ri_gp_value;
+ Sec->getFile<ELFT>()->MipsGp0 = Opt->getRegInfo().ri_gp_value;
break;
}
@@ -235,12 +238,14 @@ MipsOptionsSection<ELFT> *MipsOptionsSection<ELFT>::create() {
// MIPS .reginfo section.
template <class ELFT>
MipsReginfoSection<ELFT>::MipsReginfoSection(Elf_Mips_RegInfo Reginfo)
- : SyntheticSection<ELFT>(SHF_ALLOC, SHT_MIPS_REGINFO, 4, ".reginfo"),
- Reginfo(Reginfo) {}
+ : SyntheticSection(SHF_ALLOC, SHT_MIPS_REGINFO, 4, ".reginfo"),
+ Reginfo(Reginfo) {
+ this->Entsize = sizeof(Elf_Mips_RegInfo);
+}
template <class ELFT> void MipsReginfoSection<ELFT>::writeTo(uint8_t *Buf) {
if (!Config->Relocatable)
- Reginfo.ri_gp_value = In<ELFT>::MipsGot->getGp();
+ Reginfo.ri_gp_value = InX::MipsGot->getGp();
memcpy(Buf, &Reginfo, sizeof(Reginfo));
}
@@ -253,22 +258,24 @@ MipsReginfoSection<ELFT> *MipsReginfoSection<ELFT>::create() {
Elf_Mips_RegInfo Reginfo = {};
bool Create = false;
- for (InputSectionBase<ELFT> *Sec : Symtab<ELFT>::X->Sections) {
- if (!Sec->Live || Sec->Type != SHT_MIPS_REGINFO)
+ for (InputSectionBase *Sec : InputSections) {
+ if (Sec->Type != SHT_MIPS_REGINFO)
continue;
Sec->Live = false;
Create = true;
if (Sec->Data.size() != sizeof(Elf_Mips_RegInfo)) {
- error(toString(Sec->getFile()) + ": invalid size of .reginfo section");
+ error(toString(Sec->getFile<ELFT>()) +
+ ": 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->getFile()) + ": unsupported non-zero ri_gp_value");
+ error(toString(Sec->getFile<ELFT>()) +
+ ": unsupported non-zero ri_gp_value");
Reginfo.ri_gprmask |= R->ri_gprmask;
- Sec->getFile()->MipsGp0 = R->ri_gp_value;
+ Sec->getFile<ELFT>()->MipsGp0 = R->ri_gp_value;
};
if (Create)
@@ -276,15 +283,24 @@ MipsReginfoSection<ELFT> *MipsReginfoSection<ELFT>::create() {
return nullptr;
}
-template <class ELFT> InputSection<ELFT> *elf::createInterpSection() {
- auto *Ret = make<InputSection<ELFT>>(SHF_ALLOC, SHT_PROGBITS, 1,
- ArrayRef<uint8_t>(), ".interp");
- Ret->Live = true;
-
+InputSection *elf::createInterpSection() {
// StringSaver guarantees that the returned string ends with '\0'.
StringRef S = Saver.save(Config->DynamicLinker);
- Ret->Data = {(const uint8_t *)S.data(), S.size() + 1};
- return Ret;
+ ArrayRef<uint8_t> Contents = {(const uint8_t *)S.data(), S.size() + 1};
+
+ auto *Sec =
+ make<InputSection>(SHF_ALLOC, SHT_PROGBITS, 1, Contents, ".interp");
+ Sec->Live = true;
+ return Sec;
+}
+
+SymbolBody *elf::addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value,
+ uint64_t Size, InputSectionBase *Section) {
+ auto *S = make<DefinedRegular>(Name, /*IsLocal*/ true, STV_DEFAULT, Type,
+ Value, Size, Section, nullptr);
+ if (InX::SymTab)
+ InX::SymTab->addSymbol(S);
+ return S;
}
static size_t getHashSize() {
@@ -303,16 +319,15 @@ static size_t getHashSize() {
}
}
-template <class ELFT>
-BuildIdSection<ELFT>::BuildIdSection()
- : SyntheticSection<ELFT>(SHF_ALLOC, SHT_NOTE, 1, ".note.gnu.build-id"),
+BuildIdSection::BuildIdSection()
+ : SyntheticSection(SHF_ALLOC, SHT_NOTE, 1, ".note.gnu.build-id"),
HashSize(getHashSize()) {}
-template <class ELFT> void BuildIdSection<ELFT>::writeTo(uint8_t *Buf) {
- const endianness E = ELFT::TargetEndianness;
- write32<E>(Buf, 4); // Name size
- write32<E>(Buf + 4, HashSize); // Content size
- write32<E>(Buf + 8, NT_GNU_BUILD_ID); // Type
+void BuildIdSection::writeTo(uint8_t *Buf) {
+ endianness E = Config->Endianness;
+ write32(Buf, 4, E); // Name size
+ write32(Buf + 4, HashSize, E); // Content size
+ write32(Buf + 8, NT_GNU_BUILD_ID, E); // Type
memcpy(Buf + 12, "GNU", 4); // Name string
HashBuf = Buf + 16;
}
@@ -334,23 +349,33 @@ static std::vector<ArrayRef<uint8_t>> split(ArrayRef<uint8_t> Arr,
// In order to utilize multiple cores, we first split data into 1MB
// chunks, compute a hash for each chunk, and then compute a hash value
// of the hash values.
-template <class ELFT>
-void BuildIdSection<ELFT>::computeHash(
+void BuildIdSection::computeHash(
llvm::ArrayRef<uint8_t> Data,
std::function<void(uint8_t *Dest, ArrayRef<uint8_t> Arr)> HashFn) {
std::vector<ArrayRef<uint8_t>> Chunks = split(Data, 1024 * 1024);
std::vector<uint8_t> Hashes(Chunks.size() * HashSize);
// Compute hash values.
- forLoop(0, Chunks.size(),
- [&](size_t I) { HashFn(Hashes.data() + I * HashSize, Chunks[I]); });
+ parallelForEachN(0, Chunks.size(), [&](size_t I) {
+ HashFn(Hashes.data() + I * HashSize, Chunks[I]);
+ });
// Write to the final output buffer.
HashFn(HashBuf, Hashes);
}
-template <class ELFT>
-void BuildIdSection<ELFT>::writeBuildId(ArrayRef<uint8_t> Buf) {
+BssSection::BssSection(StringRef Name)
+ : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_NOBITS, 0, Name) {}
+
+size_t BssSection::reserveSpace(uint64_t Size, uint32_t Alignment) {
+ if (OutputSection *Sec = getParent())
+ Sec->updateAlignment(Alignment);
+ this->Size = alignTo(this->Size, Alignment) + Size;
+ this->Alignment = std::max(this->Alignment, Alignment);
+ return this->Size - Size;
+}
+
+void BuildIdSection::writeBuildId(ArrayRef<uint8_t> Buf) {
switch (Config->BuildId) {
case BuildIdKind::Fast:
computeHash(Buf, [](uint8_t *Dest, ArrayRef<uint8_t> Arr) {
@@ -380,16 +405,229 @@ void BuildIdSection<ELFT>::writeBuildId(ArrayRef<uint8_t> Buf) {
}
template <class ELFT>
-GotSection<ELFT>::GotSection()
- : SyntheticSection<ELFT>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
- Target->GotEntrySize, ".got") {}
+EhFrameSection<ELFT>::EhFrameSection()
+ : SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 1, ".eh_frame") {}
+
+// Search for an existing CIE record or create a new one.
+// CIE records from input object files are uniquified by their contents
+// and where their relocations point to.
+template <class ELFT>
+template <class RelTy>
+CieRecord *EhFrameSection<ELFT>::addCie(EhSectionPiece &Piece,
+ ArrayRef<RelTy> Rels) {
+ auto *Sec = cast<EhInputSection>(Piece.ID);
+ const endianness E = ELFT::TargetEndianness;
+ if (read32<E>(Piece.data().data() + 4) != 0)
+ fatal(toString(Sec) + ": CIE expected at beginning of .eh_frame");
+
+ SymbolBody *Personality = nullptr;
+ unsigned FirstRelI = Piece.FirstRelocation;
+ if (FirstRelI != (unsigned)-1)
+ Personality =
+ &Sec->template getFile<ELFT>()->getRelocTargetSym(Rels[FirstRelI]);
+
+ // Search for an existing CIE by CIE contents/relocation target pair.
+ CieRecord *Cie = &CieMap[{Piece.data(), Personality}];
+
+ // If not found, create a new one.
+ if (Cie->Piece == nullptr) {
+ Cie->Piece = &Piece;
+ Cies.push_back(Cie);
+ }
+ return Cie;
+}
+
+// There is one FDE per function. Returns true if a given FDE
+// points to a live function.
+template <class ELFT>
+template <class RelTy>
+bool EhFrameSection<ELFT>::isFdeLive(EhSectionPiece &Piece,
+ ArrayRef<RelTy> Rels) {
+ auto *Sec = cast<EhInputSection>(Piece.ID);
+ unsigned FirstRelI = Piece.FirstRelocation;
+ if (FirstRelI == (unsigned)-1)
+ return false;
+ const RelTy &Rel = Rels[FirstRelI];
+ SymbolBody &B = Sec->template getFile<ELFT>()->getRelocTargetSym(Rel);
+ auto *D = dyn_cast<DefinedRegular>(&B);
+ if (!D || !D->Section)
+ return false;
+ auto *Target =
+ cast<InputSectionBase>(cast<InputSectionBase>(D->Section)->Repl);
+ return Target && Target->Live;
+}
-template <class ELFT> void GotSection<ELFT>::addEntry(SymbolBody &Sym) {
+// .eh_frame is a sequence of CIE or FDE records. In general, there
+// is one CIE record per input object file which is followed by
+// a list of FDEs. This function searches an existing CIE or create a new
+// one and associates FDEs to the CIE.
+template <class ELFT>
+template <class RelTy>
+void EhFrameSection<ELFT>::addSectionAux(EhInputSection *Sec,
+ ArrayRef<RelTy> Rels) {
+ const endianness E = ELFT::TargetEndianness;
+
+ DenseMap<size_t, CieRecord *> OffsetToCie;
+ 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<E>(Piece.data().data() + 4);
+ if (ID == 0) {
+ OffsetToCie[Offset] = addCie(Piece, Rels);
+ continue;
+ }
+
+ uint32_t CieOffset = Offset + 4 - ID;
+ CieRecord *Cie = OffsetToCie[CieOffset];
+ if (!Cie)
+ fatal(toString(Sec) + ": invalid CIE reference");
+
+ if (!isFdeLive(Piece, Rels))
+ continue;
+ Cie->FdePieces.push_back(&Piece);
+ NumFdes++;
+ }
+}
+
+template <class ELFT>
+void EhFrameSection<ELFT>::addSection(InputSectionBase *C) {
+ auto *Sec = cast<EhInputSection>(C);
+ Sec->Parent = this;
+ updateAlignment(Sec->Alignment);
+ Sections.push_back(Sec);
+ 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;
+
+ if (Sec->NumRelocations) {
+ if (Sec->AreRelocsRela)
+ addSectionAux(Sec, Sec->template relas<ELFT>());
+ else
+ addSectionAux(Sec, Sec->template rels<ELFT>());
+ return;
+ }
+ addSectionAux(Sec, makeArrayRef<Elf_Rela>(nullptr, nullptr));
+}
+
+template <class ELFT>
+static void writeCieFde(uint8_t *Buf, ArrayRef<uint8_t> D) {
+ memcpy(Buf, D.data(), D.size());
+
+ // Fix the size field. -4 since size does not include the size field itself.
+ const endianness E = ELFT::TargetEndianness;
+ write32<E>(Buf, alignTo(D.size(), sizeof(typename ELFT::uint)) - 4);
+}
+
+template <class ELFT> void EhFrameSection<ELFT>::finalizeContents() {
+ if (this->Size)
+ return; // Already finalized.
+
+ size_t Off = 0;
+ for (CieRecord *Cie : Cies) {
+ Cie->Piece->OutputOff = Off;
+ Off += alignTo(Cie->Piece->size(), Config->Wordsize);
+
+ for (EhSectionPiece *Fde : Cie->FdePieces) {
+ Fde->OutputOff = Off;
+ Off += alignTo(Fde->size(), Config->Wordsize);
+ }
+ }
+
+ // 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;
+
+ this->Size = Off;
+}
+
+template <class ELFT> static uint64_t readFdeAddr(uint8_t *Buf, int Size) {
+ const endianness E = ELFT::TargetEndianness;
+ switch (Size) {
+ case DW_EH_PE_udata2:
+ return read16<E>(Buf);
+ case DW_EH_PE_udata4:
+ return read32<E>(Buf);
+ case DW_EH_PE_udata8:
+ return read64<E>(Buf);
+ case DW_EH_PE_absptr:
+ if (ELFT::Is64Bits)
+ return read64<E>(Buf);
+ return read32<E>(Buf);
+ }
+ fatal("unknown FDE size encoding");
+}
+
+// Returns the VA to which a given FDE (on a mmap'ed buffer) is applied to.
+// We need it to create .eh_frame_hdr section.
+template <class ELFT>
+uint64_t EhFrameSection<ELFT>::getFdePc(uint8_t *Buf, size_t FdeOff,
+ uint8_t Enc) {
+ // The starting address to which this FDE applies is
+ // stored at FDE + 8 byte.
+ size_t Off = FdeOff + 8;
+ uint64_t Addr = readFdeAddr<ELFT>(Buf + Off, Enc & 0x7);
+ if ((Enc & 0x70) == DW_EH_PE_absptr)
+ return Addr;
+ if ((Enc & 0x70) == DW_EH_PE_pcrel)
+ return Addr + getParent()->Addr + Off;
+ fatal("unknown FDE size relative encoding");
+}
+
+template <class ELFT> void EhFrameSection<ELFT>::writeTo(uint8_t *Buf) {
+ const endianness E = ELFT::TargetEndianness;
+ for (CieRecord *Cie : Cies) {
+ size_t CieOffset = Cie->Piece->OutputOff;
+ writeCieFde<ELFT>(Buf + CieOffset, Cie->Piece->data());
+
+ for (EhSectionPiece *Fde : Cie->FdePieces) {
+ size_t Off = Fde->OutputOff;
+ writeCieFde<ELFT>(Buf + Off, Fde->data());
+
+ // FDE's second word should have the offset to an associated CIE.
+ // Write it.
+ write32<E>(Buf + Off + 4, Off + 4 - CieOffset);
+ }
+ }
+
+ for (EhInputSection *S : Sections)
+ S->relocateAlloc(Buf, nullptr);
+
+ // Construct .eh_frame_hdr. .eh_frame_hdr is a binary search table
+ // to get a FDE from an address to which FDE is applied. So here
+ // we obtain two addresses and pass them to EhFrameHdr object.
+ if (In<ELFT>::EhFrameHdr) {
+ for (CieRecord *Cie : Cies) {
+ uint8_t Enc = getFdeEncoding<ELFT>(Cie->Piece);
+ for (SectionPiece *Fde : Cie->FdePieces) {
+ uint64_t Pc = getFdePc(Buf, Fde->OutputOff, Enc);
+ uint64_t FdeVA = getParent()->Addr + Fde->OutputOff;
+ In<ELFT>::EhFrameHdr->addFde(Pc, FdeVA);
+ }
+ }
+ }
+}
+
+GotSection::GotSection()
+ : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
+ Target->GotEntrySize, ".got") {}
+
+void GotSection::addEntry(SymbolBody &Sym) {
Sym.GotIndex = NumEntries;
++NumEntries;
}
-template <class ELFT> bool GotSection<ELFT>::addDynTlsEntry(SymbolBody &Sym) {
+bool GotSection::addDynTlsEntry(SymbolBody &Sym) {
if (Sym.GlobalDynIndex != -1U)
return false;
Sym.GlobalDynIndex = NumEntries;
@@ -400,48 +638,42 @@ template <class ELFT> bool GotSection<ELFT>::addDynTlsEntry(SymbolBody &Sym) {
// Reserves TLS entries for a TLS module ID and a TLS block offset.
// In total it takes two GOT slots.
-template <class ELFT> bool GotSection<ELFT>::addTlsIndex() {
+bool GotSection::addTlsIndex() {
if (TlsIndexOff != uint32_t(-1))
return false;
- TlsIndexOff = NumEntries * sizeof(uintX_t);
+ TlsIndexOff = NumEntries * Config->Wordsize;
NumEntries += 2;
return true;
}
-template <class ELFT>
-typename GotSection<ELFT>::uintX_t
-GotSection<ELFT>::getGlobalDynAddr(const SymbolBody &B) const {
- return this->getVA() + B.GlobalDynIndex * sizeof(uintX_t);
+uint64_t GotSection::getGlobalDynAddr(const SymbolBody &B) const {
+ return this->getVA() + B.GlobalDynIndex * Config->Wordsize;
}
-template <class ELFT>
-typename GotSection<ELFT>::uintX_t
-GotSection<ELFT>::getGlobalDynOffset(const SymbolBody &B) const {
- return B.GlobalDynIndex * sizeof(uintX_t);
+uint64_t GotSection::getGlobalDynOffset(const SymbolBody &B) const {
+ return B.GlobalDynIndex * Config->Wordsize;
}
-template <class ELFT> void GotSection<ELFT>::finalize() {
- Size = NumEntries * sizeof(uintX_t);
-}
+void GotSection::finalizeContents() { Size = NumEntries * Config->Wordsize; }
-template <class ELFT> bool GotSection<ELFT>::empty() const {
+bool GotSection::empty() const {
// If we have a relocation that is relative to GOT (such as GOTOFFREL),
// we need to emit a GOT even if it's empty.
return NumEntries == 0 && !HasGotOffRel;
}
-template <class ELFT> void GotSection<ELFT>::writeTo(uint8_t *Buf) {
- this->relocate(Buf, Buf + Size);
+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.
+ relocateAlloc(Buf - OutSecOff, Buf - OutSecOff + Size);
}
-template <class ELFT>
-MipsGotSection<ELFT>::MipsGotSection()
- : SyntheticSection<ELFT>(SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL,
- SHT_PROGBITS, 16, ".got") {}
+MipsGotSection::MipsGotSection()
+ : SyntheticSection(SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL, SHT_PROGBITS, 16,
+ ".got") {}
-template <class ELFT>
-void MipsGotSection<ELFT>::addEntry(SymbolBody &Sym, uintX_t Addend,
- RelExpr Expr) {
+void MipsGotSection::addEntry(SymbolBody &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:
//
@@ -472,7 +704,7 @@ void MipsGotSection<ELFT>::addEntry(SymbolBody &Sym, uintX_t Addend,
// 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({cast<DefinedRegular<ELFT>>(&Sym)->Section->OutSec, 0});
+ PageIndexMap.insert({Sym.getOutputSection(), 0});
return;
}
if (Sym.isTls()) {
@@ -483,7 +715,7 @@ void MipsGotSection<ELFT>::addEntry(SymbolBody &Sym, uintX_t Addend,
TlsEntries.push_back(&Sym);
return;
}
- auto AddEntry = [&](SymbolBody &S, uintX_t A, GotEntries &Items) {
+ auto AddEntry = [&](SymbolBody &S, uint64_t A, GotEntries &Items) {
if (S.isInGot() && !A)
return;
size_t NewIndex = Items.size();
@@ -508,8 +740,7 @@ void MipsGotSection<ELFT>::addEntry(SymbolBody &Sym, uintX_t Addend,
}
}
-template <class ELFT>
-bool MipsGotSection<ELFT>::addDynTlsEntry(SymbolBody &Sym) {
+bool MipsGotSection::addDynTlsEntry(SymbolBody &Sym) {
if (Sym.GlobalDynIndex != -1U)
return false;
Sym.GlobalDynIndex = TlsEntries.size();
@@ -521,10 +752,10 @@ bool MipsGotSection<ELFT>::addDynTlsEntry(SymbolBody &Sym) {
// Reserves TLS entries for a TLS module ID and a TLS block offset.
// In total it takes two GOT slots.
-template <class ELFT> bool MipsGotSection<ELFT>::addTlsIndex() {
+bool MipsGotSection::addTlsIndex() {
if (TlsIndexOff != uint32_t(-1))
return false;
- TlsIndexOff = TlsEntries.size() * sizeof(uintX_t);
+ TlsIndexOff = TlsEntries.size() * Config->Wordsize;
TlsEntries.push_back(nullptr);
TlsEntries.push_back(nullptr);
return true;
@@ -538,25 +769,20 @@ static uint64_t getMipsPageCount(uint64_t Size) {
return (Size + 0xfffe) / 0xffff + 1;
}
-template <class ELFT>
-typename MipsGotSection<ELFT>::uintX_t
-MipsGotSection<ELFT>::getPageEntryOffset(const SymbolBody &B,
- uintX_t Addend) const {
- const OutputSectionBase *OutSec =
- cast<DefinedRegular<ELFT>>(&B)->Section->OutSec;
- uintX_t SecAddr = getMipsPageAddr(OutSec->Addr);
- uintX_t SymAddr = getMipsPageAddr(B.getVA<ELFT>(Addend));
- uintX_t Index = PageIndexMap.lookup(OutSec) + (SymAddr - SecAddr) / 0xffff;
+uint64_t MipsGotSection::getPageEntryOffset(const SymbolBody &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) * sizeof(uintX_t);
+ return (HeaderEntriesNum + Index) * Config->Wordsize;
}
-template <class ELFT>
-typename MipsGotSection<ELFT>::uintX_t
-MipsGotSection<ELFT>::getBodyEntryOffset(const SymbolBody &B,
- uintX_t Addend) const {
+uint64_t MipsGotSection::getBodyEntryOffset(const SymbolBody &B,
+ int64_t Addend) const {
// Calculate offset of the GOT entries block: TLS, global, local.
- uintX_t Index = HeaderEntriesNum + PageEntriesNum;
+ uint64_t Index = HeaderEntriesNum + PageEntriesNum;
if (B.isTls())
Index += LocalEntries.size() + LocalEntries32.size() + GlobalEntries.size();
else if (B.IsInGlobalMipsGot)
@@ -571,35 +797,31 @@ MipsGotSection<ELFT>::getBodyEntryOffset(const SymbolBody &B,
assert(It != EntryIndexMap.end());
Index += It->second;
}
- return Index * sizeof(uintX_t);
+ return Index * Config->Wordsize;
}
-template <class ELFT>
-typename MipsGotSection<ELFT>::uintX_t
-MipsGotSection<ELFT>::getTlsOffset() const {
- return (getLocalEntriesNum() + GlobalEntries.size()) * sizeof(uintX_t);
+uint64_t MipsGotSection::getTlsOffset() const {
+ return (getLocalEntriesNum() + GlobalEntries.size()) * Config->Wordsize;
}
-template <class ELFT>
-typename MipsGotSection<ELFT>::uintX_t
-MipsGotSection<ELFT>::getGlobalDynOffset(const SymbolBody &B) const {
- return B.GlobalDynIndex * sizeof(uintX_t);
+uint64_t MipsGotSection::getGlobalDynOffset(const SymbolBody &B) const {
+ return B.GlobalDynIndex * Config->Wordsize;
}
-template <class ELFT>
-const SymbolBody *MipsGotSection<ELFT>::getFirstGlobalEntry() const {
+const SymbolBody *MipsGotSection::getFirstGlobalEntry() const {
return GlobalEntries.empty() ? nullptr : GlobalEntries.front().first;
}
-template <class ELFT>
-unsigned MipsGotSection<ELFT>::getLocalEntriesNum() const {
+unsigned MipsGotSection::getLocalEntriesNum() const {
return HeaderEntriesNum + PageEntriesNum + LocalEntries.size() +
LocalEntries32.size();
}
-template <class ELFT> void MipsGotSection<ELFT>::finalize() {
+void MipsGotSection::finalizeContents() { updateAllocSize(); }
+
+void MipsGotSection::updateAllocSize() {
PageEntriesNum = 0;
- for (std::pair<const OutputSectionBase *, size_t> &P : PageIndexMap) {
+ 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 -
@@ -610,27 +832,31 @@ template <class ELFT> void MipsGotSection<ELFT>::finalize() {
PageEntriesNum += getMipsPageCount(P.first->Size);
}
Size = (getLocalEntriesNum() + GlobalEntries.size() + TlsEntries.size()) *
- sizeof(uintX_t);
+ Config->Wordsize;
}
-template <class ELFT> bool MipsGotSection<ELFT>::empty() const {
+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;
}
-template <class ELFT>
-typename MipsGotSection<ELFT>::uintX_t MipsGotSection<ELFT>::getGp() const {
- return ElfSym<ELFT>::MipsGp->template getVA<ELFT>(0);
+uint64_t MipsGotSection::getGp() const { return ElfSym::MipsGp->getVA(0); }
+
+static uint64_t readUint(uint8_t *Buf) {
+ if (Config->Is64)
+ return read64(Buf, Config->Endianness);
+ return read32(Buf, Config->Endianness);
}
-template <class ELFT>
-static void writeUint(uint8_t *Buf, typename ELFT::uint Val) {
- typedef typename ELFT::uint uintX_t;
- write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Buf, Val);
+static void writeUint(uint8_t *Buf, uint64_t Val) {
+ if (Config->Is64)
+ write64(Buf, Val, Config->Endianness);
+ else
+ write32(Buf, Val, Config->Endianness);
}
-template <class ELFT> void MipsGotSection<ELFT>::writeTo(uint8_t *Buf) {
+void MipsGotSection::writeTo(uint8_t *Buf) {
// Set the MSB of the second GOT slot. This is not required by any
// MIPS ABI documentation, though.
//
@@ -645,25 +871,24 @@ template <class ELFT> void MipsGotSection<ELFT>::writeTo(uint8_t *Buf) {
// we've been doing this for years, it is probably a safe bet to
// keep doing this for now. We really need to revisit this to see
// if we had to do this.
- auto *P = reinterpret_cast<typename ELFT::Off *>(Buf);
- P[1] = uintX_t(1) << (ELFT::Is64Bits ? 63 : 31);
- Buf += HeaderEntriesNum * sizeof(uintX_t);
+ 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 OutputSectionBase *, size_t> &L : PageIndexMap) {
+ for (std::pair<const OutputSection *, size_t> &L : PageIndexMap) {
size_t PageCount = getMipsPageCount(L.first->Size);
- uintX_t FirstPageAddr = getMipsPageAddr(L.first->Addr);
+ uint64_t FirstPageAddr = getMipsPageAddr(L.first->Addr);
for (size_t PI = 0; PI < PageCount; ++PI) {
- uint8_t *Entry = Buf + (L.second + PI) * sizeof(uintX_t);
- writeUint<ELFT>(Entry, FirstPageAddr + PI * 0x10000);
+ uint8_t *Entry = Buf + (L.second + PI) * Config->Wordsize;
+ writeUint(Entry, FirstPageAddr + PI * 0x10000);
}
}
- Buf += PageEntriesNum * sizeof(uintX_t);
+ Buf += PageEntriesNum * Config->Wordsize;
auto AddEntry = [&](const GotEntry &SA) {
uint8_t *Entry = Buf;
- Buf += sizeof(uintX_t);
+ Buf += Config->Wordsize;
const SymbolBody *Body = SA.first;
- uintX_t VA = Body->template getVA<ELFT>(SA.second);
- writeUint<ELFT>(Entry, VA);
+ uint64_t VA = Body->getVA(SA.second);
+ writeUint(Entry, VA);
};
std::for_each(std::begin(LocalEntries), std::end(LocalEntries), AddEntry);
std::for_each(std::begin(LocalEntries32), std::end(LocalEntries32), AddEntry);
@@ -674,86 +899,83 @@ template <class ELFT> void MipsGotSection<ELFT>::writeTo(uint8_t *Buf) {
// for thread-local storage.
// https://www.linux-mips.org/wiki/NPTL
if (TlsIndexOff != -1U && !Config->Pic)
- writeUint<ELFT>(Buf + TlsIndexOff, 1);
+ writeUint(Buf + TlsIndexOff, 1);
for (const SymbolBody *B : TlsEntries) {
if (!B || B->isPreemptible())
continue;
- uintX_t VA = B->getVA<ELFT>();
+ uint64_t VA = B->getVA();
if (B->GotIndex != -1U) {
- uint8_t *Entry = Buf + B->GotIndex * sizeof(uintX_t);
- writeUint<ELFT>(Entry, VA - 0x7000);
+ uint8_t *Entry = Buf + B->GotIndex * Config->Wordsize;
+ writeUint(Entry, VA - 0x7000);
}
if (B->GlobalDynIndex != -1U) {
- uint8_t *Entry = Buf + B->GlobalDynIndex * sizeof(uintX_t);
- writeUint<ELFT>(Entry, 1);
- Entry += sizeof(uintX_t);
- writeUint<ELFT>(Entry, VA - 0x8000);
+ uint8_t *Entry = Buf + B->GlobalDynIndex * Config->Wordsize;
+ writeUint(Entry, 1);
+ Entry += Config->Wordsize;
+ writeUint(Entry, VA - 0x8000);
}
}
}
-template <class ELFT>
-GotPltSection<ELFT>::GotPltSection()
- : SyntheticSection<ELFT>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
- Target->GotPltEntrySize, ".got.plt") {}
+GotPltSection::GotPltSection()
+ : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
+ Target->GotPltEntrySize, ".got.plt") {}
-template <class ELFT> void GotPltSection<ELFT>::addEntry(SymbolBody &Sym) {
+void GotPltSection::addEntry(SymbolBody &Sym) {
Sym.GotPltIndex = Target->GotPltHeaderEntriesNum + Entries.size();
Entries.push_back(&Sym);
}
-template <class ELFT> size_t GotPltSection<ELFT>::getSize() const {
+size_t GotPltSection::getSize() const {
return (Target->GotPltHeaderEntriesNum + Entries.size()) *
Target->GotPltEntrySize;
}
-template <class ELFT> void GotPltSection<ELFT>::writeTo(uint8_t *Buf) {
+void GotPltSection::writeTo(uint8_t *Buf) {
Target->writeGotPltHeader(Buf);
Buf += Target->GotPltHeaderEntriesNum * Target->GotPltEntrySize;
for (const SymbolBody *B : Entries) {
Target->writeGotPlt(Buf, *B);
- Buf += sizeof(uintX_t);
+ Buf += Config->Wordsize;
}
}
// On ARM the IgotPltSection is part of the GotSection, on other Targets it is
// part of the .got.plt
-template <class ELFT>
-IgotPltSection<ELFT>::IgotPltSection()
- : SyntheticSection<ELFT>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
- Target->GotPltEntrySize,
- Config->EMachine == EM_ARM ? ".got" : ".got.plt") {
-}
+IgotPltSection::IgotPltSection()
+ : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
+ Target->GotPltEntrySize,
+ Config->EMachine == EM_ARM ? ".got" : ".got.plt") {}
-template <class ELFT> void IgotPltSection<ELFT>::addEntry(SymbolBody &Sym) {
+void IgotPltSection::addEntry(SymbolBody &Sym) {
Sym.IsInIgot = true;
Sym.GotPltIndex = Entries.size();
Entries.push_back(&Sym);
}
-template <class ELFT> size_t IgotPltSection<ELFT>::getSize() const {
+size_t IgotPltSection::getSize() const {
return Entries.size() * Target->GotPltEntrySize;
}
-template <class ELFT> void IgotPltSection<ELFT>::writeTo(uint8_t *Buf) {
+void IgotPltSection::writeTo(uint8_t *Buf) {
for (const SymbolBody *B : Entries) {
Target->writeIgotPlt(Buf, *B);
- Buf += sizeof(uintX_t);
+ Buf += Config->Wordsize;
}
}
-template <class ELFT>
-StringTableSection<ELFT>::StringTableSection(StringRef Name, bool Dynamic)
- : SyntheticSection<ELFT>(Dynamic ? (uintX_t)SHF_ALLOC : 0, SHT_STRTAB, 1,
- Name),
- Dynamic(Dynamic) {}
+StringTableSection::StringTableSection(StringRef Name, bool Dynamic)
+ : SyntheticSection(Dynamic ? (uint64_t)SHF_ALLOC : 0, SHT_STRTAB, 1, Name),
+ Dynamic(Dynamic) {
+ // ELF string tables start with a NUL byte.
+ addString("");
+}
// Adds a string to the string table. If HashIt is true we hash and check for
// duplicates. It is optional because the name of global symbols are already
// uniqued and hashing them again has a big cost for a small value: uniquing
// them with some other string that happens to be the same.
-template <class ELFT>
-unsigned StringTableSection<ELFT>::addString(StringRef S, bool HashIt) {
+unsigned StringTableSection::addString(StringRef S, bool HashIt) {
if (HashIt) {
auto R = StringMap.insert(std::make_pair(S, this->Size));
if (!R.second)
@@ -765,9 +987,7 @@ unsigned StringTableSection<ELFT>::addString(StringRef S, bool HashIt) {
return Ret;
}
-template <class ELFT> void StringTableSection<ELFT>::writeTo(uint8_t *Buf) {
- // ELF string tables start with NUL byte, so advance the pointer by one.
- ++Buf;
+void StringTableSection::writeTo(uint8_t *Buf) {
for (StringRef S : Strings) {
memcpy(Buf, S.data(), S.size());
Buf += S.size() + 1;
@@ -781,13 +1001,15 @@ static unsigned getVerDefNum() { return Config->VersionDefinitions.size() + 1; }
template <class ELFT>
DynamicSection<ELFT>::DynamicSection()
- : SyntheticSection<ELFT>(SHF_ALLOC | SHF_WRITE, SHT_DYNAMIC,
- sizeof(uintX_t), ".dynamic") {
+ : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_DYNAMIC, Config->Wordsize,
+ ".dynamic") {
this->Entsize = ELFT::Is64Bits ? 16 : 8;
- // .dynamic section is not writable on MIPS.
+
+ // .dynamic section is not writable on MIPS and on Fuchsia OS
+ // which passes -z rodynamic.
// See "Special Section" in Chapter 4 in the following document:
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
- if (Config->EMachine == EM_MIPS)
+ if (Config->EMachine == EM_MIPS || Config->ZRodynamic)
this->Flags = SHF_ALLOC;
addEntries();
@@ -798,16 +1020,18 @@ DynamicSection<ELFT>::DynamicSection()
template <class ELFT> void DynamicSection<ELFT>::addEntries() {
// Add strings to .dynstr early so that .dynstr's size will be
// fixed early.
+ for (StringRef S : Config->FilterList)
+ add({DT_FILTER, InX::DynStrTab->addString(S)});
for (StringRef S : Config->AuxiliaryList)
- add({DT_AUXILIARY, In<ELFT>::DynStrTab->addString(S)});
- if (!Config->RPath.empty())
+ add({DT_AUXILIARY, InX::DynStrTab->addString(S)});
+ if (!Config->Rpath.empty())
add({Config->EnableNewDtags ? DT_RUNPATH : DT_RPATH,
- In<ELFT>::DynStrTab->addString(Config->RPath)});
+ InX::DynStrTab->addString(Config->Rpath)});
for (SharedFile<ELFT> *F : Symtab<ELFT>::X->getSharedFiles())
if (F->isNeeded())
- add({DT_NEEDED, In<ELFT>::DynStrTab->addString(F->getSoName())});
+ add({DT_NEEDED, InX::DynStrTab->addString(F->SoName)});
if (!Config->SoName.empty())
- add({DT_SONAME, In<ELFT>::DynStrTab->addString(Config->SoName)});
+ add({DT_SONAME, InX::DynStrTab->addString(Config->SoName)});
// Set DT_FLAGS and DT_FLAGS_1.
uint32_t DtFlags = 0;
@@ -832,22 +1056,31 @@ template <class ELFT> void DynamicSection<ELFT>::addEntries() {
if (DtFlags1)
add({DT_FLAGS_1, DtFlags1});
- if (!Config->Shared && !Config->Relocatable)
+ // DT_DEBUG is a pointer to debug informaion used by debuggers at runtime. We
+ // need it for each process, so we don't write it for DSOs. The loader writes
+ // the pointer into this entry.
+ //
+ // DT_DEBUG is the only .dynamic entry that needs to be written to. Some
+ // systems (currently only Fuchsia OS) provide other means to give the
+ // debugger this information. Such systems may choose make .dynamic read-only.
+ // If the target is such a system (used -z rodynamic) don't write DT_DEBUG.
+ if (!Config->Shared && !Config->Relocatable && !Config->ZRodynamic)
add({DT_DEBUG, (uint64_t)0});
}
// Add remaining entries to complete .dynamic contents.
-template <class ELFT> void DynamicSection<ELFT>::finalize() {
+template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
if (this->Size)
return; // Already finalized.
- this->Link = In<ELFT>::DynStrTab->OutSec->SectionIndex;
- if (In<ELFT>::RelaDyn->OutSec->Size > 0) {
- bool IsRela = Config->Rela;
+ this->Link = InX::DynStrTab->getParent()->SectionIndex;
+ if (In<ELFT>::RelaDyn->getParent() && !In<ELFT>::RelaDyn->empty()) {
+ bool IsRela = Config->IsRela;
add({IsRela ? DT_RELA : DT_REL, In<ELFT>::RelaDyn});
- add({IsRela ? DT_RELASZ : DT_RELSZ, In<ELFT>::RelaDyn->OutSec->Size});
+ add({IsRela ? DT_RELASZ : DT_RELSZ, In<ELFT>::RelaDyn->getParent(),
+ Entry::SecSize});
add({IsRela ? DT_RELAENT : DT_RELENT,
- uintX_t(IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel))});
+ uint64_t(IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel))});
// MIPS dynamic loader does not support RELCOUNT tag.
// The problem is in the tight relation between dynamic
@@ -858,34 +1091,45 @@ template <class ELFT> void DynamicSection<ELFT>::finalize() {
add({IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels});
}
}
- if (In<ELFT>::RelaPlt->OutSec->Size > 0) {
+ if (In<ELFT>::RelaPlt->getParent() && !In<ELFT>::RelaPlt->empty()) {
add({DT_JMPREL, In<ELFT>::RelaPlt});
- add({DT_PLTRELSZ, In<ELFT>::RelaPlt->OutSec->Size});
- add({Config->EMachine == EM_MIPS ? DT_MIPS_PLTGOT : DT_PLTGOT,
- In<ELFT>::GotPlt});
- add({DT_PLTREL, uint64_t(Config->Rela ? DT_RELA : DT_REL)});
+ add({DT_PLTRELSZ, In<ELFT>::RelaPlt->getParent(), Entry::SecSize});
+ switch (Config->EMachine) {
+ case EM_MIPS:
+ add({DT_MIPS_PLTGOT, In<ELFT>::GotPlt});
+ break;
+ case EM_SPARCV9:
+ add({DT_PLTGOT, In<ELFT>::Plt});
+ break;
+ default:
+ add({DT_PLTGOT, In<ELFT>::GotPlt});
+ break;
+ }
+ add({DT_PLTREL, uint64_t(Config->IsRela ? DT_RELA : DT_REL)});
}
- add({DT_SYMTAB, In<ELFT>::DynSymTab});
+ add({DT_SYMTAB, InX::DynSymTab});
add({DT_SYMENT, sizeof(Elf_Sym)});
- add({DT_STRTAB, In<ELFT>::DynStrTab});
- add({DT_STRSZ, In<ELFT>::DynStrTab->getSize()});
- if (In<ELFT>::GnuHashTab)
- add({DT_GNU_HASH, In<ELFT>::GnuHashTab});
+ add({DT_STRTAB, InX::DynStrTab});
+ add({DT_STRSZ, InX::DynStrTab->getSize()});
+ if (!Config->ZText)
+ add({DT_TEXTREL, (uint64_t)0});
+ if (InX::GnuHashTab)
+ add({DT_GNU_HASH, InX::GnuHashTab});
if (In<ELFT>::HashTab)
add({DT_HASH, In<ELFT>::HashTab});
- if (Out<ELFT>::PreinitArray) {
- add({DT_PREINIT_ARRAY, Out<ELFT>::PreinitArray});
- add({DT_PREINIT_ARRAYSZ, Out<ELFT>::PreinitArray, Entry::SecSize});
+ if (Out::PreinitArray) {
+ add({DT_PREINIT_ARRAY, Out::PreinitArray});
+ add({DT_PREINIT_ARRAYSZ, Out::PreinitArray, Entry::SecSize});
}
- if (Out<ELFT>::InitArray) {
- add({DT_INIT_ARRAY, Out<ELFT>::InitArray});
- add({DT_INIT_ARRAYSZ, Out<ELFT>::InitArray, Entry::SecSize});
+ if (Out::InitArray) {
+ add({DT_INIT_ARRAY, Out::InitArray});
+ add({DT_INIT_ARRAYSZ, Out::InitArray, Entry::SecSize});
}
- if (Out<ELFT>::FiniArray) {
- add({DT_FINI_ARRAY, Out<ELFT>::FiniArray});
- add({DT_FINI_ARRAYSZ, Out<ELFT>::FiniArray, Entry::SecSize});
+ if (Out::FiniArray) {
+ add({DT_FINI_ARRAY, Out::FiniArray});
+ add({DT_FINI_ARRAYSZ, Out::FiniArray, Entry::SecSize});
}
if (SymbolBody *B = Symtab<ELFT>::X->findInCurrentDSO(Config->Init))
@@ -909,19 +1153,18 @@ template <class ELFT> void DynamicSection<ELFT>::finalize() {
add({DT_MIPS_RLD_VERSION, 1});
add({DT_MIPS_FLAGS, RHF_NOTPOT});
add({DT_MIPS_BASE_ADDRESS, Config->ImageBase});
- add({DT_MIPS_SYMTABNO, In<ELFT>::DynSymTab->getNumSymbols()});
- add({DT_MIPS_LOCAL_GOTNO, In<ELFT>::MipsGot->getLocalEntriesNum()});
- if (const SymbolBody *B = In<ELFT>::MipsGot->getFirstGlobalEntry())
+ add({DT_MIPS_SYMTABNO, InX::DynSymTab->getNumSymbols()});
+ add({DT_MIPS_LOCAL_GOTNO, InX::MipsGot->getLocalEntriesNum()});
+ if (const SymbolBody *B = InX::MipsGot->getFirstGlobalEntry())
add({DT_MIPS_GOTSYM, B->DynsymIndex});
else
- add({DT_MIPS_GOTSYM, In<ELFT>::DynSymTab->getNumSymbols()});
- add({DT_PLTGOT, In<ELFT>::MipsGot});
- if (In<ELFT>::MipsRldMap)
- add({DT_MIPS_RLD_MAP, In<ELFT>::MipsRldMap});
+ add({DT_MIPS_GOTSYM, InX::DynSymTab->getNumSymbols()});
+ add({DT_PLTGOT, InX::MipsGot});
+ if (InX::MipsRldMap)
+ add({DT_MIPS_RLD_MAP, InX::MipsRldMap});
}
- this->OutSec->Entsize = this->Entsize;
- this->OutSec->Link = this->Link;
+ getParent()->Link = this->Link;
// +1 for DT_NULL
this->Size = (Entries.size() + 1) * this->Entsize;
@@ -937,13 +1180,13 @@ template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) {
P->d_un.d_ptr = E.OutSec->Addr;
break;
case Entry::InSecAddr:
- P->d_un.d_ptr = E.InSec->OutSec->Addr + E.InSec->OutSecOff;
+ P->d_un.d_ptr = E.InSec->getParent()->Addr + E.InSec->OutSecOff;
break;
case Entry::SecSize:
P->d_un.d_val = E.OutSec->Size;
break;
case Entry::SymAddr:
- P->d_un.d_ptr = E.Sym->template getVA<ELFT>();
+ P->d_un.d_ptr = E.Sym->getVA();
break;
case Entry::PlainInt:
P->d_un.d_val = E.Val;
@@ -953,21 +1196,17 @@ template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) {
}
}
-template <class ELFT>
-typename ELFT::uint DynamicReloc<ELFT>::getOffset() const {
- if (OutputSec)
- return OutputSec->Addr + OffsetInSec;
- return InputSec->OutSec->Addr + InputSec->getOffset(OffsetInSec);
+uint64_t DynamicReloc::getOffset() const {
+ return InputSec->getOutputSection()->Addr + InputSec->getOffset(OffsetInSec);
}
-template <class ELFT>
-typename ELFT::uint DynamicReloc<ELFT>::getAddend() const {
+int64_t DynamicReloc::getAddend() const {
if (UseSymVA)
- return Sym->getVA<ELFT>(Addend);
+ return Sym->getVA(Addend);
return Addend;
}
-template <class ELFT> uint32_t DynamicReloc<ELFT>::getSymIndex() const {
+uint32_t DynamicReloc::getSymIndex() const {
if (Sym && !UseSymVA)
return Sym->DynsymIndex;
return 0;
@@ -975,14 +1214,14 @@ template <class ELFT> uint32_t DynamicReloc<ELFT>::getSymIndex() const {
template <class ELFT>
RelocationSection<ELFT>::RelocationSection(StringRef Name, bool Sort)
- : SyntheticSection<ELFT>(SHF_ALLOC, Config->Rela ? SHT_RELA : SHT_REL,
- sizeof(uintX_t), Name),
+ : SyntheticSection(SHF_ALLOC, Config->IsRela ? SHT_RELA : SHT_REL,
+ Config->Wordsize, Name),
Sort(Sort) {
- this->Entsize = Config->Rela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
+ this->Entsize = Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
}
template <class ELFT>
-void RelocationSection<ELFT>::addReloc(const DynamicReloc<ELFT> &Reloc) {
+void RelocationSection<ELFT>::addReloc(const DynamicReloc &Reloc) {
if (Reloc.Type == Target->RelativeRel)
++NumRelativeRelocs;
Relocs.push_back(Reloc);
@@ -990,33 +1229,33 @@ void RelocationSection<ELFT>::addReloc(const DynamicReloc<ELFT> &Reloc) {
template <class ELFT, class RelTy>
static bool compRelocations(const RelTy &A, const RelTy &B) {
- bool AIsRel = A.getType(Config->Mips64EL) == Target->RelativeRel;
- bool BIsRel = B.getType(Config->Mips64EL) == Target->RelativeRel;
+ bool AIsRel = A.getType(Config->IsMips64EL) == Target->RelativeRel;
+ bool BIsRel = B.getType(Config->IsMips64EL) == Target->RelativeRel;
if (AIsRel != BIsRel)
return AIsRel;
- return A.getSymbol(Config->Mips64EL) < B.getSymbol(Config->Mips64EL);
+ return A.getSymbol(Config->IsMips64EL) < B.getSymbol(Config->IsMips64EL);
}
template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
uint8_t *BufBegin = Buf;
- for (const DynamicReloc<ELFT> &Rel : Relocs) {
+ for (const DynamicReloc &Rel : Relocs) {
auto *P = reinterpret_cast<Elf_Rela *>(Buf);
- Buf += Config->Rela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
+ Buf += Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
- if (Config->Rela)
+ if (Config->IsRela)
P->r_addend = Rel.getAddend();
P->r_offset = Rel.getOffset();
- if (Config->EMachine == EM_MIPS && Rel.getInputSec() == In<ELFT>::MipsGot)
+ if (Config->EMachine == EM_MIPS && Rel.getInputSec() == InX::MipsGot)
// Dynamic relocation against MIPS GOT section make deal TLS entries
// allocated in the end of the GOT. We need to adjust the offset to take
// in account 'local' and 'global' GOT entries.
- P->r_offset += In<ELFT>::MipsGot->getTlsOffset();
- P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->Mips64EL);
+ P->r_offset += InX::MipsGot->getTlsOffset();
+ P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->IsMips64EL);
}
if (Sort) {
- if (Config->Rela)
+ if (Config->IsRela)
std::stable_sort((Elf_Rela *)BufBegin,
(Elf_Rela *)BufBegin + Relocs.size(),
compRelocations<ELFT, Elf_Rela>);
@@ -1030,314 +1269,284 @@ template <class ELFT> unsigned RelocationSection<ELFT>::getRelocOffset() {
return this->Entsize * Relocs.size();
}
-template <class ELFT> void RelocationSection<ELFT>::finalize() {
- this->Link = In<ELFT>::DynSymTab ? In<ELFT>::DynSymTab->OutSec->SectionIndex
- : In<ELFT>::SymTab->OutSec->SectionIndex;
+template <class ELFT> void RelocationSection<ELFT>::finalizeContents() {
+ this->Link = InX::DynSymTab ? InX::DynSymTab->getParent()->SectionIndex
+ : InX::SymTab->getParent()->SectionIndex;
// Set required output section properties.
- this->OutSec->Link = this->Link;
- this->OutSec->Entsize = this->Entsize;
+ getParent()->Link = this->Link;
}
-template <class ELFT>
-SymbolTableSection<ELFT>::SymbolTableSection(
- StringTableSection<ELFT> &StrTabSec)
- : SyntheticSection<ELFT>(StrTabSec.isDynamic() ? (uintX_t)SHF_ALLOC : 0,
- StrTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB,
- sizeof(uintX_t),
- StrTabSec.isDynamic() ? ".dynsym" : ".symtab"),
- StrTabSec(StrTabSec) {
- this->Entsize = sizeof(Elf_Sym);
-}
+SymbolTableBaseSection::SymbolTableBaseSection(StringTableSection &StrTabSec)
+ : SyntheticSection(StrTabSec.isDynamic() ? (uint64_t)SHF_ALLOC : 0,
+ StrTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB,
+ Config->Wordsize,
+ StrTabSec.isDynamic() ? ".dynsym" : ".symtab"),
+ StrTabSec(StrTabSec) {}
// Orders symbols according to their positions in the GOT,
// in compliance with MIPS ABI rules.
// 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
-static bool sortMipsSymbols(const SymbolBody *L, const SymbolBody *R) {
+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->IsInGlobalMipsGot;
- bool RIsInLocalGot = !R->IsInGlobalMipsGot;
+ bool LIsInLocalGot = !L.Symbol->IsInGlobalMipsGot;
+ bool RIsInLocalGot = !R.Symbol->IsInGlobalMipsGot;
if (LIsInLocalGot || RIsInLocalGot)
return !RIsInLocalGot;
- return L->GotIndex < R->GotIndex;
-}
-
-template <class ELFT> void SymbolTableSection<ELFT>::finalize() {
- this->OutSec->Link = this->Link = StrTabSec.OutSec->SectionIndex;
- this->OutSec->Info = this->Info = NumLocals + 1;
- this->OutSec->Entsize = this->Entsize;
-
- if (Config->Relocatable)
- return;
+ return L.Symbol->GotIndex < R.Symbol->GotIndex;
+}
+
+// Finalize a symbol table. 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.)
+void SymbolTableBaseSection::finalizeContents() {
+ getParent()->Link = StrTabSec.getParent()->SectionIndex;
+
+ // 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);
+ }
- if (!StrTabSec.isDynamic()) {
- auto GlobBegin = Symbols.begin() + NumLocals;
- auto It = std::stable_partition(
- GlobBegin, Symbols.end(), [](const SymbolTableEntry &S) {
- return S.Symbol->symbol()->computeBinding() == STB_LOCAL;
- });
- // update sh_info with number of Global symbols output with computed
- // binding of STB_LOCAL
- this->OutSec->Info = this->Info = 1 + It - Symbols.begin();
+ size_t I = 0;
+ for (const SymbolTableEntry &S : Symbols)
+ S.Symbol->DynsymIndex = ++I;
return;
}
-
- if (In<ELFT>::GnuHashTab)
- // NB: It also sorts Symbols to meet the GNU hash table requirements.
- In<ELFT>::GnuHashTab->addSymbols(Symbols);
- else if (Config->EMachine == EM_MIPS)
- std::stable_sort(Symbols.begin(), Symbols.end(),
- [](const SymbolTableEntry &L, const SymbolTableEntry &R) {
- return sortMipsSymbols(L.Symbol, R.Symbol);
- });
- size_t I = 0;
- for (const SymbolTableEntry &S : Symbols)
- S.Symbol->DynsymIndex = ++I;
}
-template <class ELFT> void SymbolTableSection<ELFT>::addGlobal(SymbolBody *B) {
- Symbols.push_back({B, StrTabSec.addString(B->getName(), false)});
+void SymbolTableBaseSection::postThunkContents() {
+ if (this->Type == SHT_DYNSYM)
+ return;
+ // move all local symbols before global symbols.
+ auto It = std::stable_partition(
+ Symbols.begin(), Symbols.end(), [](const SymbolTableEntry &S) {
+ return S.Symbol->isLocal() ||
+ S.Symbol->symbol()->computeBinding() == STB_LOCAL;
+ });
+ size_t NumLocals = It - Symbols.begin();
+ getParent()->Info = NumLocals + 1;
}
-template <class ELFT> void SymbolTableSection<ELFT>::addLocal(SymbolBody *B) {
- assert(!StrTabSec.isDynamic());
- ++NumLocals;
- Symbols.push_back({B, StrTabSec.addString(B->getName())});
+void SymbolTableBaseSection::addSymbol(SymbolBody *B) {
+ // Adding a local symbol to a .dynsym is a bug.
+ assert(this->Type != SHT_DYNSYM || !B->isLocal());
+
+ bool HashIt = B->isLocal();
+ Symbols.push_back({B, StrTabSec.addString(B->getName(), HashIt)});
}
-template <class ELFT>
-size_t SymbolTableSection<ELFT>::getSymbolIndex(SymbolBody *Body) {
- auto I = llvm::find_if(
- Symbols, [&](const SymbolTableEntry &E) { return E.Symbol == Body; });
+size_t SymbolTableBaseSection::getSymbolIndex(SymbolBody *Body) {
+ auto I = llvm::find_if(Symbols, [&](const SymbolTableEntry &E) {
+ if (E.Symbol == Body)
+ return true;
+ // This is used for -r, so we have to handle multiple section
+ // symbols being combined.
+ if (Body->Type == STT_SECTION && E.Symbol->Type == STT_SECTION)
+ return Body->getOutputSection() == E.Symbol->getOutputSection();
+ return false;
+ });
if (I == Symbols.end())
return 0;
return I - Symbols.begin() + 1;
}
+template <class ELFT>
+SymbolTableSection<ELFT>::SymbolTableSection(StringTableSection &StrTabSec)
+ : SymbolTableBaseSection(StrTabSec) {
+ this->Entsize = sizeof(Elf_Sym);
+}
+
+// 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.
Buf += sizeof(Elf_Sym);
- // All symbols with STB_LOCAL binding precede the weak and global symbols.
- // .dynsym only contains global symbols.
- if (Config->Discard != DiscardPolicy::All && !StrTabSec.isDynamic())
- writeLocalSymbols(Buf);
-
- writeGlobalSymbols(Buf);
-}
-
-template <class ELFT>
-void SymbolTableSection<ELFT>::writeLocalSymbols(uint8_t *&Buf) {
- // Iterate over all input object files to copy their local symbols
- // to the output symbol table pointed by Buf.
+ auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
- for (auto I = Symbols.begin(); I != Symbols.begin() + NumLocals; ++I) {
- const DefinedRegular<ELFT> &Body = *cast<DefinedRegular<ELFT>>(I->Symbol);
- InputSectionBase<ELFT> *Section = Body.Section;
- auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
+ for (SymbolTableEntry &Ent : Symbols) {
+ SymbolBody *Body = Ent.Symbol;
- if (!Section) {
- ESym->st_shndx = SHN_ABS;
- ESym->st_value = Body.Value;
+ // Set st_info and st_other.
+ if (Body->isLocal()) {
+ ESym->setBindingAndType(STB_LOCAL, Body->Type);
} else {
- const OutputSectionBase *OutSec = Section->OutSec;
- ESym->st_shndx = OutSec->SectionIndex;
- ESym->st_value = OutSec->Addr + Section->getOffset(Body);
+ ESym->setBindingAndType(Body->symbol()->computeBinding(), Body->Type);
+ ESym->setVisibility(Body->symbol()->Visibility);
}
- ESym->st_name = I->StrTabOffset;
- ESym->st_size = Body.template getSize<ELFT>();
- ESym->setBindingAndType(STB_LOCAL, Body.Type);
- Buf += sizeof(*ESym);
- }
-}
-
-template <class ELFT>
-void SymbolTableSection<ELFT>::writeGlobalSymbols(uint8_t *Buf) {
- // Write the internal symbol table contents to the output symbol table
- // pointed by Buf.
- auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
-
- for (auto I = Symbols.begin() + NumLocals; I != Symbols.end(); ++I) {
- const SymbolTableEntry &S = *I;
- SymbolBody *Body = S.Symbol;
- size_t StrOff = S.StrTabOffset;
- uint8_t Type = Body->Type;
- uintX_t Size = Body->getSize<ELFT>();
+ ESym->st_name = Ent.StrTabOffset;
- ESym->setBindingAndType(Body->symbol()->computeBinding(), Type);
- ESym->st_size = Size;
- ESym->st_name = StrOff;
- ESym->setVisibility(Body->symbol()->Visibility);
- ESym->st_value = Body->getVA<ELFT>();
-
- if (const OutputSectionBase *OutSec = getOutputSection(Body)) {
+ // Set a section index.
+ if (const OutputSection *OutSec = Body->getOutputSection())
ESym->st_shndx = OutSec->SectionIndex;
- } else if (isa<DefinedRegular<ELFT>>(Body)) {
+ else if (isa<DefinedRegular>(Body))
ESym->st_shndx = SHN_ABS;
- } else if (isa<DefinedCommon>(Body)) {
+ else if (isa<DefinedCommon>(Body))
ESym->st_shndx = SHN_COMMON;
+
+ // 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
+ // the case. We'll leave it as zero because by not setting a value, we can
+ // get the exact same outputs for two sets of input files that differ only
+ // in undefined symbol size in DSOs.
+ if (ESym->st_shndx != SHN_UNDEF)
+ ESym->st_size = Body->getSize<ELFT>();
+
+ // 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 (!Config->DefineCommon && isa<DefinedCommon>(Body))
ESym->st_value = cast<DefinedCommon>(Body)->Alignment;
- }
+ else
+ ESym->st_value = Body->getVA();
- if (Config->EMachine == EM_MIPS) {
- // On MIPS we need to mark symbol which has a PLT entry and requires
- // pointer equality by STO_MIPS_PLT flag. That is necessary to help
- // dynamic linker distinguish such symbols and MIPS lazy-binding stubs.
- // https://sourceware.org/ml/binutils/2008-07/txt00000.txt
- if (Body->isInPlt() && Body->NeedsCopyOrPltAddr)
- ESym->st_other |= STO_MIPS_PLT;
- if (Config->Relocatable) {
- auto *D = dyn_cast<DefinedRegular<ELFT>>(Body);
- if (D && D->isMipsPIC())
- ESym->st_other |= STO_MIPS_PIC;
- }
- }
++ESym;
}
-}
-template <class ELFT>
-const OutputSectionBase *
-SymbolTableSection<ELFT>::getOutputSection(SymbolBody *Sym) {
- switch (Sym->kind()) {
- case SymbolBody::DefinedSyntheticKind:
- return cast<DefinedSynthetic>(Sym)->Section;
- case SymbolBody::DefinedRegularKind: {
- auto &D = cast<DefinedRegular<ELFT>>(*Sym);
- if (D.Section)
- return D.Section->OutSec;
- break;
- }
- case SymbolBody::DefinedCommonKind:
- if (!Config->DefineCommon)
- return nullptr;
- return In<ELFT>::Common->OutSec;
- case SymbolBody::SharedKind: {
- auto &SS = cast<SharedSymbol<ELFT>>(*Sym);
- if (SS.needsCopy())
- return SS.getBssSectionForCopy();
- break;
- }
- case SymbolBody::UndefinedKind:
- case SymbolBody::LazyArchiveKind:
- case SymbolBody::LazyObjectKind:
- break;
- }
- return nullptr;
-}
-
-template <class ELFT>
-GnuHashTableSection<ELFT>::GnuHashTableSection()
- : SyntheticSection<ELFT>(SHF_ALLOC, SHT_GNU_HASH, sizeof(uintX_t),
- ".gnu.hash") {
- this->Entsize = ELFT::Is64Bits ? 0 : 4;
-}
-
-template <class ELFT>
-unsigned GnuHashTableSection<ELFT>::calcNBuckets(unsigned NumHashed) {
- if (!NumHashed)
- return 0;
-
- // These values are prime numbers which are not greater than 2^(N-1) + 1.
- // In result, for any particular NumHashed we return a prime number
- // which is not greater than NumHashed.
- static const unsigned Primes[] = {
- 1, 1, 3, 3, 7, 13, 31, 61, 127, 251,
- 509, 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071};
-
- return Primes[std::min<unsigned>(Log2_32_Ceil(NumHashed),
- array_lengthof(Primes) - 1)];
-}
-
-// Bloom filter estimation: at least 8 bits for each hashed symbol.
-// GNU Hash table requirement: it should be a power of 2,
-// the minimum value is 1, even for an empty table.
-// Expected results for a 32-bit target:
-// calcMaskWords(0..4) = 1
-// calcMaskWords(5..8) = 2
-// calcMaskWords(9..16) = 4
-// For a 64-bit target:
-// calcMaskWords(0..8) = 1
-// calcMaskWords(9..16) = 2
-// calcMaskWords(17..32) = 4
-template <class ELFT>
-unsigned GnuHashTableSection<ELFT>::calcMaskWords(unsigned NumHashed) {
- if (!NumHashed)
- return 1;
- return NextPowerOf2((NumHashed - 1) / sizeof(Elf_Off));
-}
+ // On MIPS we need to mark symbol which has a PLT entry and requires
+ // pointer equality by STO_MIPS_PLT flag. That is necessary to help
+ // dynamic linker distinguish such symbols and MIPS lazy-binding stubs.
+ // https://sourceware.org/ml/binutils/2008-07/txt00000.txt
+ if (Config->EMachine == EM_MIPS) {
+ auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
-template <class ELFT> void GnuHashTableSection<ELFT>::finalize() {
- unsigned NumHashed = Symbols.size();
- NBuckets = calcNBuckets(NumHashed);
- MaskWords = calcMaskWords(NumHashed);
- // Second hash shift estimation: just predefined values.
- Shift2 = ELFT::Is64Bits ? 6 : 5;
+ for (SymbolTableEntry &Ent : Symbols) {
+ SymbolBody *Body = Ent.Symbol;
+ if (Body->isInPlt() && Body->NeedsPltAddr)
+ ESym->st_other |= STO_MIPS_PLT;
- this->OutSec->Entsize = this->Entsize;
- this->OutSec->Link = this->Link = In<ELFT>::DynSymTab->OutSec->SectionIndex;
- this->Size = sizeof(Elf_Word) * 4 // Header
- + sizeof(Elf_Off) * MaskWords // Bloom Filter
- + sizeof(Elf_Word) * NBuckets // Hash Buckets
- + sizeof(Elf_Word) * NumHashed; // Hash Values
+ if (Config->Relocatable)
+ if (auto *D = dyn_cast<DefinedRegular>(Body))
+ if (D->isMipsPIC<ELFT>())
+ ESym->st_other |= STO_MIPS_PIC;
+ ++ESym;
+ }
+ }
}
-template <class ELFT> void GnuHashTableSection<ELFT>::writeTo(uint8_t *Buf) {
- writeHeader(Buf);
+// .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
+// don't have them, the dynamic linker has to do linear search on all
+// dynamic symbols, which makes programs slower. Therefore, a .hash
+// section is added to a DSO by default. A .gnu.hash is added if you
+// give the -hash-style=gnu or -hash-style=both option.
+//
+// The Unix semantics of resolving dynamic symbols is somewhat expensive.
+// Each ELF file has a list of DSOs that the ELF file depends on and a
+// list of dynamic symbols that need to be resolved from any of the
+// DSOs. That means resolving all dynamic symbols takes O(m)*O(n)
+// where m is the number of DSOs and n is the number of dynamic
+// symbols. For modern large programs, both m and n are large. So
+// making each step faster by using hash tables substiantially
+// improves time to load programs.
+//
+// (Note that this is not the only way to design the shared library.
+// For instance, the Windows DLL takes a different approach. On
+// Windows, each dynamic symbol has a name of DLL from which the symbol
+// has to be resolved. That makes the cost of symbol resolution O(n).
+// This disables some hacky techniques you can use on Unix such as
+// LD_PRELOAD, but this is arguably better semantics than the Unix ones.)
+//
+// Due to historical reasons, we have two different hash tables, .hash
+// and .gnu.hash. They are for the same purpose, and .gnu.hash is a new
+// and better version of .hash. .hash is just an on-disk hash table, but
+// .gnu.hash has a bloom filter in addition to a hash table to skip
+// DSOs very quickly. If you are sure that your dynamic linker knows
+// about .gnu.hash, you want to specify -hash-style=gnu. Otherwise, a
+// safe bet is to specify -hash-style=both for backward compatibilty.
+GnuHashTableSection::GnuHashTableSection()
+ : SyntheticSection(SHF_ALLOC, SHT_GNU_HASH, Config->Wordsize, ".gnu.hash") {
+}
+
+void GnuHashTableSection::finalizeContents() {
+ getParent()->Link = InX::DynSymTab->getParent()->SectionIndex;
+
+ // Computes bloom filter size in word size. We want to allocate 8
+ // bits for each symbol. It must be a power of two.
if (Symbols.empty())
- return;
+ MaskWords = 1;
+ else
+ MaskWords = NextPowerOf2((Symbols.size() - 1) / Config->Wordsize);
+
+ Size = 16; // Header
+ Size += Config->Wordsize * MaskWords; // Bloom filter
+ Size += NBuckets * 4; // Hash buckets
+ Size += Symbols.size() * 4; // Hash values
+}
+
+void GnuHashTableSection::writeTo(uint8_t *Buf) {
+ // Write a header.
+ write32(Buf, NBuckets, Config->Endianness);
+ write32(Buf + 4, InX::DynSymTab->getNumSymbols() - Symbols.size(),
+ Config->Endianness);
+ write32(Buf + 8, MaskWords, Config->Endianness);
+ write32(Buf + 12, getShift2(), Config->Endianness);
+ Buf += 16;
+
+ // Write a bloom filter and a hash table.
writeBloomFilter(Buf);
+ Buf += Config->Wordsize * MaskWords;
writeHashTable(Buf);
}
-template <class ELFT>
-void GnuHashTableSection<ELFT>::writeHeader(uint8_t *&Buf) {
- auto *P = reinterpret_cast<Elf_Word *>(Buf);
- *P++ = NBuckets;
- *P++ = In<ELFT>::DynSymTab->getNumSymbols() - Symbols.size();
- *P++ = MaskWords;
- *P++ = Shift2;
- Buf = reinterpret_cast<uint8_t *>(P);
-}
-
-template <class ELFT>
-void GnuHashTableSection<ELFT>::writeBloomFilter(uint8_t *&Buf) {
- unsigned C = sizeof(Elf_Off) * 8;
-
- auto *Masks = reinterpret_cast<Elf_Off *>(Buf);
- for (const SymbolData &Sym : Symbols) {
- size_t Pos = (Sym.Hash / C) & (MaskWords - 1);
- uintX_t V = (uintX_t(1) << (Sym.Hash % C)) |
- (uintX_t(1) << ((Sym.Hash >> Shift2) % C));
- Masks[Pos] |= V;
+// This function writes a 2-bit bloom filter. This bloom filter alone
+// usually filters out 80% or more of all symbol lookups [1].
+// The dynamic linker uses the hash table only when a symbol is not
+// filtered out by a bloom filter.
+//
+// [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;
+ 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);
+ writeUint(Buf + I * Config->Wordsize, Val);
}
- Buf += sizeof(Elf_Off) * MaskWords;
}
-template <class ELFT>
-void GnuHashTableSection<ELFT>::writeHashTable(uint8_t *Buf) {
- Elf_Word *Buckets = reinterpret_cast<Elf_Word *>(Buf);
- Elf_Word *Values = Buckets + NBuckets;
-
- int PrevBucket = -1;
- int I = 0;
- for (const SymbolData &Sym : Symbols) {
- int Bucket = Sym.Hash % NBuckets;
- assert(PrevBucket <= Bucket);
- if (Bucket != PrevBucket) {
- Buckets[Bucket] = Sym.Body->DynsymIndex;
- PrevBucket = Bucket;
- if (I > 0)
- Values[I - 1] |= 1;
- }
- Values[I] = Sym.Hash & ~1;
- ++I;
+void GnuHashTableSection::writeHashTable(uint8_t *Buf) {
+ // Group symbols by hash value.
+ std::vector<std::vector<Entry>> Syms(NBuckets);
+ for (const Entry &Ent : Symbols)
+ Syms[Ent.Hash % NBuckets].push_back(Ent);
+
+ // Write hash buckets. Hash buckets contain indices in the following
+ // hash value table.
+ uint32_t *Buckets = reinterpret_cast<uint32_t *>(Buf);
+ for (size_t I = 0; I < NBuckets; ++I)
+ if (!Syms[I].empty())
+ write32(Buckets + I, Syms[I][0].Body->DynsymIndex, Config->Endianness);
+
+ // Write a hash value table. It represents a sequence of chains that
+ // share the same hash modulo value. The last element of each chain
+ // is terminated by LSB 1.
+ uint32_t *Values = Buckets + NBuckets;
+ size_t I = 0;
+ for (std::vector<Entry> &Vec : Syms) {
+ if (Vec.empty())
+ continue;
+ for (const Entry &Ent : makeArrayRef(Vec).drop_back())
+ write32(Values + I++, Ent.Hash & ~1, Config->Endianness);
+ write32(Values + I++, Vec.back().Hash | 1, Config->Endianness);
}
- if (I > 0)
- Values[I - 1] |= 1;
}
static uint32_t hashGnu(StringRef Name) {
@@ -1347,58 +1556,76 @@ static uint32_t hashGnu(StringRef Name) {
return H;
}
+// Returns a number of hash buckets to accomodate given number of elements.
+// We want to choose a moderate number that is not too small (which
+// causes too many hash collisions) and not too large (which wastes
+// disk space.)
+//
+// We return a prime number because it (is believed to) achieve good
+// hash distribution.
+static size_t getBucketSize(size_t NumSymbols) {
+ // List of largest prime numbers that are not greater than 2^n + 1.
+ for (size_t N : {131071, 65521, 32749, 16381, 8191, 4093, 2039, 1021, 509,
+ 251, 127, 61, 31, 13, 7, 3, 1})
+ if (N <= NumSymbols)
+ return N;
+ return 0;
+}
+
// Add symbols to this symbol hash table. Note that this function
// destructively sort a given vector -- which is needed because
// GNU-style hash table places some sorting requirements.
-template <class ELFT>
-void GnuHashTableSection<ELFT>::addSymbols(std::vector<SymbolTableEntry> &V) {
- // Ideally this will just be 'auto' but GCC 6.1 is not able
- // to deduce it correctly.
+void GnuHashTableSection::addSymbols(std::vector<SymbolTableEntry> &V) {
+ // We cannot use 'auto' for Mid because GCC 6.1 cannot deduce
+ // its type correctly.
std::vector<SymbolTableEntry>::iterator Mid =
std::stable_partition(V.begin(), V.end(), [](const SymbolTableEntry &S) {
return S.Symbol->isUndefined();
});
if (Mid == V.end())
return;
- for (auto I = Mid, E = V.end(); I != E; ++I) {
- SymbolBody *B = I->Symbol;
- size_t StrOff = I->StrTabOffset;
- Symbols.push_back({B, StrOff, hashGnu(B->getName())});
+
+ for (SymbolTableEntry &Ent : llvm::make_range(Mid, V.end())) {
+ SymbolBody *B = Ent.Symbol;
+ Symbols.push_back({B, Ent.StrTabOffset, hashGnu(B->getName())});
}
- unsigned NBuckets = calcNBuckets(Symbols.size());
+ NBuckets = getBucketSize(Symbols.size());
std::stable_sort(Symbols.begin(), Symbols.end(),
- [&](const SymbolData &L, const SymbolData &R) {
+ [&](const Entry &L, const Entry &R) {
return L.Hash % NBuckets < R.Hash % NBuckets;
});
V.erase(Mid, V.end());
- for (const SymbolData &Sym : Symbols)
- V.push_back({Sym.Body, Sym.STName});
+ for (const Entry &Ent : Symbols)
+ V.push_back({Ent.Body, Ent.StrTabOffset});
}
template <class ELFT>
HashTableSection<ELFT>::HashTableSection()
- : SyntheticSection<ELFT>(SHF_ALLOC, SHT_HASH, sizeof(Elf_Word), ".hash") {
- this->Entsize = sizeof(Elf_Word);
+ : SyntheticSection(SHF_ALLOC, SHT_HASH, 4, ".hash") {
+ this->Entsize = 4;
}
-template <class ELFT> void HashTableSection<ELFT>::finalize() {
- this->OutSec->Link = this->Link = In<ELFT>::DynSymTab->OutSec->SectionIndex;
- this->OutSec->Entsize = this->Entsize;
+template <class ELFT> void HashTableSection<ELFT>::finalizeContents() {
+ getParent()->Link = InX::DynSymTab->getParent()->SectionIndex;
- unsigned NumEntries = 2; // nbucket and nchain.
- NumEntries += In<ELFT>::DynSymTab->getNumSymbols(); // The chain entries.
+ unsigned NumEntries = 2; // nbucket and nchain.
+ NumEntries += InX::DynSymTab->getNumSymbols(); // The chain entries.
// Create as many buckets as there are symbols.
// FIXME: This is simplistic. We can try to optimize it, but implementing
// support for SHT_GNU_HASH is probably even more profitable.
- NumEntries += In<ELFT>::DynSymTab->getNumSymbols();
- this->Size = NumEntries * sizeof(Elf_Word);
+ NumEntries += InX::DynSymTab->getNumSymbols();
+ this->Size = NumEntries * 4;
}
template <class ELFT> void HashTableSection<ELFT>::writeTo(uint8_t *Buf) {
- unsigned NumSymbols = In<ELFT>::DynSymTab->getNumSymbols();
+ // A 32-bit integer type in the target endianness.
+ typedef typename ELFT::Word Elf_Word;
+
+ unsigned NumSymbols = InX::DynSymTab->getNumSymbols();
+
auto *P = reinterpret_cast<Elf_Word *>(Buf);
*P++ = NumSymbols; // nbucket
*P++ = NumSymbols; // nchain
@@ -1406,7 +1633,7 @@ template <class ELFT> void HashTableSection<ELFT>::writeTo(uint8_t *Buf) {
Elf_Word *Buckets = P;
Elf_Word *Chains = P + NumSymbols;
- for (const SymbolTableEntry &S : In<ELFT>::DynSymTab->getSymbols()) {
+ for (const SymbolTableEntry &S : InX::DynSymTab->getSymbols()) {
SymbolBody *Body = S.Symbol;
StringRef Name = Body->getName();
unsigned I = Body->DynsymIndex;
@@ -1416,78 +1643,69 @@ template <class ELFT> void HashTableSection<ELFT>::writeTo(uint8_t *Buf) {
}
}
-template <class ELFT>
-PltSection<ELFT>::PltSection()
- : SyntheticSection<ELFT>(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16,
- ".plt") {}
+PltSection::PltSection(size_t S)
+ : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, ".plt"),
+ HeaderSize(S) {
+ // 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)
+ this->Flags |= SHF_WRITE;
+}
-template <class ELFT> void PltSection<ELFT>::writeTo(uint8_t *Buf) {
- // At beginning of PLT, we have code to call the dynamic linker
- // to resolve dynsyms at runtime. Write such code.
- Target->writePltHeader(Buf);
- size_t Off = Target->PltHeaderSize;
+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)
+ Target->writePltHeader(Buf);
+ size_t Off = HeaderSize;
+ // The IPlt is immediately after the Plt, account for this in RelOff
+ unsigned PltOff = getPltRelocOff();
for (auto &I : Entries) {
const SymbolBody *B = I.first;
- unsigned RelOff = I.second;
- uint64_t Got = B->getGotPltVA<ELFT>();
+ unsigned RelOff = I.second + PltOff;
+ uint64_t Got = B->getGotPltVA();
uint64_t Plt = this->getVA() + Off;
Target->writePlt(Buf + Off, Got, Plt, B->PltIndex, RelOff);
Off += Target->PltEntrySize;
}
}
-template <class ELFT> void PltSection<ELFT>::addEntry(SymbolBody &Sym) {
+template <class ELFT> void PltSection::addEntry(SymbolBody &Sym) {
Sym.PltIndex = Entries.size();
- unsigned RelOff = In<ELFT>::RelaPlt->getRelocOffset();
+ RelocationSection<ELFT> *PltRelocSection = In<ELFT>::RelaPlt;
+ if (HeaderSize == 0) {
+ PltRelocSection = In<ELFT>::RelaIplt;
+ Sym.IsInIplt = true;
+ }
+ unsigned RelOff = PltRelocSection->getRelocOffset();
Entries.push_back(std::make_pair(&Sym, RelOff));
}
-template <class ELFT> size_t PltSection<ELFT>::getSize() const {
- return Target->PltHeaderSize + Entries.size() * Target->PltEntrySize;
+size_t PltSection::getSize() const {
+ return HeaderSize + Entries.size() * Target->PltEntrySize;
}
-template <class ELFT>
-IpltSection<ELFT>::IpltSection()
- : SyntheticSection<ELFT>(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16,
- ".plt") {}
-
-template <class ELFT> void IpltSection<ELFT>::writeTo(uint8_t *Buf) {
- // The IRelative relocations do not support lazy binding so no header is
- // needed
- size_t Off = 0;
- for (auto &I : Entries) {
- const SymbolBody *B = I.first;
- unsigned RelOff = I.second + In<ELFT>::Plt->getSize();
- uint64_t Got = B->getGotPltVA<ELFT>();
- uint64_t Plt = this->getVA() + Off;
- Target->writePlt(Buf + Off, Got, Plt, B->PltIndex, RelOff);
+// Some architectures such as additional symbols in the PLT section. For
+// 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)
+ Target->addPltHeaderSymbols(this);
+ size_t Off = HeaderSize;
+ for (size_t I = 0; I < Entries.size(); ++I) {
+ Target->addPltSymbols(this, Off);
Off += Target->PltEntrySize;
}
}
-template <class ELFT> void IpltSection<ELFT>::addEntry(SymbolBody &Sym) {
- Sym.PltIndex = Entries.size();
- Sym.IsInIplt = true;
- unsigned RelOff = In<ELFT>::RelaIplt->getRelocOffset();
- Entries.push_back(std::make_pair(&Sym, RelOff));
+unsigned PltSection::getPltRelocOff() const {
+ return (HeaderSize == 0) ? InX::Plt->getSize() : 0;
}
-template <class ELFT> size_t IpltSection<ELFT>::getSize() const {
- return Entries.size() * Target->PltEntrySize;
-}
-
-template <class ELFT>
-GdbIndexSection<ELFT>::GdbIndexSection()
- : SyntheticSection<ELFT>(0, SHT_PROGBITS, 1, ".gdb_index"),
- StringPool(llvm::StringTableBuilder::ELF) {}
-
-template <class ELFT> void GdbIndexSection<ELFT>::parseDebugSections() {
- for (InputSectionBase<ELFT> *S : Symtab<ELFT>::X->Sections)
- if (InputSection<ELFT> *IS = dyn_cast<InputSection<ELFT>>(S))
- if (IS->OutSec && IS->Name == ".debug_info")
- readDwarf(IS);
-}
+GdbIndexSection::GdbIndexSection(std::vector<GdbIndexChunk> &&Chunks)
+ : SyntheticSection(0, SHT_PROGBITS, 1, ".gdb_index"),
+ StringPool(llvm::StringTableBuilder::ELF), Chunks(std::move(Chunks)) {}
// Iterative hash function for symbol's name is described in .gdb_index format
// specification. Note that we use one for version 5 to 7 here, it is different
@@ -1499,57 +1717,149 @@ static uint32_t hash(StringRef Str) {
return R;
}
-template <class ELFT>
-void GdbIndexSection<ELFT>::readDwarf(InputSection<ELFT> *I) {
- GdbIndexBuilder<ELFT> Builder(I);
- if (ErrorCount)
- return;
+static std::vector<CompilationUnitEntry> readCuList(DWARFContext &Dwarf) {
+ std::vector<CompilationUnitEntry> Ret;
+ for (std::unique_ptr<DWARFCompileUnit> &CU : Dwarf.compile_units())
+ Ret.push_back({CU->getOffset(), CU->getLength() + 4});
+ return Ret;
+}
+
+static std::vector<AddressEntry> readAddressArea(DWARFContext &Dwarf,
+ InputSection *Sec) {
+ std::vector<AddressEntry> Ret;
+
+ uint32_t CurrentCu = 0;
+ for (std::unique_ptr<DWARFCompileUnit> &CU : Dwarf.compile_units()) {
+ DWARFAddressRangesVector Ranges;
+ CU->collectAddressRanges(Ranges);
+
+ ArrayRef<InputSectionBase *> Sections = Sec->File->getSections();
+ for (DWARFAddressRange &R : Ranges) {
+ InputSectionBase *S = Sections[R.SectionIndex];
+ if (!S || S == &InputSection::Discarded || !S->Live)
+ continue;
+ // Range list with zero size has no effect.
+ if (R.LowPC == R.HighPC)
+ continue;
+ Ret.push_back({cast<InputSection>(S), R.LowPC, R.HighPC, CurrentCu});
+ }
+ ++CurrentCu;
+ }
+ return Ret;
+}
+
+static std::vector<NameTypeEntry> readPubNamesAndTypes(DWARFContext &Dwarf,
+ bool IsLE) {
+ StringRef Data[] = {Dwarf.getGnuPubNamesSection(),
+ Dwarf.getGnuPubTypesSection()};
- size_t CuId = CompilationUnits.size();
- std::vector<std::pair<uintX_t, uintX_t>> CuList = Builder.readCUList();
- CompilationUnits.insert(CompilationUnits.end(), CuList.begin(), CuList.end());
+ std::vector<NameTypeEntry> Ret;
+ for (StringRef D : Data) {
+ DWARFDebugPubTable PubTable(D, IsLE, true);
+ for (const DWARFDebugPubTable::Set &Set : PubTable.getData())
+ for (const DWARFDebugPubTable::Entry &Ent : Set.Entries)
+ Ret.push_back({Ent.Name, Ent.Descriptor.toBits()});
+ }
+ return Ret;
+}
- std::vector<AddressEntry<ELFT>> AddrArea = Builder.readAddressArea(CuId);
- AddressArea.insert(AddressArea.end(), AddrArea.begin(), AddrArea.end());
+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;
+}
- std::vector<std::pair<StringRef, uint8_t>> NamesAndTypes =
- Builder.readPubNamesAndTypes();
+void GdbIndexSection::buildIndex() {
+ if (Chunks.empty())
+ return;
- for (std::pair<StringRef, uint8_t> &Pair : NamesAndTypes) {
- uint32_t Hash = hash(Pair.first);
- size_t Offset = StringPool.add(Pair.first);
+ uint32_t CuId = 0;
+ for (GdbIndexChunk &D : Chunks) {
+ for (AddressEntry &E : D.AddressArea)
+ E.CuIndex += CuId;
+
+ // Populate constant pool area.
+ for (NameTypeEntry &NameType : D.NamesAndTypes) {
+ uint32_t Hash = hash(NameType.Name);
+ size_t Offset = StringPool.add(NameType.Name);
+
+ bool IsNew;
+ GdbSymbol *Sym;
+ std::tie(IsNew, Sym) = SymbolTable.add(Hash, Offset);
+ if (IsNew) {
+ Sym->CuVectorIndex = CuVectors.size();
+ CuVectors.resize(CuVectors.size() + 1);
+ }
- bool IsNew;
- GdbSymbol *Sym;
- std::tie(IsNew, Sym) = SymbolTable.add(Hash, Offset);
- if (IsNew) {
- Sym->CuVectorIndex = CuVectors.size();
- CuVectors.push_back({{CuId, Pair.second}});
- continue;
+ CuVectors[Sym->CuVectorIndex].insert(CuId | (NameType.Type << 24));
}
- std::vector<std::pair<uint32_t, uint8_t>> &CuVec =
- CuVectors[Sym->CuVectorIndex];
- CuVec.push_back({CuId, Pair.second});
+ CuId += D.CompilationUnits.size();
+ }
+}
+
+static GdbIndexChunk readDwarf(DWARFContextInMemory &Dwarf, InputSection *Sec) {
+ GdbIndexChunk Ret;
+ Ret.DebugInfoSec = Sec;
+ Ret.CompilationUnits = readCuList(Dwarf);
+ Ret.AddressArea = readAddressArea(Dwarf, Sec);
+ Ret.NamesAndTypes = readPubNamesAndTypes(Dwarf, Config->IsLE);
+ return Ret;
+}
+
+template <class ELFT> GdbIndexSection *elf::createGdbIndex() {
+ std::vector<GdbIndexChunk> Chunks;
+ for (InputSection *Sec : getDebugInfoSections()) {
+ InputFile *F = Sec->File;
+ std::error_code EC;
+ ELFObjectFile<ELFT> Obj(F->MB, EC);
+ if (EC)
+ fatal(EC.message());
+ DWARFContextInMemory Dwarf(Obj, nullptr, [&](Error E) {
+ error(toString(F) + ": error parsing DWARF data:\n>>> " +
+ toString(std::move(E)));
+ return ErrorPolicy::Continue;
+ });
+ Chunks.push_back(readDwarf(Dwarf, Sec));
}
+ return make<GdbIndexSection>(std::move(Chunks));
+}
+
+static size_t getCuSize(std::vector<GdbIndexChunk> &C) {
+ size_t Ret = 0;
+ for (GdbIndexChunk &D : C)
+ Ret += D.CompilationUnits.size();
+ return Ret;
}
-template <class ELFT> void GdbIndexSection<ELFT>::finalize() {
+static size_t getAddressAreaSize(std::vector<GdbIndexChunk> &C) {
+ size_t Ret = 0;
+ for (GdbIndexChunk &D : C)
+ Ret += D.AddressArea.size();
+ return Ret;
+}
+
+void GdbIndexSection::finalizeContents() {
if (Finalized)
return;
Finalized = true;
- parseDebugSections();
+ buildIndex();
+
+ SymbolTable.finalizeContents();
// GdbIndex header consist from version fields
// and 5 more fields with different kinds of offsets.
- CuTypesOffset = CuListOffset + CompilationUnits.size() * CompilationUnitSize;
- SymTabOffset = CuTypesOffset + AddressArea.size() * AddressEntrySize;
+ CuTypesOffset = CuListOffset + getCuSize(Chunks) * CompilationUnitSize;
+ SymTabOffset = CuTypesOffset + getAddressAreaSize(Chunks) * AddressEntrySize;
ConstantPoolOffset =
SymTabOffset + SymbolTable.getCapacity() * SymTabEntrySize;
- for (std::vector<std::pair<uint32_t, uint8_t>> &CuVec : CuVectors) {
+ for (std::set<uint32_t> &CuVec : CuVectors) {
CuVectorsOffset.push_back(CuVectorsSize);
CuVectorsSize += OffsetTypeSize * (CuVec.size() + 1);
}
@@ -1558,12 +1868,12 @@ template <class ELFT> void GdbIndexSection<ELFT>::finalize() {
StringPool.finalizeInOrder();
}
-template <class ELFT> size_t GdbIndexSection<ELFT>::getSize() const {
- const_cast<GdbIndexSection<ELFT> *>(this)->finalize();
+size_t GdbIndexSection::getSize() const {
+ const_cast<GdbIndexSection *>(this)->finalizeContents();
return StringPoolOffset + StringPool.getSize();
}
-template <class ELFT> void GdbIndexSection<ELFT>::writeTo(uint8_t *Buf) {
+void GdbIndexSection::writeTo(uint8_t *Buf) {
write32le(Buf, 7); // Write version.
write32le(Buf + 4, CuListOffset); // CU list offset.
write32le(Buf + 8, CuTypesOffset); // Types CU list offset.
@@ -1573,19 +1883,24 @@ template <class ELFT> void GdbIndexSection<ELFT>::writeTo(uint8_t *Buf) {
Buf += 24;
// Write the CU list.
- for (std::pair<uintX_t, uintX_t> CU : CompilationUnits) {
- write64le(Buf, CU.first);
- write64le(Buf + 8, CU.second);
- Buf += 16;
+ for (GdbIndexChunk &D : Chunks) {
+ for (CompilationUnitEntry &Cu : D.CompilationUnits) {
+ write64le(Buf, D.DebugInfoSec->OutSecOff + Cu.CuOffset);
+ write64le(Buf + 8, Cu.CuLength);
+ Buf += 16;
+ }
}
// Write the address area.
- for (AddressEntry<ELFT> &E : AddressArea) {
- uintX_t BaseAddr = E.Section->OutSec->Addr + E.Section->getOffset(0);
- write64le(Buf, BaseAddr + E.LowAddress);
- write64le(Buf + 8, BaseAddr + E.HighAddress);
- write32le(Buf + 16, E.CuIndex);
- Buf += 20;
+ for (GdbIndexChunk &D : Chunks) {
+ for (AddressEntry &E : D.AddressArea) {
+ uint64_t BaseAddr =
+ E.Section->getParent()->Addr + E.Section->getOffset(0);
+ write64le(Buf, BaseAddr + E.LowAddress);
+ write64le(Buf + 8, BaseAddr + E.HighAddress);
+ write32le(Buf + 16, E.CuIndex);
+ Buf += 20;
+ }
}
// Write the symbol table.
@@ -1602,14 +1917,11 @@ template <class ELFT> void GdbIndexSection<ELFT>::writeTo(uint8_t *Buf) {
}
// Write the CU vectors into the constant pool.
- for (std::vector<std::pair<uint32_t, uint8_t>> &CuVec : CuVectors) {
+ for (std::set<uint32_t> &CuVec : CuVectors) {
write32le(Buf, CuVec.size());
Buf += 4;
- for (std::pair<uint32_t, uint8_t> &P : CuVec) {
- uint32_t Index = P.first;
- uint8_t Flags = P.second;
- Index |= Flags << 24;
- write32le(Buf, Index);
+ for (uint32_t Val : CuVec) {
+ write32le(Buf, Val);
Buf += 4;
}
}
@@ -1617,13 +1929,11 @@ template <class ELFT> void GdbIndexSection<ELFT>::writeTo(uint8_t *Buf) {
StringPool.write(Buf);
}
-template <class ELFT> bool GdbIndexSection<ELFT>::empty() const {
- return !Out<ELFT>::DebugInfo;
-}
+bool GdbIndexSection::empty() const { return !Out::DebugInfo; }
template <class ELFT>
EhFrameHeader<ELFT>::EhFrameHeader()
- : SyntheticSection<ELFT>(SHF_ALLOC, SHT_PROGBITS, 1, ".eh_frame_hdr") {}
+ : SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 1, ".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,
@@ -1644,11 +1954,11 @@ template <class ELFT> void EhFrameHeader<ELFT>::writeTo(uint8_t *Buf) {
Buf[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4;
Buf[2] = DW_EH_PE_udata4;
Buf[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4;
- write32<E>(Buf + 4, Out<ELFT>::EhFrame->Addr - this->getVA() - 4);
+ write32<E>(Buf + 4, In<ELFT>::EhFrame->getParent()->Addr - this->getVA() - 4);
write32<E>(Buf + 8, Fdes.size());
Buf += 12;
- uintX_t VA = this->getVA();
+ uint64_t VA = this->getVA();
for (FdeData &Fde : Fdes) {
write32<E>(Buf, Fde.Pc - VA);
write32<E>(Buf + 4, Fde.FdeVA - VA);
@@ -1658,7 +1968,7 @@ template <class ELFT> void EhFrameHeader<ELFT>::writeTo(uint8_t *Buf) {
template <class ELFT> size_t EhFrameHeader<ELFT>::getSize() const {
// .eh_frame_hdr has a 12 bytes header followed by an array of FDEs.
- return 12 + Out<ELFT>::EhFrame->NumFdes * 8;
+ return 12 + In<ELFT>::EhFrame->NumFdes * 8;
}
template <class ELFT>
@@ -1667,13 +1977,13 @@ void EhFrameHeader<ELFT>::addFde(uint32_t Pc, uint32_t FdeVA) {
}
template <class ELFT> bool EhFrameHeader<ELFT>::empty() const {
- return Out<ELFT>::EhFrame->empty();
+ return In<ELFT>::EhFrame->empty();
}
template <class ELFT>
VersionDefinitionSection<ELFT>::VersionDefinitionSection()
- : SyntheticSection<ELFT>(SHF_ALLOC, SHT_GNU_verdef, sizeof(uint32_t),
- ".gnu.version_d") {}
+ : SyntheticSection(SHF_ALLOC, SHT_GNU_verdef, sizeof(uint32_t),
+ ".gnu.version_d") {}
static StringRef getFileDefName() {
if (!Config->SoName.empty())
@@ -1681,17 +1991,17 @@ static StringRef getFileDefName() {
return Config->OutputFile;
}
-template <class ELFT> void VersionDefinitionSection<ELFT>::finalize() {
- FileDefNameOff = In<ELFT>::DynStrTab->addString(getFileDefName());
+template <class ELFT> void VersionDefinitionSection<ELFT>::finalizeContents() {
+ FileDefNameOff = InX::DynStrTab->addString(getFileDefName());
for (VersionDefinition &V : Config->VersionDefinitions)
- V.NameOff = In<ELFT>::DynStrTab->addString(V.Name);
+ V.NameOff = InX::DynStrTab->addString(V.Name);
- this->OutSec->Link = this->Link = In<ELFT>::DynStrTab->OutSec->SectionIndex;
+ getParent()->Link = InX::DynStrTab->getParent()->SectionIndex;
// sh_info should be set to the number of definitions. This fact is missed in
// documentation, but confirmed by binutils community:
// https://sourceware.org/ml/binutils/2014-11/msg00355.html
- this->OutSec->Info = this->Info = getVerDefNum();
+ getParent()->Info = getVerDefNum();
}
template <class ELFT>
@@ -1731,23 +2041,24 @@ template <class ELFT> size_t VersionDefinitionSection<ELFT>::getSize() const {
template <class ELFT>
VersionTableSection<ELFT>::VersionTableSection()
- : SyntheticSection<ELFT>(SHF_ALLOC, SHT_GNU_versym, sizeof(uint16_t),
- ".gnu.version") {}
+ : SyntheticSection(SHF_ALLOC, SHT_GNU_versym, sizeof(uint16_t),
+ ".gnu.version") {
+ this->Entsize = sizeof(Elf_Versym);
+}
-template <class ELFT> void VersionTableSection<ELFT>::finalize() {
- this->OutSec->Entsize = this->Entsize = sizeof(Elf_Versym);
+template <class ELFT> void VersionTableSection<ELFT>::finalizeContents() {
// At the moment of june 2016 GNU docs does not mention that sh_link field
// should be set, but Sun docs do. Also readelf relies on this field.
- this->OutSec->Link = this->Link = In<ELFT>::DynSymTab->OutSec->SectionIndex;
+ getParent()->Link = InX::DynSymTab->getParent()->SectionIndex;
}
template <class ELFT> size_t VersionTableSection<ELFT>::getSize() const {
- return sizeof(Elf_Versym) * (In<ELFT>::DynSymTab->getSymbols().size() + 1);
+ return sizeof(Elf_Versym) * (InX::DynSymTab->getSymbols().size() + 1);
}
template <class ELFT> void VersionTableSection<ELFT>::writeTo(uint8_t *Buf) {
auto *OutVersym = reinterpret_cast<Elf_Versym *>(Buf) + 1;
- for (const SymbolTableEntry &S : In<ELFT>::DynSymTab->getSymbols()) {
+ for (const SymbolTableEntry &S : InX::DynSymTab->getSymbols()) {
OutVersym->vs_index = S.Symbol->symbol()->VersionId;
++OutVersym;
}
@@ -1759,8 +2070,8 @@ template <class ELFT> bool VersionTableSection<ELFT>::empty() const {
template <class ELFT>
VersionNeedSection<ELFT>::VersionNeedSection()
- : SyntheticSection<ELFT>(SHF_ALLOC, SHT_GNU_verneed, sizeof(uint32_t),
- ".gnu.version_r") {
+ : SyntheticSection(SHF_ALLOC, SHT_GNU_verneed, sizeof(uint32_t),
+ ".gnu.version_r") {
// Identifiers in verneed section start at 2 because 0 and 1 are reserved
// for VER_NDX_LOCAL and VER_NDX_GLOBAL.
// First identifiers are reserved by verdef section if it exist.
@@ -1768,24 +2079,27 @@ VersionNeedSection<ELFT>::VersionNeedSection()
}
template <class ELFT>
-void VersionNeedSection<ELFT>::addSymbol(SharedSymbol<ELFT> *SS) {
- if (!SS->Verdef) {
+void VersionNeedSection<ELFT>::addSymbol(SharedSymbol *SS) {
+ auto *Ver = reinterpret_cast<const typename ELFT::Verdef *>(SS->Verdef);
+ if (!Ver) {
SS->symbol()->VersionId = VER_NDX_GLOBAL;
return;
}
- SharedFile<ELFT> *F = SS->file();
+
+ auto *File = cast<SharedFile<ELFT>>(SS->File);
+
// If we don't already know that we need an Elf_Verneed for this DSO, prepare
// to create one by adding it to our needed list and creating a dynstr entry
// for the soname.
- if (F->VerdefMap.empty())
- Needed.push_back({F, In<ELFT>::DynStrTab->addString(F->getSoName())});
- typename SharedFile<ELFT>::NeededVer &NV = F->VerdefMap[SS->Verdef];
+ if (File->VerdefMap.empty())
+ Needed.push_back({File, InX::DynStrTab->addString(File->SoName)});
+ 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.
if (NV.Index == 0) {
- NV.StrTab = In<ELFT>::DynStrTab->addString(
- SS->file()->getStringTable().data() + SS->Verdef->getAux()->vda_name);
+ NV.StrTab = InX::DynStrTab->addString(File->getStringTable().data() +
+ Ver->getAux()->vda_name);
NV.Index = NextIndex++;
}
SS->symbol()->VersionId = NV.Index;
@@ -1826,9 +2140,9 @@ template <class ELFT> void VersionNeedSection<ELFT>::writeTo(uint8_t *Buf) {
Verneed[-1].vn_next = 0;
}
-template <class ELFT> void VersionNeedSection<ELFT>::finalize() {
- this->OutSec->Link = this->Link = In<ELFT>::DynStrTab->OutSec->SectionIndex;
- this->OutSec->Info = this->Info = Needed.size();
+template <class ELFT> void VersionNeedSection<ELFT>::finalizeContents() {
+ getParent()->Link = InX::DynStrTab->getParent()->SectionIndex;
+ getParent()->Info = Needed.size();
}
template <class ELFT> size_t VersionNeedSection<ELFT>::getSize() const {
@@ -1842,53 +2156,219 @@ template <class ELFT> bool VersionNeedSection<ELFT>::empty() const {
return getNeedNum() == 0;
}
-template <class ELFT>
-MipsRldMapSection<ELFT>::MipsRldMapSection()
- : SyntheticSection<ELFT>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
- sizeof(typename ELFT::uint), ".rld_map") {}
+MergeSyntheticSection::MergeSyntheticSection(StringRef Name, uint32_t Type,
+ uint64_t Flags, uint32_t Alignment)
+ : SyntheticSection(Flags, Type, Alignment, Name),
+ Builder(StringTableBuilder::RAW, Alignment) {}
+
+void MergeSyntheticSection::addSection(MergeInputSection *MS) {
+ MS->Parent = this;
+ Sections.push_back(MS);
+}
+
+void MergeSyntheticSection::writeTo(uint8_t *Buf) { Builder.write(Buf); }
+
+bool MergeSyntheticSection::shouldTailMerge() const {
+ return (this->Flags & SHF_STRINGS) && Config->Optimize >= 2;
+}
+
+void MergeSyntheticSection::finalizeTailMerge() {
+ // Add all string pieces to the string table builder to create section
+ // contents.
+ for (MergeInputSection *Sec : Sections)
+ for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
+ if (Sec->Pieces[I].Live)
+ Builder.add(Sec->getData(I));
+
+ // Fix the string table content. After this, the contents will never change.
+ Builder.finalize();
+
+ // finalize() fixed tail-optimized strings, so we can now get
+ // offsets of strings. Get an offset for each string and save it
+ // to a corresponding StringPiece for easy access.
+ for (MergeInputSection *Sec : Sections)
+ for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
+ if (Sec->Pieces[I].Live)
+ Sec->Pieces[I].OutputOff = Builder.getOffset(Sec->getData(I));
+}
+
+void MergeSyntheticSection::finalizeNoTailMerge() {
+ // Add all string pieces to the string table builder to create section
+ // contents. Because we are not tail-optimizing, offsets of strings are
+ // fixed when they are added to the builder (string table builder contains
+ // a hash table from strings to offsets).
+ for (MergeInputSection *Sec : Sections)
+ for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
+ if (Sec->Pieces[I].Live)
+ Sec->Pieces[I].OutputOff = Builder.add(Sec->getData(I));
+
+ Builder.finalizeInOrder();
+}
+
+void MergeSyntheticSection::finalizeContents() {
+ if (shouldTailMerge())
+ finalizeTailMerge();
+ else
+ finalizeNoTailMerge();
+}
+
+size_t MergeSyntheticSection::getSize() const { return Builder.getSize(); }
+
+// This function decompresses compressed sections and scans over the input
+// sections to create mergeable synthetic sections. It removes
+// MergeInputSections from the input section array and adds new synthetic
+// sections at the location of the first input section 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::decompressAndMergeSections() {
+ // splitIntoPieces needs to be called on each MergeInputSection before calling
+ // finalizeContents(). Do that first.
+ parallelForEach(InputSections.begin(), InputSections.end(),
+ [](InputSectionBase *S) {
+ if (!S->Live)
+ return;
+ if (Decompressor::isCompressedELFSection(S->Flags, S->Name))
+ S->uncompress();
+ if (auto *MS = dyn_cast<MergeInputSection>(S))
+ MS->splitIntoPieces();
+ });
+
+ std::vector<MergeSyntheticSection *> MergeSections;
+ for (InputSectionBase *&S : InputSections) {
+ MergeInputSection *MS = dyn_cast<MergeInputSection>(S);
+ if (!MS)
+ continue;
+
+ // We do not want to handle sections that are not alive, so just remove
+ // them instead of trying to merge.
+ if (!MS->Live)
+ continue;
+
+ StringRef OutsecName = getOutputSectionName(MS->Name);
+ uint64_t Flags = MS->Flags & ~(uint64_t)SHF_GROUP;
+ uint32_t Alignment = std::max<uint32_t>(MS->Alignment, MS->Entsize);
+
+ auto I = llvm::find_if(MergeSections, [=](MergeSyntheticSection *Sec) {
+ return Sec->Name == OutsecName && Sec->Flags == Flags &&
+ Sec->Alignment == Alignment;
+ });
+ if (I == MergeSections.end()) {
+ MergeSyntheticSection *Syn =
+ make<MergeSyntheticSection>(OutsecName, MS->Type, Flags, Alignment);
+ MergeSections.push_back(Syn);
+ I = std::prev(MergeSections.end());
+ S = Syn;
+ } else {
+ S = nullptr;
+ }
+ (*I)->addSection(MS);
+ }
+ for (auto *MS : MergeSections)
+ MS->finalizeContents();
-template <class ELFT> void MipsRldMapSection<ELFT>::writeTo(uint8_t *Buf) {
- // Apply filler from linker script.
- uint64_t Filler = Script<ELFT>::X->getFiller(this->Name);
- Filler = (Filler << 32) | Filler;
- memcpy(Buf, &Filler, getSize());
+ std::vector<InputSectionBase *> &V = InputSections;
+ V.erase(std::remove(V.begin(), V.end(), nullptr), V.end());
}
-template <class ELFT>
-ARMExidxSentinelSection<ELFT>::ARMExidxSentinelSection()
- : SyntheticSection<ELFT>(SHF_ALLOC | SHF_LINK_ORDER, SHT_ARM_EXIDX,
- sizeof(typename ELFT::uint), ".ARM.exidx") {}
+MipsRldMapSection::MipsRldMapSection()
+ : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Config->Wordsize,
+ ".rld_map") {}
+
+ARMExidxSentinelSection::ARMExidxSentinelSection()
+ : SyntheticSection(SHF_ALLOC | SHF_LINK_ORDER, SHT_ARM_EXIDX,
+ Config->Wordsize, ".ARM.exidx") {}
// Write a terminating sentinel entry to the end of the .ARM.exidx table.
// This section will have been sorted last in the .ARM.exidx table.
// This table entry will have the form:
// | PREL31 upper bound of code that has exception tables | EXIDX_CANTUNWIND |
-template <class ELFT>
-void ARMExidxSentinelSection<ELFT>::writeTo(uint8_t *Buf) {
- // Get the InputSection before us, we are by definition last
- auto RI = cast<OutputSection<ELFT>>(this->OutSec)->Sections.rbegin();
- InputSection<ELFT> *LE = *(++RI);
- InputSection<ELFT> *LC = cast<InputSection<ELFT>>(LE->getLinkOrderDep());
- uint64_t S = LC->OutSec->Addr + LC->getOffset(LC->getSize());
- uint64_t P = this->getVA();
+// The sentinel must have the PREL31 value of an address higher than any
+// address described by any other table entry.
+void ARMExidxSentinelSection::writeTo(uint8_t *Buf) {
+ // The Sections are sorted in order of ascending PREL31 address with the
+ // sentinel last. We need to find the InputSection that precedes the
+ // sentinel. By construction the Sentinel is in the last
+ // InputSectionDescription as the InputSection that precedes it.
+ OutputSectionCommand *C = Script->getCmd(getParent());
+ auto ISD = std::find_if(C->Commands.rbegin(), C->Commands.rend(),
+ [](const BaseCommand *Base) {
+ return isa<InputSectionDescription>(Base);
+ });
+ auto L = cast<InputSectionDescription>(*ISD);
+ InputSection *Highest = L->Sections[L->Sections.size() - 2];
+ InputSection *LS = Highest->getLinkOrderDep();
+ uint64_t S = LS->getParent()->Addr + LS->getOffset(LS->getSize());
+ uint64_t P = getVA();
Target->relocateOne(Buf, R_ARM_PREL31, S - P);
write32le(Buf + 4, 0x1);
}
-template InputSection<ELF32LE> *elf::createCommonSection();
-template InputSection<ELF32BE> *elf::createCommonSection();
-template InputSection<ELF64LE> *elf::createCommonSection();
-template InputSection<ELF64BE> *elf::createCommonSection();
-
-template InputSection<ELF32LE> *elf::createInterpSection();
-template InputSection<ELF32BE> *elf::createInterpSection();
-template InputSection<ELF64LE> *elf::createInterpSection();
-template InputSection<ELF64BE> *elf::createInterpSection();
-
-template MergeInputSection<ELF32LE> *elf::createCommentSection();
-template MergeInputSection<ELF32BE> *elf::createCommentSection();
-template MergeInputSection<ELF64LE> *elf::createCommentSection();
-template MergeInputSection<ELF64BE> *elf::createCommentSection();
+ThunkSection::ThunkSection(OutputSection *OS, uint64_t Off)
+ : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS,
+ Config->Wordsize, ".text.thunk") {
+ this->Parent = OS;
+ this->OutSecOff = 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);
+}
+
+InputSection *ThunkSection::getTargetInputSection() const {
+ const Thunk *T = Thunks.front();
+ return T->getTargetInputSection();
+}
+
+InputSection *InX::ARMAttributes;
+BssSection *InX::Bss;
+BssSection *InX::BssRelRo;
+BuildIdSection *InX::BuildId;
+InputSection *InX::Common;
+SyntheticSection *InX::Dynamic;
+StringTableSection *InX::DynStrTab;
+SymbolTableBaseSection *InX::DynSymTab;
+InputSection *InX::Interp;
+GdbIndexSection *InX::GdbIndex;
+GotSection *InX::Got;
+GotPltSection *InX::GotPlt;
+GnuHashTableSection *InX::GnuHashTab;
+IgotPltSection *InX::IgotPlt;
+MipsGotSection *InX::MipsGot;
+MipsRldMapSection *InX::MipsRldMap;
+PltSection *InX::Plt;
+PltSection *InX::Iplt;
+StringTableSection *InX::ShStrTab;
+StringTableSection *InX::StrTab;
+SymbolTableBaseSection *InX::SymTab;
+
+template GdbIndexSection *elf::createGdbIndex<ELF32LE>();
+template GdbIndexSection *elf::createGdbIndex<ELF32BE>();
+template GdbIndexSection *elf::createGdbIndex<ELF64LE>();
+template GdbIndexSection *elf::createGdbIndex<ELF64BE>();
+
+template void PltSection::addEntry<ELF32LE>(SymbolBody &Sym);
+template void PltSection::addEntry<ELF32BE>(SymbolBody &Sym);
+template void PltSection::addEntry<ELF64LE>(SymbolBody &Sym);
+template void PltSection::addEntry<ELF64BE>(SymbolBody &Sym);
+
+template InputSection *elf::createCommonSection<ELF32LE>();
+template InputSection *elf::createCommonSection<ELF32BE>();
+template InputSection *elf::createCommonSection<ELF64LE>();
+template InputSection *elf::createCommonSection<ELF64BE>();
+
+template MergeInputSection *elf::createCommentSection<ELF32LE>();
+template MergeInputSection *elf::createCommentSection<ELF32BE>();
+template MergeInputSection *elf::createCommentSection<ELF64LE>();
+template MergeInputSection *elf::createCommentSection<ELF64BE>();
template class elf::MipsAbiFlagsSection<ELF32LE>;
template class elf::MipsAbiFlagsSection<ELF32BE>;
@@ -1905,36 +2385,6 @@ template class elf::MipsReginfoSection<ELF32BE>;
template class elf::MipsReginfoSection<ELF64LE>;
template class elf::MipsReginfoSection<ELF64BE>;
-template class elf::BuildIdSection<ELF32LE>;
-template class elf::BuildIdSection<ELF32BE>;
-template class elf::BuildIdSection<ELF64LE>;
-template class elf::BuildIdSection<ELF64BE>;
-
-template class elf::GotSection<ELF32LE>;
-template class elf::GotSection<ELF32BE>;
-template class elf::GotSection<ELF64LE>;
-template class elf::GotSection<ELF64BE>;
-
-template class elf::MipsGotSection<ELF32LE>;
-template class elf::MipsGotSection<ELF32BE>;
-template class elf::MipsGotSection<ELF64LE>;
-template class elf::MipsGotSection<ELF64BE>;
-
-template class elf::GotPltSection<ELF32LE>;
-template class elf::GotPltSection<ELF32BE>;
-template class elf::GotPltSection<ELF64LE>;
-template class elf::GotPltSection<ELF64BE>;
-
-template class elf::IgotPltSection<ELF32LE>;
-template class elf::IgotPltSection<ELF32BE>;
-template class elf::IgotPltSection<ELF64LE>;
-template class elf::IgotPltSection<ELF64BE>;
-
-template class elf::StringTableSection<ELF32LE>;
-template class elf::StringTableSection<ELF32BE>;
-template class elf::StringTableSection<ELF64LE>;
-template class elf::StringTableSection<ELF64BE>;
-
template class elf::DynamicSection<ELF32LE>;
template class elf::DynamicSection<ELF32BE>;
template class elf::DynamicSection<ELF64LE>;
@@ -1950,31 +2400,11 @@ template class elf::SymbolTableSection<ELF32BE>;
template class elf::SymbolTableSection<ELF64LE>;
template class elf::SymbolTableSection<ELF64BE>;
-template class elf::GnuHashTableSection<ELF32LE>;
-template class elf::GnuHashTableSection<ELF32BE>;
-template class elf::GnuHashTableSection<ELF64LE>;
-template class elf::GnuHashTableSection<ELF64BE>;
-
template class elf::HashTableSection<ELF32LE>;
template class elf::HashTableSection<ELF32BE>;
template class elf::HashTableSection<ELF64LE>;
template class elf::HashTableSection<ELF64BE>;
-template class elf::PltSection<ELF32LE>;
-template class elf::PltSection<ELF32BE>;
-template class elf::PltSection<ELF64LE>;
-template class elf::PltSection<ELF64BE>;
-
-template class elf::IpltSection<ELF32LE>;
-template class elf::IpltSection<ELF32BE>;
-template class elf::IpltSection<ELF64LE>;
-template class elf::IpltSection<ELF64BE>;
-
-template class elf::GdbIndexSection<ELF32LE>;
-template class elf::GdbIndexSection<ELF32BE>;
-template class elf::GdbIndexSection<ELF64LE>;
-template class elf::GdbIndexSection<ELF64BE>;
-
template class elf::EhFrameHeader<ELF32LE>;
template class elf::EhFrameHeader<ELF32BE>;
template class elf::EhFrameHeader<ELF64LE>;
@@ -1995,12 +2425,7 @@ template class elf::VersionDefinitionSection<ELF32BE>;
template class elf::VersionDefinitionSection<ELF64LE>;
template class elf::VersionDefinitionSection<ELF64BE>;
-template class elf::MipsRldMapSection<ELF32LE>;
-template class elf::MipsRldMapSection<ELF32BE>;
-template class elf::MipsRldMapSection<ELF64LE>;
-template class elf::MipsRldMapSection<ELF64BE>;
-
-template class elf::ARMExidxSentinelSection<ELF32LE>;
-template class elf::ARMExidxSentinelSection<ELF32BE>;
-template class elf::ARMExidxSentinelSection<ELF64LE>;
-template class elf::ARMExidxSentinelSection<ELF64BE>;
+template class elf::EhFrameSection<ELF32LE>;
+template class elf::EhFrameSection<ELF32BE>;
+template class elf::EhFrameSection<ELF64LE>;
+template class elf::EhFrameSection<ELF64BE>;
diff --git a/gnu/llvm/tools/lld/tools/lld/lld.cpp b/gnu/llvm/tools/lld/tools/lld/lld.cpp
index 037f43c8cb6..4a68ed7cab9 100644
--- a/gnu/llvm/tools/lld/tools/lld/lld.cpp
+++ b/gnu/llvm/tools/lld/tools/lld/lld.cpp
@@ -43,9 +43,9 @@ LLVM_ATTRIBUTE_NORETURN static void die(const Twine &S) {
static Flavor getFlavor(StringRef S) {
return StringSwitch<Flavor>(S)
- .Cases("ld", "ld.lld", "gnu", Gnu)
- .Case("link", WinLink)
- .Case("darwin", Darwin)
+ .CasesLower("ld", "ld.lld", "gnu", Gnu)
+ .CaseLower("link", WinLink)
+ .CaseLower("darwin", Darwin)
.Default(Invalid);
}
@@ -110,6 +110,6 @@ int main(int Argc, const char **Argv) {
#endif
default:
die("lld is a generic driver.\n"
- "Invoke ld.lld (Unix), ld (Mac) or lld-link (Windows) instead.");
+ "Invoke ld.lld (Unix), ld (macOS) or lld-link (Windows) instead.");
}
}