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
case typeLazyPointer:
case typeLazyDylibPointer:
case typeThunkTLV:
+ case typeDataDirectoryEntry:
return permRW_;
case typeGOT:
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; }
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.
StringRef _unmangledName;
StringRef _loadName;
std::string _mangledName;
+ const DefinedAtom *_importTableEntry;
};
//===----------------------------------------------------------------------===//
--- /dev/null
+//===- 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
//===----------------------------------------------------------------------===//
#include "GroupedSectionsPass.h"
+#include "IdataPass.h"
#include "lld/Core/PassManager.h"
#include "lld/Passes/LayoutPass.h"
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()));
}
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; }
public:
enum Kind {
kindHeader,
- kindSection
+ kindSection,
+ kindDataDirectory
};
explicit Chunk(Kind kind) : _kind(kind), _size(0), _align(1) {}
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 {
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.
}
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) {
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);
}
// 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);
.code
main:
+ nop
end main
- 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
- 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
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
NumberOfAuxSymbols: 1
- AuxiliaryData: 000000000000000000000000000000000000
+ AuxiliaryData: 010000000000000000000000000000000000
- Name: .data
Value: 0
SectionNumber: 2
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
--- /dev/null
+__declspec(dllimport) int var;
+__declspec(dllimport) int fn(void);
+
+int main() {
+ return var + fn();
+}
--- /dev/null
+---
+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
+...
--- /dev/null
+// 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;
+}
--- /dev/null
+---
+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:
+...
# 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