Add way to represent static archives in yaml test cases.
Add SharedLibraryFile and ArchiveLibraryFile subclasses of File.
Add command line options to lld-core to set various ResolverOptions settings
and added lots of test cases to verify the options work.
llvm-svn: 155183
diff --git a/lld/lib/Core/CMakeLists.txt b/lld/lib/Core/CMakeLists.txt
index 2e39dff..076d335 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 0000000..5840151
--- /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 a758a86..f16a67a 100644
--- a/lld/lib/Core/Resolver.cpp
+++ b/lld/lib/Core/Resolver.cpp
@@ -137,7 +137,7 @@
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 @@
}
}
// 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 e22697490..0bfe6da 100644
--- a/lld/lib/Core/SymbolTable.cpp
+++ b/lld/lib/Core/SymbolTable.cpp
@@ -330,4 +330,16 @@
}
}
+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 abf6f16..19abf4f 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::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 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 f474fb3..2265c5f 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 @@
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 6af7111..7f53295 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 @@
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 @@
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 @@
_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 @@
, 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 @@
haveAtom = false;
}
file->bindTargetReferences();
- result.push_back(file);
+ allFiles.push_back(file);
}
file = new YAMLFile();
inAtoms = false;
@@ -853,9 +893,24 @@
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 @@
}
}
}
+ 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 @@
}
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);
}