Index: COFF/Writer.cpp =================================================================== --- COFF/Writer.cpp +++ COFF/Writer.cpp @@ -240,6 +240,8 @@ IdataContents idata; Chunk *importTableStart = nullptr; uint64_t importTableSize = 0; + Chunk *edataStart = nullptr; + uint64_t edataSize = 0; 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,15 @@ } void Writer::createExportTable() { - if (config->exports.empty()) - return; - for (Chunk *c : edata.chunks) - edataSec->addChunk(c); + if (!config->exports.empty() && edataSec->chunks.empty()) { + for (Chunk *c : edata.chunks) + edataSec->addChunk(c); + } + if (!edataSec->chunks.empty()) { + edataStart = edataSec->chunks.front(); + for (Chunk *c : edataSec->chunks) + edataSize += c->getSize(); + } } void Writer::removeUnusedSections() { @@ -1361,9 +1369,9 @@ // 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 (edataSize) { + dir[EXPORT_TABLE].RelativeVirtualAddress = edataStart->getRVA(); + dir[EXPORT_TABLE].Size = edataSize; } if (importTableStart) { dir[IMPORT_TABLE].RelativeVirtualAddress = importTableStart->getRVA(); Index: test/COFF/edata.s =================================================================== --- /dev/null +++ test/COFF/edata.s @@ -0,0 +1,59 @@ +# 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 +# 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: + + .text + .globl myfunc +myfunc: + ret + .globl exportfunc +exportfunc: + ret + +// The object contains an export directive for exportfunc + .section .drectve + .asciz "-export:exportfunc" + +// The object also contains a manually crafted .edata section, +// which instead exports myfunc, not exportfunc. + .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"