diff options
Diffstat (limited to 'gnu/llvm')
-rw-r--r-- | gnu/llvm/tools/lld/ELF/Config.h | 68 | ||||
-rw-r--r-- | gnu/llvm/tools/lld/ELF/Driver.cpp | 573 | ||||
-rw-r--r-- | gnu/llvm/tools/lld/ELF/Options.td | 124 | ||||
-rw-r--r-- | gnu/llvm/tools/lld/ELF/Symbols.cpp | 215 | ||||
-rw-r--r-- | gnu/llvm/tools/lld/ELF/SyntheticSections.cpp | 13 |
5 files changed, 718 insertions, 275 deletions
diff --git a/gnu/llvm/tools/lld/ELF/Config.h b/gnu/llvm/tools/lld/ELF/Config.h index 2ccd95e8877..b7706205a5b 100644 --- a/gnu/llvm/tools/lld/ELF/Config.h +++ b/gnu/llvm/tools/lld/ELF/Config.h @@ -12,6 +12,7 @@ #include "llvm/ADT/MapVector.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSet.h" #include "llvm/Support/ELF.h" #include <vector> @@ -30,21 +31,36 @@ enum ELFKind { ELF64BEKind }; -enum class BuildIdKind { None, Fnv1, Md5, Sha1, Hexstring }; +// For --build-id. +enum class BuildIdKind { None, Fast, Md5, Sha1, Hexstring, Uuid }; -enum class UnresolvedPolicy { NoUndef, Error, Warn, Ignore }; +// For --discard-{all,locals,none} and --retain-symbols-file. +enum class DiscardPolicy { Default, All, Locals, RetainFile, None }; + +// For --strip-{all,debug}. +enum class StripPolicy { None, All, Debug }; + +// For --unresolved-symbols. +enum class UnresolvedPolicy { NoUndef, ReportError, Warn, Ignore }; + +// For --sort-section and linkerscript sorting rules. +enum class SortSectionPolicy { Default, None, Alignment, Name, Priority }; + +// For --target2 +enum class Target2Policy { Abs, Rel, GotRel }; struct SymbolVersion { llvm::StringRef Name; bool IsExternCpp; + bool HasWildcard; }; // This struct contains symbols version definition that // can be found in version script if it is used for link. struct VersionDefinition { - VersionDefinition(llvm::StringRef Name, size_t Id) : Name(Name), Id(Id) {} + VersionDefinition(llvm::StringRef Name, uint16_t Id) : Name(Name), Id(Id) {} llvm::StringRef Name; - size_t Id; + uint16_t Id; std::vector<SymbolVersion> Globals; size_t NameOff; // Offset in string table. }; @@ -54,75 +70,93 @@ struct VersionDefinition { // and such fields have the same name as the corresponding options. // Most fields are initialized by the driver. struct Configuration { - Symbol *EntrySym = nullptr; InputFile *FirstElf = nullptr; + uint8_t OSABI = 0; + llvm::StringMap<uint64_t> SectionStartMap; llvm::StringRef DynamicLinker; llvm::StringRef Entry; llvm::StringRef Emulation; llvm::StringRef Fini; llvm::StringRef Init; - llvm::StringRef LtoAAPipeline; - llvm::StringRef LtoNewPmPasses; + llvm::StringRef LTOAAPipeline; + llvm::StringRef LTONewPmPasses; llvm::StringRef OutputFile; llvm::StringRef SoName; llvm::StringRef Sysroot; + llvm::StringSet<> RetainSymbolsFile; std::string RPath; std::vector<VersionDefinition> VersionDefinitions; - std::vector<llvm::StringRef> DynamicList; + std::vector<llvm::StringRef> AuxiliaryList; std::vector<llvm::StringRef> SearchPaths; + std::vector<llvm::StringRef> SymbolOrderingFile; std::vector<llvm::StringRef> Undefined; std::vector<SymbolVersion> VersionScriptGlobals; + std::vector<SymbolVersion> VersionScriptLocals; std::vector<uint8_t> BuildIdVector; bool AllowMultipleDefinition; bool AsNeeded = false; bool Bsymbolic; bool BsymbolicFunctions; + bool ColorDiagnostics = false; + bool DefineCommon; bool Demangle = true; bool DisableVerify; - bool DiscardAll; - bool DiscardLocals; - bool DiscardNone; bool EhFrameHdr; bool EnableNewDtags; bool ExportDynamic; bool FatalWarnings; bool GcSections; + bool GdbIndex; bool GnuHash = false; bool ICF; bool Mips64EL = false; + bool MipsN32Abi = false; bool NoGnuUnique; bool NoUndefinedVersion; + bool Nostdlib; + bool OFormatBinary; + bool OMagic; bool Pic; bool Pie; bool PrintGcSections; bool Rela; bool Relocatable; bool SaveTemps; + bool SingleRoRx; bool Shared; bool Static = false; - bool StripAll; - bool StripDebug; bool SysvHash = true; + bool Target1Rel; bool Threads; bool Trace; bool Verbose; bool WarnCommon; + bool WarnMissingEntry; bool ZCombreloc; - bool ZExecStack; + bool ZExecstack; bool ZNodelete; bool ZNow; bool ZOrigin; bool ZRelro; + bool ExitEarly; + bool ZWxneeded; + DiscardPolicy Discard; + SortSectionPolicy SortSection; + StripPolicy Strip = StripPolicy::None; UnresolvedPolicy UnresolvedSymbols; + Target2Policy Target2 = Target2Policy::GotRel; BuildIdKind BuildId = BuildIdKind::None; ELFKind EKind = ELFNoneKind; uint16_t DefaultSymbolVersion = llvm::ELF::VER_NDX_GLOBAL; uint16_t EMachine = llvm::ELF::EM_NONE; - uint64_t EntryAddr = -1; + uint64_t ErrorLimit = 20; uint64_t ImageBase; - unsigned LtoJobs; - unsigned LtoO; + uint64_t MaxPageSize; + uint64_t ZStackSize; + unsigned LTOPartitions; + unsigned LTOO; unsigned Optimize; + unsigned ThinLTOJobs; }; // The only instance of Configuration struct. diff --git a/gnu/llvm/tools/lld/ELF/Driver.cpp b/gnu/llvm/tools/lld/ELF/Driver.cpp index c6ca2639236..e8d865e8b81 100644 --- a/gnu/llvm/tools/lld/ELF/Driver.cpp +++ b/gnu/llvm/tools/lld/ELF/Driver.cpp @@ -14,14 +14,20 @@ #include "InputFiles.h" #include "InputSection.h" #include "LinkerScript.h" +#include "Memory.h" #include "Strings.h" -#include "SymbolListFile.h" #include "SymbolTable.h" #include "Target.h" +#include "Threads.h" #include "Writer.h" +#include "lld/Config/Version.h" #include "lld/Driver/Driver.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/Object/Decompressor.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/TarWriter.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/raw_ostream.h" #include <cstdlib> @@ -38,48 +44,60 @@ using namespace lld::elf; Configuration *elf::Config; LinkerDriver *elf::Driver; -bool elf::link(ArrayRef<const char *> Args, raw_ostream &Error) { - HasError = false; +BumpPtrAllocator elf::BAlloc; +StringSaver elf::Saver{BAlloc}; +std::vector<SpecificAllocBase *> elf::SpecificAllocBase::Instances; + +bool elf::link(ArrayRef<const char *> Args, bool CanExitEarly, + raw_ostream &Error) { + ErrorCount = 0; ErrorOS = &Error; + Argv0 = Args[0]; + Tar = nullptr; - Configuration C; - LinkerDriver D; - ScriptConfiguration SC; - Config = &C; - Driver = &D; - ScriptConfig = &SC; + Config = make<Configuration>(); + Driver = make<LinkerDriver>(); + ScriptConfig = make<ScriptConfiguration>(); - Driver->main(Args); - return !HasError; + Driver->main(Args, CanExitEarly); + freeArena(); + return !ErrorCount; } // Parses a linker -m option. -static std::pair<ELFKind, uint16_t> parseEmulation(StringRef S) { - if (S.endswith("_fbsd")) +static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef Emul) { + uint8_t OSABI = 0; + StringRef S = Emul; + if (S.endswith("_fbsd")) { S = S.drop_back(5); + OSABI = ELFOSABI_FREEBSD; + } std::pair<ELFKind, uint16_t> Ret = StringSwitch<std::pair<ELFKind, uint16_t>>(S) - .Case("aarch64linux", {ELF64LEKind, EM_AARCH64}) + .Cases("aarch64elf", "aarch64linux", {ELF64LEKind, EM_AARCH64}) .Case("armelf_linux_eabi", {ELF32LEKind, EM_ARM}) .Case("elf32_x86_64", {ELF32LEKind, EM_X86_64}) .Case("elf32btsmip", {ELF32BEKind, EM_MIPS}) .Case("elf32ltsmip", {ELF32LEKind, EM_MIPS}) + .Case("elf32btsmipn32", {ELF32BEKind, EM_MIPS}) + .Case("elf32ltsmipn32", {ELF32LEKind, EM_MIPS}) .Case("elf32ppc", {ELF32BEKind, EM_PPC}) .Case("elf64btsmip", {ELF64BEKind, EM_MIPS}) .Case("elf64ltsmip", {ELF64LEKind, EM_MIPS}) .Case("elf64ppc", {ELF64BEKind, EM_PPC64}) + .Cases("elf_amd64", "elf_x86_64", {ELF64LEKind, EM_X86_64}) .Case("elf_i386", {ELF32LEKind, EM_386}) - .Case("elf_x86_64", {ELF64LEKind, EM_X86_64}) + .Case("elf_iamcu", {ELF32LEKind, EM_IAMCU}) .Default({ELFNoneKind, EM_NONE}); if (Ret.first == ELFNoneKind) { if (S == "i386pe" || S == "i386pep" || S == "thumb2pe") - error("Windows targets are not supported on the ELF frontend: " + S); + error("Windows targets are not supported on the ELF frontend: " + Emul); else - error("unknown emulation: " + S); + error("unknown emulation: " + Emul); } - return Ret; + return std::make_tuple(Ret.first, Ret.second, OSABI); } // Returns slices of MB by parsing MB as an archive file. @@ -87,25 +105,28 @@ static std::pair<ELFKind, uint16_t> parseEmulation(StringRef S) { std::vector<MemoryBufferRef> LinkerDriver::getArchiveMembers(MemoryBufferRef MB) { std::unique_ptr<Archive> File = - check(Archive::create(MB), "failed to parse archive"); + check(Archive::create(MB), + MB.getBufferIdentifier() + ": failed to parse archive"); std::vector<MemoryBufferRef> V; - Error Err; + Error Err = Error::success(); for (const ErrorOr<Archive::Child> &COrErr : File->children(Err)) { - Archive::Child C = check(COrErr, "could not get the child of the archive " + - File->getFileName()); + Archive::Child C = + check(COrErr, MB.getBufferIdentifier() + + ": could not get the child of the archive"); MemoryBufferRef MBRef = check(C.getMemoryBufferRef(), - "could not get the buffer for a child of the archive " + - File->getFileName()); + MB.getBufferIdentifier() + + ": could not get the buffer for a child of the archive"); V.push_back(MBRef); } if (Err) - Error(Err); + fatal(MB.getBufferIdentifier() + ": Archive::children failed: " + + toString(std::move(Err))); // Take ownership of memory buffers created for members of thin archives. for (std::unique_ptr<MemoryBuffer> &MB : File->takeThinBuffers()) - OwningMBs.push_back(std::move(MB)); + make<std::unique_ptr<MemoryBuffer>>(std::move(MB)); return V; } @@ -114,25 +135,28 @@ LinkerDriver::getArchiveMembers(MemoryBufferRef MB) { // Newly created memory buffers are owned by this driver. void LinkerDriver::addFile(StringRef Path) { using namespace sys::fs; - if (Config->Verbose) - outs() << Path << "\n"; Optional<MemoryBufferRef> Buffer = readFile(Path); if (!Buffer.hasValue()) return; MemoryBufferRef MBRef = *Buffer; + if (InBinary) { + Files.push_back(make<BinaryFile>(MBRef)); + return; + } + switch (identify_magic(MBRef.getBuffer())) { case file_magic::unknown: readLinkerScript(MBRef); return; case file_magic::archive: - if (WholeArchive) { + if (InWholeArchive) { for (MemoryBufferRef MB : getArchiveMembers(MBRef)) Files.push_back(createObjectFile(MB, Path)); return; } - Files.push_back(make_unique<ArchiveFile>(MBRef)); + Files.push_back(make<ArchiveFile>(MBRef)); return; case file_magic::elf_shared_object: if (Config->Relocatable) { @@ -143,35 +167,18 @@ void LinkerDriver::addFile(StringRef Path) { return; default: if (InLib) - Files.push_back(make_unique<LazyObjectFile>(MBRef)); + Files.push_back(make<LazyObjectFile>(MBRef)); else Files.push_back(createObjectFile(MBRef)); } } -Optional<MemoryBufferRef> LinkerDriver::readFile(StringRef Path) { - auto MBOrErr = MemoryBuffer::getFile(Path); - if (auto EC = MBOrErr.getError()) { - error(EC, "cannot open " + Path); - return None; - } - std::unique_ptr<MemoryBuffer> &MB = *MBOrErr; - MemoryBufferRef MBRef = MB->getMemBufferRef(); - OwningMBs.push_back(std::move(MB)); // take MB ownership - - if (Cpio) - Cpio->append(relativeToRoot(Path), MBRef.getBuffer()); - - return MBRef; -} - // Add a given library by searching it from input search paths. void LinkerDriver::addLibrary(StringRef Name) { - std::string Path = searchLibrary(Name); - if (Path.empty()) - error("unable to find library -l" + Name); + if (Optional<std::string> Path = searchLibrary(Name)) + addFile(*Path); else - addFile(Path); + error("unable to find library -l" + Name); } // This function is called on startup. We need this for LTO since @@ -184,12 +191,6 @@ static void initLLVM(opt::InputArgList &Args) { InitializeAllAsmPrinters(); InitializeAllAsmParsers(); - // This is a flag to discard all but GlobalValue names. - // We want to enable it by default because it saves memory. - // Disable it only when a developer option (-save-temps) is given. - Driver->Context.setDiscardValueNames(!Config->SaveTemps); - Driver->Context.enableDebugTypeODRUniquing(); - // Parse and evaluate -mllvm options. std::vector<const char *> V; V.push_back("lld (LLVM option parsing)"); @@ -206,9 +207,6 @@ static void checkOptions(opt::InputArgList &Args) { if (Config->EMachine == EM_MIPS && Config->GnuHash) error("the .gnu.hash section is not compatible with the MIPS target."); - if (Config->EMachine == EM_AMDGPU && !Config->Entry.empty()) - error("-e option is not valid for AMDGPU."); - if (Config->Pie && Config->Shared) error("-shared and -pie may not be used together"); @@ -224,8 +222,8 @@ static void checkOptions(opt::InputArgList &Args) { } } -static StringRef -getString(opt::InputArgList &Args, unsigned Key, StringRef Default = "") { +static StringRef getString(opt::InputArgList &Args, unsigned Key, + StringRef Default = "") { if (auto *Arg = Args.getLastArg(Key)) return Arg->getValue(); return Default; @@ -254,33 +252,67 @@ static bool hasZOption(opt::InputArgList &Args, StringRef Key) { return false; } -void LinkerDriver::main(ArrayRef<const char *> ArgsArr) { +static uint64_t getZOptionValue(opt::InputArgList &Args, StringRef Key, + uint64_t Default) { + for (auto *Arg : Args.filtered(OPT_z)) { + StringRef Value = Arg->getValue(); + size_t Pos = Value.find("="); + if (Pos != StringRef::npos && Key == Value.substr(0, Pos)) { + Value = Value.substr(Pos + 1); + uint64_t Result; + if (Value.getAsInteger(0, Result)) + error("invalid " + Key + ": " + Value); + return Result; + } + } + return Default; +} + +void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) { ELFOptTable Parser; opt::InputArgList Args = Parser.parse(ArgsArr.slice(1)); + + // Interpret this flag early because error() depends on them. + Config->ErrorLimit = getInteger(Args, OPT_error_limit, 20); + + // Handle -help if (Args.hasArg(OPT_help)) { printHelp(ArgsArr[0]); return; } - if (Args.hasArg(OPT_version)) { - outs() << getVersionString(); + + // GNU linkers disagree here. Though both -version and -v are mentioned + // in help to print the version information, GNU ld just normally exits, + // while gold can continue linking. We are compatible with ld.bfd here. + if (Args.hasArg(OPT_version) || Args.hasArg(OPT_v)) + outs() << getLLDVersion() << "\n"; + if (Args.hasArg(OPT_version)) return; - } + + Config->ExitEarly = CanExitEarly && !Args.hasArg(OPT_full_shutdown); 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. - Cpio.reset(CpioFile::create(Path)); - if (Cpio) { - Cpio->append("response.txt", createResponseFile(Args)); - Cpio->append("version.txt", getVersionString()); + Expected<std::unique_ptr<TarWriter>> ErrOrWriter = + TarWriter::create(Path, path::stem(Path)); + if (ErrOrWriter) { + Tar = ErrOrWriter->get(); + Tar->append("response.txt", createResponseFile(Args)); + Tar->append("version.txt", getLLDVersion() + "\n"); + make<std::unique_ptr<TarWriter>>(std::move(*ErrOrWriter)); + } else { + error(Twine("--reproduce: failed to open ") + Path + ": " + + toString(ErrOrWriter.takeError())); } } readConfigs(Args); initLLVM(Args); createFiles(Args); + inferMachineType(); checkOptions(Args); - if (HasError) + if (ErrorCount) return; switch (Config->EKind) { @@ -297,7 +329,7 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr) { link<ELF64BE>(Args); return; default: - error("-m or at least a .o file required"); + llvm_unreachable("unknown Config->EKind"); } } @@ -314,10 +346,115 @@ static UnresolvedPolicy getUnresolvedSymbolOption(opt::InputArgList &Args) { if (S == "ignore-all" || S == "ignore-in-object-files") return UnresolvedPolicy::Ignore; if (S == "ignore-in-shared-libs" || S == "report-all") - return UnresolvedPolicy::Error; + return UnresolvedPolicy::ReportError; error("unknown --unresolved-symbols value: " + S); } - return UnresolvedPolicy::Error; + return UnresolvedPolicy::ReportError; +} + +static Target2Policy getTarget2Option(opt::InputArgList &Args) { + if (auto *Arg = Args.getLastArg(OPT_target2)) { + StringRef S = Arg->getValue(); + if (S == "rel") + return Target2Policy::Rel; + if (S == "abs") + return Target2Policy::Abs; + if (S == "got-rel") + return Target2Policy::GotRel; + error("unknown --target2 option: " + S); + } + return Target2Policy::GotRel; +} + +static bool isOutputFormatBinary(opt::InputArgList &Args) { + if (auto *Arg = Args.getLastArg(OPT_oformat)) { + StringRef S = Arg->getValue(); + if (S == "binary") + return true; + error("unknown --oformat value: " + S); + } + return false; +} + +static bool getArg(opt::InputArgList &Args, unsigned K1, unsigned K2, + bool Default) { + if (auto *Arg = Args.getLastArg(K1, K2)) + return Arg->getOption().getID() == K1; + return Default; +} + +static DiscardPolicy getDiscardOption(opt::InputArgList &Args) { + if (Config->Relocatable) + return DiscardPolicy::None; + auto *Arg = + Args.getLastArg(OPT_discard_all, OPT_discard_locals, OPT_discard_none); + if (!Arg) + return DiscardPolicy::Default; + if (Arg->getOption().getID() == OPT_discard_all) + return DiscardPolicy::All; + if (Arg->getOption().getID() == OPT_discard_locals) + return DiscardPolicy::Locals; + return DiscardPolicy::None; +} + +static StripPolicy getStripOption(opt::InputArgList &Args) { + if (auto *Arg = Args.getLastArg(OPT_strip_all, OPT_strip_debug)) { + if (Arg->getOption().getID() == OPT_strip_all) + return StripPolicy::All; + return StripPolicy::Debug; + } + return StripPolicy::None; +} + +static uint64_t parseSectionAddress(StringRef S, opt::Arg *Arg) { + uint64_t VA = 0; + if (S.startswith("0x")) + S = S.drop_front(2); + if (S.getAsInteger(16, VA)) + error("invalid argument: " + toString(Arg)); + return VA; +} + +static StringMap<uint64_t> getSectionStartMap(opt::InputArgList &Args) { + StringMap<uint64_t> Ret; + for (auto *Arg : Args.filtered(OPT_section_start)) { + StringRef Name; + StringRef Addr; + std::tie(Name, Addr) = StringRef(Arg->getValue()).split('='); + Ret[Name] = parseSectionAddress(Addr, Arg); + } + + if (auto *Arg = Args.getLastArg(OPT_Ttext)) + Ret[".text"] = parseSectionAddress(Arg->getValue(), Arg); + if (auto *Arg = Args.getLastArg(OPT_Tdata)) + Ret[".data"] = parseSectionAddress(Arg->getValue(), Arg); + if (auto *Arg = Args.getLastArg(OPT_Tbss)) + Ret[".bss"] = parseSectionAddress(Arg->getValue(), Arg); + return Ret; +} + +static SortSectionPolicy getSortKind(opt::InputArgList &Args) { + StringRef S = getString(Args, OPT_sort_section); + if (S == "alignment") + return SortSectionPolicy::Alignment; + if (S == "name") + return SortSectionPolicy::Name; + if (!S.empty()) + error("unknown --sort-section rule: " + S); + return SortSectionPolicy::Default; +} + +static std::vector<StringRef> getLines(MemoryBufferRef MB) { + SmallVector<StringRef, 0> Arr; + MB.getBuffer().split(Arr, '\n'); + + std::vector<StringRef> Ret; + for (StringRef S : Arr) { + S = S.trim(); + if (!S.empty()) + Ret.push_back(S); + } + return Ret; } // Initializes Config members by the command line options. @@ -334,34 +471,39 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { if (auto *Arg = Args.getLastArg(OPT_m)) { // Parse ELF{32,64}{LE,BE} and CPU type. StringRef S = Arg->getValue(); - std::tie(Config->EKind, Config->EMachine) = parseEmulation(S); + std::tie(Config->EKind, Config->EMachine, Config->OSABI) = + parseEmulation(S); + Config->MipsN32Abi = (S == "elf32btsmipn32" || S == "elf32ltsmipn32"); Config->Emulation = S; } Config->AllowMultipleDefinition = Args.hasArg(OPT_allow_multiple_definition); Config->Bsymbolic = Args.hasArg(OPT_Bsymbolic); Config->BsymbolicFunctions = Args.hasArg(OPT_Bsymbolic_functions); - Config->Demangle = !Args.hasArg(OPT_no_demangle); + Config->Demangle = getArg(Args, OPT_demangle, OPT_no_demangle, true); Config->DisableVerify = Args.hasArg(OPT_disable_verify); - Config->DiscardAll = Args.hasArg(OPT_discard_all); - Config->DiscardLocals = Args.hasArg(OPT_discard_locals); - Config->DiscardNone = Args.hasArg(OPT_discard_none); Config->EhFrameHdr = Args.hasArg(OPT_eh_frame_hdr); Config->EnableNewDtags = !Args.hasArg(OPT_disable_new_dtags); Config->ExportDynamic = Args.hasArg(OPT_export_dynamic); Config->FatalWarnings = Args.hasArg(OPT_fatal_warnings); - Config->GcSections = Args.hasArg(OPT_gc_sections); + Config->GcSections = getArg(Args, OPT_gc_sections, OPT_no_gc_sections, false); + Config->GdbIndex = Args.hasArg(OPT_gdb_index); Config->ICF = Args.hasArg(OPT_icf); Config->NoGnuUnique = Args.hasArg(OPT_no_gnu_unique); Config->NoUndefinedVersion = Args.hasArg(OPT_no_undefined_version); - Config->Pie = Args.hasArg(OPT_pie); + Config->Nostdlib = Args.hasArg(OPT_nostdlib); + Config->OMagic = Args.hasArg(OPT_omagic); + Config->Pie = getArg(Args, OPT_pie, OPT_nopie, false); Config->PrintGcSections = Args.hasArg(OPT_print_gc_sections); Config->Relocatable = Args.hasArg(OPT_relocatable); + Config->DefineCommon = getArg(Args, OPT_define_common, OPT_no_define_common, + !Config->Relocatable); + Config->Discard = getDiscardOption(Args); Config->SaveTemps = Args.hasArg(OPT_save_temps); + Config->SingleRoRx = Args.hasArg(OPT_no_rosegment); Config->Shared = Args.hasArg(OPT_shared); - Config->StripAll = Args.hasArg(OPT_strip_all); - Config->StripDebug = Args.hasArg(OPT_strip_debug); - Config->Threads = Args.hasArg(OPT_threads); + Config->Target1Rel = getArg(Args, OPT_target1_rel, OPT_target1_abs, false); + Config->Threads = getArg(Args, OPT_threads, OPT_no_threads, true); Config->Trace = Args.hasArg(OPT_trace); Config->Verbose = Args.hasArg(OPT_verbose); Config->WarnCommon = Args.hasArg(OPT_warn_common); @@ -370,33 +512,47 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { Config->Entry = getString(Args, OPT_entry); Config->Fini = getString(Args, OPT_fini, "_fini"); Config->Init = getString(Args, OPT_init, "_init"); - Config->LtoAAPipeline = getString(Args, OPT_lto_aa_pipeline); - Config->LtoNewPmPasses = getString(Args, OPT_lto_newpm_passes); + Config->LTOAAPipeline = getString(Args, OPT_lto_aa_pipeline); + Config->LTONewPmPasses = getString(Args, OPT_lto_newpm_passes); Config->OutputFile = getString(Args, OPT_o); Config->SoName = getString(Args, OPT_soname); Config->Sysroot = getString(Args, OPT_sysroot); Config->Optimize = getInteger(Args, OPT_O, 1); - Config->LtoO = getInteger(Args, OPT_lto_O, 2); - if (Config->LtoO > 3) + Config->LTOO = getInteger(Args, OPT_lto_O, 2); + if (Config->LTOO > 3) error("invalid optimization level for LTO: " + getString(Args, OPT_lto_O)); - Config->LtoJobs = getInteger(Args, OPT_lto_jobs, 1); - if (Config->LtoJobs == 0) - error("number of threads must be > 0"); + Config->LTOPartitions = getInteger(Args, OPT_lto_partitions, 1); + if (Config->LTOPartitions == 0) + error("--lto-partitions: number of threads must be > 0"); + Config->ThinLTOJobs = getInteger(Args, OPT_thinlto_jobs, -1u); + if (Config->ThinLTOJobs == 0) + error("--thinlto-jobs: number of threads must be > 0"); Config->ZCombreloc = !hasZOption(Args, "nocombreloc"); - Config->ZExecStack = hasZOption(Args, "execstack"); + Config->ZExecstack = hasZOption(Args, "execstack"); Config->ZNodelete = hasZOption(Args, "nodelete"); Config->ZNow = hasZOption(Args, "now"); Config->ZOrigin = hasZOption(Args, "origin"); Config->ZRelro = !hasZOption(Args, "norelro"); + Config->ZStackSize = getZOptionValue(Args, "stack-size", -1); + Config->ZWxneeded = hasZOption(Args, "wxneeded"); - if (Config->Relocatable) - Config->StripAll = false; + Config->OFormatBinary = isOutputFormatBinary(Args); + Config->SectionStartMap = getSectionStartMap(Args); + Config->SortSection = getSortKind(Args); + Config->Target2 = getTarget2Option(Args); + Config->UnresolvedSymbols = getUnresolvedSymbolOption(Args); + + // --omagic is an option to create old-fashioned executables in which + // .text segments are writable. Today, the option is still in use to + // create special-purpose programs such as boot loaders. It doesn't + // make sense to create PT_GNU_RELRO for such executables. + if (Config->OMagic) + Config->ZRelro = false; - // --strip-all implies --strip-debug. - if (Config->StripAll) - Config->StripDebug = true; + if (!Config->Relocatable) + Config->Strip = getStripOption(Args); // Config->Pic is true if we are generating position-independent code. Config->Pic = Config->Pie || Config->Shared; @@ -414,13 +570,15 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { // Parse --build-id or --build-id=<style>. if (Args.hasArg(OPT_build_id)) - Config->BuildId = BuildIdKind::Fnv1; + Config->BuildId = BuildIdKind::Fast; if (auto *Arg = Args.getLastArg(OPT_build_id_eq)) { StringRef S = Arg->getValue(); if (S == "md5") { Config->BuildId = BuildIdKind::Md5; - } else if (S == "sha1") { + } else if (S == "sha1" || S == "tree") { Config->BuildId = BuildIdKind::Sha1; + } else if (S == "uuid") { + Config->BuildId = BuildIdKind::Uuid; } else if (S == "none") { Config->BuildId = BuildIdKind::None; } else if (S.startswith("0x")) { @@ -431,21 +589,58 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { } } + for (auto *Arg : Args.filtered(OPT_auxiliary)) + Config->AuxiliaryList.push_back(Arg->getValue()); + if (!Config->Shared && !Config->AuxiliaryList.empty()) + error("-f may not be used without -shared"); + for (auto *Arg : Args.filtered(OPT_undefined)) Config->Undefined.push_back(Arg->getValue()); - Config->UnresolvedSymbols = getUnresolvedSymbolOption(Args); - if (auto *Arg = Args.getLastArg(OPT_dynamic_list)) if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue())) - parseDynamicList(*Buffer); + readDynamicList(*Buffer); + + if (auto *Arg = Args.getLastArg(OPT_symbol_ordering_file)) + if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue())) + Config->SymbolOrderingFile = getLines(*Buffer); + + // If --retain-symbol-file is used, we'll retail only the symbols listed in + // the file and discard all others. + if (auto *Arg = Args.getLastArg(OPT_retain_symbols_file)) { + Config->Discard = DiscardPolicy::RetainFile; + if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue())) + for (StringRef S : getLines(*Buffer)) + Config->RetainSymbolsFile.insert(S); + } for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol)) - Config->DynamicList.push_back(Arg->getValue()); + Config->VersionScriptGlobals.push_back( + {Arg->getValue(), /*IsExternCpp*/ false, /*HasWildcard*/ false}); + + // Dynamic lists are a simplified linker script that doesn't need the + // "global:" and implicitly ends with a "local:*". Set the variables needed to + // simulate that. + if (Args.hasArg(OPT_dynamic_list) || Args.hasArg(OPT_export_dynamic_symbol)) { + Config->ExportDynamic = true; + if (!Config->Shared) + Config->DefaultSymbolVersion = VER_NDX_LOCAL; + } if (auto *Arg = Args.getLastArg(OPT_version_script)) if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue())) - parseVersionScript(*Buffer); + readVersionScript(*Buffer); +} + +// Returns a value of "-format" option. +static bool getBinaryOption(StringRef S) { + if (S == "binary") + return true; + if (S == "elf" || S == "default") + return false; + error("unknown -format value: " + S + + " (supported formats: elf, default, binary)"); + return false; } void LinkerDriver::createFiles(opt::InputArgList &Args) { @@ -454,14 +649,20 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) { case OPT_l: addLibrary(Arg->getValue()); break; - case OPT_alias_script_T: case OPT_INPUT: - case OPT_script: addFile(Arg->getValue()); break; + case OPT_alias_script_T: + case OPT_script: + if (Optional<MemoryBufferRef> MB = readFile(Arg->getValue())) + readLinkerScript(*MB); + break; case OPT_as_needed: Config->AsNeeded = true; break; + case OPT_format: + InBinary = getBinaryOption(Arg->getValue()); + break; case OPT_no_as_needed: Config->AsNeeded = false; break; @@ -472,10 +673,10 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) { Config->Static = false; break; case OPT_whole_archive: - WholeArchive = true; + InWholeArchive = true; break; case OPT_no_whole_archive: - WholeArchive = false; + InWholeArchive = false; break; case OPT_start_lib: InLib = true; @@ -486,19 +687,55 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) { } } - if (Files.empty() && !HasError) - error("no input files."); + if (Files.empty() && ErrorCount == 0) + error("no input files"); +} - // If -m <machine_type> was not given, infer it from object files. - if (Config->EKind == ELFNoneKind) { - for (std::unique_ptr<InputFile> &F : Files) { - if (F->EKind == ELFNoneKind) - continue; - Config->EKind = F->EKind; - Config->EMachine = F->EMachine; - break; - } +// If -m <machine_type> was not given, infer it from object files. +void LinkerDriver::inferMachineType() { + if (Config->EKind != ELFNoneKind) + return; + + for (InputFile *F : Files) { + if (F->EKind == ELFNoneKind) + continue; + Config->EKind = F->EKind; + Config->EMachine = F->EMachine; + Config->OSABI = F->OSABI; + Config->MipsN32Abi = Config->EMachine == EM_MIPS && isMipsN32Abi(F); + return; } + error("target emulation unknown: -m or at least one .o file required"); +} + +// Parse -z max-page-size=<value>. The default value is defined by +// each target. +static uint64_t getMaxPageSize(opt::InputArgList &Args) { + uint64_t Val = + getZOptionValue(Args, "max-page-size", Target->DefaultMaxPageSize); + if (!isPowerOf2_64(Val)) + error("max-page-size: value isn't a power of 2"); + return Val; +} + +// Parses -image-base option. +static uint64_t getImageBase(opt::InputArgList &Args) { + // Use default if no -image-base option is given. + // Because we are using "Target" here, this function + // has to be called after the variable is initialized. + auto *Arg = Args.getLastArg(OPT_image_base); + if (!Arg) + return Config->Pic ? 0 : Target->DefaultImageBase; + + StringRef S = Arg->getValue(); + uint64_t V; + if (S.getAsInteger(0, V)) { + error("-image-base: number expected, but got " + S); + return 0; + } + if ((V % Config->MaxPageSize) != 0) + warn("-image-base: address isn't multiple of page size: " + S); + return V; } // Do actual linking. Note that when this function is called, @@ -506,66 +743,70 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) { template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { SymbolTable<ELFT> Symtab; elf::Symtab<ELFT>::X = &Symtab; + Target = createTarget(); + ScriptBase = Script<ELFT>::X = make<LinkerScript<ELFT>>(); - std::unique_ptr<TargetInfo> TI(createTarget()); - Target = TI.get(); - LinkerScript<ELFT> LS; - Script<ELFT>::X = &LS; - - Config->Rela = ELFT::Is64Bits || Config->EMachine == EM_X86_64; + Config->Rela = + ELFT::Is64Bits || Config->EMachine == EM_X86_64 || Config->MipsN32Abi; Config->Mips64EL = (Config->EMachine == EM_MIPS && Config->EKind == ELF64LEKind); - - // Add entry symbol. Note that AMDGPU binaries have no entry points. - if (Config->Entry.empty() && !Config->Shared && !Config->Relocatable && - Config->EMachine != EM_AMDGPU) - Config->Entry = (Config->EMachine == EM_MIPS) ? "__start" : "_start"; + Config->MaxPageSize = getMaxPageSize(Args); + Config->ImageBase = getImageBase(Args); // Default output filename is "a.out" by the Unix tradition. if (Config->OutputFile.empty()) Config->OutputFile = "a.out"; + // Use default entry point name if no name was given via the command + // line nor linker scripts. For some reason, MIPS entry point name is + // different from others. + Config->WarnMissingEntry = + (!Config->Entry.empty() || (!Config->Shared && !Config->Relocatable)); + if (Config->Entry.empty() && !Config->Relocatable) + Config->Entry = (Config->EMachine == EM_MIPS) ? "__start" : "_start"; + // Handle --trace-symbol. for (auto *Arg : Args.filtered(OPT_trace_symbol)) Symtab.trace(Arg->getValue()); - // Set either EntryAddr (if S is a number) or EntrySym (otherwise). - if (!Config->Entry.empty()) { - StringRef S = Config->Entry; - if (S.getAsInteger(0, Config->EntryAddr)) - Config->EntrySym = Symtab.addUndefined(S); - } + // Add all files to the symbol table. This will add almost all + // symbols that we need to the symbol table. + for (InputFile *F : Files) + Symtab.addFile(F); - // Initialize Config->ImageBase. - if (auto *Arg = Args.getLastArg(OPT_image_base)) { - StringRef S = Arg->getValue(); - if (S.getAsInteger(0, Config->ImageBase)) - error(Arg->getSpelling() + ": number expected, but got " + S); - else if ((Config->ImageBase % Target->PageSize) != 0) - warning(Arg->getSpelling() + ": address isn't multiple of page size"); - } else { - Config->ImageBase = Config->Pic ? 0 : Target->DefaultImageBase; - } + // 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. + if (Symtab.find(Config->Entry)) + Symtab.addUndefined(Config->Entry); - for (std::unique_ptr<InputFile> &F : Files) - Symtab.addFile(std::move(F)); - if (HasError) - return; // There were duplicate symbols or incompatible files + // Return if there were name resolution errors. + if (ErrorCount) + return; Symtab.scanUndefinedFlags(); Symtab.scanShlibUndefined(); - Symtab.scanDynamicList(); Symtab.scanVersionScript(); - Symtab.scanSymbolVersions(); - Symtab.addCombinedLtoObject(); - if (HasError) + Symtab.addCombinedLTOObject(); + if (ErrorCount) return; for (auto *Arg : Args.filtered(OPT_wrap)) Symtab.wrap(Arg->getValue()); - // Write the result to the file. + // Now that we have a complete list of input files. + // Beyond this point, no new files are added. + // Aggregate all input sections into one place. + for (elf::ObjectFile<ELFT> *F : Symtab.getObjectFiles()) + for (InputSectionBase<ELFT> *S : F->getSections()) + if (S && S != &InputSection<ELFT>::Discarded) + Symtab.Sections.push_back(S); + for (BinaryFile *F : Symtab.getBinaryFiles()) + for (InputSectionData *S : F->getSections()) + Symtab.Sections.push_back(cast<InputSection<ELFT>>(S)); + + // Do size optimizations: garbage collection and identical code folding. if (Config->GcSections) markLive<ELFT>(); if (Config->ICF) @@ -573,16 +814,16 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { // MergeInputSection::splitIntoPieces needs to be called before // any call of MergeInputSection::getOffset. Do that. - for (const std::unique_ptr<elf::ObjectFile<ELFT>> &F : - Symtab.getObjectFiles()) - for (InputSectionBase<ELFT> *S : F->getSections()) { - if (!S || S == &InputSection<ELFT>::Discarded || !S->Live) - continue; - if (S->Compressed) - S->uncompress(); - if (auto *MS = dyn_cast<MergeInputSection<ELFT>>(S)) - MS->splitIntoPieces(); - } + forEach(Symtab.Sections.begin(), Symtab.Sections.end(), + [](InputSectionBase<ELFT> *S) { + if (!S->Live) + return; + if (Decompressor::isCompressedELFSection(S->Flags, S->Name)) + S->uncompress(); + if (auto *MS = dyn_cast<MergeInputSection<ELFT>>(S)) + MS->splitIntoPieces(); + }); - writeResult<ELFT>(&Symtab); + // Write the result to the file. + writeResult<ELFT>(); } diff --git a/gnu/llvm/tools/lld/ELF/Options.td b/gnu/llvm/tools/lld/ELF/Options.td index 010f37687f0..77ed4c7e466 100644 --- a/gnu/llvm/tools/lld/ELF/Options.td +++ b/gnu/llvm/tools/lld/ELF/Options.td @@ -7,6 +7,8 @@ class J<string name>: Joined<["--", "-"], name>; class S<string name>: Separate<["--", "-"], name>; class JS<string name>: JoinedOrSeparate<["--", "-"], name>; +def auxiliary: S<"auxiliary">, HelpText<"Set DT_AUXILIARY field to the specified name">; + def Bsymbolic: F<"Bsymbolic">, HelpText<"Bind defined symbols locally">; def Bsymbolic_functions: F<"Bsymbolic-functions">, @@ -25,12 +27,27 @@ def L: JoinedOrSeparate<["-"], "L">, MetaVarName<"<dir>">, def O: Joined<["-"], "O">, HelpText<"Optimize output file size">; +def Tbss: S<"Tbss">, HelpText<"Same as --section-start with .bss as the sectionname">; + +def Tdata: S<"Tdata">, HelpText<"Same as --section-start with .data as the sectionname">; + +def Ttext: S<"Ttext">, HelpText<"Same as --section-start with .text as the sectionname">; + def allow_multiple_definition: F<"allow-multiple-definition">, HelpText<"Allow multiple definitions">; def as_needed: F<"as-needed">, HelpText<"Only set DT_NEEDED for shared libraries if used">; +def color_diagnostics: F<"color-diagnostics">, + HelpText<"Use colors in diagnostics">; + +def color_diagnostics_eq: J<"color-diagnostics=">, + HelpText<"Use colors in diagnostics">; + +def define_common: F<"define-common">, + HelpText<"Assign space to common symbols">; + def disable_new_dtags: F<"disable-new-dtags">, HelpText<"Disable new dynamic tags">; @@ -60,6 +77,9 @@ def end_lib: F<"end-lib">, def entry: S<"entry">, MetaVarName<"<entry>">, HelpText<"Name of entry point symbol">; +def error_limit: S<"error-limit">, + HelpText<"Maximum number of errors to emit before stopping (0 = no limit)">; + def export_dynamic: F<"export-dynamic">, HelpText<"Put symbols in the dynamic symbol table">; @@ -72,6 +92,18 @@ def fatal_warnings: F<"fatal-warnings">, def fini: S<"fini">, MetaVarName<"<symbol>">, HelpText<"Specify a finalizer function">; +def full_shutdown : F<"full-shutdown">, + HelpText<"Perform a full shutdown instead of calling _exit">; + +def format: J<"format=">, MetaVarName<"<input-format>">, + HelpText<"Change the input format of the inputs following this option">; + +def gc_sections: F<"gc-sections">, + HelpText<"Enable garbage collection of unused sections">; + +def gdb_index: F<"gdb-index">, + HelpText<"Generate .gdb_index section">; + def hash_style: S<"hash-style">, HelpText<"Specify hash style (sysv, gnu or both)">; @@ -81,9 +113,6 @@ def icf: F<"icf=all">, HelpText<"Enable identical code folding">; def image_base : J<"image-base=">, HelpText<"Set the base address">; -def gc_sections: F<"gc-sections">, - HelpText<"Enable garbage collection of unused sections">; - def init: S<"init">, MetaVarName<"<symbol>">, HelpText<"Specify an initializer function">; @@ -95,21 +124,40 @@ def lto_O: J<"lto-O">, MetaVarName<"<opt-level>">, def m: JoinedOrSeparate<["-"], "m">, HelpText<"Set target emulation">; +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_gc_sections: F<"no-gc-sections">, + HelpText<"Disable garbage collection of unused sections">; + def no_gnu_unique: F<"no-gnu-unique">, HelpText<"Disable STB_GNU_UNIQUE symbol binding">; +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_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">; @@ -119,6 +167,12 @@ def no_undefined_version: F<"no-undefined-version">, def o: JoinedOrSeparate<["-"], "o">, MetaVarName<"<path>">, HelpText<"Path to file to write output">; +def oformat: Separate<["--"], "oformat">, MetaVarName<"<format>">, + HelpText<"Specify the binary format for the output object file">; + +def omagic: F<"omagic">, MetaVarName<"<magic>">, + HelpText<"Set the text and data sections to be readable and writable">; + def pie: F<"pie">, HelpText<"Create a position independent executable">; def print_gc_sections: F<"print-gc-sections">, @@ -131,12 +185,20 @@ def rpath: S<"rpath">, HelpText<"Add a DT_RUNPATH to the output">; def relocatable: F<"relocatable">, HelpText<"Create relocatable object file">; +def retain_symbols_file: J<"retain-symbols-file=">, MetaVarName<"<file>">, + HelpText<"Retain only the symbols listed in the file">; + def script: S<"script">, HelpText<"Read linker script">; +def section_start: S<"section-start">, MetaVarName<"<address>">, + HelpText<"Set address of section">; + def shared: F<"shared">, HelpText<"Build a shared object">; def soname: J<"soname=">, HelpText<"Set DT_SONAME">; +def sort_section: S<"sort-section">, HelpText<"Specifies sections sorting rule when linkerscript is used">; + def start_lib: F<"start-lib">, HelpText<"Start a grouping of objects that should be treated as if they were together in an archive">; @@ -144,15 +206,24 @@ def strip_all: F<"strip-all">, HelpText<"Strip all symbols">; def strip_debug: F<"strip-debug">, HelpText<"Strip debugging information">; +def symbol_ordering_file: S<"symbol-ordering-file">, + HelpText<"Layout sections in the order specified by symbol file">; + def sysroot: J<"sysroot=">, HelpText<"Set the system root">; -def threads: F<"threads">, HelpText<"Enable use of threads">; +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 target2: J<"target2=">, MetaVarName<"<type>">, HelpText<"Interpret R_ARM_TARGET2 as <type>, where <type> is one of rel, abs, or got-rel">; + +def threads: F<"threads">, HelpText<"Run the linker multi-threaded">; def trace: F<"trace">, HelpText<"Print the names of the input files">; def trace_symbol : J<"trace-symbol=">, HelpText<"Trace references to symbols">; -def undefined: J<"undefined=">, +def undefined: S<"undefined">, HelpText<"Force undefined symbol during linking">; def unresolved_symbols: J<"unresolved-symbols=">, @@ -161,9 +232,11 @@ def unresolved_symbols: J<"unresolved-symbols=">, def rsp_quoting: J<"rsp-quoting=">, HelpText<"Quoting style for response files. Values supported: windows|posix">; +def v: Flag<["-"], "v">, HelpText<"Display the version number">; + def verbose: F<"verbose">, HelpText<"Verbose mode">; -def version: F<"version">, HelpText<"Display the version number">; +def version: F<"version">, HelpText<"Display the version number and exit">; def version_script: S<"version-script">, HelpText<"Read a version script">; @@ -181,40 +254,56 @@ 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_L__library_path: J<"library-path=">, Alias<L>; +def alias_define_common_d: Flag<["-"], "d">, Alias<define_common>; +def alias_define_common_dc: F<"dc">, Alias<define_common>; +def alias_define_common_dp: F<"dp">, Alias<define_common>; def alias_discard_all_x: Flag<["-"], "x">, Alias<discard_all>; def alias_discard_locals_X: Flag<["-"], "X">, Alias<discard_locals>; def alias_dynamic_list: J<"dynamic-list=">, Alias<dynamic_list>; def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias<entry>; def alias_entry_entry: J<"entry=">, Alias<entry>; +def alias_error_limit: J<"error-limit=">, Alias<error_limit>; def alias_export_dynamic_E: Flag<["-"], "E">, Alias<export_dynamic>; def alias_export_dynamic_symbol: J<"export-dynamic-symbol=">, Alias<export_dynamic_symbol>; def alias_fini_fini: J<"fini=">, Alias<fini>; +def alias_format_b: S<"b">, Alias<format>; def alias_hash_style_hash_style: J<"hash-style=">, Alias<hash_style>; def alias_init_init: J<"init=">, Alias<init>; def alias_l__library: J<"library=">, Alias<l>; +def alias_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_relocatable_r: Flag<["-"], "r">, Alias<relocatable>; -def alias_rpath_R: Joined<["-"], "R">, Alias<rpath>; +def alias_retain_symbols_file: S<"retain-symbols-file">, Alias<retain_symbols_file>; +def alias_rpath_R: JoinedOrSeparate<["-"], "R">, Alias<rpath>; def alias_rpath_rpath: J<"rpath=">, Alias<rpath>; 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_soname_soname: S<"soname">, Alias<soname>; +def alias_sort_section: J<"sort-section=">, Alias<sort_section>; +def alias_script: J<"script=">, Alias<script>; def alias_strip_all: Flag<["-"], "s">, Alias<strip_all>; def alias_strip_debug_S: Flag<["-"], "S">, Alias<strip_debug>; +def alias_Tbss: J<"Tbss=">, Alias<Tbss>; +def alias_Tdata: J<"Tdata=">, Alias<Tdata>; def alias_trace: Flag<["-"], "t">, Alias<trace>; def alias_trace_symbol_y : JoinedOrSeparate<["-"], "y">, Alias<trace_symbol>; +def alias_Ttext: J<"Ttext=">, Alias<Ttext>; +def alias_Ttext_segment: S<"Ttext-segment">, Alias<Ttext>; +def alias_Ttext_segment_eq: J<"Ttext-segment=">, Alias<Ttext>; +def alias_undefined_eq: J<"undefined=">, Alias<undefined>; def alias_undefined_u: JoinedOrSeparate<["-"], "u">, Alias<undefined>; def alias_version_V: Flag<["-"], "V">, Alias<version>; -def alias_version_v: Flag<["-"], "v">, Alias<version>; def alias_wrap_wrap: J<"wrap=">, Alias<wrap>; // Our symbol resolution algorithm handles symbols in archive files differently @@ -239,9 +328,12 @@ def plugin_opt_eq: J<"plugin-opt=">; // Options listed below are silently ignored for now for compatibility. def allow_shlib_undefined: F<"allow-shlib-undefined">; -def define_common: F<"define-common">; +def cref: Flag<["--"], "cref">; def demangle: F<"demangle">; def detect_odr_violations: F<"detect-odr-violations">; +def g: Flag<["-"], "g">; +def M: Flag<["-"], "M">; +def Map: JS<"Map">; def no_add_needed: F<"no-add-needed">; def no_allow_shlib_undefined: F<"no-allow-shlib-undefined">; def no_copy_dt_needed_entries: F<"no-copy-dt-needed-entries">, @@ -254,23 +346,27 @@ def no_warn_mismatch: F<"no-warn-mismatch">; def rpath_link: S<"rpath-link">; def rpath_link_eq: J<"rpath-link=">; def sort_common: F<"sort-common">; +def stats: F<"stats">; def warn_execstack: F<"warn-execstack">; def warn_shared_textrel: F<"warn-shared-textrel">; -def G: Separate<["-"], "G">; +def EB : F<"EB">; +def EL : F<"EL">; +def G: JoinedOrSeparate<["-"], "G">; +def Qy : F<"Qy">; // Aliases for ignored options -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_Map_eq: J<"Map=">, Alias<Map>; def alias_version_script_version_script: J<"version-script=">, Alias<version_script>; // LTO-related options. -def lto_jobs: J<"lto-jobs=">, HelpText<"Number of threads to run codegen">; def lto_aa_pipeline: J<"lto-aa-pipeline=">, HelpText<"AA pipeline to run during LTO. Used in conjunction with -lto-newpm-passes">; def lto_newpm_passes: J<"lto-newpm-passes=">, HelpText<"Passes to run during LTO">; +def lto_partitions: J<"lto-partitions=">, + HelpText<"Number of LTO codegen partitions">; def disable_verify: F<"disable-verify">; def mllvm: S<"mllvm">; def save_temps: F<"save-temps">; +def thinlto_jobs: J<"thinlto-jobs=">, HelpText<"Number of ThinLTO jobs">; diff --git a/gnu/llvm/tools/lld/ELF/Symbols.cpp b/gnu/llvm/tools/lld/ELF/Symbols.cpp index d6a605d1118..fb752dcb3bf 100644 --- a/gnu/llvm/tools/lld/ELF/Symbols.cpp +++ b/gnu/llvm/tools/lld/ELF/Symbols.cpp @@ -12,9 +12,14 @@ #include "InputFiles.h" #include "InputSection.h" #include "OutputSections.h" +#include "Strings.h" +#include "SyntheticSections.h" #include "Target.h" +#include "Writer.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Path.h" +#include <cstring> using namespace llvm; using namespace llvm::object; @@ -30,27 +35,27 @@ static typename ELFT::uint getSymVA(const SymbolBody &Body, switch (Body.kind()) { case SymbolBody::DefinedSyntheticKind: { - auto &D = cast<DefinedSynthetic<ELFT>>(Body); - const OutputSectionBase<ELFT> *Sec = D.Section; + auto &D = cast<DefinedSynthetic>(Body); + const OutputSectionBase *Sec = D.Section; if (!Sec) return D.Value; - if (D.Value == DefinedSynthetic<ELFT>::SectionEnd) - return Sec->getVA() + Sec->getSize(); - return Sec->getVA() + D.Value; + if (D.Value == uintX_t(-1)) + return Sec->Addr + Sec->Size; + return Sec->Addr + D.Value; } case SymbolBody::DefinedRegularKind: { auto &D = cast<DefinedRegular<ELFT>>(Body); - InputSectionBase<ELFT> *SC = D.Section; + InputSectionBase<ELFT> *IS = D.Section; // According to the ELF spec reference to a local symbol from outside // the group are not allowed. Unfortunately .eh_frame breaks that rule // and must be treated specially. For now we just replace the symbol with // 0. - if (SC == &InputSection<ELFT>::Discarded) + if (IS == &InputSection<ELFT>::Discarded) return 0; // This is an absolute symbol. - if (!SC) + if (!IS) return D.Value; uintX_t Offset = D.Value; @@ -58,20 +63,27 @@ static typename ELFT::uint getSymVA(const SymbolBody &Body, Offset += Addend; Addend = 0; } - uintX_t VA = SC->OutSec->getVA() + SC->getOffset(Offset); - if (D.isTls()) + uintX_t VA = (IS->OutSec ? IS->OutSec->Addr : 0) + IS->getOffset(Offset); + if (D.isTls() && !Config->Relocatable) { + if (!Out<ELFT>::TlsPhdr) + fatal(toString(D.File) + + " has a STT_TLS symbol but doesn't have a PT_TLS section"); return VA - Out<ELFT>::TlsPhdr->p_vaddr; + } return VA; } case SymbolBody::DefinedCommonKind: - return Out<ELFT>::Bss->getVA() + cast<DefinedCommon>(Body).OffsetInBss; + if (!Config->DefineCommon) + return 0; + return In<ELFT>::Common->OutSec->Addr + In<ELFT>::Common->OutSecOff + + cast<DefinedCommon>(Body).Offset; case SymbolBody::SharedKind: { auto &SS = cast<SharedSymbol<ELFT>>(Body); if (!SS.NeedsCopyOrPltAddr) return 0; if (SS.isFunc()) return Body.getPltVA<ELFT>(); - return Out<ELFT>::Bss->getVA() + SS.OffsetInBss; + return SS.getBssSectionForCopy()->Addr + SS.CopyOffset; } case SymbolBody::UndefinedKind: return 0; @@ -79,32 +91,16 @@ static typename ELFT::uint getSymVA(const SymbolBody &Body, case SymbolBody::LazyObjectKind: assert(Body.symbol()->IsUsedInRegularObj && "lazy symbol reached writer"); return 0; - case SymbolBody::DefinedBitcodeKind: - llvm_unreachable("should have been replaced"); } llvm_unreachable("invalid symbol kind"); } -SymbolBody::SymbolBody(Kind K, uint32_t NameOffset, uint8_t StOther, +SymbolBody::SymbolBody(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type) - : SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(true), - IsInGlobalMipsGot(false), Type(Type), StOther(StOther), - NameOffset(NameOffset) {} - -SymbolBody::SymbolBody(Kind K, StringRef Name, uint8_t StOther, uint8_t Type) - : SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(false), - IsInGlobalMipsGot(false), Type(Type), StOther(StOther), - Name({Name.data(), Name.size()}) {} - -StringRef SymbolBody::getName() const { - assert(!isLocal()); - return StringRef(Name.S, Name.Len); -} - -void SymbolBody::setName(StringRef S) { - Name.S = S.data(); - Name.Len = S.size(); -} + : SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(IsLocal), + IsInGlobalMipsGot(false), Is32BitMipsGot(false), IsInIplt(false), + IsInIgot(false), CopyIsInBssRelRo(false), Type(Type), StOther(StOther), + Name(Name) {} // Returns true if a symbol can be replaced at load-time by a symbol // with the same name defined in other ELF executable or DSO. @@ -151,7 +147,7 @@ typename ELFT::uint SymbolBody::getVA(typename ELFT::uint Addend) const { } template <class ELFT> typename ELFT::uint SymbolBody::getGotVA() const { - return Out<ELFT>::Got->getVA() + getGotOffset<ELFT>(); + return In<ELFT>::Got->getVA() + getGotOffset<ELFT>(); } template <class ELFT> typename ELFT::uint SymbolBody::getGotOffset() const { @@ -159,7 +155,9 @@ template <class ELFT> typename ELFT::uint SymbolBody::getGotOffset() const { } template <class ELFT> typename ELFT::uint SymbolBody::getGotPltVA() const { - return Out<ELFT>::GotPlt->getVA() + getGotPltOffset<ELFT>(); + if (this->IsInIgot) + return In<ELFT>::IgotPlt->getVA() + getGotPltOffset<ELFT>(); + return In<ELFT>::GotPlt->getVA() + getGotPltOffset<ELFT>(); } template <class ELFT> typename ELFT::uint SymbolBody::getGotPltOffset() const { @@ -167,7 +165,9 @@ template <class ELFT> typename ELFT::uint SymbolBody::getGotPltOffset() const { } template <class ELFT> typename ELFT::uint SymbolBody::getPltVA() const { - return Out<ELFT>::Plt->getVA() + Target->PltHeaderSize + + if (this->IsInIplt) + return In<ELFT>::Iplt->getVA() + PltIndex * Target->PltEntrySize; + return In<ELFT>::Plt->getVA() + Target->PltHeaderSize + PltIndex * Target->PltEntrySize; } @@ -176,6 +176,8 @@ template <class ELFT> typename ELFT::uint SymbolBody::getThunkVA() const { return DR->ThunkData->getVA(); if (const auto *S = dyn_cast<SharedSymbol<ELFT>>(this)) return S->ThunkData->getVA(); + if (const auto *S = dyn_cast<Undefined<ELFT>>(this)) + return S->ThunkData->getVA(); fatal("getThunkVA() not supported for Symbol class\n"); } @@ -189,48 +191,78 @@ template <class ELFT> typename ELFT::uint SymbolBody::getSize() const { return 0; } -Defined::Defined(Kind K, StringRef Name, uint8_t StOther, uint8_t Type) - : SymbolBody(K, Name, StOther, Type) {} - -Defined::Defined(Kind K, uint32_t NameOffset, uint8_t StOther, uint8_t Type) - : SymbolBody(K, NameOffset, StOther, Type) {} +// If a symbol name contains '@', the characters after that is +// a symbol version name. This function parses that. +void SymbolBody::parseSymbolVersion() { + StringRef S = getName(); + size_t Pos = S.find('@'); + if (Pos == 0 || Pos == StringRef::npos) + return; + StringRef Verstr = S.substr(Pos + 1); + if (Verstr.empty()) + return; + + // Truncate the symbol name so that it doesn't include the version string. + Name = {S.data(), Pos}; + + // If this is an undefined or shared symbol it is not a definition. + if (isUndefined() || isShared()) + return; + + // '@@' in a symbol name means the default version. + // It is usually the most recent one. + bool IsDefault = (Verstr[0] == '@'); + if (IsDefault) + Verstr = Verstr.substr(1); + + for (VersionDefinition &Ver : Config->VersionDefinitions) { + if (Ver.Name != Verstr) + continue; + + if (IsDefault) + symbol()->VersionId = Ver.Id; + else + symbol()->VersionId = Ver.Id | VERSYM_HIDDEN; + return; + } -DefinedBitcode::DefinedBitcode(StringRef Name, uint8_t StOther, uint8_t Type, - BitcodeFile *F) - : Defined(DefinedBitcodeKind, Name, StOther, Type) { - this->File = F; + // It is an error if the specified version is not defined. + error(toString(File) + ": symbol " + S + " has undefined version " + Verstr); } -bool DefinedBitcode::classof(const SymbolBody *S) { - return S->kind() == DefinedBitcodeKind; -} +Defined::Defined(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther, + uint8_t Type) + : SymbolBody(K, Name, IsLocal, StOther, Type) {} -Undefined::Undefined(StringRef Name, uint8_t StOther, uint8_t Type, - InputFile *File) - : SymbolBody(SymbolBody::UndefinedKind, Name, StOther, Type) { - this->File = File; +template <class ELFT> bool DefinedRegular<ELFT>::isMipsPIC() const { + if (!Section || !isFunc()) + return false; + return (this->StOther & STO_MIPS_MIPS16) == STO_MIPS_PIC || + (Section->getFile()->getObj().getHeader()->e_flags & EF_MIPS_PIC); } -Undefined::Undefined(uint32_t NameOffset, uint8_t StOther, uint8_t Type, - InputFile *File) - : SymbolBody(SymbolBody::UndefinedKind, NameOffset, StOther, Type) { +template <typename ELFT> +Undefined<ELFT>::Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther, + uint8_t Type, InputFile *File) + : SymbolBody(SymbolBody::UndefinedKind, Name, IsLocal, StOther, Type) { this->File = File; } template <typename ELFT> -DefinedSynthetic<ELFT>::DefinedSynthetic(StringRef N, uintX_t Value, - OutputSectionBase<ELFT> *Section) - : Defined(SymbolBody::DefinedSyntheticKind, N, STV_HIDDEN, 0 /* Type */), - Value(Value), Section(Section) {} +OutputSection<ELFT> *SharedSymbol<ELFT>::getBssSectionForCopy() const { + assert(needsCopy()); + return CopyIsInBssRelRo ? Out<ELFT>::BssRelRo : Out<ELFT>::Bss; +} -DefinedCommon::DefinedCommon(StringRef N, uint64_t Size, uint64_t Alignment, +DefinedCommon::DefinedCommon(StringRef Name, uint64_t Size, uint64_t Alignment, uint8_t StOther, uint8_t Type, InputFile *File) - : Defined(SymbolBody::DefinedCommonKind, N, StOther, Type), + : Defined(SymbolBody::DefinedCommonKind, Name, /*IsLocal=*/false, StOther, + Type), Alignment(Alignment), Size(Size) { this->File = File; } -std::unique_ptr<InputFile> Lazy::fetch() { +InputFile *Lazy::fetch() { if (auto *S = dyn_cast<LazyArchive>(this)) return S->fetch(); return cast<LazyObject>(this)->fetch(); @@ -247,34 +279,47 @@ LazyObject::LazyObject(StringRef Name, LazyObjectFile &File, uint8_t Type) this->File = &File; } -std::unique_ptr<InputFile> LazyArchive::fetch() { - MemoryBufferRef MBRef = file()->getMember(&Sym); +InputFile *LazyArchive::fetch() { + std::pair<MemoryBufferRef, uint64_t> MBInfo = file()->getMember(&Sym); // getMember returns an empty buffer if the member was already // read from the library. - if (MBRef.getBuffer().empty()) - return std::unique_ptr<InputFile>(nullptr); - return createObjectFile(MBRef, file()->getName()); + if (MBInfo.first.getBuffer().empty()) + return nullptr; + return createObjectFile(MBInfo.first, file()->getName(), MBInfo.second); } -std::unique_ptr<InputFile> LazyObject::fetch() { +InputFile *LazyObject::fetch() { MemoryBufferRef MBRef = file()->getBuffer(); if (MBRef.getBuffer().empty()) - return std::unique_ptr<InputFile>(nullptr); + return nullptr; return createObjectFile(MBRef); } -bool Symbol::includeInDynsym() const { +uint8_t Symbol::computeBinding() const { + if (Config->Relocatable) + return Binding; if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED) + return STB_LOCAL; + const SymbolBody *Body = body(); + if (VersionId == VER_NDX_LOCAL && !Body->isUndefined() && !Body->isShared()) + return STB_LOCAL; + if (Config->NoGnuUnique && Binding == STB_GNU_UNIQUE) + return STB_GLOBAL; + return Binding; +} + +bool Symbol::includeInDynsym() const { + if (computeBinding() == STB_LOCAL) return false; - return (ExportDynamic && VersionId != VER_NDX_LOCAL) || body()->isShared() || + return ExportDynamic || body()->isShared() || (body()->isUndefined() && Config->Shared); } // Print out a log message for --trace-symbol. void elf::printTraceSymbol(Symbol *Sym) { SymbolBody *B = Sym->body(); - outs() << getFilename(B->File); + outs() << toString(B->File); if (B->isUndefined()) outs() << ": reference to "; @@ -285,6 +330,14 @@ void elf::printTraceSymbol(Symbol *Sym) { outs() << B->getName() << "\n"; } +// Returns a symbol for an error message. +std::string lld::toString(const SymbolBody &B) { + if (Config->Demangle) + if (Optional<std::string> S = demangle(B.getName())) + return *S; + return B.getName(); +} + template bool SymbolBody::hasThunk<ELF32LE>() const; template bool SymbolBody::hasThunk<ELF32BE>() const; template bool SymbolBody::hasThunk<ELF64LE>() const; @@ -330,7 +383,17 @@ template uint32_t SymbolBody::template getSize<ELF32BE>() const; template uint64_t SymbolBody::template getSize<ELF64LE>() const; template uint64_t SymbolBody::template getSize<ELF64BE>() const; -template class elf::DefinedSynthetic<ELF32LE>; -template class elf::DefinedSynthetic<ELF32BE>; -template class elf::DefinedSynthetic<ELF64LE>; -template class elf::DefinedSynthetic<ELF64BE>; +template class elf::Undefined<ELF32LE>; +template class elf::Undefined<ELF32BE>; +template class elf::Undefined<ELF64LE>; +template class elf::Undefined<ELF64BE>; + +template class elf::SharedSymbol<ELF32LE>; +template class elf::SharedSymbol<ELF32BE>; +template class elf::SharedSymbol<ELF64LE>; +template class elf::SharedSymbol<ELF64BE>; + +template class elf::DefinedRegular<ELF32LE>; +template class elf::DefinedRegular<ELF32BE>; +template class elf::DefinedRegular<ELF64LE>; +template class elf::DefinedRegular<ELF64BE>; diff --git a/gnu/llvm/tools/lld/ELF/SyntheticSections.cpp b/gnu/llvm/tools/lld/ELF/SyntheticSections.cpp index 5486b38eec1..2e6c80e575d 100644 --- a/gnu/llvm/tools/lld/ELF/SyntheticSections.cpp +++ b/gnu/llvm/tools/lld/ELF/SyntheticSections.cpp @@ -59,6 +59,9 @@ template <class ELFT> InputSection<ELFT> *elf::createCommonSection() { ArrayRef<uint8_t>(), "COMMON"); Ret->Live = true; + if (!Config->DefineCommon) + return Ret; + // Sort the common symbols by alignment as an heuristic to pack them better. std::vector<DefinedCommon *> Syms = getCommonSymbols<ELFT>(); std::stable_sort(Syms.begin(), Syms.end(), @@ -1154,10 +1157,14 @@ void SymbolTableSection<ELFT>::writeGlobalSymbols(uint8_t *Buf) { ESym->setVisibility(Body->symbol()->Visibility); ESym->st_value = Body->getVA<ELFT>(); - if (const OutputSectionBase *OutSec = getOutputSection(Body)) + if (const OutputSectionBase *OutSec = getOutputSection(Body)) { ESym->st_shndx = OutSec->SectionIndex; - else if (isa<DefinedRegular<ELFT>>(Body)) + } else if (isa<DefinedRegular<ELFT>>(Body)) { ESym->st_shndx = SHN_ABS; + } else if (isa<DefinedCommon>(Body)) { + ESym->st_shndx = SHN_COMMON; + ESym->st_value = cast<DefinedCommon>(Body)->Alignment; + } if (Config->EMachine == EM_MIPS) { // On MIPS we need to mark symbol which has a PLT entry and requires @@ -1189,6 +1196,8 @@ SymbolTableSection<ELFT>::getOutputSection(SymbolBody *Sym) { break; } case SymbolBody::DefinedCommonKind: + if (!Config->DefineCommon) + return nullptr; return In<ELFT>::Common->OutSec; case SymbolBody::SharedKind: { auto &SS = cast<SharedSymbol<ELFT>>(*Sym); |