mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-02-13 22:00:14 +00:00
Adding support to resolve symbols with archive libraries in lld
llvm-svn: 167854
This commit is contained in:
parent
15b28be9da
commit
70b4dcfbcd
80
lld/include/lld/ReaderWriter/ReaderArchive.h
Normal file
80
lld/include/lld/ReaderWriter/ReaderArchive.h
Normal 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
|
@ -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);
|
||||
|
||||
|
||||
|
||||
|
@ -6,4 +6,5 @@ add_subdirectory(YAML)
|
||||
add_lld_library(lldReaderWriter
|
||||
Reader.cpp
|
||||
Writer.cpp
|
||||
ReaderArchive.cpp
|
||||
)
|
||||
|
@ -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
|
||||
|
160
lld/lib/ReaderWriter/ReaderArchive.cpp
Normal file
160
lld/lib/ReaderWriter/ReaderArchive.cpp
Normal 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
|
BIN
lld/test/elf/Inputs/libfnarchive.x86_64
Normal file
BIN
lld/test/elf/Inputs/libfnarchive.x86_64
Normal file
Binary file not shown.
BIN
lld/test/elf/Inputs/mainobj.x86_64
Normal file
BIN
lld/test/elf/Inputs/mainobj.x86_64
Normal file
Binary file not shown.
48
lld/test/elf/archive-elf-forceload.objtxt
Normal file
48
lld/test/elf/archive-elf-forceload.objtxt
Normal 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
|
39
lld/test/elf/archive-elf.objtxt
Normal file
39
lld/test/elf/archive-elf.objtxt
Normal 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
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user