[lld] r239869 - COFF: Support creating DLLs.
Rui Ueyama
ruiu at google.com
Tue Jun 16 17:16:33 PDT 2015
Author: ruiu
Date: Tue Jun 16 19:16:33 2015
New Revision: 239869
URL: http://llvm.org/viewvc/llvm-project?rev=239869&view=rev
Log:
COFF: Support creating DLLs.
DLL files are in the same format as executables but they have export tables.
The format of the export table is described in PE/COFF spec section 5.3.
A new class, EdataContents, takes care of creating chunks for export tables.
What we need to do is to parse command line flags for dllexports, and then
instantiate the class to create chunks. For the writer, export table chunks
are opaque data -- it just add chunks to .edata section.
Added:
lld/trunk/test/COFF/Inputs/export.yaml
lld/trunk/test/COFF/export.test
Modified:
lld/trunk/COFF/Config.h
lld/trunk/COFF/DLL.cpp
lld/trunk/COFF/DLL.h
lld/trunk/COFF/Driver.cpp
lld/trunk/COFF/Driver.h
lld/trunk/COFF/DriverUtils.cpp
lld/trunk/COFF/SymbolTable.cpp
lld/trunk/COFF/Writer.cpp
lld/trunk/COFF/Writer.h
Modified: lld/trunk/COFF/Config.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Config.h?rev=239869&r1=239868&r2=239869&view=diff
==============================================================================
--- lld/trunk/COFF/Config.h (original)
+++ lld/trunk/COFF/Config.h Tue Jun 16 19:16:33 2015
@@ -22,9 +22,21 @@ namespace coff {
using llvm::COFF::WindowsSubsystem;
using llvm::StringRef;
+class Defined;
-class Configuration {
-public:
+// Represents an /export option.
+struct Export {
+ StringRef Name;
+ StringRef ExtName;
+ Defined *Sym = nullptr;
+ uint16_t Ordinal = 0;
+ bool Noname = false;
+ bool Data = false;
+ bool Private = false;
+};
+
+// Global configuration.
+struct Configuration {
llvm::COFF::MachineTypes MachineType = llvm::COFF::IMAGE_FILE_MACHINE_AMD64;
bool Verbose = false;
WindowsSubsystem Subsystem = llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN;
@@ -39,6 +51,10 @@ public:
std::set<StringRef> NoDefaultLibs;
bool NoDefaultLibAll = false;
+ // True if we are creating a DLL.
+ bool DLL = false;
+ std::vector<Export> Exports;
+
// Used by /failifmismatch option.
std::map<StringRef, StringRef> MustMatch;
Modified: lld/trunk/COFF/DLL.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/DLL.cpp?rev=239869&r1=239868&r2=239869&view=diff
==============================================================================
--- lld/trunk/COFF/DLL.cpp (original)
+++ lld/trunk/COFF/DLL.cpp Tue Jun 16 19:16:33 2015
@@ -23,6 +23,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/Endian.h"
+#include "llvm/Support/Path.h"
using namespace llvm;
using namespace llvm::object;
@@ -31,11 +32,12 @@ using namespace llvm::COFF;
using llvm::RoundUpToAlignment;
static const size_t LookupChunkSize = sizeof(uint64_t);
-static const size_t DirectoryChunkSize = sizeof(ImportDirectoryTableEntry);
namespace lld {
namespace coff {
+// Import table
+
// A chunk for the import descriptor table.
class HintNameChunk : public Chunk {
public:
@@ -88,10 +90,10 @@ public:
};
// A chunk for the import descriptor table.
-class DirectoryChunk : public Chunk {
+class ImportDirectoryChunk : public Chunk {
public:
- explicit DirectoryChunk(Chunk *N) : DLLName(N) {}
- size_t getSize() const override { return DirectoryChunkSize; }
+ explicit ImportDirectoryChunk(Chunk *N) : DLLName(N) {}
+ size_t getSize() const override { return sizeof(ImportDirectoryTableEntry); }
void writeTo(uint8_t *Buf) override {
auto *E = (coff_import_directory_table_entry *)(Buf + FileOff);
@@ -118,7 +120,7 @@ private:
};
uint64_t IdataContents::getDirSize() {
- return Dirs.size() * DirectoryChunkSize;
+ return Dirs.size() * sizeof(ImportDirectoryTableEntry);
}
uint64_t IdataContents::getIATSize() {
@@ -192,13 +194,120 @@ void IdataContents::create() {
// Create the import table header.
if (!DLLNames.count(Name))
DLLNames[Name] = make_unique<StringChunk>(Name);
- auto Dir = make_unique<DirectoryChunk>(DLLNames[Name].get());
+ auto Dir = make_unique<ImportDirectoryChunk>(DLLNames[Name].get());
Dir->LookupTab = Lookups[Base].get();
Dir->AddressTab = Addresses[Base].get();
Dirs.push_back(std::move(Dir));
}
// Add null terminator.
- Dirs.push_back(make_unique<NullChunk>(DirectoryChunkSize));
+ Dirs.push_back(make_unique<NullChunk>(sizeof(ImportDirectoryTableEntry)));
+}
+
+// Export table
+// Read Microsoft PE/COFF spec 5.3 for details.
+
+// A chunk for the export descriptor table.
+class ExportDirectoryChunk : public Chunk {
+public:
+ ExportDirectoryChunk(int I, int J, Chunk *D, Chunk *A, Chunk *N, Chunk *O)
+ : MaxOrdinal(I), NameTabSize(J), DLLName(D), AddressTab(A), NameTab(N),
+ OrdinalTab(O) {}
+
+ size_t getSize() const override {
+ return sizeof(export_directory_table_entry);
+ }
+
+ void writeTo(uint8_t *Buf) override {
+ auto *E = (export_directory_table_entry *)(Buf + FileOff);
+ E->NameRVA = DLLName->getRVA();
+ E->OrdinalBase = 0;
+ E->AddressTableEntries = MaxOrdinal + 1;
+ E->NumberOfNamePointers = NameTabSize;
+ E->ExportAddressTableRVA = AddressTab->getRVA();
+ E->NamePointerRVA = NameTab->getRVA();
+ E->OrdinalTableRVA = OrdinalTab->getRVA();
+ }
+
+ uint16_t MaxOrdinal;
+ uint16_t NameTabSize;
+ Chunk *DLLName;
+ Chunk *AddressTab;
+ Chunk *NameTab;
+ Chunk *OrdinalTab;
+};
+
+class AddressTableChunk : public Chunk {
+public:
+ explicit AddressTableChunk(size_t MaxOrdinal) : Size(MaxOrdinal + 1) {}
+ size_t getSize() const override { return Size * 4; }
+
+ void writeTo(uint8_t *Buf) override {
+ for (Export &E : Config->Exports)
+ write32le(Buf + FileOff + E.Ordinal * 4, E.Sym->getRVA());
+ }
+
+private:
+ size_t Size;
+};
+
+class NamePointersChunk : public Chunk {
+public:
+ explicit NamePointersChunk(std::vector<Chunk *> &V) : Chunks(V) {}
+ size_t getSize() const override { return Chunks.size() * 4; }
+
+ void writeTo(uint8_t *Buf) override {
+ uint8_t *P = Buf + FileOff;
+ for (Chunk *C : Chunks) {
+ write32le(P, C->getRVA());
+ P += 4;
+ }
+ }
+
+private:
+ std::vector<Chunk *> Chunks;
+};
+
+class ExportOrdinalChunk : public Chunk {
+public:
+ explicit ExportOrdinalChunk(size_t I) : Size(I) {}
+ size_t getSize() const override { return Size * 2; }
+
+ void writeTo(uint8_t *Buf) override {
+ uint8_t *P = Buf + FileOff;
+ for (Export &E : Config->Exports) {
+ if (E.Noname)
+ continue;
+ write16le(P, E.Ordinal);
+ P += 2;
+ }
+ }
+
+private:
+ size_t Size;
+};
+
+EdataContents::EdataContents() {
+ uint16_t MaxOrdinal = 0;
+ for (Export &E : Config->Exports)
+ MaxOrdinal = std::max(MaxOrdinal, E.Ordinal);
+
+ auto *DLLName = new StringChunk(sys::path::filename(Config->OutputFile));
+ auto *AddressTab = new AddressTableChunk(MaxOrdinal);
+ std::vector<Chunk *> Names;
+ for (Export &E : Config->Exports)
+ if (!E.Noname)
+ Names.push_back(new StringChunk(E.ExtName));
+ auto *NameTab = new NamePointersChunk(Names);
+ auto *OrdinalTab = new ExportOrdinalChunk(Names.size());
+ auto *Dir = new ExportDirectoryChunk(MaxOrdinal, Names.size(), DLLName,
+ AddressTab, NameTab, OrdinalTab);
+ Chunks.push_back(std::unique_ptr<Chunk>(Dir));
+ Chunks.push_back(std::unique_ptr<Chunk>(DLLName));
+ Chunks.push_back(std::unique_ptr<Chunk>(AddressTab));
+ Chunks.push_back(std::unique_ptr<Chunk>(NameTab));
+ Chunks.push_back(std::unique_ptr<Chunk>(OrdinalTab));
+ for (Chunk *C : Names)
+ Chunks.push_back(std::unique_ptr<Chunk>(C));
}
} // namespace coff
Modified: lld/trunk/COFF/DLL.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/DLL.h?rev=239869&r1=239868&r2=239869&view=diff
==============================================================================
--- lld/trunk/COFF/DLL.h (original)
+++ lld/trunk/COFF/DLL.h Tue Jun 16 19:16:33 2015
@@ -17,7 +17,7 @@ namespace lld {
namespace coff {
// Windows-specific.
-// IdataContents creates all chunks for the .idata section.
+// IdataContents creates all chunks for the DLL import table.
// You are supposed to call add() to add symbols and then
// call getChunks() to get a list of chunks.
class IdataContents {
@@ -41,6 +41,14 @@ private:
std::map<StringRef, std::unique_ptr<Chunk>> DLLNames;
};
+// Windows-specific.
+// EdataContents creates all chunks for the DLL export table.
+class EdataContents {
+public:
+ EdataContents();
+ std::vector<std::unique_ptr<Chunk>> Chunks;
+};
+
} // namespace coff
} // namespace lld
Modified: lld/trunk/COFF/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Driver.cpp?rev=239869&r1=239868&r2=239869&view=diff
==============================================================================
--- lld/trunk/COFF/Driver.cpp (original)
+++ lld/trunk/COFF/Driver.cpp Tue Jun 16 19:16:33 2015
@@ -91,6 +91,14 @@ LinkerDriver::parseDirectives(StringRef
return EC;
std::unique_ptr<llvm::opt::InputArgList> Args = std::move(ArgsOrErr.get());
+ // Handle /export
+ for (auto *Arg : Args->filtered(OPT_export)) {
+ ErrorOr<Export> E = parseExport(Arg->getValue());
+ if (auto EC = E.getError())
+ return EC;
+ Config->Exports.push_back(E.get());
+ }
+
// Handle /failifmismatch
if (auto EC = checkFailIfMismatch(Args.get()))
return EC;
@@ -180,6 +188,17 @@ std::vector<StringRef> LinkerDriver::get
return Ret;
}
+static WindowsSubsystem inferSubsystem() {
+ if (Config->DLL)
+ return IMAGE_SUBSYSTEM_WINDOWS_GUI;
+ return StringSwitch<WindowsSubsystem>(Config->EntryName)
+ .Case("mainCRTStartup", IMAGE_SUBSYSTEM_WINDOWS_CUI)
+ .Case("wmainCRTStartup", IMAGE_SUBSYSTEM_WINDOWS_CUI)
+ .Case("WinMainCRTStartup", IMAGE_SUBSYSTEM_WINDOWS_GUI)
+ .Case("wWinMainCRTStartup", IMAGE_SUBSYSTEM_WINDOWS_GUI)
+ .Default(IMAGE_SUBSYSTEM_UNKNOWN);
+}
+
bool LinkerDriver::link(int Argc, const char *Argv[]) {
// Needed for LTO.
llvm::InitializeAllTargetInfos();
@@ -221,6 +240,10 @@ bool LinkerDriver::link(int Argc, const
if (Args->hasArg(OPT_verbose))
Config->Verbose = true;
+ // Handle /dll
+ if (Args->hasArg(OPT_dll))
+ Config->DLL = true;
+
// Handle /entry
if (auto *Arg = Args->getLastArg(OPT_entry))
Config->EntryName = Arg->getValue();
@@ -318,6 +341,14 @@ bool LinkerDriver::link(int Argc, const
}
}
+ // Handle /export
+ for (auto *Arg : Args->filtered(OPT_export)) {
+ ErrorOr<Export> E = parseExport(Arg->getValue());
+ if (E.getError())
+ return false;
+ Config->Exports.push_back(E.get());
+ }
+
// Handle /failifmismatch
if (auto EC = checkFailIfMismatch(Args.get())) {
llvm::errs() << "/failifmismatch: " << EC.message() << "\n";
@@ -414,6 +445,15 @@ bool LinkerDriver::link(int Argc, const
}
}
+ // Windows specific -- Make sure we resolve all dllexported symbols.
+ // (We don't cache the size here because Symtab.resolve() may add
+ // new entries to Config->Exports.)
+ for (size_t I = 0; I < Config->Exports.size(); ++I) {
+ StringRef Sym = Config->Exports[I].Name;
+ Symtab.addUndefined(Sym);
+ Config->GCRoots.insert(Sym);
+ }
+
// Windows specific -- If entry point name is not given, we need to
// infer that from user-defined entry name. The symbol table takes
// care of details.
@@ -441,19 +481,21 @@ bool LinkerDriver::link(int Argc, const
// Windows specific -- if no /subsystem is given, we need to infer
// that from entry point name.
if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) {
- Config->Subsystem =
- StringSwitch<WindowsSubsystem>(Config->EntryName)
- .Case("mainCRTStartup", IMAGE_SUBSYSTEM_WINDOWS_CUI)
- .Case("wmainCRTStartup", IMAGE_SUBSYSTEM_WINDOWS_CUI)
- .Case("WinMainCRTStartup", IMAGE_SUBSYSTEM_WINDOWS_GUI)
- .Case("wWinMainCRTStartup", IMAGE_SUBSYSTEM_WINDOWS_GUI)
- .Default(IMAGE_SUBSYSTEM_UNKNOWN);
+ Config->Subsystem = inferSubsystem();
if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) {
llvm::errs() << "subsystem must be defined\n";
return false;
}
}
+ // Windows specific -- fix up dllexported symbols.
+ if (!Config->Exports.empty()) {
+ for (Export &E : Config->Exports)
+ E.Sym = Symtab.find(E.Name);
+ if (fixupExports())
+ return false;
+ }
+
// Write the result.
Writer Out(&Symtab);
if (auto EC = Out.write(Config->OutputFile)) {
Modified: lld/trunk/COFF/Driver.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Driver.h?rev=239869&r1=239868&r2=239869&view=diff
==============================================================================
--- lld/trunk/COFF/Driver.h (original)
+++ lld/trunk/COFF/Driver.h Tue Jun 16 19:16:33 2015
@@ -10,6 +10,7 @@
#ifndef LLD_COFF_DRIVER_H
#define LLD_COFF_DRIVER_H
+#include "Config.h"
#include "lld/Core/LLVM.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringRef.h"
@@ -115,6 +116,10 @@ std::error_code parseVersion(StringRef A
std::error_code parseSubsystem(StringRef Arg, WindowsSubsystem *Sys,
uint32_t *Major, uint32_t *Minor);
+// Used for dllexported symbols.
+ErrorOr<Export> parseExport(StringRef Arg);
+std::error_code fixupExports();
+
// Parses a string in the form of "key=value" and check
// if value matches previous values for the key.
// This feature used in the directive section to reject
Modified: lld/trunk/COFF/DriverUtils.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/DriverUtils.cpp?rev=239869&r1=239868&r2=239869&view=diff
==============================================================================
--- lld/trunk/COFF/DriverUtils.cpp (original)
+++ lld/trunk/COFF/DriverUtils.cpp Tue Jun 16 19:16:33 2015
@@ -114,6 +114,99 @@ std::error_code parseSubsystem(StringRef
return std::error_code();
}
+// Parse a string in the form of
+// "<name>[=<internalname>][, at ordinal[,NONAME]][,DATA][,PRIVATE]".
+// Used for parsing /export arguments.
+ErrorOr<Export> parseExport(StringRef Arg) {
+ Export E;
+ StringRef Rest;
+ std::tie(E.Name, Rest) = Arg.split(",");
+ if (E.Name.empty())
+ goto err;
+ if (E.Name.find('=') != StringRef::npos) {
+ std::tie(E.ExtName, E.Name) = E.Name.split("=");
+ if (E.Name.empty())
+ goto err;
+ } else {
+ E.ExtName = E.Name;
+ }
+
+ while (!Rest.empty()) {
+ StringRef Tok;
+ std::tie(Tok, Rest) = Rest.split(",");
+ if (Tok.equals_lower("noname")) {
+ if (E.Ordinal == 0)
+ goto err;
+ E.Noname = true;
+ continue;
+ }
+ if (Tok.equals_lower("data")) {
+ E.Data = true;
+ continue;
+ }
+ if (Tok.equals_lower("private")) {
+ E.Private = true;
+ continue;
+ }
+ if (Tok.startswith("@")) {
+ int32_t Ord;
+ if (Tok.substr(1).getAsInteger(0, Ord))
+ goto err;
+ if (Ord <= 0 || 65535 < Ord)
+ goto err;
+ E.Ordinal = Ord;
+ continue;
+ }
+ goto err;
+ }
+ return E;
+
+err:
+ llvm::errs() << "invalid /export: " << Arg << "\n";
+ return make_error_code(LLDError::InvalidOption);
+}
+
+// Performs error checking on all /export arguments.
+// It also sets ordinals.
+std::error_code fixupExports() {
+ // Symbol ordinals must be unique.
+ std::set<uint16_t> Ords;
+ for (Export &E : Config->Exports) {
+ if (E.Ordinal == 0)
+ continue;
+ if (!Ords.insert(E.Ordinal).second) {
+ llvm::errs() << "duplicate export ordinal: " << E.Name << "\n";
+ return make_error_code(LLDError::InvalidOption);
+ }
+ }
+
+ // Uniquefy by name.
+ std::set<StringRef> Names;
+ std::vector<Export> V;
+ for (Export &E : Config->Exports) {
+ if (!Names.insert(E.Name).second) {
+ llvm::errs() << "warning: duplicate /export option: " << E.Name << "\n";
+ continue;
+ }
+ V.push_back(E);
+ }
+ Config->Exports = std::move(V);
+
+ // Sort by name.
+ std::sort(
+ Config->Exports.begin(), Config->Exports.end(),
+ [](const Export &A, const Export &B) { return A.ExtName < B.ExtName; });
+
+ // Assign unique ordinals if default (= 0).
+ uint16_t Max = 0;
+ for (Export &E : Config->Exports)
+ Max = std::max(Max, E.Ordinal);
+ for (Export &E : Config->Exports)
+ if (E.Ordinal == 0)
+ E.Ordinal = ++Max;
+ return std::error_code();
+}
+
// Parses a string in the form of "key=value" and check
// if value matches previous values for the same key.
std::error_code checkFailIfMismatch(llvm::opt::InputArgList *Args) {
Modified: lld/trunk/COFF/SymbolTable.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/SymbolTable.cpp?rev=239869&r1=239868&r2=239869&view=diff
==============================================================================
--- lld/trunk/COFF/SymbolTable.cpp (original)
+++ lld/trunk/COFF/SymbolTable.cpp Tue Jun 16 19:16:33 2015
@@ -189,6 +189,14 @@ Defined *SymbolTable::find(StringRef Nam
// Windows specific -- Link default entry point name.
ErrorOr<StringRef> SymbolTable::findDefaultEntry() {
+ // If it's DLL, the rule is easy.
+ if (Config->DLL) {
+ StringRef Sym = "_DllMainCRTStartup";
+ if (auto EC = resolve(new (Alloc) Undefined(Sym)))
+ return EC;
+ return Sym;
+ }
+
// User-defined main functions and their corresponding entry points.
static const char *Entries[][2] = {
{"main", "mainCRTStartup"},
Modified: lld/trunk/COFF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Writer.cpp?rev=239869&r1=239868&r2=239869&view=diff
==============================================================================
--- lld/trunk/COFF/Writer.cpp (original)
+++ lld/trunk/COFF/Writer.cpp Tue Jun 16 19:16:33 2015
@@ -42,6 +42,7 @@ std::error_code Writer::write(StringRef
markLive();
createSections();
createImportTables();
+ createExportTable();
if (Config->Relocatable)
createSection(".reloc");
assignAddresses();
@@ -174,6 +175,15 @@ void Writer::createImportTables() {
Sec->addChunk(C);
}
+void Writer::createExportTable() {
+ if (Config->Exports.empty())
+ return;
+ Edata.reset(new EdataContents());
+ OutputSection *Sec = createSection(".edata");
+ for (std::unique_ptr<Chunk> &C : Edata->Chunks)
+ Sec->addChunk(C.get());
+}
+
// The Windows loader doesn't seem to like empty sections,
// so we remove them if any.
void Writer::removeEmptySections() {
@@ -243,6 +253,8 @@ void Writer::writeHeader() {
COFF->NumberOfSections = OutputSections.size();
COFF->Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE;
COFF->Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE;
+ if (Config->DLL)
+ COFF->Characteristics |= IMAGE_FILE_DLL;
if (!Config->Relocatable)
COFF->Characteristics |= IMAGE_FILE_RELOCS_STRIPPED;
COFF->SizeOfOptionalHeader =
@@ -292,6 +304,10 @@ void Writer::writeHeader() {
// Write data directory
auto *DataDirectory = reinterpret_cast<data_directory *>(Buf);
Buf += sizeof(*DataDirectory) * NumberfOfDataDirectory;
+ if (OutputSection *Sec = findSection(".edata")) {
+ DataDirectory[EXPORT_TABLE].RelativeVirtualAddress = Sec->getRVA();
+ DataDirectory[EXPORT_TABLE].Size = Sec->getVirtualSize();
+ }
if (Idata) {
DataDirectory[IMPORT_TABLE].RelativeVirtualAddress = Idata->getDirRVA();
DataDirectory[IMPORT_TABLE].Size = Idata->getDirSize();
@@ -397,6 +413,7 @@ OutputSection *Writer::createSection(Str
.Case(".bss", BSS | R | W)
.Case(".data", DATA | R | W)
.Case(".didat", DATA | R)
+ .Case(".edata", DATA | R)
.Case(".idata", DATA | R)
.Case(".rdata", DATA | R)
.Case(".reloc", DATA | DISCARDABLE | R)
Modified: lld/trunk/COFF/Writer.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Writer.h?rev=239869&r1=239868&r2=239869&view=diff
==============================================================================
--- lld/trunk/COFF/Writer.h (original)
+++ lld/trunk/COFF/Writer.h Tue Jun 16 19:16:33 2015
@@ -78,6 +78,7 @@ private:
void markLive();
void createSections();
void createImportTables();
+ void createExportTable();
void assignAddresses();
void removeEmptySections();
std::error_code openFile(StringRef OutputPath);
@@ -99,6 +100,7 @@ private:
llvm::SpecificBumpPtrAllocator<BaserelChunk> BAlloc;
std::vector<OutputSection *> OutputSections;
std::unique_ptr<IdataContents> Idata;
+ std::unique_ptr<EdataContents> Edata;
uint64_t FileSize;
uint64_t SizeOfImage;
Added: lld/trunk/test/COFF/Inputs/export.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/Inputs/export.yaml?rev=239869&view=auto
==============================================================================
--- lld/trunk/test/COFF/Inputs/export.yaml (added)
+++ lld/trunk/test/COFF/Inputs/export.yaml Tue Jun 16 19:16:33 2015
@@ -0,0 +1,51 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: []
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: B800000000506800000000680000000050E80000000050E800000000
+ - Name: .drectve
+ Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+ Alignment: 2147483648
+ SectionData: 2f6578706f72743a6578706f7274666e3300 # /export:exportfn3
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 28
+ NumberOfRelocations: 4
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: _DllMainCRTStartup
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: exportfn1
+ Value: 8
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: exportfn2
+ Value: 16
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: exportfn3
+ Value: 16
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
Added: lld/trunk/test/COFF/export.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/export.test?rev=239869&view=auto
==============================================================================
--- lld/trunk/test/COFF/export.test (added)
+++ lld/trunk/test/COFF/export.test Tue Jun 16 19:16:33 2015
@@ -0,0 +1,51 @@
+# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj
+#
+# RUN: lld -flavor link2 /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2
+# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK1 %s
+
+CHECK1: Export Table:
+CHECK1: DLL name: export.test.tmp.dll
+CHECK1: Ordinal RVA Name
+CHECK1-NEXT: 0 0
+CHECK1-NEXT: 1 0x1008 exportfn1
+CHECK1-NEXT: 2 0x1010 exportfn2
+
+# RUN: lld -flavor link2 /out:%t.dll /dll %t.obj /export:exportfn1, at 5 /export:exportfn2
+# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK2 %s
+
+CHECK2: Export Table:
+CHECK2: DLL name: export.test.tmp.dll
+CHECK2: Ordinal RVA Name
+CHECK2-NEXT: 0 0
+CHECK2-NEXT: 1 0
+CHECK2-NEXT: 2 0
+CHECK2-NEXT: 3 0
+CHECK2-NEXT: 4 0
+CHECK2-NEXT: 5 0x1008 exportfn1
+CHECK2-NEXT: 6 0x1010 exportfn2
+CHECK2-NEXT: 7 0x1010 exportfn3
+
+# RUN: lld -flavor link2 /out:%t.dll /dll %t.obj /export:exportfn1, at 5,noname /export:exportfn2
+# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK3 %s
+
+CHECK3: Export Table:
+CHECK3: DLL name: export.test.tmp.dll
+CHECK3: Ordinal RVA Name
+CHECK3-NEXT: 0 0
+CHECK3-NEXT: 1 0
+CHECK3-NEXT: 2 0
+CHECK3-NEXT: 3 0
+CHECK3-NEXT: 4 0
+CHECK3-NEXT: 5 0x1008
+CHECK3-NEXT: 6 0x1010 exportfn2
+
+# RUN: lld -flavor link2 /out:%t.dll /dll %t.obj /export:f1=exportfn1 /export:f2 at 4=exportfn2
+# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK4 %s
+
+CHECK4: Export Table:
+CHECK4: DLL name: export.test.tmp.dll
+CHECK4: Ordinal RVA Name
+CHECK4-NEXT: 0 0
+CHECK4-NEXT: 1 0x1010 exportfn3
+CHECK4-NEXT: 2 0x1008 f1
+CHECK4-NEXT: 3 0x1010 f2
More information about the llvm-commits
mailing list