From 70b4dcfbcd1f388b8dc8adef8c175a4924fa0121 Mon Sep 17 00:00:00 2001 From: Shankar Easwaran Date: Tue, 13 Nov 2012 18:39:10 +0000 Subject: [PATCH] Adding support to resolve symbols with archive libraries in lld llvm-svn: 167854 --- lld/include/lld/ReaderWriter/ReaderArchive.h | 80 ++++++++++++++ lld/include/lld/ReaderWriter/ReaderELF.h | 4 +- lld/lib/ReaderWriter/CMakeLists.txt | 1 + lld/lib/ReaderWriter/ELF/ReaderELF.cpp | 83 +++++++++----- lld/lib/ReaderWriter/ReaderArchive.cpp | 160 +++++++++++++++++++++++++++ lld/test/elf/Inputs/libfnarchive.x86_64 | Bin 0 -> 2656 bytes lld/test/elf/Inputs/mainobj.x86_64 | Bin 0 -> 1360 bytes lld/test/elf/archive-elf-forceload.objtxt | 48 ++++++++ lld/test/elf/archive-elf.objtxt | 39 +++++++ lld/tools/lld-core/lld-core.cpp | 11 +- 10 files changed, 398 insertions(+), 28 deletions(-) create mode 100644 lld/include/lld/ReaderWriter/ReaderArchive.h create mode 100644 lld/lib/ReaderWriter/ReaderArchive.cpp create mode 100644 lld/test/elf/Inputs/libfnarchive.x86_64 create mode 100644 lld/test/elf/Inputs/mainobj.x86_64 create mode 100644 lld/test/elf/archive-elf-forceload.objtxt create mode 100644 lld/test/elf/archive-elf.objtxt diff --git a/lld/include/lld/ReaderWriter/ReaderArchive.h b/lld/include/lld/ReaderWriter/ReaderArchive.h new file mode 100644 index 0000000..f63006c --- /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 +#include +#include + +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 mb, + std::vector> &result); + + virtual ~ReaderArchive() { } + +private: + ReaderOptionsArchive &_options; + std::unique_ptr _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 5644b81..93434dd 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 85ec90b..c73d6b5 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 6fa3025..e239fd7 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 @@ -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 mb, std::vector< - std::unique_ptr > &result) { + std::unique_ptr > &result) { + llvm::error_code ec; + std::unique_ptr f; + std::pair Ident; - std::pair 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(mb->getBufferSize())); + switch (fileType) { - std::unique_ptr 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(std::move(mb), ec)); + if (Ident.first == llvm::ELF::ELFCLASS32 && Ident.second + == llvm::ELF::ELFDATA2LSB) { + f.reset(new FileELF(std::move(mb), ec)); - } else if (Ident.first == llvm::ELF::ELFCLASS32 && Ident.second - == llvm::ELF::ELFDATA2MSB) { - f.reset(new FileELF (std::move(mb), ec)); + } else if (Ident.first == llvm::ELF::ELFCLASS32 && Ident.second + == llvm::ELF::ELFDATA2MSB) { + f.reset(new FileELF (std::move(mb), ec)); - } else if (Ident.first == llvm::ELF::ELFCLASS64 && Ident.second - == llvm::ELF::ELFDATA2MSB) { - f.reset(new FileELF (std::move(mb), ec)); + } else if (Ident.first == llvm::ELF::ELFCLASS64 && Ident.second + == llvm::ELF::ELFDATA2MSB) { + f.reset(new FileELF (std::move(mb), ec)); - } else if (Ident.first == llvm::ELF::ELFCLASS64 && Ident.second - == llvm::ELF::ELFDATA2LSB) { - f.reset(new FileELF (std::move(mb), ec)); + } else if (Ident.first == llvm::ELF::ELFCLASS64 && Ident.second + == llvm::ELF::ELFDATA2LSB) { + f.reset(new FileELF (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 0000000..437db2a --- /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> result; + + if ((ec = _options.reader()->parseFile(std::unique_ptr + (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 &f : result) { + return f.release(); + } + + return nullptr; + } + + virtual void addAtom(const Atom&) { + llvm_unreachable("cannot add atoms to archive files"); + } + + virtual const atom_collection &defined() const { + return _definedAtoms; + } + + virtual const atom_collection &undefined() const { + return _undefinedAtoms; + } + + virtual const atom_collection &sharedLibrary() const { + return _sharedLibraryAtoms; + } + + virtual const atom_collection &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 _archive; + const ReaderOptionsArchive _options; + atom_collection_vector _definedAtoms; + atom_collection_vector _undefinedAtoms; + atom_collection_vector _sharedLibraryAtoms; + atom_collection_vector _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 mb, + std::vector> &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 + (mf->getBuffer()), result))) + return ec; + } + } else { + std::unique_ptr 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 new file mode 100644 index 0000000000000000000000000000000000000000..753acd6e2c658d95c9bce094485b8e0007f6cc94 GIT binary patch literal 2656 zcmeHI&2G~`5FW?<2`Qi!aX>1E?TH`Jt-VRx6rn08YKu_B0TGD1eBU z8VAWh)a0&Io7J;XczU94RcdHI`xX{kU^bZ>I4IvGhe?as+_dv=V35w|PxJ3!F7@|t za54RFa}aG>OJejkv$KGnUU7%nCeJ_*(IAW-HKsHndkYLZK-)eO3ZHB6nqGSW zHQkZPH~1Q2_SsR&IZY@}ay6Ol{mL^pKON*j1~bc#ul*fryGw(1S?YrdVuJXj4!xf(Ox?KgXls zZxKA|UC{ZGU0v6l#DU#!=9`(F*-7?leP<(OS)|0GRrDpkwbsn|p;%Ww>2T^^8ip0>vN zI=k+<<~Z|MkP&Qa1L>PozQ1Fi17M5hg&(>_#;_6NsnQx=%@v_{9+D`#p-ZCJY?3I| zecub13+kaKHg^k|X6TmANJQb@=}D#G`W}w{4{`VqjIP5tEGO;gPMWVx)1i*>GCA;0 zJ9eVc7^sI4b)uPQ{DkCfMqLhdL(|P#Gwj2ef6brgT=X@^OBYptS|?dYEJWdorbiCB zUF(LXt2{;Ru>vlo2#L26mknOcPtn_~m@|QIIbr^t%&UC$T?UymXNUYpY%E7HeC=lc zNxdW3kxjkI%w9&+HtTmYmsCG3`%lY!1!jH4n~1nJdiyYW*!I`g`{}h4J3)NXgu$Dy zCO*$5O!~LjBrm18FpnXvANAh)nK$nqrTK0(5G4XoC5YY?c>F(@<@-l04(kx``oHxF DS0zlf literal 0 HcmV?d00001 diff --git a/lld/test/elf/archive-elf-forceload.objtxt b/lld/test/elf/archive-elf-forceload.objtxt new file mode 100644 index 0000000..2e53a21 --- /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 0000000..0b85e42 --- /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 5512961..eeb4929 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 +cmdLineForceLoad("force-load", + llvm::cl::desc("force load all members of the archive")); + +llvm::cl::opt 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); -- 2.7.4