llvm-project/lld/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp
Rui Ueyama b24241bae3 [PECOFF] Implement the reader for the import library.
This is the first patch toward full DLL support. With this patch, lld can
read .lib file for a DLL.

Reviewers: Bigcheese

CC: llvm-commits

Differential Revision: http://llvm-reviews.chandlerc.com/D987

llvm-svn: 184101
2013-06-17 18:43:13 +00:00

151 lines
4.8 KiB
C++

//===- lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp ---------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file \brief This file provides a way to read an import library
/// member in a .lib file.
///
/// In Windows, archive files with .lib file extension serve two different
/// purposes.
///
/// - For static linking: An archive file in this use case contains multiple
/// normal .obj files and is used for static linking. This is the same
/// usage as .a file in Unix.
///
/// - For dynamic linking: An archive file in this case contains pseudo .obj
/// files to describe exported symbols of a DLL. Each .obj file in an archive
/// has a name of an exported symbol and a DLL filename from which the symbol
/// can be imported. When you link a DLL on Windows, you pass the name of the
/// .lib file for the DLL instead of the DLL filename itself. That is the
/// Windows way of linking a shared library.
///
/// This file contains a function to parse the pseudo object file.
///
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "ReaderImportHeader"
#include "lld/Core/File.h"
#include "lld/Core/Error.h"
#include "lld/Core/SharedLibraryAtom.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/COFF.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Memory.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
#include <map>
#include <vector>
#include <cstring>
using namespace lld;
using namespace llvm;
namespace lld {
namespace coff {
namespace {
class COFFDynamicAtom : public SharedLibraryAtom {
public:
COFFDynamicAtom(File &file, StringRef symbolName, StringRef dllName)
: _owningFile(file), _symbolName(symbolName), _dllName(dllName) {}
virtual const File &file() const { return _owningFile; }
virtual StringRef name() const { return _symbolName; }
virtual StringRef loadName() const { return _dllName; }
virtual bool canBeNullAtRuntime() const { return true; }
private:
const File &_owningFile;
StringRef _symbolName;
StringRef _dllName;
};
class FileImportLibrary : public File {
public:
FileImportLibrary(const TargetInfo &ti,
std::unique_ptr<llvm::MemoryBuffer> mb,
llvm::error_code &ec)
: File(mb->getBufferIdentifier(), kindSharedLibrary), _targetInfo(ti) {
const char *buf = mb->getBufferStart();
const char *end = mb->getBufferEnd();
// The size of the string that follows the header.
uint32_t dataSize =
*reinterpret_cast<const support::ulittle32_t *>(buf + 12);
// Check if the total size is valid. The file header is 20 byte long.
if (end - buf != 20 + dataSize) {
ec = make_error_code(native_reader_error::unknown_file_format);
return;
}
StringRef symbolName(buf + 20);
StringRef dllName(buf + 20 + symbolName.size() + 1);
auto *atom = new (allocator.Allocate<COFFDynamicAtom>())
COFFDynamicAtom(*this, symbolName, dllName);
_sharedLibraryAtoms._atoms.push_back(atom);
ec = error_code::success();
}
virtual const atom_collection<DefinedAtom> &defined() const {
return _noDefinedAtoms;
}
virtual const atom_collection<UndefinedAtom> &undefined() const {
return _noUndefinedAtoms;
}
virtual const atom_collection<SharedLibraryAtom> &sharedLibrary() const {
return _sharedLibraryAtoms;
}
virtual const atom_collection<AbsoluteAtom> &absolute() const {
return _noAbsoluteAtoms;
}
virtual const TargetInfo &getTargetInfo() const { return _targetInfo; }
private:
atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
const TargetInfo &_targetInfo;
mutable llvm::BumpPtrAllocator allocator;
};
} // end anonymous namespace
error_code parseCOFFImportLibrary(const TargetInfo &targetInfo,
std::unique_ptr<MemoryBuffer> &mb,
std::vector<std::unique_ptr<File> > &result) {
// Check the file magic.
const char *buf = mb->getBufferStart();
const char *end = mb->getBufferEnd();
if (end - buf < 20 || memcmp(buf, "\0\0\xFF\xFF", 4))
return make_error_code(native_reader_error::unknown_file_format);
error_code ec;
auto file = std::unique_ptr<File>(
new FileImportLibrary(targetInfo, std::move(mb), ec));
if (ec)
return ec;
result.push_back(std::move(file));
return error_code::success();
}
} // end namespace coff
} // end namespace lld