diff options
author | Patrick Wildt <patrick@cvs.openbsd.org> | 2017-10-04 20:51:30 +0000 |
---|---|---|
committer | Patrick Wildt <patrick@cvs.openbsd.org> | 2017-10-04 20:51:30 +0000 |
commit | d46291b91182428a0bc2c850c95991c82421fbdd (patch) | |
tree | 0a9bdef38d98f04ef4c1bb2c4a982261d120dbd9 /gnu/llvm/tools/lld | |
parent | ce4942c67154008535160eec8b913fb008038b6b (diff) |
Merge LLVM 5.0.0 release.
Diffstat (limited to 'gnu/llvm/tools/lld')
-rw-r--r-- | gnu/llvm/tools/lld/ELF/Config.h | 103 | ||||
-rw-r--r-- | gnu/llvm/tools/lld/ELF/Driver.cpp | 673 | ||||
-rw-r--r-- | gnu/llvm/tools/lld/ELF/DriverUtils.cpp | 27 | ||||
-rw-r--r-- | gnu/llvm/tools/lld/ELF/Options.td | 90 | ||||
-rw-r--r-- | gnu/llvm/tools/lld/ELF/OutputSections.cpp | 715 | ||||
-rw-r--r-- | gnu/llvm/tools/lld/ELF/SymbolTable.cpp | 304 | ||||
-rw-r--r-- | gnu/llvm/tools/lld/ELF/Symbols.cpp | 290 | ||||
-rw-r--r-- | gnu/llvm/tools/lld/ELF/SyntheticSections.cpp | 1937 | ||||
-rw-r--r-- | gnu/llvm/tools/lld/tools/lld/lld.cpp | 8 |
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."); } } |