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:
Nick Kledzik 2012-04-20 01:24:37 +00:00
parent 205ee3b389
commit 20e652d627
22 changed files with 735 additions and 107 deletions

View File

@ -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_

View File

@ -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;
};

View File

@ -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

View File

@ -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_

View File

@ -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();

View File

@ -1,6 +1,7 @@
add_lld_library(lldCore
Error.cpp
File.cpp
InputFiles.cpp
NativeFileFormat.h
NativeReader.cpp
NativeWriter.cpp

View File

@ -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

View File

@ -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);
}
}
}
}

View File

@ -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

View File

@ -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 {

View File

@ -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;

View File

@ -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);
}

View File

@ -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: ...

View File

@ -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: ...

View File

@ -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: ...

View File

@ -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

View File

@ -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: ...

View File

@ -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: ...

View File

@ -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

View File

@ -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

View File

@ -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: ...

View File

@ -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