diff options
| -rw-r--r-- | lld/include/lld/ReaderWriter/ReaderArchive.h | 80 | ||||
| -rw-r--r-- | lld/include/lld/ReaderWriter/ReaderELF.h | 4 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/ReaderELF.cpp | 83 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ReaderArchive.cpp | 160 | ||||
| -rw-r--r-- | lld/test/elf/Inputs/libfnarchive.x86_64 | bin | 0 -> 2656 bytes | |||
| -rw-r--r-- | lld/test/elf/Inputs/mainobj.x86_64 | bin | 0 -> 1360 bytes | |||
| -rw-r--r-- | lld/test/elf/archive-elf-forceload.objtxt | 48 | ||||
| -rw-r--r-- | lld/test/elf/archive-elf.objtxt | 39 | ||||
| -rw-r--r-- | lld/tools/lld-core/lld-core.cpp | 11 |
10 files changed, 398 insertions, 28 deletions
diff --git a/lld/include/lld/ReaderWriter/ReaderArchive.h b/lld/include/lld/ReaderWriter/ReaderArchive.h new file mode 100644 index 00000000000..f63006c508c --- /dev/null +++ b/lld/include/lld/ReaderWriter/ReaderArchive.h @@ -0,0 +1,80 @@ +//===- ReaderWriter/ReaderArchive.h - Archive Library Reader ------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===--------------------------------------------------------------------===// + +#ifndef LLD_READER_ARCHIVE_H +#define LLD_READER_ARCHIVE_H + +#include "lld/Core/ArchiveLibraryFile.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/system_error.h" +#include "llvm/Object/Archive.h" +#include "lld/Core/File.h" +#include "lld/Core/LLVM.h" +#include "lld/ReaderWriter/Reader.h" +#include "lld/ReaderWriter/ReaderArchive.h" +#include <memory> +#include <bits/unique_ptr.h> +#include <vector> + +namespace lld +{ +/// +/// The ReaderOptionsArchive encapsulates the options used by the ReaderArchive. +/// The option objects are the only way to control the behaviour of Readers. +/// +class ReaderOptionsArchive +{ +public: + ReaderOptionsArchive(bool is_force_load=false): _isForceLoad(is_force_load), + _reader(nullptr) + { } + + bool isForceLoad() const { + return _isForceLoad; + } + + Reader *reader() const { + return _reader; + } + + void setReader(Reader *r) { + _reader = r; + } + +private: + bool _isForceLoad; + Reader *_reader; +}; + +// ReaderArchive is a class for reading archive libraries +class ReaderArchive final +{ +public: + ReaderArchive(ReaderOptionsArchive &options) : _options(options), + _archive() + { } + + // Returns a vector of Files that are contained in the archive file + // pointed to by the Memorybuffer + virtual error_code parseFile(std::unique_ptr<llvm::MemoryBuffer> mb, + std::vector<std::unique_ptr<File>> &result); + + virtual ~ReaderArchive() { } + +private: + ReaderOptionsArchive &_options; + std::unique_ptr<llvm::object::Archive> _archive; +}; + +} // namespace lld + +#endif // LLD_READER_ARCHIVE_H diff --git a/lld/include/lld/ReaderWriter/ReaderELF.h b/lld/include/lld/ReaderWriter/ReaderELF.h index 5644b81fa25..93434ddf84a 100644 --- a/lld/include/lld/ReaderWriter/ReaderELF.h +++ b/lld/include/lld/ReaderWriter/ReaderELF.h @@ -11,6 +11,7 @@ #define LLD_READERWRITER_READER_ELF_H_ #include "lld/ReaderWriter/Reader.h" +#include "lld/ReaderWriter/ReaderArchive.h" #include "lld/Core/LLVM.h" @@ -56,7 +57,8 @@ protected: /// ReaderOptionsELF object supplied, so the objects object must not be /// destroyed before the Reader object. /// -Reader* createReaderELF(const ReaderOptionsELF &options); +Reader* createReaderELF(const ReaderOptionsELF &options, + ReaderOptionsArchive &optionsArchive); diff --git a/lld/lib/ReaderWriter/CMakeLists.txt b/lld/lib/ReaderWriter/CMakeLists.txt index 85ec90bc60f..c73d6b59c8f 100644 --- a/lld/lib/ReaderWriter/CMakeLists.txt +++ b/lld/lib/ReaderWriter/CMakeLists.txt @@ -6,4 +6,5 @@ add_subdirectory(YAML) add_lld_library(lldReaderWriter Reader.cpp Writer.cpp + ReaderArchive.cpp ) diff --git a/lld/lib/ReaderWriter/ELF/ReaderELF.cpp b/lld/lib/ReaderWriter/ELF/ReaderELF.cpp index 6fa30252993..e239fd77910 100644 --- a/lld/lib/ReaderWriter/ELF/ReaderELF.cpp +++ b/lld/lib/ReaderWriter/ELF/ReaderELF.cpp @@ -12,9 +12,9 @@ // //===----------------------------------------------------------------------===// #include "lld/ReaderWriter/ReaderELF.h" +#include "lld/ReaderWriter/ReaderArchive.h" #include "lld/Core/File.h" #include "lld/Core/Reference.h" - #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" @@ -30,6 +30,7 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/system_error.h" +#include "llvm/Support/Path.h" #include <map> @@ -751,43 +752,72 @@ private: class ReaderELF: public Reader { public: - ReaderELF(const ReaderOptionsELF &) {} + ReaderELF(const ReaderOptionsELF &readerELFOptions, + ReaderOptionsArchive &readerOptionsArchive) + : _readerELFOptions(readerELFOptions), + _readerOptionsArchive(readerOptionsArchive), + _readerArchive(_readerOptionsArchive) { + _readerOptionsArchive.setReader(this); + } + error_code parseFile(std::unique_ptr<MemoryBuffer> mb, std::vector< - std::unique_ptr<File> > &result) { + std::unique_ptr<File> > &result) { + llvm::error_code ec; + std::unique_ptr<File> f; + std::pair<unsigned char, unsigned char> Ident; - std::pair<unsigned char, unsigned char> Ident = - llvm::object::getElfArchType(&*mb); - llvm::error_code ec; - // Instantiate the correct FileELF template instance - // based on the Ident pair. Once the File is created - // we push the file to the vector of files already - // created during parser's life. + llvm::sys::LLVMFileType fileType = + llvm::sys::IdentifyFileType(mb->getBufferStart(), + static_cast<unsigned>(mb->getBufferSize())); + switch (fileType) { - std::unique_ptr<File> f; + case llvm::sys::ELF_Relocatable_FileType: + + Ident = llvm::object::getElfArchType(&*mb); + // Instantiate the correct FileELF template instance + // based on the Ident pair. Once the File is created + // we push the file to the vector of files already + // created during parser's life. - if (Ident.first == llvm::ELF::ELFCLASS32 && Ident.second - == llvm::ELF::ELFDATA2LSB) { - f.reset(new FileELF<llvm::support::little, false>(std::move(mb), ec)); + if (Ident.first == llvm::ELF::ELFCLASS32 && Ident.second + == llvm::ELF::ELFDATA2LSB) { + f.reset(new FileELF<llvm::support::little, false>(std::move(mb), ec)); - } else if (Ident.first == llvm::ELF::ELFCLASS32 && Ident.second - == llvm::ELF::ELFDATA2MSB) { - f.reset(new FileELF<llvm::support::big, false> (std::move(mb), ec)); + } else if (Ident.first == llvm::ELF::ELFCLASS32 && Ident.second + == llvm::ELF::ELFDATA2MSB) { + f.reset(new FileELF<llvm::support::big, false> (std::move(mb), ec)); - } else if (Ident.first == llvm::ELF::ELFCLASS64 && Ident.second - == llvm::ELF::ELFDATA2MSB) { - f.reset(new FileELF<llvm::support::big, true> (std::move(mb), ec)); + } else if (Ident.first == llvm::ELF::ELFCLASS64 && Ident.second + == llvm::ELF::ELFDATA2MSB) { + f.reset(new FileELF<llvm::support::big, true> (std::move(mb), ec)); - } else if (Ident.first == llvm::ELF::ELFCLASS64 && Ident.second - == llvm::ELF::ELFDATA2LSB) { - f.reset(new FileELF<llvm::support::little, true> (std::move(mb), ec)); + } else if (Ident.first == llvm::ELF::ELFCLASS64 && Ident.second + == llvm::ELF::ELFDATA2LSB) { + f.reset(new FileELF<llvm::support::little, true> (std::move(mb), ec)); + } + if (!ec) + result.push_back(std::move(f)); + break; + + case llvm::sys::Archive_FileType: + ec = _readerArchive.parseFile(std::move(mb), result); + break; + + default: + llvm_unreachable("not supported format"); + break; } if (ec) return ec; - result.push_back(std::move(f)); return error_code::success(); } + +private: + const ReaderOptionsELF &_readerELFOptions; + ReaderOptionsArchive &_readerOptionsArchive; + ReaderArchive _readerArchive; }; } // namespace anonymous @@ -800,8 +830,9 @@ ReaderOptionsELF::ReaderOptionsELF() { ReaderOptionsELF::~ReaderOptionsELF() { } -Reader *createReaderELF(const ReaderOptionsELF &options) { - return new ReaderELF(options); +Reader *createReaderELF(const ReaderOptionsELF &options, + ReaderOptionsArchive &optionsArchive) { + return new ReaderELF(options, optionsArchive); } } // namespace LLD diff --git a/lld/lib/ReaderWriter/ReaderArchive.cpp b/lld/lib/ReaderWriter/ReaderArchive.cpp new file mode 100644 index 00000000000..437db2aea8a --- /dev/null +++ b/lld/lib/ReaderWriter/ReaderArchive.cpp @@ -0,0 +1,160 @@ +//===- lib/ReaderWriter/ReaderArchive.cpp - Archive Library Reader--------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// +#include "lld/ReaderWriter/ReaderArchive.h" + +namespace lld +{ +// The FileArchive class represents an Archive Library file +class FileArchive : public ArchiveLibraryFile { +public: + + virtual ~FileArchive() { } + + /// Check if any member of the archive contains an Atom with the + /// specified name and return the File object for that member, or nullptr. + virtual const File *find(StringRef name, bool dataSymbolOnly) const { + error_code ec; + llvm::object::Archive::child_iterator ci; + + ci = _archive.get()->findSym(name); + if (ci == _archive->end_children()) + return nullptr; + + if (dataSymbolOnly && (ec = isDataSymbol(ci->getBuffer(), name))) + return nullptr; + + std::vector<std::unique_ptr<File>> result; + + if ((ec = _options.reader()->parseFile(std::unique_ptr<MemoryBuffer> + (ci->getBuffer()), result))) + return nullptr; + + assert(result.size() == 1); + + // give up the pointer so that this object no longer manages it + for (std::unique_ptr<File> &f : result) { + return f.release(); + } + + return nullptr; + } + + virtual void addAtom(const Atom&) { + llvm_unreachable("cannot add atoms to archive files"); + } + + virtual const atom_collection<DefinedAtom> &defined() const { + return _definedAtoms; + } + + virtual const atom_collection<UndefinedAtom> &undefined() const { + return _undefinedAtoms; + } + + virtual const atom_collection<SharedLibraryAtom> &sharedLibrary() const { + return _sharedLibraryAtoms; + } + + virtual const atom_collection<AbsoluteAtom> &absolute() const { + return _absoluteAtoms; + } + +protected: + error_code isDataSymbol(MemoryBuffer *mb, StringRef symbol) const + { + llvm::object::ObjectFile *obj = + llvm::object::ObjectFile::createObjectFile(mb); + error_code ec; + llvm::object::SymbolRef::Type symtype; + uint32_t symflags; + llvm::object::symbol_iterator ibegin = obj->begin_symbols(); + llvm::object::symbol_iterator iend = obj->end_symbols(); + StringRef symbolname; + + for (llvm::object::symbol_iterator i = ibegin; i != iend; i.increment(ec)) { + if (ec) return ec; + + // Get symbol name + if ((ec = (i->getName(symbolname)))) return ec; + + if (symbolname != symbol) + continue; + + // Get symbol flags + if ((ec = (i->getFlags(symflags)))) return ec; + + if (symflags <= llvm::object::SymbolRef::SF_Undefined) + continue; + + // Get Symbol Type + if ((ec = (i->getType(symtype)))) return ec; + + if (symtype == llvm::object::SymbolRef::ST_Data) { + return error_code::success(); + } + } + return llvm::object::object_error::parse_failed; + } + +private: + llvm::MemoryBuffer *_mb; + std::unique_ptr<llvm::object::Archive> _archive; + const ReaderOptionsArchive _options; + atom_collection_vector<DefinedAtom> _definedAtoms; + atom_collection_vector<UndefinedAtom> _undefinedAtoms; + atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms; + atom_collection_vector<AbsoluteAtom> _absoluteAtoms; + +public: + /// only subclasses of ArchiveLibraryFile can be instantiated + explicit FileArchive(llvm::MemoryBuffer *mb, + const ReaderOptionsArchive &options, + error_code &ec) + :ArchiveLibraryFile(mb->getBufferIdentifier()), + _mb(mb), + _archive(nullptr), + _options(options) { + auto *archive_obj = new llvm::object::Archive(mb, ec); + if (ec) + return; + _archive.reset(archive_obj); + } +}; // class FileArchive + +// Returns a vector of Files that are contained in the archive file +// pointed to by the MemoryBuffer +error_code ReaderArchive::parseFile(std::unique_ptr<llvm::MemoryBuffer> mb, + std::vector<std::unique_ptr<File>> &result) { + error_code ec; + + if (_options.isForceLoad()) + { + _archive.reset(new llvm::object::Archive(mb.release(), ec)); + if (ec) + return ec; + + for (auto mf = _archive->begin_children(), + me = _archive->end_children(); mf != me; ++mf) + { + if ((ec = _options.reader()->parseFile(std::unique_ptr<MemoryBuffer> + (mf->getBuffer()), result))) + return ec; + } + } else { + std::unique_ptr<File> f; + f.reset(new FileArchive(mb.release(), _options, ec)); + if (ec) + return ec; + + result.push_back(std::move(f)); + } + return llvm::error_code::success(); +} + +} // namespace lld diff --git a/lld/test/elf/Inputs/libfnarchive.x86_64 b/lld/test/elf/Inputs/libfnarchive.x86_64 Binary files differnew file mode 100644 index 00000000000..753acd6e2c6 --- /dev/null +++ b/lld/test/elf/Inputs/libfnarchive.x86_64 diff --git a/lld/test/elf/Inputs/mainobj.x86_64 b/lld/test/elf/Inputs/mainobj.x86_64 Binary files differnew file mode 100644 index 00000000000..d0f29418237 --- /dev/null +++ b/lld/test/elf/Inputs/mainobj.x86_64 diff --git a/lld/test/elf/archive-elf-forceload.objtxt b/lld/test/elf/archive-elf-forceload.objtxt new file mode 100644 index 00000000000..2e53a2114aa --- /dev/null +++ b/lld/test/elf/archive-elf-forceload.objtxt @@ -0,0 +1,48 @@ +# Tests the functionality of archive libraries reading +# and resolution +# Note: The binary files would not be required once we have support to generate +# binary archives from textual(yaml) input +# +# Tests generated using the source files below +# main file +# int main() +# { +# fn(); +# return 0; +# } +# +# archive file +# int fn() +# { +# return 0; +# } +# +# int fn1() +# { +# return 0; +# } +# gcc -c main.c fn.c fn1.c + +RUN: lld-core -reader ELF %p/Inputs/mainobj.x86_64 %p/Inputs/libfnarchive.x86_64 -force-load | FileCheck -check-prefix FORCELOAD %s + +FORCELOAD: - name: fn1 +FORCELOAD: scope: global +FORCELOAD: type: code +FORCELOAD: section-choice: custom-required +FORCELOAD: section-name: .text +FORCELOAD: content: [ 55, 48, 89, E5, B8, 00, 00, 00, 00, 5D, C3 ] +FORCELOAD: - name: fn +FORCELOAD: scope: global +FORCELOAD: type: code +FORCELOAD: section-choice: custom-required +FORCELOAD: section-name: .text +FORCELOAD: content: [ 55, 48, 89, E5, B8, 00, 00, 00, 00, 5D, C3 ] +FORCELOAD: - name: main.c +FORCELOAD: definition: absolute +FORCELOAD: value: 0x0 +FORCELOAD: - name: fn1.c +FORCELOAD: definition: absolute +FORCELOAD: value: 0x0 +FORCELOAD: - name: fn.c +FORCELOAD: definition: absolute +FORCELOAD: value: 0x0 diff --git a/lld/test/elf/archive-elf.objtxt b/lld/test/elf/archive-elf.objtxt new file mode 100644 index 00000000000..0b85e4238f3 --- /dev/null +++ b/lld/test/elf/archive-elf.objtxt @@ -0,0 +1,39 @@ +# Tests the functionality of archive libraries reading +# and resolution +# Note: The binary files would not be required once we have support to generate +# binary archives from textual(yaml) input +# +# Tests generated using the source files below +# main file +# int main() +# { +# fn(); +# return 0; +# } +# +# archive file +# int fn() +# { +# return 0; +# } +# +# int fn1() +# { +# return 0; +# } +# gcc -c main.c fn.c fn1.c + +RUN: lld-core -reader ELF %p/Inputs/mainobj.x86_64 %p/Inputs/libfnarchive.x86_64 | FileCheck -check-prefix NOFORCELOAD %s + +NOFORCELOAD: - name: fn +NOFORCELOAD: scope: global +NOFORCELOAD: type: code +NOFORCELOAD: section-choice: custom-required +NOFORCELOAD: section-name: .text +NOFORCELOAD: content: [ 55, 48, 89, E5, B8, 00, 00, 00, 00, 5D, C3 ] +NOFORCELOAD: - name: main.c +NOFORCELOAD: definition: absolute +NOFORCELOAD: value: 0x0 +NOFORCELOAD: - name: fn.c +NOFORCELOAD: definition: absolute +NOFORCELOAD: value: 0x0 diff --git a/lld/tools/lld-core/lld-core.cpp b/lld/tools/lld-core/lld-core.cpp index 5512961ebf3..eeb49296234 100644 --- a/lld/tools/lld-core/lld-core.cpp +++ b/lld/tools/lld-core/lld-core.cpp @@ -12,6 +12,7 @@ #include "lld/Core/Pass.h" #include "lld/Core/Resolver.h" #include "lld/ReaderWriter/Reader.h" +#include "lld/ReaderWriter/ReaderArchive.h" #include "lld/ReaderWriter/ReaderNative.h" #include "lld/ReaderWriter/ReaderYAML.h" #include "lld/ReaderWriter/ReaderELF.h" @@ -76,6 +77,10 @@ cmdLineUndefinesIsError("undefines-are-errors", llvm::cl::desc("Any undefined symbols at end is an error")); llvm::cl::opt<bool> +cmdLineForceLoad("force-load", + llvm::cl::desc("force load all members of the archive")); + +llvm::cl::opt<bool> cmdLineCommonsSearchArchives("commons-search-archives", llvm::cl::desc("Tentative definitions trigger archive search")); @@ -214,6 +219,8 @@ int main(int argc, char *argv[]) { // create object to mange input files InputFiles inputFiles; + ReaderOptionsArchive readerOptionsArchive(cmdLineForceLoad); + // read input files into in-memory File objects TestingReaderOptionsYAML readerOptionsYAML; @@ -231,7 +238,9 @@ int main(int argc, char *argv[]) { reader = createReaderPECOFF(lld::ReaderOptionsPECOFF()); break; case readerELF: - reader = createReaderELF(lld::ReaderOptionsELF()); + reader = createReaderELF(lld::ReaderOptionsELF(), + readerOptionsArchive); + break; default: reader = createReaderYAML(readerOptionsYAML); |

