Index: lld/trunk/COFF/Config.h =================================================================== --- lld/trunk/COFF/Config.h +++ lld/trunk/COFF/Config.h @@ -122,6 +122,7 @@ bool dll = false; StringRef implib; std::vector exports; + bool hadExplicitExports; std::set delayLoads; std::map dllOrder; Symbol *delayLoadHelper = nullptr; Index: lld/trunk/COFF/Driver.cpp =================================================================== --- lld/trunk/COFF/Driver.cpp +++ lld/trunk/COFF/Driver.cpp @@ -1817,6 +1817,7 @@ if (errorCount()) return; + config->hadExplicitExports = !config->exports.empty(); if (config->mingw) { // In MinGW, all symbols are automatically exported if no symbols // are chosen to be exported. Index: lld/trunk/COFF/Writer.cpp =================================================================== --- lld/trunk/COFF/Writer.cpp +++ lld/trunk/COFF/Writer.cpp @@ -240,6 +240,8 @@ IdataContents idata; Chunk *importTableStart = nullptr; uint64_t importTableSize = 0; + Chunk *edataStart = nullptr; + Chunk *edataEnd = nullptr; Chunk *iatStart = nullptr; uint64_t iatSize = 0; DelayLoadContents delayIdata; @@ -837,6 +839,7 @@ } fixPartialSectionChars(".rsrc", data | r); + fixPartialSectionChars(".edata", data | r); // Even in non MinGW cases, we might need to link against GNU import // libraries. bool hasIdata = fixGnuImportChunks(); @@ -1011,10 +1014,19 @@ } void Writer::createExportTable() { - if (config->exports.empty()) - return; - for (Chunk *c : edata.chunks) - edataSec->addChunk(c); + if (!edataSec->chunks.empty()) { + // Allow using a custom built export table from input object files, instead + // of having the linker synthesize the tables. + if (config->hadExplicitExports) + warn("literal .edata sections override exports"); + } else if (!config->exports.empty()) { + for (Chunk *c : edata.chunks) + edataSec->addChunk(c); + } + if (!edataSec->chunks.empty()) { + edataStart = edataSec->chunks.front(); + edataEnd = edataSec->chunks.back(); + } } void Writer::removeUnusedSections() { @@ -1363,9 +1375,10 @@ // Write data directory auto *dir = reinterpret_cast(buf); buf += sizeof(*dir) * numberOfDataDirectory; - if (!config->exports.empty()) { - dir[EXPORT_TABLE].RelativeVirtualAddress = edata.getRVA(); - dir[EXPORT_TABLE].Size = edata.getSize(); + if (edataStart) { + dir[EXPORT_TABLE].RelativeVirtualAddress = edataStart->getRVA(); + dir[EXPORT_TABLE].Size = + edataEnd->getRVA() + edataEnd->getSize() - edataStart->getRVA(); } if (importTableStart) { dir[IMPORT_TABLE].RelativeVirtualAddress = importTableStart->getRVA(); Index: lld/trunk/test/COFF/edata.s =================================================================== --- lld/trunk/test/COFF/edata.s +++ lld/trunk/test/COFF/edata.s @@ -0,0 +1,61 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-mingw32 -o %t.o %s +# RUN: lld-link -lldmingw -dll -out:%t.dll %t.o -entry:__ImageBase 2>&1 | FileCheck %s --allow-empty --check-prefix=NOWARNING +# RUN: llvm-readobj --coff-exports %t.dll | FileCheck %s +# RUN: lld-link -lldmingw -dll -out:%t.dll %t.o -entry:__ImageBase -export:otherfunc 2>&1 | FileCheck %s --check-prefix=WARNING +# RUN: llvm-readobj --coff-exports %t.dll | FileCheck %s + +# Check that the export table contains the manually crafted content +# instead of the linker generated exports. + +# CHECK: Export { +# CHECK-NEXT: Ordinal: 1 +# CHECK-NEXT: Name: myfunc +# CHECK-NEXT: RVA: +# CHECK-NEXT: } +# CHECK-EMPTY: + +# NOWARNING-NOT: warning + +# WARNING: warning: literal .edata sections override exports + + .text + .globl myfunc +myfunc: + ret + .globl otherfunc +otherfunc: + ret + +// The object contains a manually crafted .edata section, which exports +// myfunc, not otherfunc. + .section .edata, "drw" + .align 4 +exports: + .long 0 // ExportFlags + .long 0 // TimeDateStamp + .long 0 // MajorVersion + MinorVersion + .rva name // NameRVA + .long 1 // OrdinalBase + .long 1 // AddressTableEntries + .long 1 // NumberOfNamePointers + .rva functions // ExportAddressTableRVA + .rva names // NamePointerRVA + .rva nameordinals // OrdinalTableRVA + +names: + .rva funcname_myfunc + +nameordinals: + .short 0 + +functions: + .rva myfunc + .long 0 + +funcname_myfunc: + .asciz "myfunc" + +name: + .asciz "mydll.dll"