diff options
Diffstat (limited to 'lld')
| -rw-r--r-- | lld/include/lld/Core/ArchiveLibraryFile.h | 54 | ||||
| -rw-r--r-- | lld/include/lld/Core/File.h | 33 | ||||
| -rw-r--r-- | lld/include/lld/Core/InputFiles.h | 17 | ||||
| -rw-r--r-- | lld/include/lld/Core/SharedLibraryFile.h | 52 | ||||
| -rw-r--r-- | lld/include/lld/Core/SymbolTable.h | 3 | ||||
| -rw-r--r-- | lld/lib/Core/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | lld/lib/Core/InputFiles.cpp | 84 | ||||
| -rw-r--r-- | lld/lib/Core/Resolver.cpp | 30 | ||||
| -rw-r--r-- | lld/lib/Core/SymbolTable.cpp | 12 | ||||
| -rw-r--r-- | lld/lib/Core/YamlKeyValues.cpp | 31 | ||||
| -rw-r--r-- | lld/lib/Core/YamlKeyValues.h | 8 | ||||
| -rw-r--r-- | lld/lib/Core/YamlReader.cpp | 107 | ||||
| -rw-r--r-- | lld/test/archive-basic.objtxt | 47 | ||||
| -rw-r--r-- | lld/test/archive-chain.objtxt | 74 | ||||
| -rw-r--r-- | lld/test/archive-tentdef-search.objtxt | 45 | ||||
| -rw-r--r-- | lld/test/darwin/hello-world.objtxt | 2 | ||||
| -rw-r--r-- | lld/test/dead-strip-basic.objtxt | 63 | ||||
| -rw-r--r-- | lld/test/dead-strip-globals.objtxt | 62 | ||||
| -rw-r--r-- | lld/test/pass-got-basic.objtxt | 2 | ||||
| -rw-r--r-- | lld/test/pass-stubs-basic.objtxt | 2 | ||||
| -rw-r--r-- | lld/test/undef-coalesce-error.objtxt | 23 | ||||
| -rw-r--r-- | lld/tools/lld-core/lld-core.cpp | 90 |
22 files changed, 735 insertions, 107 deletions
diff --git a/lld/include/lld/Core/ArchiveLibraryFile.h b/lld/include/lld/Core/ArchiveLibraryFile.h new file mode 100644 index 00000000000..f80b11a5221 --- /dev/null +++ b/lld/include/lld/Core/ArchiveLibraryFile.h @@ -0,0 +1,54 @@ +//===- Core/ArchiveLibraryFile.h - Models static library ------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_ARCHIVE_LIBRARY_FILE_H_ +#define LLD_CORE_ARCHIVE_LIBRARY_FILE_H_ + +#include "lld/Core/File.h" + +namespace lld { + + +/// +/// The ArchiveLibraryFile subclass of File is used to represent unix +/// static library archives. These libraries provide no atoms to the +/// initial set of atoms linked. Instead, when the Resolver will query +/// ArchiveLibraryFile instances for specific symbols names using the +/// find() method. If the archive contains an object file which has a +/// DefinedAtom whose scope is not translationUnit, then that entire +/// object file File is returned. +/// +class ArchiveLibraryFile : public File { +public: + ArchiveLibraryFile(StringRef path) : File(path) { + } + + virtual ~ArchiveLibraryFile() { + } + + virtual Kind kind() const { + return kindArchiveLibrary; + } + + static inline bool classof(const File *f) { + return f->kind() == kindArchiveLibrary; + } + static inline bool classof(const ArchiveLibraryFile *) { + return true; + } + + /// 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 = 0; + +}; + +} // namespace lld + +#endif // LLD_CORE_ARCHIVE_LIBRARY_FILE_H_ diff --git a/lld/include/lld/Core/File.h b/lld/include/lld/Core/File.h index 07b60aac2c0..e3afaeb5d03 100644 --- a/lld/include/lld/Core/File.h +++ b/lld/include/lld/Core/File.h @@ -27,8 +27,11 @@ namespace lld { /// object file (.o) to be parsed by some reader and produce a single /// File object that represents the content of that object file. /// -/// The File class has *begin() and *end() methods for use iterating through -/// the Atoms in a File object. +/// To iterate through the Atoms in a File there are four methods that +/// return collections. For instance to iterate through all the DefinedAtoms +/// in a File object use: +/// for (const DefinedAtoms *atom : file->defined()) { +/// } /// /// The Atom objects in a File are owned by the File object. The Atom objects /// are destroyed when the File object is destroyed. @@ -37,6 +40,18 @@ class File { public: virtual ~File(); + /// Kinds of files that are supported. + enum Kind { + kindObject, ///< object file (.o) + kindSharedLibrary, ///< shared library (.so) + kindArchiveLibrary, ///< archive (.a) + }; + + /// Returns file kind. Need for dyn_cast<> on File objects. + virtual Kind kind() const { + return kindObject; + } + /// For error messages and debugging, this returns the path to the file /// which was used to create this object (e.g. "/tmp/foo.o"). StringRef path() const { @@ -49,6 +64,11 @@ public: /// be ascertained, this method returns the empty string. virtual StringRef translationUnitSource() const; + + static inline bool classof(const File *) { + return true; + } + protected: template <typename T> class atom_iterator; // forward reference public: @@ -144,7 +164,7 @@ public: /// Must be implemented to return the atom_collection object for /// all AbsoluteAtoms in this File. virtual const atom_collection<AbsoluteAtom>& absolute() const = 0; - + protected: /// This is a convenience class for File subclasses which manage their /// atoms as a simple std::vector<>. @@ -152,11 +172,12 @@ protected: class atom_collection_vector : public atom_collection<T> { public: virtual atom_iterator<T> begin() const { - return atom_iterator<T>(*this, reinterpret_cast<const void*>(_atoms.data())); + return atom_iterator<T>(*this, reinterpret_cast<const void*> + (_atoms.data())); } virtual atom_iterator<T> end() const{ return atom_iterator<T>(*this, reinterpret_cast<const void*> - (_atoms.data() + _atoms.size())); + (_atoms.data() + _atoms.size())); } virtual const T* deref(const void* it) const { return *reinterpret_cast<const T* const*>(it); @@ -169,8 +190,6 @@ protected: std::vector<const T*> _atoms; }; - -private: StringRef _path; }; diff --git a/lld/include/lld/Core/InputFiles.h b/lld/include/lld/Core/InputFiles.h index 13de819d0e3..f3111f8d16a 100644 --- a/lld/include/lld/Core/InputFiles.h +++ b/lld/include/lld/Core/InputFiles.h @@ -34,23 +34,30 @@ public: virtual void doAbsoluteAtom(const class AbsoluteAtom &) = 0; }; + InputFiles(); + virtual ~InputFiles(); /// Used by platforms to insert platform specific files. - virtual void prependFile(const File&) = 0; + virtual void prependFile(const File&); /// Used by platforms to insert platform specific files. - virtual void appendFile(const File&) = 0; + virtual void appendFile(const File&); /// @brief iterates all atoms in initial files - virtual void forEachInitialAtom(Handler &) const = 0; + virtual void forEachInitialAtom(Handler &) const; /// @brief searches libraries for name virtual bool searchLibraries( StringRef name - , bool searchDylibs + , bool searchSharedLibs , bool searchArchives , bool dataSymbolOnly - , Handler &) const = 0; + , Handler &) const; + +protected: + void handleFile(const File *file, InputFiles::Handler &handler) const; + + std::vector<const File*> _files; }; } // namespace lld diff --git a/lld/include/lld/Core/SharedLibraryFile.h b/lld/include/lld/Core/SharedLibraryFile.h new file mode 100644 index 00000000000..b3cb00c94c7 --- /dev/null +++ b/lld/include/lld/Core/SharedLibraryFile.h @@ -0,0 +1,52 @@ +//===- Core/SharedLibraryFile.h - Models shared libraries as Atoms --------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_SHARED_LIBRARY_FILE_H_ +#define LLD_CORE_SHARED_LIBRARY_FILE_H_ + +#include "lld/Core/File.h" +#include "lld/Core/SharedLibraryAtom.h" + +namespace lld { + + +/// +/// The SharedLibraryFile subclass of File is used to represent dynamic +/// shared libraries being linked against. +/// +class SharedLibraryFile : public File { +public: + SharedLibraryFile(StringRef path) : File(path) { + } + virtual ~SharedLibraryFile() { + } + + virtual Kind kind() const { + return kindSharedLibrary; + } + + static inline bool classof(const File *f) { + return f->kind() == kindSharedLibrary; + } + static inline bool classof(const SharedLibraryFile *) { + return true; + } + + + /// Check if the shared library exports a symbol with the specified name. + /// If so, return a SharedLibraryAtom which represents that exported + /// symbol. Otherwise return nullptr. + virtual const SharedLibraryAtom *exports(StringRef name, + bool dataSymbolOnly) const; + +}; + +} // namespace lld + +#endif // LLD_CORE_SHARED_LIBRARY_FILE_H_ diff --git a/lld/include/lld/Core/SymbolTable.h b/lld/include/lld/Core/SymbolTable.h index fc9249ceeaa..e648f7820d7 100644 --- a/lld/include/lld/Core/SymbolTable.h +++ b/lld/include/lld/Core/SymbolTable.h @@ -59,6 +59,9 @@ public: /// @brief returns vector of remaining UndefinedAtoms void undefines(std::vector<const Atom *>&); + + /// returns vector of tentative definitions + void tentativeDefinitions(std::vector<StringRef> &); /// @brief count of by-name entries in symbol table unsigned int size(); diff --git a/lld/lib/Core/CMakeLists.txt b/lld/lib/Core/CMakeLists.txt index 2e39dff7fe6..076d3351504 100644 --- a/lld/lib/Core/CMakeLists.txt +++ b/lld/lib/Core/CMakeLists.txt @@ -1,6 +1,7 @@ add_lld_library(lldCore Error.cpp File.cpp + InputFiles.cpp NativeFileFormat.h NativeReader.cpp NativeWriter.cpp diff --git a/lld/lib/Core/InputFiles.cpp b/lld/lib/Core/InputFiles.cpp new file mode 100644 index 00000000000..5840151a894 --- /dev/null +++ b/lld/lib/Core/InputFiles.cpp @@ -0,0 +1,84 @@ +//===- Core/InputFiles.cpp - Manages list of Files -----------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lld/Core/InputFiles.h" +#include "lld/Core/SharedLibraryFile.h" +#include "lld/Core/ArchiveLibraryFile.h" +#include "lld/Core/LLVM.h" + +namespace lld { + +InputFiles::InputFiles() { +} + + +InputFiles::~InputFiles() { +} + +void InputFiles::forEachInitialAtom(InputFiles::Handler &handler) const { + for ( const File *file : _files ) { + this->handleFile(file, handler); + } +} + +void InputFiles::prependFile(const File &file) { + _files.insert(_files.begin(), &file); +} + +void InputFiles::appendFile(const File &file) { + _files.push_back(&file); +} + + +bool InputFiles::searchLibraries(StringRef name, bool searchSharedLibs, + bool searchArchives, bool dataSymbolOnly, + InputFiles::Handler &handler) const { + + for ( const File *file : _files ) { + if ( searchSharedLibs ) { + if (const SharedLibraryFile *shlib = dyn_cast<SharedLibraryFile>(file)) { + if ( const SharedLibraryAtom* shAtom = shlib->exports(name, + dataSymbolOnly) ) { + handler.doSharedLibraryAtom(*shAtom); + return true; + } + } + } + if ( searchArchives ) { + if (const ArchiveLibraryFile *lib = dyn_cast<ArchiveLibraryFile>(file)) { + if ( const File *member = lib->find(name, dataSymbolOnly) ) { + this->handleFile(member, handler); + return true; + } + } + } + } + return false; +} + + +void InputFiles::handleFile(const File *file, + InputFiles::Handler &handler) const { + handler.doFile(*file); + for( const DefinedAtom *atom : file->defined() ) { + handler.doDefinedAtom(*atom); + } + for( const UndefinedAtom *undefAtom : file->undefined() ) { + handler.doUndefinedAtom(*undefAtom); + } + for( const SharedLibraryAtom *shlibAtom : file->sharedLibrary() ) { + handler.doSharedLibraryAtom(*shlibAtom); + } + for( const AbsoluteAtom *absAtom : file->absolute() ) { + handler.doAbsoluteAtom(*absAtom); + } +} + + +} // namespace lld diff --git a/lld/lib/Core/Resolver.cpp b/lld/lib/Core/Resolver.cpp index a758a8628ab..f16a67a94fe 100644 --- a/lld/lib/Core/Resolver.cpp +++ b/lld/lib/Core/Resolver.cpp @@ -137,7 +137,7 @@ void Resolver::addAtoms(const std::vector<const DefinedAtom*>& newAtoms) { void Resolver::resolveUndefines() { const bool searchArchives = _options.searchArchivesToOverrideTentativeDefinitions(); - const bool searchDylibs = + const bool searchSharedLibs = _options.searchSharedLibrariesToOverrideTentativeDefinitions(); // keep looping until no more undefines were added in last loop @@ -154,24 +154,20 @@ void Resolver::resolveUndefines() { } } // search libraries for overrides of common symbols - if (searchArchives || searchDylibs) { - std::vector<const Atom *> tents; - for ( const Atom *tent : tents ) { - if (const DefinedAtom* defAtom = dyn_cast<DefinedAtom>(tent)) { - if ( defAtom->merge() == DefinedAtom::mergeAsTentative ) - tents.push_back(defAtom); - } - } - for ( const Atom *tent : tents ) { - // load for previous tentative may also have loaded - // this tentative, so check again - StringRef tentName = tent->name(); - const Atom *curAtom = _symbolTable.findByName(tentName); + if (searchArchives || searchSharedLibs) { + std::vector<StringRef> tentDefNames; + _symbolTable.tentativeDefinitions(tentDefNames); + for ( StringRef tentDefName : tentDefNames ) { + // Load for previous tentative may also have loaded + // something that overrode this tentative, so always check. + const Atom *curAtom = _symbolTable.findByName(tentDefName); assert(curAtom != nullptr); if (const DefinedAtom* curDefAtom = dyn_cast<DefinedAtom>(curAtom)) { - if (curDefAtom->merge() == DefinedAtom::mergeAsTentative ) - _inputFiles.searchLibraries(tentName, searchDylibs, - true, true, *this); + if (curDefAtom->merge() == DefinedAtom::mergeAsTentative ) { + // Still tentative definition, so look for override. + _inputFiles.searchLibraries(tentDefName, searchSharedLibs, + searchArchives, true, *this); + } } } } diff --git a/lld/lib/Core/SymbolTable.cpp b/lld/lib/Core/SymbolTable.cpp index e2269749062..0bfe6da6a78 100644 --- a/lld/lib/Core/SymbolTable.cpp +++ b/lld/lib/Core/SymbolTable.cpp @@ -330,4 +330,16 @@ void SymbolTable::undefines(std::vector<const Atom *> &undefs) { } } +void SymbolTable::tentativeDefinitions(std::vector<StringRef> &names) { + for (auto entry : _nameTable) { + const Atom *atom = entry.second; + StringRef name = entry.first; + assert(atom != nullptr); + if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom) ) { + if ( defAtom->merge() == DefinedAtom::mergeAsTentative ) + names.push_back(name); + } + } +} + } // namespace lld diff --git a/lld/lib/Core/YamlKeyValues.cpp b/lld/lib/Core/YamlKeyValues.cpp index abf6f16f8c6..19abf4ff12d 100644 --- a/lld/lib/Core/YamlKeyValues.cpp +++ b/lld/lib/Core/YamlKeyValues.cpp @@ -10,6 +10,7 @@ #include "YamlKeyValues.h" #include "llvm/Support/ErrorHandling.h" +#include "lld/Core/File.h" #include <cstring> @@ -40,6 +41,9 @@ const char* const KeyValues::fixupsKindKeyword = "kind"; const char* const KeyValues::fixupsOffsetKeyword = "offset"; const char* const KeyValues::fixupsTargetKeyword = "target"; const char* const KeyValues::fixupsAddendKeyword = "addend"; +const char* const KeyValues::fileAtomsKeyword = "atoms"; +const char* const KeyValues::fileKindKeyword = "kind"; +const char* const KeyValues::fileMembersKeyword = "members"; @@ -54,9 +58,36 @@ const DefinedAtom::ContentPermissions KeyValues::permissionsDefault = DefinedAto const bool KeyValues::isThumbDefault = false; const bool KeyValues::isAliasDefault = false; const UndefinedAtom::CanBeNull KeyValues::canBeNullDefault = UndefinedAtom::canBeNullNever; +const File::Kind KeyValues::fileKindDefault = File::kindObject; +struct FileKindMapping { + const char* string; + File::Kind value; +}; + +static const FileKindMapping fileKindMappings[] = { + { "object", File::kindObject }, + { "archive", File::kindArchiveLibrary }, + { "shared-library", File::kindSharedLibrary }, + { nullptr, File::kindObject } +}; + File::Kind KeyValues::fileKind(const char* str) { + for (const FileKindMapping* p = fileKindMappings; p->string != nullptr; ++p) { + if ( strcmp(p->string, str) == 0 ) + return p->value; + } + llvm::report_fatal_error("bad file kind value"); +} + +const char* KeyValues::fileKind(File::Kind k) { + for (const FileKindMapping* p = fileKindMappings; p->string != nullptr; ++p) { + if ( p->value == k ) + return p->string; + } + llvm::report_fatal_error("bad file kind value"); +} struct DefinitionMapping { diff --git a/lld/lib/Core/YamlKeyValues.h b/lld/lib/Core/YamlKeyValues.h index f474fb36d2d..2265c5f5596 100644 --- a/lld/lib/Core/YamlKeyValues.h +++ b/lld/lib/Core/YamlKeyValues.h @@ -13,6 +13,7 @@ #include "lld/Core/Atom.h" #include "lld/Core/DefinedAtom.h" #include "lld/Core/UndefinedAtom.h" +#include "lld/Core/File.h" namespace lld { @@ -28,6 +29,13 @@ public: static const char* const loadNameKeyword; static const char* const valueKeyword; static const char* const fixupsKeyword; + static const char* const fileAtomsKeyword; + static const char* const fileMembersKeyword; + + static const char* const fileKindKeyword; + static const File::Kind fileKindDefault; + static File::Kind fileKind(const char*); + static const char* fileKind(File::Kind); static const char* const definitionKeyword; static const Atom::Definition definitionDefault; diff --git a/lld/lib/Core/YamlReader.cpp b/lld/lib/Core/YamlReader.cpp index 6af7111b20d..7f532958765 100644 --- a/lld/lib/Core/YamlReader.cpp +++ b/lld/lib/Core/YamlReader.cpp @@ -13,6 +13,7 @@ #include "lld/Core/AbsoluteAtom.h" #include "lld/Core/Error.h" #include "lld/Core/File.h" +#include "lld/Core/ArchiveLibraryFile.h" #include "lld/Core/LLVM.h" #include "lld/Core/Platform.h" #include "lld/Core/Reference.h" @@ -30,6 +31,7 @@ #include <cstring> #include <vector> +#include <set> @@ -300,36 +302,47 @@ public: class YAMLDefinedAtom; -class YAMLFile : public File { +class YAMLFile : public ArchiveLibraryFile { public: YAMLFile() - : File("path") - , _lastRefIndex(0) {} + : ArchiveLibraryFile("<anonymous>") + , _lastRefIndex(0) + , _kind(File::kindObject) + , _inArchive(false) { + } + + virtual File::Kind kind() const { + return _kind; + } virtual const atom_collection<DefinedAtom>& defined() const { return _definedAtoms; } virtual const atom_collection<UndefinedAtom>& undefined() const { - return _undefinedAtoms; + return _undefinedAtoms; } virtual const atom_collection<SharedLibraryAtom>& sharedLibrary() const { - return _sharedLibraryAtoms; + return _sharedLibraryAtoms; } virtual const atom_collection<AbsoluteAtom>& absolute() const { - return _absoluteAtoms; + return _absoluteAtoms; } virtual void addAtom(const Atom&) { assert(0 && "cannot add atoms to YAML files"); } + virtual const File *find(StringRef name, bool dataSymbolOnly) const; + void bindTargetReferences(); void addDefinedAtom(YAMLDefinedAtom* atom, const char* refName); void addUndefinedAtom(UndefinedAtom* atom); void addSharedLibraryAtom(SharedLibraryAtom* atom); void addAbsoluteAtom(AbsoluteAtom* atom); Atom* findAtom(const char* name); - + void addMember(const char*); + void setName(const char*); + struct NameAtomPair { NameAtomPair(const char* n, Atom* a) : name(n), atom(a) {} const char* name; @@ -342,7 +355,11 @@ public: atom_collection_vector<AbsoluteAtom> _absoluteAtoms; std::vector<YAMLReference> _references; std::vector<NameAtomPair> _nameToAtomMapping; + std::vector<const char*> _memberNames; + std::vector<YAMLFile*> _memberFiles; unsigned int _lastRefIndex; + File::Kind _kind; + bool _inArchive; }; @@ -643,6 +660,25 @@ void YAMLFile::addAbsoluteAtom(AbsoluteAtom* atom) { _nameToAtomMapping.push_back(NameAtomPair(atom->name().data(), atom)); } +void YAMLFile::addMember(const char* name) { + _memberNames.push_back(name); +} + +void YAMLFile::setName(const char* name) { + _path = StringRef(name); +} + +const File *YAMLFile::find(StringRef name, bool dataSymbolOnly) const { + for (YAMLFile *file : _memberFiles) { + for (const DefinedAtom *atom : file->defined() ) { + if ( name.equals(atom->name()) ) + return file; + } + } + return NULL; +} + + class YAMLAtomState { public: @@ -810,17 +846,21 @@ error_code parseObjectText( llvm::MemoryBuffer *mb , Platform& platform , std::vector<const File *> &result) { std::vector<const YAML::Entry *> entries; + std::vector<YAMLFile*> allFiles; YAML::parse(mb, entries); YAMLFile *file = nullptr; YAMLAtomState atomState(platform); bool inAtoms = false; bool inFixups = false; + bool inMembers = false; int depthForAtoms = -1; int depthForFixups = -1; + int depthForMembers= -1; int lastDepth = -1; bool haveAtom = false; bool haveFixup = false; + bool hasArchives = false; for (std::vector<const YAML::Entry *>::iterator it = entries.begin(); it != entries.end(); ++it) { @@ -833,7 +873,7 @@ error_code parseObjectText( llvm::MemoryBuffer *mb haveAtom = false; } file->bindTargetReferences(); - result.push_back(file); + allFiles.push_back(file); } file = new YAMLFile(); inAtoms = false; @@ -853,9 +893,24 @@ error_code parseObjectText( llvm::MemoryBuffer *mb if (inFixups && (depthForFixups == -1)) { depthForFixups = entry->depth; } - if (strcmp(entry->key, "atoms") == 0) { + if (inMembers && (depthForMembers == -1)) { + depthForMembers = entry->depth; + } + if ( !inFixups && (strcmp(entry->key, KeyValues::fileKindKeyword) == 0) ) { + file->_kind = KeyValues::fileKind(entry->value); + if ( file->_kind == File::kindArchiveLibrary ) + hasArchives = true; + } + else if (strcmp(entry->key, KeyValues::fileMembersKeyword) == 0) { + inMembers = true; + } + else if (strcmp(entry->key, KeyValues::fileAtomsKeyword) == 0) { inAtoms = true; } + else if ( !inAtoms && !inMembers + && (strcmp(entry->key, KeyValues::nameKeyword) == 0) ) { + file->setName(entry->value); + } if (inAtoms) { if (depthForAtoms == entry->depth) { if (entry->beginSequence) { @@ -980,6 +1035,15 @@ error_code parseObjectText( llvm::MemoryBuffer *mb } } } + else if (inMembers) { + if (depthForMembers == entry->depth) { + if (entry->beginSequence) { + if (strcmp(entry->key, KeyValues::nameKeyword) == 0) { + file->addMember(entry->value); + } + } + } + } lastDepth = entry->depth; } if (haveAtom) { @@ -987,8 +1051,31 @@ error_code parseObjectText( llvm::MemoryBuffer *mb } if (file != nullptr) { file->bindTargetReferences(); - result.push_back(file); + allFiles.push_back(file); + } + + // If yaml contained archive files, push members down into archives + if ( hasArchives ) { + for (YAMLFile *f : allFiles) { + if ( f->kind() == File::kindArchiveLibrary ) { + for (const char *memberName : f->_memberNames ) { + for (YAMLFile *f2 : allFiles) { + if ( f2->path().equals(memberName) ) { + f2->_inArchive = true; + f->_memberFiles.push_back(f2); + } + } + } + } + } + } + // Copy files that have not been pushed into archives to result. + for (YAMLFile *f : allFiles) { + if ( ! f->_inArchive ) { + result.push_back(f); + } } + return make_error_code(yaml_reader_error::success); } diff --git a/lld/test/archive-basic.objtxt b/lld/test/archive-basic.objtxt new file mode 100644 index 00000000000..6f13d489d5e --- /dev/null +++ b/lld/test/archive-basic.objtxt @@ -0,0 +1,47 @@ +# RUN: lld-core %s | FileCheck %s + +# +# Tests archives in YAML. Tests that an undefined in a regular file will load +# all atoms in select archive members. +# + +--- +atoms: + - name: foo + type: code + + - name: bar + definition: undefined + +--- +name: bar.o +atoms: + - name: bar + scope: global + type: code + + - name: bar2 + type: code + +--- +name: baz.o +atoms: + - name: baz + scope: global + type: code + + - name: baz2 + type: code +--- +kind: archive +members: + - name: bar.o + - name: baz.o +... + +# CHECK: name: foo +# CHECK: name: bar +# CHECK-NOT: definition: undefined +# CHECK: name: bar2 +# CHECK-NOT: name: baz +# CHECK: ... diff --git a/lld/test/archive-chain.objtxt b/lld/test/archive-chain.objtxt new file mode 100644 index 00000000000..3a5f292629b --- /dev/null +++ b/lld/test/archive-chain.objtxt @@ -0,0 +1,74 @@ +# RUN: lld-core %s | FileCheck %s + +# +# Tests that an undefine in one archive can force a load from another archive. +# + +--- +atoms: + - name: foo + type: code + + - name: bar1 + definition: undefined + +--- +name: bar1.o +atoms: + - name: bar1 + scope: global + type: code + + - name: bar1b + type: code + + - name: baz1 + definition: undefined +--- +name: bar2.o +atoms: + - name: bar2 + scope: global + type: code + + - name: bar2b + type: code + +--- +name: baz1.o +atoms: + - name: baz1 + scope: global + type: code + + - name: baz1b + type: code +--- +name: baz2.o +atoms: + - name: baz2 + scope: global + type: code + + - name: baz2b + type: code +--- +kind: archive +members: + - name: bar1.o + - name: bar2.o +--- +kind: archive +members: + - name: baz1.o + - name: baz2.o +... + +# CHECK: name: foo +# CHECK: name: bar1 +# CHECK: name: bar1b +# CHECK-NOT: name: bar2 +# CHECK: name: baz1 +# CHECK: name: baz1b +# CHECK-NOT: name: baz2 +# CHECK: ... diff --git a/lld/test/archive-tentdef-search.objtxt b/lld/test/archive-tentdef-search.objtxt new file mode 100644 index 00000000000..ce93018f9a9 --- /dev/null +++ b/lld/test/archive-tentdef-search.objtxt @@ -0,0 +1,45 @@ +# RUN: lld-core -commons-search-archives=false %s | FileCheck -check-prefix=CHK1 %s +# RUN: lld-core -commons-search-archives=true %s | FileCheck -check-prefix=CHK2 %s + +# +# Tests that -commons_search_archives cause core linker to look for overrides +# of tentative definition in archives, and that not using that option +# does not search. +# + +--- +atoms: + - name: foo + type: code + + - name: bar + scope: global + content: zero-fill + merge: asTentative + +--- +name: bar.o +atoms: + - name: bar + scope: global + type: data + + - name: bar2 + type: data + +--- +kind: archive +members: + - name: bar.o +... + +# CHK1: name: foo +# CHK1: name: bar +# CHK1: merge: asTentative +# CHK1: ... + +# CHK2: name: foo +# CHK2: name: bar +# CHK2-NOT: merge: asTentative +# CHK2: name: bar2 +# CHK2: ... diff --git a/lld/test/darwin/hello-world.objtxt b/lld/test/darwin/hello-world.objtxt index 2c0aa7a5aae..bb114843750 100644 --- a/lld/test/darwin/hello-world.objtxt +++ b/lld/test/darwin/hello-world.objtxt @@ -1,4 +1,4 @@ -# RUN: lld-core -platform darwin -stubs_pass %s -o %t && llvm-nm %t | FileCheck %s +# RUN: lld-core -platform darwin -stubs-pass %s -o %t && llvm-nm %t | FileCheck %s # # Test that hello-world can be linked into a mach-o executable diff --git a/lld/test/dead-strip-basic.objtxt b/lld/test/dead-strip-basic.objtxt new file mode 100644 index 00000000000..cd09b34b089 --- /dev/null +++ b/lld/test/dead-strip-basic.objtxt @@ -0,0 +1,63 @@ +# RUN: lld-core -dead-strip=true %s | FileCheck -check-prefix=CHK1 %s +# RUN: lld-core -dead-strip=false %s | FileCheck -check-prefix=CHK2 %s + +# +# Test that -dead-strip removes unreachable code and data +# and that not using that option leaves them. +# + +--- +atoms: + - name: entry + dead-strip: never + fixups: + - offset: 1 + kind: pcrel32 + target: bar + - offset: 6 + kind: pcrel32 + target: baz + + - name: mydead1 + scope: global + + - name: bar + definition: undefined + + - name: baz + definition: undefined +--- +atoms: + - name: mydead2 + scope: global + type: data + + - name: bar + scope: global + type: data +--- +atoms: + - name: baz + scope: global + type: code + + - name: mydead3 + type: code +... + + +# CHK1: name: entry +# CHK1-NOT: name: mydead1 +# CHK1: name: bar +# CHK1-NOT: name: mydead2 +# CHK1: name: baz +# CHK1-NOT: name: mydead3 +# CHK1: ... + +# CHK2: name: entry +# CHK2: name: mydead1 +# CHK2: name: mydead2 +# CHK2: name: bar +# CHK2: name: baz +# CHK2: name: mydead3 +# CHK2: ... diff --git a/lld/test/dead-strip-globals.objtxt b/lld/test/dead-strip-globals.objtxt new file mode 100644 index 00000000000..be0d1f8189e --- /dev/null +++ b/lld/test/dead-strip-globals.objtxt @@ -0,0 +1,62 @@ +# RUN: lld-core -dead-strip -keep-globals=true %s | FileCheck -check-prefix=CHK1 %s +# RUN: lld-core -dead-strip -keep-globals=false %s | FileCheck -check-prefix=CHK2 %s + +# +# Test that -keep-globals prevents -dead-strip from removing globals. +# + +--- +atoms: + - name: entry + dead-strip: never + fixups: + - offset: 1 + kind: pcrel32 + target: bar + - offset: 6 + kind: pcrel32 + target: baz + + - name: myglobal1 + scope: global + + - name: bar + definition: undefined + + - name: baz + definition: undefined +--- +atoms: + - name: myglobal2 + scope: global + type: data + + - name: bar + scope: hidden + type: data +--- +atoms: + - name: baz + scope: hidden + type: code + + - name: mydead + type: code +... + + +# CHK1: name: entry +# CHK1: name: myglobal1 +# CHK1: name: myglobal2 +# CHK1: name: bar +# CHK1: name: baz +# CHK1-NOT: name: mydead +# CHK1: ... + +# CHK2: name: entry +# CHK2-NOT: name: myglobal1 +# CHK2-NOT: name: myglobal2 +# CHK2: name: bar +# CHK2: name: baz +# CHK2-NOT: name: mydead +# CHK2: ... diff --git a/lld/test/pass-got-basic.objtxt b/lld/test/pass-got-basic.objtxt index 1309af381c8..bce1d8331d0 100644 --- a/lld/test/pass-got-basic.objtxt +++ b/lld/test/pass-got-basic.objtxt @@ -1,4 +1,4 @@ -# RUN: lld-core %s -got_pass | FileCheck %s +# RUN: lld-core %s -got-pass | FileCheck %s # # Test that GOT pass instantiates GOT entires and alters references diff --git a/lld/test/pass-stubs-basic.objtxt b/lld/test/pass-stubs-basic.objtxt index bb88e418d5c..317372b0400 100644 --- a/lld/test/pass-stubs-basic.objtxt +++ b/lld/test/pass-stubs-basic.objtxt @@ -1,4 +1,4 @@ -# RUN: lld-core %s -stubs_pass | FileCheck %s +# RUN: lld-core %s -stubs-pass | FileCheck %s # # Test that stubs pass adds stubs and rebinds call sites to the stub diff --git a/lld/test/undef-coalesce-error.objtxt b/lld/test/undef-coalesce-error.objtxt index 732cba32d69..ab2092fb952 100644 --- a/lld/test/undef-coalesce-error.objtxt +++ b/lld/test/undef-coalesce-error.objtxt @@ -1,8 +1,10 @@ -# RUN: not lld-core -undefines_are_errors %s 2> %t.err -# RUN: FileCheck < %t.err %s +# RUN: not lld-core -undefines-are-errors %s 2> %t.err +# RUN: FileCheck -check-prefix=CHECKERR < %t.err %s +# RUN: lld-core -undefines-are-errors=false %s | FileCheck %s # -# Test that any remaining undefined symbols cause an error +# Test that -undefines-are-errors triggers and error +# and that not using that option results in undefined atoms. # --- @@ -35,6 +37,15 @@ atoms: definition: undefined ... -# CHECK: free -# CHECK: malloc -# CHECK: symbol(s) not found +# CHECKERR: free +# CHECKERR: malloc +# CHECKERR: symbol(s) not found + +# CHECK: name: foo +# CHECK: name: bar +# CHECK: name: myfunc +# CHECK: name: malloc +# CHECK: definition: undefined +# CHECK: name: free +# CHECK: definition: undefined +# CHECK: ... diff --git a/lld/tools/lld-core/lld-core.cpp b/lld/tools/lld-core/lld-core.cpp index 4ea064b2a7b..794829c5ac5 100644 --- a/lld/tools/lld-core/lld-core.cpp +++ b/lld/tools/lld-core/lld-core.cpp @@ -345,78 +345,43 @@ const TestingPlatform::KindMapping TestingPlatform::_s_kindMappings[] = { }; - -// -// A simple input files wrapper for testing. -// -class TestingInputFiles : public InputFiles { -public: - TestingInputFiles(std::vector<const File*>& f) : _files(f) { } - - // InputFiles interface - virtual void forEachInitialAtom(InputFiles::Handler& handler) const { - for ( const File *file : _files ) { - handler.doFile(*file); - for( const DefinedAtom *atom : file->defined() ) { - handler.doDefinedAtom(*atom); - } - for( const UndefinedAtom *undefAtom : file->undefined() ) { - handler.doUndefinedAtom(*undefAtom); - } - for( const SharedLibraryAtom *shlibAtom : file->sharedLibrary() ) { - handler.doSharedLibraryAtom(*shlibAtom); - } - for( const AbsoluteAtom *absAtom : file->absolute() ) { - handler.doAbsoluteAtom(*absAtom); - } - } - } - - virtual void prependFile(const File &file) { - _files.insert(_files.begin(), &file); - } - - virtual void appendFile(const File &file) { - _files.push_back(&file); - } - - virtual bool searchLibraries(StringRef name, bool searchDylibs, - bool searchArchives, bool dataSymbolOnly, - InputFiles::Handler &) const { - return false; - } - - -private: - std::vector<const File*>& _files; -}; -} - - +} // anon namespace llvm::cl::opt<std::string> -gInputFilePath(llvm::cl::Positional, +cmdLineInputFilePath(llvm::cl::Positional, llvm::cl::desc("<input file>"), llvm::cl::init("-")); llvm::cl::opt<std::string> -gOutputFilePath("o", +cmdLineOutputFilePath("o", llvm::cl::desc("Specify output filename"), llvm::cl::value_desc("filename")); llvm::cl::opt<bool> -gDoStubsPass("stubs_pass", +cmdLineDoStubsPass("stubs-pass", llvm::cl::desc("Run pass to create stub atoms")); llvm::cl::opt<bool> -gDoGotPass("got_pass", +cmdLineDoGotPass("got-pass", llvm::cl::desc("Run pass to create GOT atoms")); llvm::cl::opt<bool> -gUndefinesIsError("undefines_are_errors", +cmdLineUndefinesIsError("undefines-are-errors", llvm::cl::desc("Any undefined symbols at end is an error")); +llvm::cl::opt<bool> +cmdLineCommonsSearchArchives("commons-search-archives", + llvm::cl::desc("Tentative definitions trigger archive search")); + +llvm::cl::opt<bool> +cmdLineDeadStrip("dead-strip", + llvm::cl::desc("Remove unreachable code and data")); + +llvm::cl::opt<bool> +cmdLineGlobalsNotDeadStrip("keep-globals", + llvm::cl::desc("All global symbols are roots for dead-strip")); + enum PlatformChoice { platformTesting, platformDarwin @@ -435,7 +400,10 @@ platformSelected("platform", class TestingResolverOptions : public ResolverOptions { public: TestingResolverOptions() { - _undefinesAreErrors = gUndefinesIsError; + _undefinesAreErrors = cmdLineUndefinesIsError; + _searchArchivesToOverrideTentativeDefinitions = cmdLineCommonsSearchArchives; + _deadCodeStrip = cmdLineDeadStrip; + _globalsAreDeadStripRoots = cmdLineGlobalsNotDeadStrip; } }; @@ -466,7 +434,7 @@ int main(int argc, char *argv[]) { // read input YAML doc into object file(s) std::vector<const File *> files; - if (error(yaml::parseObjectTextFileOrSTDIN(gInputFilePath, + if (error(yaml::parseObjectTextFileOrSTDIN(cmdLineInputFilePath, *platform, files))) { return 1; } @@ -475,7 +443,10 @@ int main(int argc, char *argv[]) { TestingResolverOptions options; // create object to mange input files - TestingInputFiles inputFiles(files); + InputFiles inputFiles; + for (const File *file : files) { + inputFiles.appendFile(*file); + } platform->addFiles(inputFiles); @@ -484,11 +455,11 @@ int main(int argc, char *argv[]) { resolver.resolve(); // run passes - if ( gDoGotPass ) { + if ( cmdLineDoGotPass ) { GOTPass addGot(resolver.resultFile(), *platform); addGot.perform(); } - if ( gDoStubsPass ) { + if ( cmdLineDoStubsPass ) { StubsPass addStubs(resolver.resultFile(), *platform); addStubs.perform(); } @@ -515,7 +486,8 @@ int main(int argc, char *argv[]) { // write new atom graph std::string errorInfo; - const char* outPath = gOutputFilePath.empty() ? "-" : gOutputFilePath.c_str(); + const char* outPath = (cmdLineOutputFilePath.empty() ? "-" + : cmdLineOutputFilePath.c_str()); llvm::raw_fd_ostream out(outPath, errorInfo); if ( platformSelected == platformTesting) { // write atom graph out as YAML doc |

