diff options
-rw-r--r-- | lld/include/lld/ReaderWriter/ELFTargetInfo.h | 20 | ||||
-rw-r--r-- | lld/lib/Driver/GnuLdDriver.cpp | 7 | ||||
-rw-r--r-- | lld/lib/Driver/LDOptions.td | 8 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/ELF/DynamicLibraryWriter.h | 6 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/ELF/ExecutableWriter.h | 20 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/ELF/OutputELFWriter.h | 30 | ||||
-rw-r--r-- | lld/test/elf/X86_64/Inputs/libfn.a | bin | 0 -> 1364 bytes | |||
-rw-r--r-- | lld/test/elf/X86_64/undef.test | 19 |
8 files changed, 92 insertions, 18 deletions
diff --git a/lld/include/lld/ReaderWriter/ELFTargetInfo.h b/lld/include/lld/ReaderWriter/ELFTargetInfo.h index af8e00df118..b8f7da89fe9 100644 --- a/lld/include/lld/ReaderWriter/ELFTargetInfo.h +++ b/lld/include/lld/ReaderWriter/ELFTargetInfo.h @@ -12,6 +12,7 @@ #include "lld/Core/PassManager.h" #include "lld/Core/Pass.h" +#include "lld/Core/range.h" #include "lld/Core/TargetInfo.h" #include "lld/ReaderWriter/Reader.h" #include "lld/ReaderWriter/Writer.h" @@ -154,6 +155,22 @@ public: /// Searches directories then calls appendInputFile() bool appendLibrary(StringRef libName); + /// adds undefined symbols that are specified in the command line + void addUndefinedSymbol(StringRef symbolName) { + _undefinedSymbols.push_back(symbolName); + } + + /// Iterators for symbols that appear on the command line + typedef std::vector<StringRef> StringRefVector; + typedef StringRefVector::iterator StringRefVectorIter; + typedef StringRefVector::const_iterator StringRefVectorConstIter; + + /// Return the list of undefined symbols that are specified in the + /// linker command line, using the -u option. + range<const StringRef *> undefinedSymbols() const { + return _undefinedSymbols; + } + private: ELFTargetInfo() LLVM_DELETED_FUNCTION; protected: @@ -174,12 +191,13 @@ protected: bool _dynamicLinkerArg; bool _noAllowDynamicLibraries; OutputMagic _outputMagic; - std::vector<StringRef> _inputSearchPaths; + StringRefVector _inputSearchPaths; llvm::BumpPtrAllocator _extraStrings; std::unique_ptr<Reader> _elfReader; std::unique_ptr<Writer> _writer; std::unique_ptr<Reader> _linkerScriptReader; StringRef _dynamicLinkerPath; + StringRefVector _undefinedSymbols; }; } // end namespace lld diff --git a/lld/lib/Driver/GnuLdDriver.cpp b/lld/lib/Driver/GnuLdDriver.cpp index 57ee99b0fc2..0f8df29fc60 100644 --- a/lld/lib/Driver/GnuLdDriver.cpp +++ b/lld/lib/Driver/GnuLdDriver.cpp @@ -217,6 +217,13 @@ GnuLdDriver::parse(int argc, const char *argv[], raw_ostream &diagnostics) { if (!options->allowLinkWithDynamicLibraries()) options->setIsStaticExecutable(true); + // Handle -u, --undefined option + for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_u), + ie = parsedArgs->filtered_end(); + it != ie; ++it) { + options->addUndefinedSymbol((*it)->getValue()); + } + // Handle -Lxxx for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_L), ie = parsedArgs->filtered_end(); diff --git a/lld/lib/Driver/LDOptions.td b/lld/lib/Driver/LDOptions.td index ef605aed55f..e941d547c9b 100644 --- a/lld/lib/Driver/LDOptions.td +++ b/lld/lib/Driver/LDOptions.td @@ -72,6 +72,14 @@ def omagic_alias : Flag<["-"], "N">, Alias<omagic>; def no_omagic : Flag<["--"], "no-omagic">, HelpText<"This option negates most of the effects of the -N option. Disable linking with shared libraries">; +// TODO: remove the options with the = sign, once the change in the OptionParser +// is done to recognize the allowed suffixes for an argument. +def u : Separate<["-"], "u">, + HelpText<"Force symbol to be entered in the output file as an undefined symbol">; +def undefined : Separate<["--"], "undefined">, Alias<u>; +def u_equal : Joined<["-"], "u=">, Alias<u>; +def undefined_equal : Joined<["--"], "undefined=">, Alias<u>; + // extensions def emit_yaml : Flag<["-"], "emit-yaml">, HelpText<"Write YAML instead of ELF">; diff --git a/lld/lib/ReaderWriter/ELF/DynamicLibraryWriter.h b/lld/lib/ReaderWriter/ELF/DynamicLibraryWriter.h index ef084d4c735..4eda0adc3c4 100644 --- a/lld/lib/ReaderWriter/ELF/DynamicLibraryWriter.h +++ b/lld/lib/ReaderWriter/ELF/DynamicLibraryWriter.h @@ -31,7 +31,6 @@ public: private: void buildDynamicSymbolTable(const File &file); void addDefaultAtoms(); - void addFiles(InputFiles&); void finalizeDefaultAtomValues(); llvm::BumpPtrAllocator _alloc; @@ -63,11 +62,6 @@ void DynamicLibraryWriter<ELFT>::buildDynamicSymbolTable(const File &file) { template<class ELFT> void DynamicLibraryWriter<ELFT>::addDefaultAtoms() { } -template <class ELFT> -void DynamicLibraryWriter<ELFT>::addFiles(InputFiles &inputFiles) { - this->_targetHandler.addFiles(inputFiles); -} - template<class ELFT> void DynamicLibraryWriter<ELFT>::finalizeDefaultAtomValues() { this->_targetHandler.finalizeSymbolValues(); diff --git a/lld/lib/ReaderWriter/ELF/ExecutableWriter.h b/lld/lib/ReaderWriter/ELF/ExecutableWriter.h index 735627c34dc..de688c6280e 100644 --- a/lld/lib/ReaderWriter/ELF/ExecutableWriter.h +++ b/lld/lib/ReaderWriter/ELF/ExecutableWriter.h @@ -64,10 +64,13 @@ void ExecutableWriter<ELFT>::addDefaultAtoms() { /// \brief Hook in lld to add CRuntime file template <class ELFT> void ExecutableWriter<ELFT>::addFiles(InputFiles &inputFiles) { + // Add the default atoms as defined by executables addDefaultAtoms(); + // Add the runtime file inputFiles.prependFile(_runtimeFile); - // Give a chance for the target to add atoms - this->_targetHandler.addFiles(inputFiles); + // Add the Linker internal file for symbols that are defined by + // command line options + OutputELFWriter<ELFT>::addFiles(inputFiles); } template <class ELFT> void ExecutableWriter<ELFT>::createDefaultSections() { @@ -120,11 +123,14 @@ template <class ELFT> void ExecutableWriter<ELFT>::finalizeDefaultAtomValues() { auto bssSection = this->_layout->findOutputSection(".bss"); - (*bssStartAtomIter)->_virtualAddr = bssSection->virtualAddr(); - (*bssEndAtomIter)->_virtualAddr = - bssSection->virtualAddr() + bssSection->memSize(); - (*underScoreEndAtomIter)->_virtualAddr = (*bssEndAtomIter)->_virtualAddr; - (*endAtomIter)->_virtualAddr = (*bssEndAtomIter)->_virtualAddr; + // If we dont find a bss section, then dont set these values + if (bssSection) { + (*bssStartAtomIter)->_virtualAddr = bssSection->virtualAddr(); + (*bssEndAtomIter)->_virtualAddr = + bssSection->virtualAddr() + bssSection->memSize(); + (*underScoreEndAtomIter)->_virtualAddr = (*bssEndAtomIter)->_virtualAddr; + (*endAtomIter)->_virtualAddr = (*bssEndAtomIter)->_virtualAddr; + } // Give a chance for the target to finalize its atom values this->_targetHandler.finalizeSymbolValues(); diff --git a/lld/lib/ReaderWriter/ELF/OutputELFWriter.h b/lld/lib/ReaderWriter/ELF/OutputELFWriter.h index 32bc12c9e7b..90788f4274f 100644 --- a/lld/lib/ReaderWriter/ELF/OutputELFWriter.h +++ b/lld/lib/ReaderWriter/ELF/OutputELFWriter.h @@ -28,6 +28,15 @@ using namespace llvm::object; template<class ELFT> class OutputELFWriter; +/// \brief This acts as a internal file that the linker uses to add +/// undefined symbols that are defined by using the linker options such +/// as -u, or --defsym option. +template <class ELFT> class LinkerInternalFile : public CRuntimeFile<ELFT> { +public: + LinkerInternalFile(const ELFTargetInfo &ti) + : CRuntimeFile<ELFT>(ti, "Linker Internal File") {}; +}; + //===----------------------------------------------------------------------===// // OutputELFWriter Class //===----------------------------------------------------------------------===// @@ -78,7 +87,7 @@ protected: virtual void addDefaultAtoms() = 0; // Add any runtime files and their atoms to the output - virtual void addFiles(InputFiles&) = 0; + virtual void addFiles(InputFiles &); // Finalize the default atom values virtual void finalizeDefaultAtomValues() = 0; @@ -114,6 +123,7 @@ protected: LLD_UNIQUE_BUMP_PTR(HashSection<ELFT>) _hashTable; llvm::StringSet<> _soNeeded; /// @} + LinkerInternalFile<ELFT> _linkerInternalFile; }; //===----------------------------------------------------------------------===// @@ -121,7 +131,8 @@ protected: //===----------------------------------------------------------------------===// template <class ELFT> OutputELFWriter<ELFT>::OutputELFWriter(const ELFTargetInfo &ti) - : _targetInfo(ti), _targetHandler(ti.getTargetHandler<ELFT>()) { + : _targetInfo(ti), _targetHandler(ti.getTargetHandler<ELFT>()), + _linkerInternalFile(ti) { _layout = &_targetHandler.targetLayout(); } @@ -223,8 +234,19 @@ void OutputELFWriter<ELFT>::assignSectionsWithNoSegments() { _shdrtab->updateSection(section); } -template<class ELFT> -void OutputELFWriter<ELFT>::createDefaultSections() { +template <class ELFT> +void OutputELFWriter<ELFT>::addFiles(InputFiles &inputFiles) { + // Add all input Files that are defined by the target + _targetHandler.addFiles(inputFiles); + // Add all symbols that are specified by the -u option + // as part of the command line argument to lld + for (auto ai : _targetInfo.undefinedSymbols()) + _linkerInternalFile.addUndefinedAtom(ai); + // Make the linker internal file to be the first file + inputFiles.prependFile(_linkerInternalFile); +} + +template <class ELFT> void OutputELFWriter<ELFT>::createDefaultSections() { _Header.reset(new (_alloc) Header<ELFT>(_targetInfo)); _programHeader.reset(new (_alloc) ProgramHeader<ELFT>(_targetInfo)); _layout->setHeader(_Header.get()); diff --git a/lld/test/elf/X86_64/Inputs/libfn.a b/lld/test/elf/X86_64/Inputs/libfn.a Binary files differnew file mode 100644 index 00000000000..380844b0838 --- /dev/null +++ b/lld/test/elf/X86_64/Inputs/libfn.a diff --git a/lld/test/elf/X86_64/undef.test b/lld/test/elf/X86_64/undef.test new file mode 100644 index 00000000000..b75300d89b0 --- /dev/null +++ b/lld/test/elf/X86_64/undef.test @@ -0,0 +1,19 @@ +# This tests the functionality that an undefined symbol thats defined in the +# commmand line pulls in the required object file from the archive library +# which is usually the usecase for it +RUN: lld -flavor gnu -target x86_64 -u fn %p/Inputs/libfn.a -o %t --noinhibit-exec +RUN: llvm-readobj -symbols %t | FileCheck -check-prefix=SYMFROMARCHIVE %s +RUN: lld -flavor gnu -target x86_64 %p/Inputs/libfn.a -o %t --noinhibit-exec +RUN: llvm-readobj -symbols %t | FileCheck %s + +SYMFROMARCHIVE: Symbol { +SYMFROMARCHIVE: Name: fn (16) +SYMFROMARCHIVE: Value: 0x4001A4 +SYMFROMARCHIVE: Size: 11 +SYMFROMARCHIVE: Binding: Global (0x1) +SYMFROMARCHIVE: Type: Function (0x2) +SYMFROMARCHIVE: Other: 0 +SYMFROMARCHIVE: Section: .text (0x5) +SYMFROMARCHIVE: } + +CHECK-NOT: Name: fn |