[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:
Rui Ueyama 2013-07-11 08:46:21 +00:00
parent 67ddcd6dd0
commit c8a53795ab
17 changed files with 532 additions and 68 deletions

View File

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

View File

@ -51,6 +51,7 @@ DefinedAtom::ContentPermissions DefinedAtom::permissions(ContentType type) {
case typeLazyPointer:
case typeLazyDylibPointer:
case typeThunkTLV:
case typeDataDirectoryEntry:
return permRW_;
case typeGOT:

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -14,4 +14,5 @@ _data$1 ends
.code
main:
nop
end main

View File

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

View File

@ -0,0 +1,6 @@
__declspec(dllimport) int var;
__declspec(dllimport) int fn(void);
int main() {
return var + fn();
}

View File

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

View File

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

View File

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

View File

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