Adding support to resolve symbols with archive libraries in lld

llvm-svn: 167854
This commit is contained in:
Shankar Easwaran 2012-11-13 18:39:10 +00:00
parent 15b28be9da
commit 70b4dcfbcd
10 changed files with 399 additions and 29 deletions

View File

@ -0,0 +1,80 @@
//===- ReaderWriter/ReaderArchive.h - Archive Library Reader ------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===--------------------------------------------------------------------===//
#ifndef LLD_READER_ARCHIVE_H
#define LLD_READER_ARCHIVE_H
#include "lld/Core/ArchiveLibraryFile.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/system_error.h"
#include "llvm/Object/Archive.h"
#include "lld/Core/File.h"
#include "lld/Core/LLVM.h"
#include "lld/ReaderWriter/Reader.h"
#include "lld/ReaderWriter/ReaderArchive.h"
#include <memory>
#include <bits/unique_ptr.h>
#include <vector>
namespace lld
{
///
/// The ReaderOptionsArchive encapsulates the options used by the ReaderArchive.
/// The option objects are the only way to control the behaviour of Readers.
///
class ReaderOptionsArchive
{
public:
ReaderOptionsArchive(bool is_force_load=false): _isForceLoad(is_force_load),
_reader(nullptr)
{ }
bool isForceLoad() const {
return _isForceLoad;
}
Reader *reader() const {
return _reader;
}
void setReader(Reader *r) {
_reader = r;
}
private:
bool _isForceLoad;
Reader *_reader;
};
// ReaderArchive is a class for reading archive libraries
class ReaderArchive final
{
public:
ReaderArchive(ReaderOptionsArchive &options) : _options(options),
_archive()
{ }
// Returns a vector of Files that are contained in the archive file
// pointed to by the Memorybuffer
virtual error_code parseFile(std::unique_ptr<llvm::MemoryBuffer> mb,
std::vector<std::unique_ptr<File>> &result);
virtual ~ReaderArchive() { }
private:
ReaderOptionsArchive &_options;
std::unique_ptr<llvm::object::Archive> _archive;
};
} // namespace lld
#endif // LLD_READER_ARCHIVE_H

View File

@ -11,6 +11,7 @@
#define LLD_READERWRITER_READER_ELF_H_
#include "lld/ReaderWriter/Reader.h"
#include "lld/ReaderWriter/ReaderArchive.h"
#include "lld/Core/LLVM.h"
@ -56,7 +57,8 @@ protected:
/// ReaderOptionsELF object supplied, so the objects object must not be
/// destroyed before the Reader object.
///
Reader* createReaderELF(const ReaderOptionsELF &options);
Reader* createReaderELF(const ReaderOptionsELF &options,
ReaderOptionsArchive &optionsArchive);

View File

@ -6,4 +6,5 @@ add_subdirectory(YAML)
add_lld_library(lldReaderWriter
Reader.cpp
Writer.cpp
ReaderArchive.cpp
)

View File

@ -12,9 +12,9 @@
//
//===----------------------------------------------------------------------===//
#include "lld/ReaderWriter/ReaderELF.h"
#include "lld/ReaderWriter/ReaderArchive.h"
#include "lld/Core/File.h"
#include "lld/Core/Reference.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
@ -30,6 +30,7 @@
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
#include "llvm/Support/Path.h"
#include <map>
@ -751,43 +752,72 @@ private:
class ReaderELF: public Reader {
public:
ReaderELF(const ReaderOptionsELF &) {}
ReaderELF(const ReaderOptionsELF &readerELFOptions,
ReaderOptionsArchive &readerOptionsArchive)
: _readerELFOptions(readerELFOptions),
_readerOptionsArchive(readerOptionsArchive),
_readerArchive(_readerOptionsArchive) {
_readerOptionsArchive.setReader(this);
}
error_code parseFile(std::unique_ptr<MemoryBuffer> mb, std::vector<
std::unique_ptr<File> > &result) {
std::pair<unsigned char, unsigned char> Ident =
llvm::object::getElfArchType(&*mb);
llvm::error_code ec;
// Instantiate the correct FileELF template instance
// based on the Ident pair. Once the File is created
// we push the file to the vector of files already
// created during parser's life.
std::unique_ptr<File> > &result) {
llvm::error_code ec;
std::unique_ptr<File> f;
std::pair<unsigned char, unsigned char> Ident;
if (Ident.first == llvm::ELF::ELFCLASS32 && Ident.second
== llvm::ELF::ELFDATA2LSB) {
f.reset(new FileELF<llvm::support::little, false>(std::move(mb), ec));
llvm::sys::LLVMFileType fileType =
llvm::sys::IdentifyFileType(mb->getBufferStart(),
static_cast<unsigned>(mb->getBufferSize()));
switch (fileType) {
} else if (Ident.first == llvm::ELF::ELFCLASS32 && Ident.second
== llvm::ELF::ELFDATA2MSB) {
f.reset(new FileELF<llvm::support::big, false> (std::move(mb), ec));
case llvm::sys::ELF_Relocatable_FileType:
} else if (Ident.first == llvm::ELF::ELFCLASS64 && Ident.second
== llvm::ELF::ELFDATA2MSB) {
f.reset(new FileELF<llvm::support::big, true> (std::move(mb), ec));
Ident = llvm::object::getElfArchType(&*mb);
// Instantiate the correct FileELF template instance
// based on the Ident pair. Once the File is created
// we push the file to the vector of files already
// created during parser's life.
} else if (Ident.first == llvm::ELF::ELFCLASS64 && Ident.second
== llvm::ELF::ELFDATA2LSB) {
f.reset(new FileELF<llvm::support::little, true> (std::move(mb), ec));
if (Ident.first == llvm::ELF::ELFCLASS32 && Ident.second
== llvm::ELF::ELFDATA2LSB) {
f.reset(new FileELF<llvm::support::little, false>(std::move(mb), ec));
} else if (Ident.first == llvm::ELF::ELFCLASS32 && Ident.second
== llvm::ELF::ELFDATA2MSB) {
f.reset(new FileELF<llvm::support::big, false> (std::move(mb), ec));
} else if (Ident.first == llvm::ELF::ELFCLASS64 && Ident.second
== llvm::ELF::ELFDATA2MSB) {
f.reset(new FileELF<llvm::support::big, true> (std::move(mb), ec));
} else if (Ident.first == llvm::ELF::ELFCLASS64 && Ident.second
== llvm::ELF::ELFDATA2LSB) {
f.reset(new FileELF<llvm::support::little, true> (std::move(mb), ec));
}
if (!ec)
result.push_back(std::move(f));
break;
case llvm::sys::Archive_FileType:
ec = _readerArchive.parseFile(std::move(mb), result);
break;
default:
llvm_unreachable("not supported format");
break;
}
if (ec)
return ec;
result.push_back(std::move(f));
return error_code::success();
}
private:
const ReaderOptionsELF &_readerELFOptions;
ReaderOptionsArchive &_readerOptionsArchive;
ReaderArchive _readerArchive;
};
} // namespace anonymous
@ -800,8 +830,9 @@ ReaderOptionsELF::ReaderOptionsELF() {
ReaderOptionsELF::~ReaderOptionsELF() {
}
Reader *createReaderELF(const ReaderOptionsELF &options) {
return new ReaderELF(options);
Reader *createReaderELF(const ReaderOptionsELF &options,
ReaderOptionsArchive &optionsArchive) {
return new ReaderELF(options, optionsArchive);
}
} // namespace LLD

View File

@ -0,0 +1,160 @@
//===- lib/ReaderWriter/ReaderArchive.cpp - Archive Library Reader--------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===---------------------------------------------------------------------===//
#include "lld/ReaderWriter/ReaderArchive.h"
namespace lld
{
// The FileArchive class represents an Archive Library file
class FileArchive : public ArchiveLibraryFile {
public:
virtual ~FileArchive() { }
/// Check if any member of the archive contains an Atom with the
/// specified name and return the File object for that member, or nullptr.
virtual const File *find(StringRef name, bool dataSymbolOnly) const {
error_code ec;
llvm::object::Archive::child_iterator ci;
ci = _archive.get()->findSym(name);
if (ci == _archive->end_children())
return nullptr;
if (dataSymbolOnly && (ec = isDataSymbol(ci->getBuffer(), name)))
return nullptr;
std::vector<std::unique_ptr<File>> result;
if ((ec = _options.reader()->parseFile(std::unique_ptr<MemoryBuffer>
(ci->getBuffer()), result)))
return nullptr;
assert(result.size() == 1);
// give up the pointer so that this object no longer manages it
for (std::unique_ptr<File> &f : result) {
return f.release();
}
return nullptr;
}
virtual void addAtom(const Atom&) {
llvm_unreachable("cannot add atoms to archive files");
}
virtual const atom_collection<DefinedAtom> &defined() const {
return _definedAtoms;
}
virtual const atom_collection<UndefinedAtom> &undefined() const {
return _undefinedAtoms;
}
virtual const atom_collection<SharedLibraryAtom> &sharedLibrary() const {
return _sharedLibraryAtoms;
}
virtual const atom_collection<AbsoluteAtom> &absolute() const {
return _absoluteAtoms;
}
protected:
error_code isDataSymbol(MemoryBuffer *mb, StringRef symbol) const
{
llvm::object::ObjectFile *obj =
llvm::object::ObjectFile::createObjectFile(mb);
error_code ec;
llvm::object::SymbolRef::Type symtype;
uint32_t symflags;
llvm::object::symbol_iterator ibegin = obj->begin_symbols();
llvm::object::symbol_iterator iend = obj->end_symbols();
StringRef symbolname;
for (llvm::object::symbol_iterator i = ibegin; i != iend; i.increment(ec)) {
if (ec) return ec;
// Get symbol name
if ((ec = (i->getName(symbolname)))) return ec;
if (symbolname != symbol)
continue;
// Get symbol flags
if ((ec = (i->getFlags(symflags)))) return ec;
if (symflags <= llvm::object::SymbolRef::SF_Undefined)
continue;
// Get Symbol Type
if ((ec = (i->getType(symtype)))) return ec;
if (symtype == llvm::object::SymbolRef::ST_Data) {
return error_code::success();
}
}
return llvm::object::object_error::parse_failed;
}
private:
llvm::MemoryBuffer *_mb;
std::unique_ptr<llvm::object::Archive> _archive;
const ReaderOptionsArchive _options;
atom_collection_vector<DefinedAtom> _definedAtoms;
atom_collection_vector<UndefinedAtom> _undefinedAtoms;
atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
public:
/// only subclasses of ArchiveLibraryFile can be instantiated
explicit FileArchive(llvm::MemoryBuffer *mb,
const ReaderOptionsArchive &options,
error_code &ec)
:ArchiveLibraryFile(mb->getBufferIdentifier()),
_mb(mb),
_archive(nullptr),
_options(options) {
auto *archive_obj = new llvm::object::Archive(mb, ec);
if (ec)
return;
_archive.reset(archive_obj);
}
}; // class FileArchive
// Returns a vector of Files that are contained in the archive file
// pointed to by the MemoryBuffer
error_code ReaderArchive::parseFile(std::unique_ptr<llvm::MemoryBuffer> mb,
std::vector<std::unique_ptr<File>> &result) {
error_code ec;
if (_options.isForceLoad())
{
_archive.reset(new llvm::object::Archive(mb.release(), ec));
if (ec)
return ec;
for (auto mf = _archive->begin_children(),
me = _archive->end_children(); mf != me; ++mf)
{
if ((ec = _options.reader()->parseFile(std::unique_ptr<MemoryBuffer>
(mf->getBuffer()), result)))
return ec;
}
} else {
std::unique_ptr<File> f;
f.reset(new FileArchive(mb.release(), _options, ec));
if (ec)
return ec;
result.push_back(std::move(f));
}
return llvm::error_code::success();
}
} // namespace lld

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,48 @@
# Tests the functionality of archive libraries reading
# and resolution
# Note: The binary files would not be required once we have support to generate
# binary archives from textual(yaml) input
#
# Tests generated using the source files below
# main file
# int main()
# {
# fn();
# return 0;
# }
#
# archive file
# int fn()
# {
# return 0;
# }
#
# int fn1()
# {
# return 0;
# }
# gcc -c main.c fn.c fn1.c
RUN: lld-core -reader ELF %p/Inputs/mainobj.x86_64 %p/Inputs/libfnarchive.x86_64 -force-load | FileCheck -check-prefix FORCELOAD %s
FORCELOAD: - name: fn1
FORCELOAD: scope: global
FORCELOAD: type: code
FORCELOAD: section-choice: custom-required
FORCELOAD: section-name: .text
FORCELOAD: content: [ 55, 48, 89, E5, B8, 00, 00, 00, 00, 5D, C3 ]
FORCELOAD: - name: fn
FORCELOAD: scope: global
FORCELOAD: type: code
FORCELOAD: section-choice: custom-required
FORCELOAD: section-name: .text
FORCELOAD: content: [ 55, 48, 89, E5, B8, 00, 00, 00, 00, 5D, C3 ]
FORCELOAD: - name: main.c
FORCELOAD: definition: absolute
FORCELOAD: value: 0x0
FORCELOAD: - name: fn1.c
FORCELOAD: definition: absolute
FORCELOAD: value: 0x0
FORCELOAD: - name: fn.c
FORCELOAD: definition: absolute
FORCELOAD: value: 0x0

View File

@ -0,0 +1,39 @@
# Tests the functionality of archive libraries reading
# and resolution
# Note: The binary files would not be required once we have support to generate
# binary archives from textual(yaml) input
#
# Tests generated using the source files below
# main file
# int main()
# {
# fn();
# return 0;
# }
#
# archive file
# int fn()
# {
# return 0;
# }
#
# int fn1()
# {
# return 0;
# }
# gcc -c main.c fn.c fn1.c
RUN: lld-core -reader ELF %p/Inputs/mainobj.x86_64 %p/Inputs/libfnarchive.x86_64 | FileCheck -check-prefix NOFORCELOAD %s
NOFORCELOAD: - name: fn
NOFORCELOAD: scope: global
NOFORCELOAD: type: code
NOFORCELOAD: section-choice: custom-required
NOFORCELOAD: section-name: .text
NOFORCELOAD: content: [ 55, 48, 89, E5, B8, 00, 00, 00, 00, 5D, C3 ]
NOFORCELOAD: - name: main.c
NOFORCELOAD: definition: absolute
NOFORCELOAD: value: 0x0
NOFORCELOAD: - name: fn.c
NOFORCELOAD: definition: absolute
NOFORCELOAD: value: 0x0

View File

@ -12,6 +12,7 @@
#include "lld/Core/Pass.h"
#include "lld/Core/Resolver.h"
#include "lld/ReaderWriter/Reader.h"
#include "lld/ReaderWriter/ReaderArchive.h"
#include "lld/ReaderWriter/ReaderNative.h"
#include "lld/ReaderWriter/ReaderYAML.h"
#include "lld/ReaderWriter/ReaderELF.h"
@ -75,6 +76,10 @@ llvm::cl::opt<bool>
cmdLineUndefinesIsError("undefines-are-errors",
llvm::cl::desc("Any undefined symbols at end is an error"));
llvm::cl::opt<bool>
cmdLineForceLoad("force-load",
llvm::cl::desc("force load all members of the archive"));
llvm::cl::opt<bool>
cmdLineCommonsSearchArchives("commons-search-archives",
llvm::cl::desc("Tentative definitions trigger archive search"));
@ -214,6 +219,8 @@ int main(int argc, char *argv[]) {
// create object to mange input files
InputFiles inputFiles;
ReaderOptionsArchive readerOptionsArchive(cmdLineForceLoad);
// read input files into in-memory File objects
TestingReaderOptionsYAML readerOptionsYAML;
@ -231,7 +238,9 @@ int main(int argc, char *argv[]) {
reader = createReaderPECOFF(lld::ReaderOptionsPECOFF());
break;
case readerELF:
reader = createReaderELF(lld::ReaderOptionsELF());
reader = createReaderELF(lld::ReaderOptionsELF(),
readerOptionsArchive);
break;
default:
reader = createReaderYAML(readerOptionsYAML);