forked from OSchip/llvm-project
[PECOFF] Support linking against DLL.
This patch adds a new pass, IdataPass, to transform shared atom references to real references and to construct the .idata section data. With this patch lld can produce a working Hello World program by linking it against kernel32.dll and user32.dll. Reviewers: Bigcheese CC: llvm-commits Differential Revision: http://llvm-reviews.chandlerc.com/D1096 llvm-svn: 186071
This commit is contained in:
parent
67ddcd6dd0
commit
c8a53795ab
|
@ -144,6 +144,7 @@ public:
|
|||
typeTLVInitialData, // initial data for a TLV [Darwin]
|
||||
typeTLVInitialZeroFill, // TLV initial zero fill data [Darwin]
|
||||
typeTLVInitializerPtr, // pointer to thread local initializer [Darwin]
|
||||
typeDataDirectoryEntry, // linker created for data directory header [PECOFF]
|
||||
};
|
||||
|
||||
// Permission bits for atoms and segments. The order of these values are
|
||||
|
|
|
@ -51,6 +51,7 @@ DefinedAtom::ContentPermissions DefinedAtom::permissions(ContentType type) {
|
|||
case typeLazyPointer:
|
||||
case typeLazyDylibPointer:
|
||||
case typeThunkTLV:
|
||||
case typeDataDirectoryEntry:
|
||||
return permRW_;
|
||||
|
||||
case typeGOT:
|
||||
|
|
|
@ -223,27 +223,45 @@ public:
|
|||
virtual uint64_t ordinal() const { return 0; }
|
||||
virtual Scope scope() const { return scopeGlobal; }
|
||||
virtual Alignment alignment() const { return Alignment(1); }
|
||||
virtual uint64_t size() const { return _data->size(); }
|
||||
virtual ArrayRef<uint8_t> rawContent() const { return *_data; }
|
||||
virtual uint64_t size() const { return _data.size(); }
|
||||
virtual ArrayRef<uint8_t> rawContent() const { return _data; }
|
||||
|
||||
protected:
|
||||
COFFLinkerInternalAtom(const File &file, std::vector<uint8_t> *data,
|
||||
COFFLinkerInternalAtom(const File &file, std::vector<uint8_t> data,
|
||||
StringRef symbolName = "")
|
||||
: COFFBaseDefinedAtom(file, symbolName, Kind::Internal), _data(data) {}
|
||||
: COFFBaseDefinedAtom(file, symbolName, Kind::Internal),
|
||||
_data(std::move(data)) {}
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> *_data;
|
||||
std::vector<uint8_t> _data;
|
||||
};
|
||||
|
||||
// A COFFDataDirectoryAtom represents an entry of Optional Data Directory in the
|
||||
// COFF header.
|
||||
class COFFDataDirectoryAtom : public COFFLinkerInternalAtom {
|
||||
public:
|
||||
COFFDataDirectoryAtom(const File &file, uint64_t ordinal)
|
||||
: COFFLinkerInternalAtom(file, std::vector<uint8_t>(8)),
|
||||
_ordinal(ordinal) {}
|
||||
|
||||
virtual uint64_t ordinal() const { return _ordinal; }
|
||||
virtual ContentType contentType() const { return typeDataDirectoryEntry; }
|
||||
virtual ContentPermissions permissions() const { return permR__; }
|
||||
|
||||
private:
|
||||
uint64_t _ordinal;
|
||||
};
|
||||
|
||||
// A COFFSharedLibraryAtom represents a symbol for data in an import library. A
|
||||
// reference to a COFFSharedLibraryAtom will be transformed to a real reference
|
||||
// to an import address table entry in a pass.
|
||||
// to an import address table entry in Idata pass.
|
||||
class COFFSharedLibraryAtom : public SharedLibraryAtom {
|
||||
public:
|
||||
COFFSharedLibraryAtom(const File &file, uint16_t hint,
|
||||
StringRef symbolName, StringRef loadName)
|
||||
: _file(file), _hint(hint), _unmangledName(symbolName),
|
||||
_loadName(loadName), _mangledName(addImpPrefix(symbolName)) {}
|
||||
_loadName(loadName), _mangledName(addImpPrefix(symbolName)),
|
||||
_importTableEntry(nullptr) {}
|
||||
|
||||
virtual const File &file() const { return _file; }
|
||||
uint16_t hint() const { return _hint; }
|
||||
|
@ -252,6 +270,14 @@ public:
|
|||
virtual StringRef loadName() const { return _loadName; }
|
||||
virtual bool canBeNullAtRuntime() const { return false; }
|
||||
|
||||
void setImportTableEntry(const DefinedAtom *atom) {
|
||||
_importTableEntry = atom;
|
||||
}
|
||||
|
||||
const DefinedAtom *getImportTableEntry() const {
|
||||
return _importTableEntry;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Mangle the symbol name by adding "__imp_" prefix. See the file comment of
|
||||
/// ReaderImportHeader.cpp for details about the prefix.
|
||||
|
@ -266,6 +292,7 @@ private:
|
|||
StringRef _unmangledName;
|
||||
StringRef _loadName;
|
||||
std::string _mangledName;
|
||||
const DefinedAtom *_importTableEntry;
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -0,0 +1,313 @@
|
|||
//===- lib/ReaderWriter/PECOFF/IdataPass.h---------------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file \brief This linker pass creates atoms for the DLL import
|
||||
/// information. The defined atoms constructed in this pass will go into .idata
|
||||
/// section, unless .idata section is merged with other section such as .data.
|
||||
///
|
||||
/// For the details of the .idata section format, see Microsoft PE/COFF
|
||||
/// Specification section 5.4, The .idata Section.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_READER_WRITER_PE_COFF_IDATA_PASS_H_
|
||||
#define LLD_READER_WRITER_PE_COFF_IDATA_PASS_H_
|
||||
|
||||
#include "Atoms.h"
|
||||
|
||||
#include "lld/Core/File.h"
|
||||
#include "lld/Core/Pass.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/COFF.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
|
||||
using lld::coff::COFFBaseDefinedAtom;
|
||||
using lld::coff::COFFDefinedAtom;
|
||||
using lld::coff::COFFLinkerInternalAtom;
|
||||
using lld::coff::COFFReference;
|
||||
using lld::coff::COFFSharedLibraryAtom;
|
||||
using lld::coff::COFFSharedLibraryAtom;
|
||||
using llvm::COFF::ImportDirectoryTableEntry;
|
||||
using std::map;
|
||||
using std::vector;
|
||||
|
||||
namespace lld {
|
||||
namespace pecoff {
|
||||
|
||||
namespace {
|
||||
class DLLNameAtom;
|
||||
class HintNameAtom;
|
||||
class ImportTableEntryAtom;
|
||||
|
||||
void addDir32NBReloc(COFFBaseDefinedAtom *atom, const Atom *target,
|
||||
size_t offsetInAtom) {
|
||||
atom->addReference(std::unique_ptr<COFFReference>(new COFFReference(
|
||||
target, offsetInAtom, llvm::COFF::IMAGE_REL_I386_DIR32NB)));
|
||||
}
|
||||
|
||||
// A state object of this pass.
|
||||
struct Context {
|
||||
explicit Context(MutableFile &f) : file(f) {}
|
||||
|
||||
MutableFile &file;
|
||||
|
||||
// The object to accumulate idata atoms. Idata atoms need to be grouped by
|
||||
// type and be continuous in the output file. To force such layout, we
|
||||
// accumulate all atoms created in the pass in the following vectors, and add
|
||||
// layout edges when finishing the pass.
|
||||
vector<COFFBaseDefinedAtom *> importDirectories;
|
||||
vector<ImportTableEntryAtom *> importLookupTables;
|
||||
vector<ImportTableEntryAtom *> importAddressTables;
|
||||
vector<HintNameAtom *> hintNameAtoms;
|
||||
vector<DLLNameAtom *> dllNameAtoms;
|
||||
|
||||
map<StringRef, COFFBaseDefinedAtom *> sharedToDefinedAtom;
|
||||
};
|
||||
|
||||
/// The root class of all idata atoms.
|
||||
class IdataAtom : public COFFLinkerInternalAtom {
|
||||
public:
|
||||
virtual ContentType contentType() const { return typeData; }
|
||||
virtual ContentPermissions permissions() const { return permR__; }
|
||||
|
||||
protected:
|
||||
IdataAtom(MutableFile &file, vector<uint8_t> data)
|
||||
: COFFLinkerInternalAtom(file, data) {
|
||||
file.addAtom(*this);
|
||||
}
|
||||
};
|
||||
|
||||
/// A DLLNameAtom contains a name of a DLL and is referenced by the Name RVA
|
||||
/// field in the import directory table entry.
|
||||
class DLLNameAtom : public IdataAtom {
|
||||
public:
|
||||
DLLNameAtom(Context &ctx, StringRef name)
|
||||
: IdataAtom(ctx.file, stringRefToVector(name)) {
|
||||
ctx.dllNameAtoms.push_back(this);
|
||||
}
|
||||
|
||||
private:
|
||||
vector<uint8_t> stringRefToVector(StringRef name) {
|
||||
vector<uint8_t> ret(name.size() + 1);
|
||||
memcpy(&ret[0], name.data(), name.size());
|
||||
ret[name.size()] = 0;
|
||||
return std::move(ret);
|
||||
}
|
||||
};
|
||||
|
||||
/// A HintNameAtom represents a symbol that will be imported from a DLL at
|
||||
/// runtime. It consists with an optional hint, which is a small integer, and a
|
||||
/// symbol name.
|
||||
///
|
||||
/// A hint is an index of the export pointer table in a DLL. If the import
|
||||
/// library and DLL is in sync (i.e., ".lib" and ".dll" is for the same version
|
||||
/// or the symbol ordinal is maintained by hand with ".exp" file), the PE/COFF
|
||||
/// loader can find the symbol quickly.
|
||||
class HintNameAtom : public IdataAtom {
|
||||
public:
|
||||
HintNameAtom(Context &ctx, uint16_t hint, StringRef name)
|
||||
: IdataAtom(ctx.file, assembleRawContent(hint, name)), _name(name) {
|
||||
ctx.hintNameAtoms.push_back(this);
|
||||
}
|
||||
|
||||
StringRef getContentString() { return _name; }
|
||||
|
||||
private:
|
||||
// The first two bytes of the content is a hint, followed by a null-terminated
|
||||
// symbol name. The total size needs to be multiple of 2.
|
||||
vector<uint8_t> assembleRawContent(uint16_t hint, StringRef name) {
|
||||
name = unmangle(name);
|
||||
size_t size = llvm::RoundUpToAlignment(sizeof(hint) + name.size() + 1, 2);
|
||||
vector<uint8_t> ret(size);
|
||||
ret[name.size()] = 0;
|
||||
ret[name.size() - 1] = 0;
|
||||
*reinterpret_cast<llvm::support::ulittle16_t *>(&ret[0]) = hint;
|
||||
std::memcpy(&ret[2], name.data(), name.size());
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// Undo name mangling. In Windows, the symbol name for function is encoded
|
||||
/// as "_name@X", where X is the number of bytes of the arguments.
|
||||
StringRef unmangle(StringRef mangledName) {
|
||||
assert(mangledName.startswith("_"));
|
||||
return mangledName.substr(1).split('@').first;
|
||||
}
|
||||
|
||||
StringRef _name;
|
||||
};
|
||||
|
||||
class ImportTableEntryAtom : public IdataAtom {
|
||||
public:
|
||||
explicit ImportTableEntryAtom(Context &ctx)
|
||||
: IdataAtom(ctx.file, vector<uint8_t>(4, 0)) {}
|
||||
};
|
||||
|
||||
/// An ImportDirectoryAtom includes information to load a DLL, including a DLL
|
||||
/// name, symbols that will be resolved from the DLL, and the import address
|
||||
/// table that are overwritten by the loader with the pointers to the referenced
|
||||
/// items. The executable has one ImportDirectoryAtom per one imported DLL.
|
||||
class ImportDirectoryAtom : public IdataAtom {
|
||||
public:
|
||||
ImportDirectoryAtom(Context &ctx, StringRef loadName,
|
||||
const vector<COFFSharedLibraryAtom *> &sharedAtoms)
|
||||
: IdataAtom(ctx.file, vector<uint8_t>(20, 0)) {
|
||||
addRelocations(ctx, loadName, sharedAtoms);
|
||||
ctx.importDirectories.push_back(this);
|
||||
}
|
||||
|
||||
private:
|
||||
void addRelocations(Context &ctx, StringRef loadName,
|
||||
const vector<COFFSharedLibraryAtom *> &sharedAtoms) {
|
||||
size_t lookupEnd = ctx.importLookupTables.size();
|
||||
size_t addressEnd = ctx.importAddressTables.size();
|
||||
|
||||
// Create parallel arrays. The contents of the two are initially the
|
||||
// same. The PE/COFF loader overwrites the import address tables with the
|
||||
// pointers to the referenced items after loading the executable into
|
||||
// memory.
|
||||
addImportTableAtoms(ctx, sharedAtoms, false, ctx.importLookupTables);
|
||||
addImportTableAtoms(ctx, sharedAtoms, true, ctx.importAddressTables);
|
||||
|
||||
addDir32NBReloc(this, ctx.importLookupTables[lookupEnd],
|
||||
offsetof(ImportDirectoryTableEntry, ImportLookupTableRVA));
|
||||
addDir32NBReloc(this, ctx.importAddressTables[addressEnd],
|
||||
offsetof(ImportDirectoryTableEntry, ImportAddressTableRVA));
|
||||
addDir32NBReloc(this, new (_alloc) DLLNameAtom(ctx, loadName),
|
||||
offsetof(ImportDirectoryTableEntry, NameRVA));
|
||||
}
|
||||
|
||||
// Creates atoms for an import lookup table. The import lookup table is an
|
||||
// array of pointers to hint/name atoms. The array needs to be terminated with
|
||||
// the NULL entry.
|
||||
void addImportTableAtoms(Context &ctx,
|
||||
const vector<COFFSharedLibraryAtom *> &sharedAtoms,
|
||||
bool shouldAddReference,
|
||||
vector<ImportTableEntryAtom *> &ret) const {
|
||||
for (COFFSharedLibraryAtom *shared : sharedAtoms) {
|
||||
HintNameAtom *hintName = createHintNameAtom(ctx, shared);
|
||||
ImportTableEntryAtom *entry = new (_alloc) ImportTableEntryAtom(ctx);
|
||||
addDir32NBReloc(entry, hintName, 0);
|
||||
ret.push_back(entry);
|
||||
if (shouldAddReference)
|
||||
shared->setImportTableEntry(entry);
|
||||
}
|
||||
// Add the NULL entry.
|
||||
ret.push_back(new (_alloc) ImportTableEntryAtom(ctx));
|
||||
}
|
||||
|
||||
HintNameAtom *createHintNameAtom(
|
||||
Context &ctx, const COFFSharedLibraryAtom *atom) const {
|
||||
return new (_alloc) HintNameAtom(ctx, atom->hint(), atom->unmangledName());
|
||||
}
|
||||
|
||||
mutable llvm::BumpPtrAllocator _alloc;
|
||||
};
|
||||
|
||||
/// The last NULL entry in the import directory.
|
||||
class NullImportDirectoryAtom : public IdataAtom {
|
||||
public:
|
||||
explicit NullImportDirectoryAtom(Context &ctx)
|
||||
: IdataAtom(ctx.file, vector<uint8_t>(20, 0)) {
|
||||
ctx.importDirectories.push_back(this);
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
class IdataPass : public lld::Pass {
|
||||
public:
|
||||
virtual void perform(MutableFile &file) {
|
||||
if (file.sharedLibrary().size() == 0)
|
||||
return;
|
||||
|
||||
Context ctx(file);
|
||||
map<StringRef, vector<COFFSharedLibraryAtom *>> sharedAtoms =
|
||||
groupByLoadName(file);
|
||||
for (auto i : sharedAtoms) {
|
||||
StringRef loadName = i.first;
|
||||
vector<COFFSharedLibraryAtom *> &atoms = i.second;
|
||||
createImportDirectory(ctx, loadName, atoms);
|
||||
}
|
||||
new (_alloc) NullImportDirectoryAtom(ctx);
|
||||
connectAtoms(ctx);
|
||||
createDataDirectoryAtoms(ctx);
|
||||
replaceSharedLibraryAtoms(ctx);
|
||||
}
|
||||
|
||||
private:
|
||||
map<StringRef, vector<COFFSharedLibraryAtom *>>
|
||||
groupByLoadName(MutableFile &file) {
|
||||
map<StringRef, COFFSharedLibraryAtom *> uniqueAtoms;
|
||||
for (const SharedLibraryAtom *atom : file.sharedLibrary())
|
||||
uniqueAtoms[atom->name()] = (COFFSharedLibraryAtom *)atom;
|
||||
|
||||
map<StringRef, vector<COFFSharedLibraryAtom *>> ret;
|
||||
for (auto i : uniqueAtoms) {
|
||||
COFFSharedLibraryAtom *atom = i.second;
|
||||
ret[atom->loadName()].push_back(atom);
|
||||
}
|
||||
return std::move(ret);
|
||||
}
|
||||
|
||||
void
|
||||
createImportDirectory(Context &ctx, StringRef loadName,
|
||||
vector<COFFSharedLibraryAtom *> &dllAtoms) {
|
||||
new (_alloc) ImportDirectoryAtom(ctx, loadName, dllAtoms);
|
||||
}
|
||||
|
||||
void connectAtoms(Context &ctx) {
|
||||
coff::connectAtomsWithLayoutEdge(ctx.importDirectories);
|
||||
coff::connectAtomsWithLayoutEdge(ctx.importLookupTables);
|
||||
coff::connectAtomsWithLayoutEdge(ctx.importAddressTables);
|
||||
coff::connectAtomsWithLayoutEdge(ctx.hintNameAtoms);
|
||||
coff::connectAtomsWithLayoutEdge(ctx.dllNameAtoms);
|
||||
}
|
||||
|
||||
/// The addresses of the import dirctory and the import address table needs to
|
||||
/// be set to the COFF Optional Data Directory header. A COFFDataDirectoryAtom
|
||||
/// represents an entry in the data directory header. We create atoms of class
|
||||
/// COFFDataDirectoryAtom and set relocations to them, so that the address
|
||||
/// will be set by the writer.
|
||||
void createDataDirectoryAtoms(Context &ctx) {
|
||||
auto *dir = new (_alloc) coff::COFFDataDirectoryAtom(ctx.file, 1);
|
||||
addDir32NBReloc(dir, ctx.importDirectories[0], 0);
|
||||
ctx.file.addAtom(*dir);
|
||||
|
||||
auto *iat = new (_alloc) coff::COFFDataDirectoryAtom(ctx.file, 12);
|
||||
addDir32NBReloc(iat, ctx.importAddressTables[0], 0);
|
||||
ctx.file.addAtom(*iat);
|
||||
}
|
||||
|
||||
/// Transforms a reference to a COFFSharedLibraryAtom to a real reference.
|
||||
void replaceSharedLibraryAtoms(Context &ctx) {
|
||||
for (const DefinedAtom *atom : ctx.file.defined()) {
|
||||
for (const Reference *ref : *atom) {
|
||||
const Atom *target = ref->target();
|
||||
auto *sharedAtom = dyn_cast<SharedLibraryAtom>(target);
|
||||
if (!sharedAtom)
|
||||
continue;
|
||||
auto *coffSharedAtom = (COFFSharedLibraryAtom *)sharedAtom;
|
||||
const DefinedAtom *entry = coffSharedAtom->getImportTableEntry();
|
||||
const_cast<Reference *>(ref)->setTarget(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
llvm::BumpPtrAllocator _alloc;
|
||||
};
|
||||
|
||||
} // namespace pecoff
|
||||
} // namespace lld
|
||||
|
||||
#endif
|
|
@ -8,6 +8,7 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "GroupedSectionsPass.h"
|
||||
#include "IdataPass.h"
|
||||
|
||||
#include "lld/Core/PassManager.h"
|
||||
#include "lld/Passes/LayoutPass.h"
|
||||
|
@ -59,6 +60,7 @@ PECOFFTargetInfo::stringFromRelocKind(Reference::Kind kind) const {
|
|||
|
||||
void PECOFFTargetInfo::addPasses(PassManager &pm) const {
|
||||
pm.add(std::unique_ptr<Pass>(new pecoff::GroupedSectionsPass()));
|
||||
pm.add(std::unique_ptr<Pass>(new pecoff::IdataPass()));
|
||||
pm.add(std::unique_ptr<Pass>(new LayoutPass()));
|
||||
}
|
||||
|
||||
|
|
|
@ -135,7 +135,8 @@ namespace {
|
|||
class FuncAtom : public COFFLinkerInternalAtom {
|
||||
public:
|
||||
FuncAtom(const File &file, StringRef symbolName)
|
||||
: COFFLinkerInternalAtom(file, &rawContent, symbolName) {}
|
||||
: COFFLinkerInternalAtom(file, std::vector<uint8_t>(rawContent),
|
||||
symbolName) {}
|
||||
|
||||
virtual uint64_t ordinal() const { return 0; }
|
||||
virtual Scope scope() const { return scopeGlobal; }
|
||||
|
|
|
@ -64,7 +64,8 @@ class Chunk {
|
|||
public:
|
||||
enum Kind {
|
||||
kindHeader,
|
||||
kindSection
|
||||
kindSection,
|
||||
kindDataDirectory
|
||||
};
|
||||
|
||||
explicit Chunk(Kind kind) : _kind(kind), _size(0), _align(1) {}
|
||||
|
@ -243,43 +244,6 @@ private:
|
|||
llvm::object::pe32_header _peHeader;
|
||||
};
|
||||
|
||||
/// A DataDirectoryChunk represents data directory entries that follows the PE
|
||||
/// header in the output file. An entry consists of an 8 byte field that
|
||||
/// indicates a relative virtual address (the starting address of the entry data
|
||||
/// in memory) and 8 byte entry data size.
|
||||
class DataDirectoryChunk : public HeaderChunk {
|
||||
public:
|
||||
DataDirectoryChunk() : HeaderChunk() {
|
||||
_size = sizeof(_dirs);
|
||||
std::memset(_dirs, 0, sizeof(_dirs));
|
||||
}
|
||||
|
||||
// Set the import table address and size. The import table is usually in
|
||||
// .idata section, but because .idata section can be merged with other section
|
||||
// such as .rdata, the given address can be in any section.
|
||||
void setImportTableDirectoryRva(uint32_t rva, uint32_t size) {
|
||||
_dirs[1].RelativeVirtualAddress = rva;
|
||||
_dirs[1].Size = size;
|
||||
}
|
||||
|
||||
// Set the address and size of the import address table (IAT). This is
|
||||
// redundant information because the import table contains the file offset of
|
||||
// the IAT. Although it's redundant, it needs to be set properly, otherwise
|
||||
// the loader refuses the executable.
|
||||
void setImportAddressTableRva(uint32_t rva, uint32_t size) {
|
||||
_dirs[12].RelativeVirtualAddress = rva;
|
||||
_dirs[12].Size = size;
|
||||
}
|
||||
|
||||
virtual void write(uint8_t *fileBuffer) {
|
||||
fileBuffer += fileOffset();
|
||||
std::memcpy(fileBuffer, &_dirs, sizeof(_dirs));
|
||||
}
|
||||
|
||||
private:
|
||||
llvm::object::data_directory _dirs[16];
|
||||
};
|
||||
|
||||
/// A SectionHeaderTableChunk represents Section Table Header of PE/COFF
|
||||
/// format, which is a list of section headers.
|
||||
class SectionHeaderTableChunk : public HeaderChunk {
|
||||
|
@ -363,11 +327,51 @@ public:
|
|||
layout->_virtualAddr += rva;
|
||||
}
|
||||
|
||||
static bool classof(const Chunk *c) {
|
||||
Kind kind = c->getKind();
|
||||
return kind == kindSection || kind == kindDataDirectory;
|
||||
}
|
||||
|
||||
protected:
|
||||
AtomChunk(Kind kind) : Chunk(kind) {}
|
||||
std::vector<AtomLayout *> _atomLayouts;
|
||||
};
|
||||
|
||||
/// A DataDirectoryChunk represents data directory entries that follows the PE
|
||||
/// header in the output file. An entry consists of an 8 byte field that
|
||||
/// indicates a relative virtual address (the starting address of the entry data
|
||||
/// in memory) and 8 byte entry data size.
|
||||
class DataDirectoryChunk : public AtomChunk {
|
||||
public:
|
||||
DataDirectoryChunk(const File &linkedFile)
|
||||
: AtomChunk(kindDataDirectory) {
|
||||
// Extract atoms from the linked file and append them to this section.
|
||||
for (const DefinedAtom *atom : linkedFile.defined()) {
|
||||
if (atom->contentType() == DefinedAtom::typeDataDirectoryEntry) {
|
||||
uint64_t size = atom->ordinal() * sizeof(llvm::object::data_directory);
|
||||
_atomLayouts.push_back(new (_alloc) AtomLayout(atom, size, size));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual uint64_t size() const {
|
||||
return sizeof(llvm::object::data_directory) * 16;
|
||||
}
|
||||
|
||||
virtual void write(uint8_t *fileBuffer) {
|
||||
fileBuffer += fileOffset();
|
||||
for (const AtomLayout *layout : _atomLayouts) {
|
||||
if (!layout)
|
||||
continue;
|
||||
ArrayRef<uint8_t> content = static_cast<const DefinedAtom *>(layout->_atom)->rawContent();
|
||||
std::memcpy(fileBuffer + layout->_fileOffset, content.data(), content.size());
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
mutable llvm::BumpPtrAllocator _alloc;
|
||||
};
|
||||
|
||||
/// A SectionChunk represents a section containing atoms. It consists of a
|
||||
/// section header that to be written to PECOFF header and atoms which to be
|
||||
/// written to the raw data section.
|
||||
|
@ -453,13 +457,13 @@ private:
|
|||
}
|
||||
|
||||
void appendAtom(const DefinedAtom *atom) {
|
||||
auto *layout = new (_storage) AtomLayout(atom, _size, _size);
|
||||
auto *layout = new (_alloc) AtomLayout(atom, _size, _size);
|
||||
_atomLayouts.push_back(layout);
|
||||
_size += atom->rawContent().size();
|
||||
}
|
||||
|
||||
llvm::object::coff_section _sectionHeader;
|
||||
mutable llvm::BumpPtrAllocator _storage;
|
||||
mutable llvm::BumpPtrAllocator _alloc;
|
||||
};
|
||||
|
||||
void SectionHeaderTableChunk::addSection(SectionChunk *chunk) {
|
||||
|
@ -545,10 +549,10 @@ private:
|
|||
void applyRelocations(uint8_t *bufferStart) {
|
||||
std::map<const Atom *, uint64_t> atomToVirtualAddr;
|
||||
for (auto &cp : _chunks)
|
||||
if (SectionChunk *chunk = dyn_cast<SectionChunk>(&*cp))
|
||||
if (AtomChunk *chunk = dyn_cast<AtomChunk>(&*cp))
|
||||
chunk->buildAtomToVirtualAddr(atomToVirtualAddr);
|
||||
for (auto &cp : _chunks)
|
||||
if (SectionChunk *chunk = dyn_cast<SectionChunk>(&*cp))
|
||||
if (AtomChunk *chunk = dyn_cast<AtomChunk>(&*cp))
|
||||
chunk->applyRelocations(bufferStart, atomToVirtualAddr);
|
||||
}
|
||||
|
||||
|
@ -586,7 +590,7 @@ public:
|
|||
// Create file chunks and add them to the list.
|
||||
auto *dosStub = new DOSStubChunk();
|
||||
auto *peHeader = new PEHeaderChunk(_PECOFFTargetInfo);
|
||||
auto *dataDirectory = new DataDirectoryChunk();
|
||||
auto *dataDirectory = new DataDirectoryChunk(linkedFile);
|
||||
auto *sectionTable = new SectionHeaderTableChunk();
|
||||
auto *text = new TextSectionChunk(linkedFile);
|
||||
auto *rdata = new RDataSectionChunk(linkedFile);
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -14,4 +14,5 @@ _data$1 ends
|
|||
|
||||
.code
|
||||
main:
|
||||
nop
|
||||
end main
|
||||
|
|
|
@ -6,7 +6,7 @@ sections:
|
|||
- Name: .text
|
||||
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
|
||||
Alignment: 4
|
||||
SectionData: ""
|
||||
SectionData: 90
|
||||
- Name: .data
|
||||
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
|
||||
Alignment: 4
|
||||
|
@ -22,7 +22,7 @@ sections:
|
|||
- Name: ".debug$S"
|
||||
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
|
||||
Alignment: 1
|
||||
SectionData: 04000000F1000000670000002C000111000000005A3A5C67726F7570656473656374696F6E735C73656374696F6E2D67726F7570732E6F626A0037003C1103020000030000000000000000000A0000001B9D01004D6963726F736F667420285229204D6163726F20417373656D626C6572000000
|
||||
SectionData: 04000000F1000000590000001E000111000000005A3A5C67726F757065642D73656374696F6E732E6F626A0037003C1103020000030000000000000000000A0000001B9D01004D6963726F736F667420285229204D6163726F20417373656D626C65720000000000
|
||||
- Name: .drectve
|
||||
Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
|
||||
Alignment: 2147483648
|
||||
|
@ -41,7 +41,7 @@ symbols:
|
|||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
NumberOfAuxSymbols: 1
|
||||
AuxiliaryData: 000000000000000000000000000000000000
|
||||
AuxiliaryData: 010000000000000000000000000000000000
|
||||
- Name: .data
|
||||
Value: 0
|
||||
SectionNumber: 2
|
||||
|
@ -66,14 +66,14 @@ symbols:
|
|||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
NumberOfAuxSymbols: 1
|
||||
AuxiliaryData: 040000000000000000000000000000000000
|
||||
- Name: ."debug$S"
|
||||
- Name: ".debug$S"
|
||||
Value: 0
|
||||
SectionNumber: 5
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
NumberOfAuxSymbols: 1
|
||||
AuxiliaryData: 740000000000000000000000000000000000
|
||||
AuxiliaryData: 680000000000000000000000000000000000
|
||||
- Name: _main
|
||||
Value: 0
|
||||
SectionNumber: 1
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
__declspec(dllimport) int var;
|
||||
__declspec(dllimport) int fn(void);
|
||||
|
||||
int main() {
|
||||
return var + fn();
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
---
|
||||
header:
|
||||
Machine: IMAGE_FILE_MACHINE_I386
|
||||
Characteristics: [ ]
|
||||
sections:
|
||||
- Name: .drectve
|
||||
Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
|
||||
Alignment: 1
|
||||
SectionData: 2020202F44454641554C544C49423A224C4942434D5422202F44454641554C544C49423A224F4C444E414D45532220
|
||||
- Name: ".debug$S"
|
||||
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
|
||||
Alignment: 1
|
||||
SectionData: 04000000F10000005500000017000111000000005A3A5C766172732D6D61696E2E6F626A003A003C11002200000700100000001B9D0100100000001B9D01004D6963726F736F667420285229204F7074696D697A696E6720436F6D70696C657200000000
|
||||
- Name: .text
|
||||
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
|
||||
Alignment: 16
|
||||
SectionData: 558BECFF15000000008B0D0000000003015DC3
|
||||
Relocations:
|
||||
- VirtualAddress: 5
|
||||
SymbolName: __imp__fn
|
||||
Type: IMAGE_REL_I386_DIR32
|
||||
- VirtualAddress: 11
|
||||
SymbolName: __imp__var
|
||||
Type: IMAGE_REL_I386_DIR32
|
||||
symbols:
|
||||
- Name: "@comp.id"
|
||||
Value: 11181339
|
||||
SectionNumber: 65535
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
- Name: "@feat.00"
|
||||
Value: 1
|
||||
SectionNumber: 65535
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
- Name: .drectve
|
||||
Value: 0
|
||||
SectionNumber: 1
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
NumberOfAuxSymbols: 1
|
||||
AuxiliaryData: 2F0000000000000000000000000000000000
|
||||
- Name: ".debug$S"
|
||||
Value: 0
|
||||
SectionNumber: 2
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
NumberOfAuxSymbols: 1
|
||||
AuxiliaryData: 640000000000000000000000000000000000
|
||||
- Name: .text
|
||||
Value: 0
|
||||
SectionNumber: 3
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
NumberOfAuxSymbols: 1
|
||||
AuxiliaryData: 1300000002000000B8433CE4000000000000
|
||||
- Name: _main
|
||||
Value: 0
|
||||
SectionNumber: 3
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_FUNCTION
|
||||
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
|
||||
- Name: __imp__var
|
||||
Value: 0
|
||||
SectionNumber: 0
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
|
||||
- Name: __imp__fn
|
||||
Value: 0
|
||||
SectionNumber: 0
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
|
||||
...
|
|
@ -0,0 +1,11 @@
|
|||
// cl.exe /c vars.c
|
||||
// link.exe /debug /nodefaultlib /entry:dllmain vars.obj
|
||||
__declspec(dllexport) int var = 3;
|
||||
|
||||
__declspec(dllexport) int fn(void) {
|
||||
return 4;
|
||||
}
|
||||
|
||||
int dllmain() {
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
---
|
||||
header:
|
||||
Machine: IMAGE_FILE_MACHINE_I386
|
||||
Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_32BIT_MACHINE, IMAGE_FILE_DLL ]
|
||||
sections:
|
||||
- Name: .text
|
||||
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
|
||||
Alignment: 2147483648
|
||||
SectionData: 558BECB8090000005DC3CCCCCCCCCCCC558BECB8010000005DC3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
- Name: .rdata
|
||||
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
|
||||
Alignment: 2147483648
|
||||
SectionData: 0000000041ADCC51000000003C2000000100000002000000020000002820000030200000382000000010000000300000452000004820000000000100766172732E646C6C00666E007661720000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
- Name: .data
|
||||
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
|
||||
Alignment: 2147483648
|
||||
SectionData: 0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
symbols:
|
||||
...
|
Binary file not shown.
|
@ -1,19 +1,17 @@
|
|||
# Verify that lld can handle .lib files. "main.obj" refers _val1 and
|
||||
# _val2 that are defined in "dynamic.lib".
|
||||
# _val2 that are defined in "vars.lib".
|
||||
#
|
||||
# RUN: yaml2obj %p/Inputs/main.obj.yaml > %t.obj
|
||||
# RUN: yaml2obj %p/Inputs/vars-main.obj.yaml > %t.obj
|
||||
#
|
||||
# RUN: lld -flavor link -out %t1 -subsystem console -- %t.obj \
|
||||
# RUN: %p/Inputs/dynamic.lib && llvm-objdump -d %t1 | FileCheck %s
|
||||
# RUN: %p/Inputs/vars.lib && llvm-objdump -d %t1 | FileCheck %s
|
||||
|
||||
CHECK: Disassembly of section .text:
|
||||
CHECK: .text:
|
||||
CHECK: 1000: a1 0c 10 40 00 movl 4198412, %eax
|
||||
CHECK: 1005: 03 05 14 10 40 00 addl 4198420, %eax
|
||||
CHECK: 100b: c3 ret
|
||||
CHECK: 100c: ff 25 00 00 40 00 jmpl *4194304
|
||||
CHECK: 1012: 90 nop
|
||||
CHECK: 1013: 90 nop
|
||||
CHECK: 1014: ff 25 00 00 40 00 jmpl *4194304
|
||||
CHECK: 101a: 90 nop
|
||||
CHECK: 101b: 90 nop
|
||||
CHECK: 1000: 55 pushl %ebp
|
||||
CHECK: 1001: 8b ec movl %esp, %ebp
|
||||
CHECK: 1003: ff 15 4c 20 40 00 calll *4202572
|
||||
CHECK: 1009: 8b 0d 50 20 40 00 movl 4202576, %ecx
|
||||
CHECK: 100f: 03 01 addl (%ecx), %eax
|
||||
CHECK: 1011: 5d popl %ebp
|
||||
CHECK: 1012: c3 ret
|
||||
|
|
Loading…
Reference in New Issue