diff options
Diffstat (limited to 'contrib/llvm/tools/lld/ELF')
-rw-r--r-- | contrib/llvm/tools/lld/ELF/Driver.cpp | 24 | ||||
-rw-r--r-- | contrib/llvm/tools/lld/ELF/Driver.h | 3 | ||||
-rw-r--r-- | contrib/llvm/tools/lld/ELF/InputFiles.cpp | 57 | ||||
-rw-r--r-- | contrib/llvm/tools/lld/ELF/InputFiles.h | 8 | ||||
-rw-r--r-- | contrib/llvm/tools/lld/ELF/LinkerScript.cpp | 100 | ||||
-rw-r--r-- | contrib/llvm/tools/lld/ELF/Symbols.cpp | 4 |
6 files changed, 122 insertions, 74 deletions
diff --git a/contrib/llvm/tools/lld/ELF/Driver.cpp b/contrib/llvm/tools/lld/ELF/Driver.cpp index 6afbe62e5ec7..c8ea821ec522 100644 --- a/contrib/llvm/tools/lld/ELF/Driver.cpp +++ b/contrib/llvm/tools/lld/ELF/Driver.cpp @@ -26,6 +26,7 @@ #include "llvm/ADT/StringSwitch.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> @@ -51,6 +52,7 @@ bool elf::link(ArrayRef<const char *> Args, bool CanExitEarly, ErrorCount = 0; ErrorOS = &Error; Argv0 = Args[0]; + Tar = nullptr; Config = make<Configuration>(); Driver = make<LinkerDriver>(); @@ -170,25 +172,6 @@ void LinkerDriver::addFile(StringRef Path) { } } -Optional<MemoryBufferRef> LinkerDriver::readFile(StringRef Path) { - if (Config->Verbose) - outs() << Path << "\n"; - - 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(); - make<std::unique_ptr<MemoryBuffer>>(std::move(MB)); // take MB ownership - - if (Tar) - Tar->append(relativeToRoot(Path), MBRef.getBuffer()); - - return MBRef; -} - // Add a given library by searching it from input search paths. void LinkerDriver::addLibrary(StringRef Name) { if (Optional<std::string> Path = searchLibrary(Name)) @@ -313,9 +296,10 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) { Expected<std::unique_ptr<TarWriter>> ErrOrWriter = TarWriter::create(Path, path::stem(Path)); if (ErrOrWriter) { - Tar = std::move(*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())); diff --git a/contrib/llvm/tools/lld/ELF/Driver.h b/contrib/llvm/tools/lld/ELF/Driver.h index edb6bc8757f4..b600fae34823 100644 --- a/contrib/llvm/tools/lld/ELF/Driver.h +++ b/contrib/llvm/tools/lld/ELF/Driver.h @@ -17,7 +17,6 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/Option/ArgList.h" -#include "llvm/Support/TarWriter.h" #include "llvm/Support/raw_ostream.h" namespace lld { @@ -30,11 +29,9 @@ public: void main(ArrayRef<const char *> Args, bool CanExitEarly); void addFile(StringRef Path); void addLibrary(StringRef Name); - std::unique_ptr<llvm::TarWriter> Tar; // for reproduce private: std::vector<MemoryBufferRef> getArchiveMembers(MemoryBufferRef MB); - llvm::Optional<MemoryBufferRef> readFile(StringRef Path); void readConfigs(llvm::opt::InputArgList &Args); void createFiles(llvm::opt::InputArgList &Args); void inferMachineType(); diff --git a/contrib/llvm/tools/lld/ELF/InputFiles.cpp b/contrib/llvm/tools/lld/ELF/InputFiles.cpp index bd9f25873c87..1fddf40f5b22 100644 --- a/contrib/llvm/tools/lld/ELF/InputFiles.cpp +++ b/contrib/llvm/tools/lld/ELF/InputFiles.cpp @@ -8,7 +8,6 @@ //===----------------------------------------------------------------------===// #include "InputFiles.h" -#include "Driver.h" #include "Error.h" #include "InputSection.h" #include "LinkerScript.h" @@ -26,6 +25,7 @@ #include "llvm/MC/StringTableBuilder.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/Support/Path.h" +#include "llvm/Support/TarWriter.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -36,6 +36,8 @@ using namespace llvm::sys::fs; using namespace lld; using namespace lld::elf; +TarWriter *elf::Tar; + namespace { // In ELF object file all section addresses are zero. If we have multiple // .text sections (when using -ffunction-section or comdat group) then @@ -53,6 +55,24 @@ public: }; } +Optional<MemoryBufferRef> elf::readFile(StringRef Path) { + if (Config->Verbose) + outs() << Path << "\n"; + + 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(); + make<std::unique_ptr<MemoryBuffer>>(std::move(MB)); // take MB ownership + + if (Tar) + Tar->append(relativeToRoot(Path), MBRef.getBuffer()); + return MBRef; +} + template <class ELFT> void elf::ObjectFile<ELFT>::initializeDwarfLine() { std::unique_ptr<object::ObjectFile> Obj = check(object::ObjectFile::createObjectFile(this->MB), @@ -398,6 +418,14 @@ elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec, if (Config->Strip != StripPolicy::None && Name.startswith(".debug")) return &InputSection<ELFT>::Discarded; + // The linkonce feature is a sort of proto-comdat. Some glibc i386 object + // files contain definitions of symbol "__x86.get_pc_thunk.bx" in linkonce + // sections. Drop those sections to avoid duplicate symbol errors. + // FIXME: This is glibc PR20543, we should remove this hack once that has been + // fixed for a while. + if (Name.startswith(".gnu.linkonce.")) + return &InputSection<ELFT>::Discarded; + // The linker merges EH (exception handling) frames and creates a // .eh_frame_hdr section for runtime. So we handle them with a special // class. For relocatable outputs, they are just passed through. @@ -524,9 +552,8 @@ ArchiveFile::getMember(const Archive::Symbol *Sym) { "could not get the buffer for the member defining symbol " + Sym->getName()); - if (C.getParent()->isThin() && Driver->Tar) - Driver->Tar->append(relativeToRoot(check(C.getFullName())), - Ret.getBuffer()); + if (C.getParent()->isThin() && Tar) + Tar->append(relativeToRoot(check(C.getFullName())), Ret.getBuffer()); if (C.getParent()->isThin()) return {Ret, 0}; return {Ret, C.getChildOffset()}; @@ -651,6 +678,8 @@ template <class ELFT> void SharedFile<ELFT>::parseRest() { VersymIndex = Versym->vs_index; ++Versym; } + bool Hidden = VersymIndex & VERSYM_HIDDEN; + VersymIndex = VersymIndex & ~VERSYM_HIDDEN; StringRef Name = check(Sym.getName(this->StringTable)); if (Sym.isUndefined()) { @@ -658,15 +687,23 @@ template <class ELFT> void SharedFile<ELFT>::parseRest() { continue; } - if (Versym) { - // Ignore local symbols and non-default versions. - if (VersymIndex == VER_NDX_LOCAL || (VersymIndex & VERSYM_HIDDEN)) - continue; - } + // Ignore local symbols. + if (Versym && VersymIndex == VER_NDX_LOCAL) + continue; const Elf_Verdef *V = VersymIndex == VER_NDX_GLOBAL ? nullptr : Verdefs[VersymIndex]; - elf::Symtab<ELFT>::X->addShared(this, Name, Sym, V); + + if (!Hidden) + elf::Symtab<ELFT>::X->addShared(this, Name, Sym, V); + + // Also add the symbol with the versioned name to handle undefined symbols + // with explicit versions. + if (V) { + StringRef VerName = this->StringTable.data() + V->getAux()->vda_name; + Name = Saver.save(Twine(Name) + "@" + VerName); + elf::Symtab<ELFT>::X->addShared(this, Name, Sym, V); + } } } diff --git a/contrib/llvm/tools/lld/ELF/InputFiles.h b/contrib/llvm/tools/lld/ELF/InputFiles.h index 8b188348199f..73dda7b566b8 100644 --- a/contrib/llvm/tools/lld/ELF/InputFiles.h +++ b/contrib/llvm/tools/lld/ELF/InputFiles.h @@ -29,6 +29,7 @@ namespace llvm { class DWARFDebugLine; +class TarWriter; namespace lto { class InputFile; } @@ -49,6 +50,13 @@ using llvm::object::Archive; class Lazy; class SymbolBody; +// If -reproduce option is given, all input files are written +// to this tar archive. +extern llvm::TarWriter *Tar; + +// Opens a given file. +llvm::Optional<MemoryBufferRef> readFile(StringRef Path); + // The root class of input files. class InputFile { public: diff --git a/contrib/llvm/tools/lld/ELF/LinkerScript.cpp b/contrib/llvm/tools/lld/ELF/LinkerScript.cpp index ccc1059949db..59ef36c87de5 100644 --- a/contrib/llvm/tools/lld/ELF/LinkerScript.cpp +++ b/contrib/llvm/tools/lld/ELF/LinkerScript.cpp @@ -56,29 +56,30 @@ using namespace lld::elf; LinkerScriptBase *elf::ScriptBase; ScriptConfiguration *elf::ScriptConfig; -template <class ELFT> static void addRegular(SymbolAssignment *Cmd) { +template <class ELFT> static SymbolBody *addRegular(SymbolAssignment *Cmd) { uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT; - Symbol *Sym = Symtab<ELFT>::X->addRegular(Cmd->Name, Visibility, STT_NOTYPE, - 0, 0, STB_GLOBAL, nullptr, nullptr); - Cmd->Sym = Sym->body(); + Symbol *Sym = Symtab<ELFT>::X->addUndefined( + Cmd->Name, /*IsLocal=*/false, STB_GLOBAL, Visibility, + /*Type*/ 0, + /*CanOmitFromDynSym*/ false, /*File*/ nullptr); - // If we have no SECTIONS then we don't have '.' and don't call - // assignAddresses(). We calculate symbol value immediately in this case. - if (!ScriptConfig->HasSections) - cast<DefinedRegular<ELFT>>(Cmd->Sym)->Value = Cmd->Expression(0); + replaceBody<DefinedRegular<ELFT>>(Sym, Cmd->Name, /*IsLocal=*/false, + Visibility, STT_NOTYPE, 0, 0, nullptr, + nullptr); + return Sym->body(); } -template <class ELFT> static void addSynthetic(SymbolAssignment *Cmd) { - // If we have SECTIONS block then output sections haven't been created yet. +template <class ELFT> static SymbolBody *addSynthetic(SymbolAssignment *Cmd) { + uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT; const OutputSectionBase *Sec = ScriptConfig->HasSections ? nullptr : Cmd->Expression.Section(); - Symbol *Sym = Symtab<ELFT>::X->addSynthetic( - Cmd->Name, Sec, 0, Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT); - Cmd->Sym = Sym->body(); + Symbol *Sym = Symtab<ELFT>::X->addUndefined( + Cmd->Name, /*IsLocal=*/false, STB_GLOBAL, Visibility, + /*Type*/ 0, + /*CanOmitFromDynSym*/ false, /*File*/ nullptr); - // If we already know section then we can calculate symbol value immediately. - if (Sec) - cast<DefinedSynthetic>(Cmd->Sym)->Value = Cmd->Expression(0) - Sec->Addr; + replaceBody<DefinedSynthetic>(Sym, Cmd->Name, 0, Sec); + return Sym->body(); } static bool isUnderSysroot(StringRef Path) { @@ -90,21 +91,39 @@ static bool isUnderSysroot(StringRef Path) { return false; } -template <class ELFT> static void addSymbol(SymbolAssignment *Cmd) { - if (Cmd->Expression.IsAbsolute()) - addRegular<ELFT>(Cmd); - else - addSynthetic<ELFT>(Cmd); +template <class ELFT> static void assignSymbol(SymbolAssignment *Cmd) { + // If there are sections, then let the value be assigned later in + // `assignAddresses`. + if (ScriptConfig->HasSections) + return; + + uint64_t Value = Cmd->Expression(0); + if (Cmd->Expression.IsAbsolute()) { + cast<DefinedRegular<ELFT>>(Cmd->Sym)->Value = Value; + } else { + const OutputSectionBase *Sec = Cmd->Expression.Section(); + if (Sec) + cast<DefinedSynthetic>(Cmd->Sym)->Value = Value - Sec->Addr; + } } -// If a symbol was in PROVIDE(), we need to define it only when -// it is an undefined symbol. -template <class ELFT> static bool shouldDefine(SymbolAssignment *Cmd) { + +template <class ELFT> static void addSymbol(SymbolAssignment *Cmd) { if (Cmd->Name == ".") - return false; - if (!Cmd->Provide) - return true; + return; + + // If a symbol was in PROVIDE(), we need to define it only when + // it is a referenced undefined symbol. SymbolBody *B = Symtab<ELFT>::X->find(Cmd->Name); - return B && B->isUndefined(); + if (Cmd->Provide && (!B || B->isDefined())) + return; + + // Otherwise, create a new symbol if one does not exist or an + // undefined one does exist. + if (Cmd->Expression.IsAbsolute()) + Cmd->Sym = addRegular<ELFT>(Cmd); + else + Cmd->Sym = addSynthetic<ELFT>(Cmd); + assignSymbol<ELFT>(Cmd); } bool SymbolAssignment::classof(const BaseCommand *C) { @@ -283,8 +302,7 @@ void LinkerScript<ELFT>::processCommands(OutputSectionFactory<ELFT> &Factory) { // Handle symbol assignments outside of any output section. if (auto *Cmd = dyn_cast<SymbolAssignment>(Base1.get())) { - if (shouldDefine<ELFT>(Cmd)) - addSymbol<ELFT>(Cmd); + addSymbol<ELFT>(Cmd); continue; } @@ -326,8 +344,7 @@ void LinkerScript<ELFT>::processCommands(OutputSectionFactory<ELFT> &Factory) { // ".foo : { ...; bar = .; }". Handle them. for (const std::unique_ptr<BaseCommand> &Base : Cmd->Commands) if (auto *OutCmd = dyn_cast<SymbolAssignment>(Base.get())) - if (shouldDefine<ELFT>(OutCmd)) - addSymbol<ELFT>(OutCmd); + addSymbol<ELFT>(OutCmd); // Handle subalign (e.g. ".foo : SUBALIGN(32) { ... }"). If subalign // is given, input sections are aligned to that value, whether the @@ -1143,20 +1160,21 @@ void ScriptParser::readGroup() { void ScriptParser::readInclude() { StringRef Tok = unquote(next()); + // https://sourceware.org/binutils/docs/ld/File-Commands.html: // The file will be searched for in the current directory, and in any // directory specified with the -L option. - auto MBOrErr = MemoryBuffer::getFile(Tok); - if (!MBOrErr) - if (Optional<std::string> Path = findFromSearchPaths(Tok)) - MBOrErr = MemoryBuffer::getFile(*Path); - if (!MBOrErr) { - setError("cannot open " + Tok); + if (sys::fs::exists(Tok)) { + if (Optional<MemoryBufferRef> MB = readFile(Tok)) + tokenize(*MB); + return; + } + if (Optional<std::string> Path = findFromSearchPaths(Tok)) { + if (Optional<MemoryBufferRef> MB = readFile(*Path)) + tokenize(*MB); return; } - MemoryBufferRef MBRef = (*MBOrErr)->getMemBufferRef(); - make<std::unique_ptr<MemoryBuffer>>(std::move(*MBOrErr)); // take MB ownership - tokenize(MBRef); + setError("cannot open " + Tok); } void ScriptParser::readOutput() { diff --git a/contrib/llvm/tools/lld/ELF/Symbols.cpp b/contrib/llvm/tools/lld/ELF/Symbols.cpp index 72bcff4e0f4d..f3edafaf4b78 100644 --- a/contrib/llvm/tools/lld/ELF/Symbols.cpp +++ b/contrib/llvm/tools/lld/ELF/Symbols.cpp @@ -202,6 +202,10 @@ void SymbolBody::parseSymbolVersion() { // 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] == '@'); |