forked from OSchip/llvm-project
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
This commit is contained in:
parent
205ee3b389
commit
20e652d627
|
@ -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_
|
|
@ -27,8 +27,11 @@ namespace lld {
|
||||||
/// object file (.o) to be parsed by some reader and produce a single
|
/// object file (.o) to be parsed by some reader and produce a single
|
||||||
/// File object that represents the content of that object file.
|
/// File object that represents the content of that object file.
|
||||||
///
|
///
|
||||||
/// The File class has *begin() and *end() methods for use iterating through
|
/// To iterate through the Atoms in a File there are four methods that
|
||||||
/// the Atoms in a File object.
|
/// 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
|
/// The Atom objects in a File are owned by the File object. The Atom objects
|
||||||
/// are destroyed when the File object is destroyed.
|
/// are destroyed when the File object is destroyed.
|
||||||
|
@ -37,6 +40,18 @@ class File {
|
||||||
public:
|
public:
|
||||||
virtual ~File();
|
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
|
/// For error messages and debugging, this returns the path to the file
|
||||||
/// which was used to create this object (e.g. "/tmp/foo.o").
|
/// which was used to create this object (e.g. "/tmp/foo.o").
|
||||||
StringRef path() const {
|
StringRef path() const {
|
||||||
|
@ -49,6 +64,11 @@ public:
|
||||||
/// be ascertained, this method returns the empty string.
|
/// be ascertained, this method returns the empty string.
|
||||||
virtual StringRef translationUnitSource() const;
|
virtual StringRef translationUnitSource() const;
|
||||||
|
|
||||||
|
|
||||||
|
static inline bool classof(const File *) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
template <typename T> class atom_iterator; // forward reference
|
template <typename T> class atom_iterator; // forward reference
|
||||||
public:
|
public:
|
||||||
|
@ -144,7 +164,7 @@ public:
|
||||||
/// Must be implemented to return the atom_collection object for
|
/// Must be implemented to return the atom_collection object for
|
||||||
/// all AbsoluteAtoms in this File.
|
/// all AbsoluteAtoms in this File.
|
||||||
virtual const atom_collection<AbsoluteAtom>& absolute() const = 0;
|
virtual const atom_collection<AbsoluteAtom>& absolute() const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// This is a convenience class for File subclasses which manage their
|
/// This is a convenience class for File subclasses which manage their
|
||||||
/// atoms as a simple std::vector<>.
|
/// atoms as a simple std::vector<>.
|
||||||
|
@ -152,11 +172,12 @@ protected:
|
||||||
class atom_collection_vector : public atom_collection<T> {
|
class atom_collection_vector : public atom_collection<T> {
|
||||||
public:
|
public:
|
||||||
virtual atom_iterator<T> begin() const {
|
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{
|
virtual atom_iterator<T> end() const{
|
||||||
return atom_iterator<T>(*this, reinterpret_cast<const void*>
|
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 {
|
virtual const T* deref(const void* it) const {
|
||||||
return *reinterpret_cast<const T* const*>(it);
|
return *reinterpret_cast<const T* const*>(it);
|
||||||
|
@ -169,8 +190,6 @@ protected:
|
||||||
std::vector<const T*> _atoms;
|
std::vector<const T*> _atoms;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
StringRef _path;
|
StringRef _path;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -34,23 +34,30 @@ public:
|
||||||
virtual void doAbsoluteAtom(const class AbsoluteAtom &) = 0;
|
virtual void doAbsoluteAtom(const class AbsoluteAtom &) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
InputFiles();
|
||||||
|
virtual ~InputFiles();
|
||||||
|
|
||||||
/// Used by platforms to insert platform specific files.
|
/// 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.
|
/// 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
|
/// @brief iterates all atoms in initial files
|
||||||
virtual void forEachInitialAtom(Handler &) const = 0;
|
virtual void forEachInitialAtom(Handler &) const;
|
||||||
|
|
||||||
/// @brief searches libraries for name
|
/// @brief searches libraries for name
|
||||||
virtual bool searchLibraries( StringRef name
|
virtual bool searchLibraries( StringRef name
|
||||||
, bool searchDylibs
|
, bool searchSharedLibs
|
||||||
, bool searchArchives
|
, bool searchArchives
|
||||||
, bool dataSymbolOnly
|
, bool dataSymbolOnly
|
||||||
, Handler &) const = 0;
|
, Handler &) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void handleFile(const File *file, InputFiles::Handler &handler) const;
|
||||||
|
|
||||||
|
std::vector<const File*> _files;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace lld
|
} // namespace lld
|
||||||
|
|
|
@ -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_
|
|
@ -59,6 +59,9 @@ public:
|
||||||
|
|
||||||
/// @brief returns vector of remaining UndefinedAtoms
|
/// @brief returns vector of remaining UndefinedAtoms
|
||||||
void undefines(std::vector<const Atom *>&);
|
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
|
/// @brief count of by-name entries in symbol table
|
||||||
unsigned int size();
|
unsigned int size();
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
add_lld_library(lldCore
|
add_lld_library(lldCore
|
||||||
Error.cpp
|
Error.cpp
|
||||||
File.cpp
|
File.cpp
|
||||||
|
InputFiles.cpp
|
||||||
NativeFileFormat.h
|
NativeFileFormat.h
|
||||||
NativeReader.cpp
|
NativeReader.cpp
|
||||||
NativeWriter.cpp
|
NativeWriter.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
|
|
@ -137,7 +137,7 @@ void Resolver::addAtoms(const std::vector<const DefinedAtom*>& newAtoms) {
|
||||||
void Resolver::resolveUndefines() {
|
void Resolver::resolveUndefines() {
|
||||||
const bool searchArchives =
|
const bool searchArchives =
|
||||||
_options.searchArchivesToOverrideTentativeDefinitions();
|
_options.searchArchivesToOverrideTentativeDefinitions();
|
||||||
const bool searchDylibs =
|
const bool searchSharedLibs =
|
||||||
_options.searchSharedLibrariesToOverrideTentativeDefinitions();
|
_options.searchSharedLibrariesToOverrideTentativeDefinitions();
|
||||||
|
|
||||||
// keep looping until no more undefines were added in last loop
|
// 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
|
// search libraries for overrides of common symbols
|
||||||
if (searchArchives || searchDylibs) {
|
if (searchArchives || searchSharedLibs) {
|
||||||
std::vector<const Atom *> tents;
|
std::vector<StringRef> tentDefNames;
|
||||||
for ( const Atom *tent : tents ) {
|
_symbolTable.tentativeDefinitions(tentDefNames);
|
||||||
if (const DefinedAtom* defAtom = dyn_cast<DefinedAtom>(tent)) {
|
for ( StringRef tentDefName : tentDefNames ) {
|
||||||
if ( defAtom->merge() == DefinedAtom::mergeAsTentative )
|
// Load for previous tentative may also have loaded
|
||||||
tents.push_back(defAtom);
|
// something that overrode this tentative, so always check.
|
||||||
}
|
const Atom *curAtom = _symbolTable.findByName(tentDefName);
|
||||||
}
|
|
||||||
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);
|
|
||||||
assert(curAtom != nullptr);
|
assert(curAtom != nullptr);
|
||||||
if (const DefinedAtom* curDefAtom = dyn_cast<DefinedAtom>(curAtom)) {
|
if (const DefinedAtom* curDefAtom = dyn_cast<DefinedAtom>(curAtom)) {
|
||||||
if (curDefAtom->merge() == DefinedAtom::mergeAsTentative )
|
if (curDefAtom->merge() == DefinedAtom::mergeAsTentative ) {
|
||||||
_inputFiles.searchLibraries(tentName, searchDylibs,
|
// Still tentative definition, so look for override.
|
||||||
true, true, *this);
|
_inputFiles.searchLibraries(tentDefName, searchSharedLibs,
|
||||||
|
searchArchives, true, *this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
} // namespace lld
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "YamlKeyValues.h"
|
#include "YamlKeyValues.h"
|
||||||
|
|
||||||
#include "llvm/Support/ErrorHandling.h"
|
#include "llvm/Support/ErrorHandling.h"
|
||||||
|
#include "lld/Core/File.h"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
@ -40,6 +41,9 @@ const char* const KeyValues::fixupsKindKeyword = "kind";
|
||||||
const char* const KeyValues::fixupsOffsetKeyword = "offset";
|
const char* const KeyValues::fixupsOffsetKeyword = "offset";
|
||||||
const char* const KeyValues::fixupsTargetKeyword = "target";
|
const char* const KeyValues::fixupsTargetKeyword = "target";
|
||||||
const char* const KeyValues::fixupsAddendKeyword = "addend";
|
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::isThumbDefault = false;
|
||||||
const bool KeyValues::isAliasDefault = false;
|
const bool KeyValues::isAliasDefault = false;
|
||||||
const UndefinedAtom::CanBeNull KeyValues::canBeNullDefault = UndefinedAtom::canBeNullNever;
|
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 {
|
struct DefinitionMapping {
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "lld/Core/Atom.h"
|
#include "lld/Core/Atom.h"
|
||||||
#include "lld/Core/DefinedAtom.h"
|
#include "lld/Core/DefinedAtom.h"
|
||||||
#include "lld/Core/UndefinedAtom.h"
|
#include "lld/Core/UndefinedAtom.h"
|
||||||
|
#include "lld/Core/File.h"
|
||||||
|
|
||||||
|
|
||||||
namespace lld {
|
namespace lld {
|
||||||
|
@ -28,6 +29,13 @@ public:
|
||||||
static const char* const loadNameKeyword;
|
static const char* const loadNameKeyword;
|
||||||
static const char* const valueKeyword;
|
static const char* const valueKeyword;
|
||||||
static const char* const fixupsKeyword;
|
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 char* const definitionKeyword;
|
||||||
static const Atom::Definition definitionDefault;
|
static const Atom::Definition definitionDefault;
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "lld/Core/AbsoluteAtom.h"
|
#include "lld/Core/AbsoluteAtom.h"
|
||||||
#include "lld/Core/Error.h"
|
#include "lld/Core/Error.h"
|
||||||
#include "lld/Core/File.h"
|
#include "lld/Core/File.h"
|
||||||
|
#include "lld/Core/ArchiveLibraryFile.h"
|
||||||
#include "lld/Core/LLVM.h"
|
#include "lld/Core/LLVM.h"
|
||||||
#include "lld/Core/Platform.h"
|
#include "lld/Core/Platform.h"
|
||||||
#include "lld/Core/Reference.h"
|
#include "lld/Core/Reference.h"
|
||||||
|
@ -30,6 +31,7 @@
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -300,36 +302,47 @@ public:
|
||||||
|
|
||||||
class YAMLDefinedAtom;
|
class YAMLDefinedAtom;
|
||||||
|
|
||||||
class YAMLFile : public File {
|
class YAMLFile : public ArchiveLibraryFile {
|
||||||
public:
|
public:
|
||||||
YAMLFile()
|
YAMLFile()
|
||||||
: File("path")
|
: ArchiveLibraryFile("<anonymous>")
|
||||||
, _lastRefIndex(0) {}
|
, _lastRefIndex(0)
|
||||||
|
, _kind(File::kindObject)
|
||||||
|
, _inArchive(false) {
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual File::Kind kind() const {
|
||||||
|
return _kind;
|
||||||
|
}
|
||||||
|
|
||||||
virtual const atom_collection<DefinedAtom>& defined() const {
|
virtual const atom_collection<DefinedAtom>& defined() const {
|
||||||
return _definedAtoms;
|
return _definedAtoms;
|
||||||
}
|
}
|
||||||
virtual const atom_collection<UndefinedAtom>& undefined() const {
|
virtual const atom_collection<UndefinedAtom>& undefined() const {
|
||||||
return _undefinedAtoms;
|
return _undefinedAtoms;
|
||||||
}
|
}
|
||||||
virtual const atom_collection<SharedLibraryAtom>& sharedLibrary() const {
|
virtual const atom_collection<SharedLibraryAtom>& sharedLibrary() const {
|
||||||
return _sharedLibraryAtoms;
|
return _sharedLibraryAtoms;
|
||||||
}
|
}
|
||||||
virtual const atom_collection<AbsoluteAtom>& absolute() const {
|
virtual const atom_collection<AbsoluteAtom>& absolute() const {
|
||||||
return _absoluteAtoms;
|
return _absoluteAtoms;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void addAtom(const Atom&) {
|
virtual void addAtom(const Atom&) {
|
||||||
assert(0 && "cannot add atoms to YAML files");
|
assert(0 && "cannot add atoms to YAML files");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual const File *find(StringRef name, bool dataSymbolOnly) const;
|
||||||
|
|
||||||
void bindTargetReferences();
|
void bindTargetReferences();
|
||||||
void addDefinedAtom(YAMLDefinedAtom* atom, const char* refName);
|
void addDefinedAtom(YAMLDefinedAtom* atom, const char* refName);
|
||||||
void addUndefinedAtom(UndefinedAtom* atom);
|
void addUndefinedAtom(UndefinedAtom* atom);
|
||||||
void addSharedLibraryAtom(SharedLibraryAtom* atom);
|
void addSharedLibraryAtom(SharedLibraryAtom* atom);
|
||||||
void addAbsoluteAtom(AbsoluteAtom* atom);
|
void addAbsoluteAtom(AbsoluteAtom* atom);
|
||||||
Atom* findAtom(const char* name);
|
Atom* findAtom(const char* name);
|
||||||
|
void addMember(const char*);
|
||||||
|
void setName(const char*);
|
||||||
|
|
||||||
struct NameAtomPair {
|
struct NameAtomPair {
|
||||||
NameAtomPair(const char* n, Atom* a) : name(n), atom(a) {}
|
NameAtomPair(const char* n, Atom* a) : name(n), atom(a) {}
|
||||||
const char* name;
|
const char* name;
|
||||||
|
@ -342,7 +355,11 @@ public:
|
||||||
atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
|
atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
|
||||||
std::vector<YAMLReference> _references;
|
std::vector<YAMLReference> _references;
|
||||||
std::vector<NameAtomPair> _nameToAtomMapping;
|
std::vector<NameAtomPair> _nameToAtomMapping;
|
||||||
|
std::vector<const char*> _memberNames;
|
||||||
|
std::vector<YAMLFile*> _memberFiles;
|
||||||
unsigned int _lastRefIndex;
|
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));
|
_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 {
|
class YAMLAtomState {
|
||||||
public:
|
public:
|
||||||
|
@ -810,17 +846,21 @@ error_code parseObjectText( llvm::MemoryBuffer *mb
|
||||||
, Platform& platform
|
, Platform& platform
|
||||||
, std::vector<const File *> &result) {
|
, std::vector<const File *> &result) {
|
||||||
std::vector<const YAML::Entry *> entries;
|
std::vector<const YAML::Entry *> entries;
|
||||||
|
std::vector<YAMLFile*> allFiles;
|
||||||
YAML::parse(mb, entries);
|
YAML::parse(mb, entries);
|
||||||
|
|
||||||
YAMLFile *file = nullptr;
|
YAMLFile *file = nullptr;
|
||||||
YAMLAtomState atomState(platform);
|
YAMLAtomState atomState(platform);
|
||||||
bool inAtoms = false;
|
bool inAtoms = false;
|
||||||
bool inFixups = false;
|
bool inFixups = false;
|
||||||
|
bool inMembers = false;
|
||||||
int depthForAtoms = -1;
|
int depthForAtoms = -1;
|
||||||
int depthForFixups = -1;
|
int depthForFixups = -1;
|
||||||
|
int depthForMembers= -1;
|
||||||
int lastDepth = -1;
|
int lastDepth = -1;
|
||||||
bool haveAtom = false;
|
bool haveAtom = false;
|
||||||
bool haveFixup = false;
|
bool haveFixup = false;
|
||||||
|
bool hasArchives = false;
|
||||||
|
|
||||||
for (std::vector<const YAML::Entry *>::iterator it = entries.begin();
|
for (std::vector<const YAML::Entry *>::iterator it = entries.begin();
|
||||||
it != entries.end(); ++it) {
|
it != entries.end(); ++it) {
|
||||||
|
@ -833,7 +873,7 @@ error_code parseObjectText( llvm::MemoryBuffer *mb
|
||||||
haveAtom = false;
|
haveAtom = false;
|
||||||
}
|
}
|
||||||
file->bindTargetReferences();
|
file->bindTargetReferences();
|
||||||
result.push_back(file);
|
allFiles.push_back(file);
|
||||||
}
|
}
|
||||||
file = new YAMLFile();
|
file = new YAMLFile();
|
||||||
inAtoms = false;
|
inAtoms = false;
|
||||||
|
@ -853,9 +893,24 @@ error_code parseObjectText( llvm::MemoryBuffer *mb
|
||||||
if (inFixups && (depthForFixups == -1)) {
|
if (inFixups && (depthForFixups == -1)) {
|
||||||
depthForFixups = entry->depth;
|
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;
|
inAtoms = true;
|
||||||
}
|
}
|
||||||
|
else if ( !inAtoms && !inMembers
|
||||||
|
&& (strcmp(entry->key, KeyValues::nameKeyword) == 0) ) {
|
||||||
|
file->setName(entry->value);
|
||||||
|
}
|
||||||
if (inAtoms) {
|
if (inAtoms) {
|
||||||
if (depthForAtoms == entry->depth) {
|
if (depthForAtoms == entry->depth) {
|
||||||
if (entry->beginSequence) {
|
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;
|
lastDepth = entry->depth;
|
||||||
}
|
}
|
||||||
if (haveAtom) {
|
if (haveAtom) {
|
||||||
|
@ -987,8 +1051,31 @@ error_code parseObjectText( llvm::MemoryBuffer *mb
|
||||||
}
|
}
|
||||||
if (file != nullptr) {
|
if (file != nullptr) {
|
||||||
file->bindTargetReferences();
|
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);
|
return make_error_code(yaml_reader_error::success);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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: ...
|
|
@ -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: ...
|
|
@ -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: ...
|
|
@ -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
|
# Test that hello-world can be linked into a mach-o executable
|
||||||
|
|
|
@ -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: ...
|
|
@ -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: ...
|
|
@ -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
|
# Test that GOT pass instantiates GOT entires and alters references
|
||||||
|
|
|
@ -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
|
# Test that stubs pass adds stubs and rebinds call sites to the stub
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
# RUN: not lld-core -undefines_are_errors %s 2> %t.err
|
# RUN: not lld-core -undefines-are-errors %s 2> %t.err
|
||||||
# RUN: FileCheck < %t.err %s
|
# 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
|
definition: undefined
|
||||||
...
|
...
|
||||||
|
|
||||||
# CHECK: free
|
# CHECKERR: free
|
||||||
# CHECK: malloc
|
# CHECKERR: malloc
|
||||||
# CHECK: symbol(s) not found
|
# 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: ...
|
||||||
|
|
|
@ -345,78 +345,43 @@ const TestingPlatform::KindMapping TestingPlatform::_s_kindMappings[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // anon namespace
|
||||||
//
|
|
||||||
// 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;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
llvm::cl::opt<std::string>
|
llvm::cl::opt<std::string>
|
||||||
gInputFilePath(llvm::cl::Positional,
|
cmdLineInputFilePath(llvm::cl::Positional,
|
||||||
llvm::cl::desc("<input file>"),
|
llvm::cl::desc("<input file>"),
|
||||||
llvm::cl::init("-"));
|
llvm::cl::init("-"));
|
||||||
|
|
||||||
llvm::cl::opt<std::string>
|
llvm::cl::opt<std::string>
|
||||||
gOutputFilePath("o",
|
cmdLineOutputFilePath("o",
|
||||||
llvm::cl::desc("Specify output filename"),
|
llvm::cl::desc("Specify output filename"),
|
||||||
llvm::cl::value_desc("filename"));
|
llvm::cl::value_desc("filename"));
|
||||||
|
|
||||||
llvm::cl::opt<bool>
|
llvm::cl::opt<bool>
|
||||||
gDoStubsPass("stubs_pass",
|
cmdLineDoStubsPass("stubs-pass",
|
||||||
llvm::cl::desc("Run pass to create stub atoms"));
|
llvm::cl::desc("Run pass to create stub atoms"));
|
||||||
|
|
||||||
llvm::cl::opt<bool>
|
llvm::cl::opt<bool>
|
||||||
gDoGotPass("got_pass",
|
cmdLineDoGotPass("got-pass",
|
||||||
llvm::cl::desc("Run pass to create GOT atoms"));
|
llvm::cl::desc("Run pass to create GOT atoms"));
|
||||||
|
|
||||||
llvm::cl::opt<bool>
|
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::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 {
|
enum PlatformChoice {
|
||||||
platformTesting, platformDarwin
|
platformTesting, platformDarwin
|
||||||
|
@ -435,7 +400,10 @@ platformSelected("platform",
|
||||||
class TestingResolverOptions : public ResolverOptions {
|
class TestingResolverOptions : public ResolverOptions {
|
||||||
public:
|
public:
|
||||||
TestingResolverOptions() {
|
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)
|
// read input YAML doc into object file(s)
|
||||||
std::vector<const File *> files;
|
std::vector<const File *> files;
|
||||||
if (error(yaml::parseObjectTextFileOrSTDIN(gInputFilePath,
|
if (error(yaml::parseObjectTextFileOrSTDIN(cmdLineInputFilePath,
|
||||||
*platform, files))) {
|
*platform, files))) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -475,7 +443,10 @@ int main(int argc, char *argv[]) {
|
||||||
TestingResolverOptions options;
|
TestingResolverOptions options;
|
||||||
|
|
||||||
// create object to mange input files
|
// create object to mange input files
|
||||||
TestingInputFiles inputFiles(files);
|
InputFiles inputFiles;
|
||||||
|
for (const File *file : files) {
|
||||||
|
inputFiles.appendFile(*file);
|
||||||
|
}
|
||||||
|
|
||||||
platform->addFiles(inputFiles);
|
platform->addFiles(inputFiles);
|
||||||
|
|
||||||
|
@ -484,11 +455,11 @@ int main(int argc, char *argv[]) {
|
||||||
resolver.resolve();
|
resolver.resolve();
|
||||||
|
|
||||||
// run passes
|
// run passes
|
||||||
if ( gDoGotPass ) {
|
if ( cmdLineDoGotPass ) {
|
||||||
GOTPass addGot(resolver.resultFile(), *platform);
|
GOTPass addGot(resolver.resultFile(), *platform);
|
||||||
addGot.perform();
|
addGot.perform();
|
||||||
}
|
}
|
||||||
if ( gDoStubsPass ) {
|
if ( cmdLineDoStubsPass ) {
|
||||||
StubsPass addStubs(resolver.resultFile(), *platform);
|
StubsPass addStubs(resolver.resultFile(), *platform);
|
||||||
addStubs.perform();
|
addStubs.perform();
|
||||||
}
|
}
|
||||||
|
@ -515,7 +486,8 @@ int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
// write new atom graph
|
// write new atom graph
|
||||||
std::string errorInfo;
|
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);
|
llvm::raw_fd_ostream out(outPath, errorInfo);
|
||||||
if ( platformSelected == platformTesting) {
|
if ( platformSelected == platformTesting) {
|
||||||
// write atom graph out as YAML doc
|
// write atom graph out as YAML doc
|
||||||
|
|
Loading…
Reference in New Issue