Skip to content

Commit dadc6f2

Browse files
committed
[COFF] Allow using custom .edata from input object files
This is used by Wine for manually crafting export tables. If the input object contains .edata sections, GNU ld references them in the export directory instead of synthesizing an export table using either export directives or the normal auto export mechanism. (AFAIK, historically, way way back, GNU ld didn't support synthesizing the export table - one was supposed to generate it using dlltool and link it in instead.) If faced with --out-implib and --output-def, GNU ld still populates those output files with the same export info as it would have generated otherwise, disregarding the input .edata. As this isn't an intended usage combination, I'm not adding checks for that in tests. Differential Revision: https://reviews.llvm.org/D65903 llvm-svn: 369358
1 parent e64af75 commit dadc6f2

File tree

4 files changed

+83
-7
lines changed

4 files changed

+83
-7
lines changed

lld/COFF/Config.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ struct Configuration {
122122
bool dll = false;
123123
StringRef implib;
124124
std::vector<Export> exports;
125+
bool hadExplicitExports;
125126
std::set<std::string> delayLoads;
126127
std::map<std::string, int> dllOrder;
127128
Symbol *delayLoadHelper = nullptr;

lld/COFF/Driver.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1817,6 +1817,7 @@ void LinkerDriver::link(ArrayRef<const char *> argsArr) {
18171817
if (errorCount())
18181818
return;
18191819

1820+
config->hadExplicitExports = !config->exports.empty();
18201821
if (config->mingw) {
18211822
// In MinGW, all symbols are automatically exported if no symbols
18221823
// are chosen to be exported.

lld/COFF/Writer.cpp

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,8 @@ class Writer {
240240
IdataContents idata;
241241
Chunk *importTableStart = nullptr;
242242
uint64_t importTableSize = 0;
243+
Chunk *edataStart = nullptr;
244+
Chunk *edataEnd = nullptr;
243245
Chunk *iatStart = nullptr;
244246
uint64_t iatSize = 0;
245247
DelayLoadContents delayIdata;
@@ -837,6 +839,7 @@ void Writer::createSections() {
837839
}
838840

839841
fixPartialSectionChars(".rsrc", data | r);
842+
fixPartialSectionChars(".edata", data | r);
840843
// Even in non MinGW cases, we might need to link against GNU import
841844
// libraries.
842845
bool hasIdata = fixGnuImportChunks();
@@ -1011,10 +1014,19 @@ void Writer::appendImportThunks() {
10111014
}
10121015

10131016
void Writer::createExportTable() {
1014-
if (config->exports.empty())
1015-
return;
1016-
for (Chunk *c : edata.chunks)
1017-
edataSec->addChunk(c);
1017+
if (!edataSec->chunks.empty()) {
1018+
// Allow using a custom built export table from input object files, instead
1019+
// of having the linker synthesize the tables.
1020+
if (config->hadExplicitExports)
1021+
warn("literal .edata sections override exports");
1022+
} else if (!config->exports.empty()) {
1023+
for (Chunk *c : edata.chunks)
1024+
edataSec->addChunk(c);
1025+
}
1026+
if (!edataSec->chunks.empty()) {
1027+
edataStart = edataSec->chunks.front();
1028+
edataEnd = edataSec->chunks.back();
1029+
}
10181030
}
10191031

10201032
void Writer::removeUnusedSections() {
@@ -1363,9 +1375,10 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
13631375
// Write data directory
13641376
auto *dir = reinterpret_cast<data_directory *>(buf);
13651377
buf += sizeof(*dir) * numberOfDataDirectory;
1366-
if (!config->exports.empty()) {
1367-
dir[EXPORT_TABLE].RelativeVirtualAddress = edata.getRVA();
1368-
dir[EXPORT_TABLE].Size = edata.getSize();
1378+
if (edataStart) {
1379+
dir[EXPORT_TABLE].RelativeVirtualAddress = edataStart->getRVA();
1380+
dir[EXPORT_TABLE].Size =
1381+
edataEnd->getRVA() + edataEnd->getSize() - edataStart->getRVA();
13691382
}
13701383
if (importTableStart) {
13711384
dir[IMPORT_TABLE].RelativeVirtualAddress = importTableStart->getRVA();

lld/test/COFF/edata.s

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# REQUIRES: x86
2+
3+
# RUN: llvm-mc -filetype=obj -triple=x86_64-mingw32 -o %t.o %s
4+
# RUN: lld-link -lldmingw -dll -out:%t.dll %t.o -entry:__ImageBase 2>&1 | FileCheck %s --allow-empty --check-prefix=NOWARNING
5+
# RUN: llvm-readobj --coff-exports %t.dll | FileCheck %s
6+
# RUN: lld-link -lldmingw -dll -out:%t.dll %t.o -entry:__ImageBase -export:otherfunc 2>&1 | FileCheck %s --check-prefix=WARNING
7+
# RUN: llvm-readobj --coff-exports %t.dll | FileCheck %s
8+
9+
# Check that the export table contains the manually crafted content
10+
# instead of the linker generated exports.
11+
12+
# CHECK: Export {
13+
# CHECK-NEXT: Ordinal: 1
14+
# CHECK-NEXT: Name: myfunc
15+
# CHECK-NEXT: RVA:
16+
# CHECK-NEXT: }
17+
# CHECK-EMPTY:
18+
19+
# NOWARNING-NOT: warning
20+
21+
# WARNING: warning: literal .edata sections override exports
22+
23+
.text
24+
.globl myfunc
25+
myfunc:
26+
ret
27+
.globl otherfunc
28+
otherfunc:
29+
ret
30+
31+
// The object contains a manually crafted .edata section, which exports
32+
// myfunc, not otherfunc.
33+
.section .edata, "drw"
34+
.align 4
35+
exports:
36+
.long 0 // ExportFlags
37+
.long 0 // TimeDateStamp
38+
.long 0 // MajorVersion + MinorVersion
39+
.rva name // NameRVA
40+
.long 1 // OrdinalBase
41+
.long 1 // AddressTableEntries
42+
.long 1 // NumberOfNamePointers
43+
.rva functions // ExportAddressTableRVA
44+
.rva names // NamePointerRVA
45+
.rva nameordinals // OrdinalTableRVA
46+
47+
names:
48+
.rva funcname_myfunc
49+
50+
nameordinals:
51+
.short 0
52+
53+
functions:
54+
.rva myfunc
55+
.long 0
56+
57+
funcname_myfunc:
58+
.asciz "myfunc"
59+
60+
name:
61+
.asciz "mydll.dll"

0 commit comments

Comments
 (0)