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