[lld] r369358 - [COFF] Allow using custom .edata from input object files

Martin Storsjo via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 20 02:53:06 PDT 2019


Author: mstorsjo
Date: Tue Aug 20 02:53:06 2019
New Revision: 369358

URL: http://llvm.org/viewvc/llvm-project?rev=369358&view=rev
Log:
[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

Added:
    lld/trunk/test/COFF/edata.s
Modified:
    lld/trunk/COFF/Config.h
    lld/trunk/COFF/Driver.cpp
    lld/trunk/COFF/Writer.cpp

Modified: lld/trunk/COFF/Config.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Config.h?rev=369358&r1=369357&r2=369358&view=diff
==============================================================================
--- lld/trunk/COFF/Config.h (original)
+++ lld/trunk/COFF/Config.h Tue Aug 20 02:53:06 2019
@@ -122,6 +122,7 @@ struct Configuration {
   bool dll = false;
   StringRef implib;
   std::vector<Export> exports;
+  bool hadExplicitExports;
   std::set<std::string> delayLoads;
   std::map<std::string, int> dllOrder;
   Symbol *delayLoadHelper = nullptr;

Modified: lld/trunk/COFF/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Driver.cpp?rev=369358&r1=369357&r2=369358&view=diff
==============================================================================
--- lld/trunk/COFF/Driver.cpp (original)
+++ lld/trunk/COFF/Driver.cpp Tue Aug 20 02:53:06 2019
@@ -1817,6 +1817,7 @@ void LinkerDriver::link(ArrayRef<const c
   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.

Modified: lld/trunk/COFF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Writer.cpp?rev=369358&r1=369357&r2=369358&view=diff
==============================================================================
--- lld/trunk/COFF/Writer.cpp (original)
+++ lld/trunk/COFF/Writer.cpp Tue Aug 20 02:53:06 2019
@@ -240,6 +240,8 @@ private:
   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 @@ void Writer::createSections() {
   }
 
   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::appendImportThunks() {
 }
 
 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 @@ template <typename PEHeaderTy> void Writ
   // Write data directory
   auto *dir = reinterpret_cast<data_directory *>(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();

Added: lld/trunk/test/COFF/edata.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/edata.s?rev=369358&view=auto
==============================================================================
--- lld/trunk/test/COFF/edata.s (added)
+++ lld/trunk/test/COFF/edata.s Tue Aug 20 02:53:06 2019
@@ -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"




More information about the llvm-commits mailing list