[lld] [LLD][COFF] Add support for hybrid exports on ARM64X (PR #123724)

Jacek Caban via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 21 02:09:19 PST 2025


https://github.com/cjacek created https://github.com/llvm/llvm-project/pull/123724

None

>From e9700633e684a833d5b643242ff23ffdbfbc24ee Mon Sep 17 00:00:00 2001
From: Jacek Caban <jacek at codeweavers.com>
Date: Wed, 25 Dec 2024 16:16:17 +0100
Subject: [PATCH 1/2] [LLD][COFF] Implement ARM64X relocations for the
 exception table

---
 lld/COFF/Chunks.cpp              | 12 +++++++++++-
 lld/COFF/Chunks.h                |  7 ++++++-
 lld/COFF/Writer.cpp              | 20 ++++++++++++++++++++
 lld/test/COFF/pdata-arm64ec.test | 21 ++++++++++++++++-----
 4 files changed, 53 insertions(+), 7 deletions(-)

diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp
index ff3c89884c24df..2ef74cb4ce6259 100644
--- a/lld/COFF/Chunks.cpp
+++ b/lld/COFF/Chunks.cpp
@@ -1167,7 +1167,7 @@ uint32_t ImportThunkChunkARM64EC::extendRanges() {
 }
 
 uint64_t Arm64XRelocVal::get() const {
-  return (sym ? sym->getRVA() : 0) + value;
+  return (sym ? sym->getRVA() : 0) + (chunk ? chunk->getRVA() : 0) + value;
 }
 
 size_t Arm64XDynamicRelocEntry::getSize() const {
@@ -1230,6 +1230,16 @@ void DynamicRelocsChunk::finalize() {
   size = alignTo(size, sizeof(uint32_t));
 }
 
+// Set the reloc value. The reloc entry must be allocated beforehand.
+void DynamicRelocsChunk::set(uint32_t rva, Arm64XRelocVal value) {
+  Arm64XDynamicRelocEntry &entry =
+      *llvm::find_if(arm64xRelocs, [rva](const Arm64XDynamicRelocEntry &e) {
+        return e.offset.get() == rva;
+      });
+  assert(!entry.value.get());
+  entry.value = value;
+}
+
 void DynamicRelocsChunk::writeTo(uint8_t *buf) const {
   auto table = reinterpret_cast<coff_dynamic_reloc_table *>(buf);
   table->Version = 1;
diff --git a/lld/COFF/Chunks.h b/lld/COFF/Chunks.h
index 7ba58e336451fc..d6216efdd90bdd 100644
--- a/lld/COFF/Chunks.h
+++ b/lld/COFF/Chunks.h
@@ -840,10 +840,13 @@ class Arm64XRelocVal {
 public:
   Arm64XRelocVal(uint64_t value = 0) : value(value) {}
   Arm64XRelocVal(Defined *sym, int32_t offset = 0) : sym(sym), value(offset) {}
+  Arm64XRelocVal(Chunk *chunk, int32_t offset = 0)
+      : chunk(chunk), value(offset) {}
   uint64_t get() const;
 
 private:
   Defined *sym = nullptr;
+  Chunk *chunk = nullptr;
   uint64_t value;
 };
 
@@ -874,10 +877,12 @@ class DynamicRelocsChunk : public NonSectionChunk {
   void finalize();
 
   void add(llvm::COFF::Arm64XFixupType type, uint8_t size,
-           Arm64XRelocVal offset, Arm64XRelocVal value) {
+           Arm64XRelocVal offset, Arm64XRelocVal value = Arm64XRelocVal()) {
     arm64xRelocs.emplace_back(type, size, offset, value);
   }
 
+  void set(uint32_t rva, Arm64XRelocVal value);
+
 private:
   std::vector<Arm64XDynamicRelocEntry> arm64xRelocs;
   size_t size;
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index 3d95d219a493cd..507621d1e95f80 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -2392,6 +2392,13 @@ void Writer::setECSymbols() {
       symtab->findUnderscore("__arm64x_native_entrypoint")
           ->replaceKeepingName(altEntrySym, sizeof(SymbolUnion));
     }
+
+    if (hybridPdata.first)
+      ctx.dynamicRelocs->set(
+          dataDirOffset64 + EXCEPTION_TABLE * sizeof(data_directory) +
+              offsetof(data_directory, Size),
+          hybridPdata.last->getRVA() - hybridPdata.first->getRVA() +
+              hybridPdata.last->getSize());
   }
 }
 
@@ -2644,6 +2651,19 @@ void Writer::createDynamicRelocs() {
       Warn(ctx) << "'__chpe_metadata' is missing for ARM64X target";
   }
 
+  if (pdata.first != hybridPdata.first) {
+    ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t),
+                           dataDirOffset64 +
+                               EXCEPTION_TABLE * sizeof(data_directory) +
+                               offsetof(data_directory, RelativeVirtualAddress),
+                           hybridPdata.first);
+    // The Size value is assigned after addresses are finalized.
+    ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t),
+                           dataDirOffset64 +
+                               EXCEPTION_TABLE * sizeof(data_directory) +
+                               offsetof(data_directory, Size));
+  }
+
   // Set the hybrid load config to the EC load config.
   ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t),
                          dataDirOffset64 +
diff --git a/lld/test/COFF/pdata-arm64ec.test b/lld/test/COFF/pdata-arm64ec.test
index 7f20c460dc1099..fbec797525f7f8 100644
--- a/lld/test/COFF/pdata-arm64ec.test
+++ b/lld/test/COFF/pdata-arm64ec.test
@@ -6,6 +6,7 @@ Test handlign of hybrid .pdata section on ARM64EC target.
 RUN: llvm-mc -filetype=obj -triple=arm64-windows arm64-func-sym.s -o arm64-func-sym.obj
 RUN: llvm-mc -filetype=obj -triple=arm64ec-windows arm64ec-func-sym.s -o arm64ec-func-sym.obj
 RUN: llvm-mc -filetype=obj -triple=x86_64-windows x86_64-func-sym.s -o x86_64-func-sym.obj
+RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64.s -o loadconfig-arm64.obj
 RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %p/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64ec.obj
 
 Only arm64ec code:
@@ -55,11 +56,21 @@ DATA3: 180005000 00100000 11000001 00200000 0e200000
 Mixed arm64x code:
 
 RUN: lld-link -out:test4.dll -machine:arm64x arm64-func-sym.obj arm64ec-func-sym.obj \
-RUN:          x86_64-func-sym.obj loadconfig-arm64ec.obj -dll -noentry
+RUN:          x86_64-func-sym.obj loadconfig-arm64.obj loadconfig-arm64ec.obj -dll -noentry
 
 RUN: llvm-readobj --headers test4.dll | FileCheck -check-prefix=DIR3 %s
-DIR3:      ExceptionTableRVA: 0x6000
-DIR3-NEXT: ExceptionTableSize: 0x10
+DIR3:      ImageOptionalHeader {
+DIR3:        DataDirectory {
+DIR3:          ExceptionTableRVA: 0x6000
+DIR3-NEXT:     ExceptionTableSize: 0x10
+DIR3:        }
+DIR3:      }
+DIR3:      HybridObject {
+DIR3:        ImageOptionalHeader {
+DIR3:          ExceptionTableRVA: 0x6010
+DIR3-NEXT:     ExceptionTableSize: 0xC
+DIR3:        }
+DIR3:      }
 
 RUN: llvm-objdump -s --section=.pdata test4.dll | FileCheck -check-prefix=DATA4 %s
 DATA4: 180006000 00100000 11000001 00200000 11000001  ......... ......
@@ -74,12 +85,12 @@ RUN: llvm-readobj --headers test5.dll | FileCheck -check-prefix=DIR2 %s
 RUN: llvm-objdump -s --section=.pdata test5.dll | FileCheck -check-prefix=DATA3 %s
 
 RUN: lld-link -out:test6.dll -machine:arm64x arm64ec-func-sym.obj x86_64-func-sym.obj \
-RUN:          arm64-func-sym.obj loadconfig-arm64ec.obj -dll -noentry
+RUN:          arm64-func-sym.obj loadconfig-arm64.obj loadconfig-arm64ec.obj -dll -noentry
 RUN: llvm-readobj --headers test6.dll | FileCheck -check-prefix=DIR3 %s
 RUN: llvm-objdump -s --section=.pdata test6.dll | FileCheck -check-prefix=DATA4 %s
 
 RUN: lld-link -out:test7.dll -machine:arm64x x86_64-func-sym.obj arm64ec-func-sym.obj \
-RUN:          arm64-func-sym.obj loadconfig-arm64ec.obj -dll -noentry
+RUN:          arm64-func-sym.obj loadconfig-arm64.obj loadconfig-arm64ec.obj -dll -noentry
 RUN: llvm-readobj --headers test7.dll | FileCheck -check-prefix=DIR3 %s
 RUN: llvm-objdump -s --section=.pdata test7.dll | FileCheck -check-prefix=DATA4 %s
 

>From dc7153d0817318e896860ea9295b65ba09e91899 Mon Sep 17 00:00:00 2001
From: Jacek Caban <jacek at codeweavers.com>
Date: Mon, 20 Jan 2025 23:05:04 +0100
Subject: [PATCH 2/2] [LLD][COFF] Add support for hybrid exports on ARM64X

---
 lld/COFF/SymbolTable.h           |   3 +
 lld/COFF/Writer.cpp              |  84 ++++++++++++++++++------
 lld/test/COFF/arm64x-export.test | 108 +++++++++++++++++++++++++++++++
 3 files changed, 174 insertions(+), 21 deletions(-)

diff --git a/lld/COFF/SymbolTable.h b/lld/COFF/SymbolTable.h
index a0acf5db469032..e5b02ce5904c49 100644
--- a/lld/COFF/SymbolTable.h
+++ b/lld/COFF/SymbolTable.h
@@ -155,6 +155,9 @@ class SymbolTable {
   llvm::DenseSet<StringRef> directivesExports;
   bool hadExplicitExports;
 
+  Chunk *edataStart = nullptr;
+  Chunk *edataEnd = nullptr;
+
   void fixupExports();
   void assignExportOrdinals();
 
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index 507621d1e95f80..bef2ced9f2957d 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -288,8 +288,6 @@ class Writer {
   IdataContents idata;
   Chunk *importTableStart = nullptr;
   uint64_t importTableSize = 0;
-  Chunk *edataStart = nullptr;
-  Chunk *edataEnd = nullptr;
   Chunk *iatStart = nullptr;
   uint64_t iatSize = 0;
   DelayLoadContents delayIdata;
@@ -1331,22 +1329,46 @@ void Writer::createExportTable() {
   if (!edataSec->chunks.empty()) {
     // Allow using a custom built export table from input object files, instead
     // of having the linker synthesize the tables.
-    if (ctx.symtab.hadExplicitExports)
-      Warn(ctx) << "literal .edata sections override exports";
-  } else if (!ctx.symtab.exports.empty()) {
-    std::vector<Chunk *> edataChunks;
-    createEdataChunks(ctx.symtab, edataChunks);
-    for (Chunk *c : edataChunks)
-      edataSec->addChunk(c);
-  }
-  if (!edataSec->chunks.empty()) {
-    edataStart = edataSec->chunks.front();
-    edataEnd = edataSec->chunks.back();
+    if (!ctx.hybridSymtab) {
+      ctx.symtab.edataStart = edataSec->chunks.front();
+      ctx.symtab.edataEnd = edataSec->chunks.back();
+    } else {
+      // On hybrid target, split EC and native chunks.
+      llvm::stable_sort(edataSec->chunks, [=](const Chunk *a, const Chunk *b) {
+        return (a->getMachine() != ARM64) < (b->getMachine() != ARM64);
+      });
+
+      for (auto chunk : edataSec->chunks) {
+        if (chunk->getMachine() != ARM64) {
+          ctx.hybridSymtab->edataStart = chunk;
+          ctx.hybridSymtab->edataEnd = edataSec->chunks.back();
+          break;
+        }
+
+        if (!ctx.symtab.edataStart)
+          ctx.symtab.edataStart = chunk;
+        ctx.symtab.edataEnd = chunk;
+      }
+    }
   }
-  // Warn on exported deleting destructor.
-  for (auto e : ctx.symtab.exports)
-    if (e.sym && e.sym->getName().starts_with("??_G"))
-      Warn(ctx) << "export of deleting dtor: " << e.sym;
+  ctx.forEachSymtab([&](SymbolTable &symtab) {
+    if (symtab.edataStart) {
+      if (symtab.hadExplicitExports)
+        Warn(ctx) << "literal .edata sections override exports";
+    } else if (!symtab.exports.empty()) {
+      std::vector<Chunk *> edataChunks;
+      createEdataChunks(symtab, edataChunks);
+      for (Chunk *c : edataChunks)
+        edataSec->addChunk(c);
+      symtab.edataStart = edataChunks.front();
+      symtab.edataEnd = edataChunks.back();
+    }
+
+    // Warn on exported deleting destructor.
+    for (auto e : symtab.exports)
+      if (e.sym && e.sym->getName().starts_with("??_G"))
+        Warn(ctx) << "export of deleting dtor: " << toString(ctx, *e.sym);
+  });
 }
 
 void Writer::removeUnusedSections() {
@@ -1819,10 +1841,11 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
          dataDirOffset64 == buf - buffer->getBufferStart());
   auto *dir = reinterpret_cast<data_directory *>(buf);
   buf += sizeof(*dir) * numberOfDataDirectory;
-  if (edataStart) {
-    dir[EXPORT_TABLE].RelativeVirtualAddress = edataStart->getRVA();
-    dir[EXPORT_TABLE].Size =
-        edataEnd->getRVA() + edataEnd->getSize() - edataStart->getRVA();
+  if (ctx.symtab.edataStart) {
+    dir[EXPORT_TABLE].RelativeVirtualAddress = ctx.symtab.edataStart->getRVA();
+    dir[EXPORT_TABLE].Size = ctx.symtab.edataEnd->getRVA() +
+                             ctx.symtab.edataEnd->getSize() -
+                             ctx.symtab.edataStart->getRVA();
   }
   if (importTableStart) {
     dir[IMPORT_TABLE].RelativeVirtualAddress = importTableStart->getRVA();
@@ -2393,6 +2416,12 @@ void Writer::setECSymbols() {
           ->replaceKeepingName(altEntrySym, sizeof(SymbolUnion));
     }
 
+    if (symtab->edataStart)
+      ctx.dynamicRelocs->set(
+          dataDirOffset64 + EXPORT_TABLE * sizeof(data_directory) +
+              offsetof(data_directory, Size),
+          symtab->edataEnd->getRVA() - symtab->edataStart->getRVA() +
+              symtab->edataEnd->getSize());
     if (hybridPdata.first)
       ctx.dynamicRelocs->set(
           dataDirOffset64 + EXCEPTION_TABLE * sizeof(data_directory) +
@@ -2651,6 +2680,19 @@ void Writer::createDynamicRelocs() {
       Warn(ctx) << "'__chpe_metadata' is missing for ARM64X target";
   }
 
+  if (ctx.symtab.edataStart != ctx.hybridSymtab->edataStart) {
+    ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t),
+                           dataDirOffset64 +
+                               EXPORT_TABLE * sizeof(data_directory) +
+                               offsetof(data_directory, RelativeVirtualAddress),
+                           ctx.hybridSymtab->edataStart);
+    // The Size value is assigned after addresses are finalized.
+    ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t),
+                           dataDirOffset64 +
+                               EXPORT_TABLE * sizeof(data_directory) +
+                               offsetof(data_directory, Size));
+  }
+
   if (pdata.first != hybridPdata.first) {
     ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t),
                            dataDirOffset64 +
diff --git a/lld/test/COFF/arm64x-export.test b/lld/test/COFF/arm64x-export.test
index e5d0307e570efd..526be633973581 100644
--- a/lld/test/COFF/arm64x-export.test
+++ b/lld/test/COFF/arm64x-export.test
@@ -5,6 +5,8 @@ RUN: llvm-mc -filetype=obj -triple=arm64ec-windows arm64ec-func.s -o arm64ec-fun
 RUN: llvm-mc -filetype=obj -triple=aarch64-windows arm64-func.s -o arm64-func.obj
 RUN: llvm-mc -filetype=obj -triple=arm64ec-windows func-drectve.s -o arm64ec-drectve.obj
 RUN: llvm-mc -filetype=obj -triple=aarch64-windows func-drectve.s -o arm64-drectve.obj
+RUN: llvm-mc -filetype=obj -triple=aarch64-windows edata.s -o arm64-edata.obj
+RUN: llvm-mc -filetype=obj -triple=arm64ec-windows edata.s -o arm64ec-edata.obj
 RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64ec.obj
 RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64.s -o loadconfig-arm64.obj
 
@@ -36,6 +38,15 @@ RUN: llvm-readobj --headers --coff-exports out-cmd.dll | FileCheck --check-prefi
 EXPORTS-EC:      ExportTableRVA: 0x0
 EXPORTS-EC-NEXT: ExportTableSize: 0x0
 EXPORTS-EC-NOT:  Name: func
+EXPORTS-EC:      HybridObject {
+EXPORTS-EC:        ExportTableRVA: 0x3{{.*}}
+EXPORTS-EC-NEXT:   ExportTableSize: 0x4{{.*}}
+EXPORTS-EC:        Export {
+EXPORTS-EC-NEXT:     Ordinal: 1
+EXPORTS-EC-NEXT:     Name: func
+EXPORTS-EC-NEXT:     RVA: 0x2000
+EXPORTS-EC-NEXT:   }
+EXPORTS-EC-NEXT: }
 
 # Export using the EC .drectve section.
 
@@ -44,6 +55,30 @@ RUN:          loadconfig-arm64.obj loadconfig-arm64ec.obj arm64ec-drectve.obj -n
 RUN: llvm-objdump -d out-drectve-ec.dll | FileCheck --check-prefix=DISASM-EC %s
 RUN: llvm-readobj --headers --coff-exports out-drectve-ec.dll | FileCheck --check-prefix=EXPORTS-EC %s
 
+# Export using the EC .edata section.
+
+RUN: lld-link -machine:arm64x -dll -out:out-edata-ec.dll arm64ec-func.obj arm64-func.obj \
+RUN:          loadconfig-arm64.obj loadconfig-arm64ec.obj arm64ec-edata.obj -noentry
+
+RUN: llvm-objdump -d out-edata-ec.dll | FileCheck --check-prefix=DISASM-EDATA-EC %s
+DISASM-EDATA-EC:      0000000180001000 <.text>:
+DISASM-EDATA-EC-NEXT: 180001000: 52800040     mov     w0, #0x2                // =2
+DISASM-EDATA-EC-NEXT: 180001004: d65f03c0     ret
+
+RUN: llvm-readobj --headers --coff-exports out-edata-ec.dll | FileCheck --check-prefix=EXPORTS-EDATA-EC %s
+EXPORTS-EDATA-EC:      ExportTableRVA: 0x0
+EXPORTS-EDATA-EC-NEXT: ExportTableSize: 0x0
+EXPORTS-EDATA-EC-NOT:  Name: func
+EXPORTS-EDATA-EC:      HybridObject {
+EXPORTS-EDATA-EC:        ExportTableRVA: 0x2{{.*}}
+EXPORTS-EDATA-EC-NEXT:   ExportTableSize: 0x4{{.*}}
+EXPORTS-EDATA-EC:        Export {
+EXPORTS-EDATA-EC-NEXT:     Ordinal: 1
+EXPORTS-EDATA-EC-NEXT:     Name: func
+EXPORTS-EDATA-EC-NEXT:     RVA: 0x1000
+EXPORTS-EDATA-EC-NEXT:   }
+EXPORTS-EDATA-EC-NEXT: }
+
 # Export using the native .drectve section.
 
 RUN: lld-link -machine:arm64x -dll -out:out-drectve-native.dll arm64ec-func.obj arm64-func.obj \
@@ -64,6 +99,17 @@ EXPORTS-NATIVE-NEXT:   Ordinal: 1
 EXPORTS-NATIVE-NEXT:   Name: func
 EXPORTS-NATIVE-NEXT:   RVA: 0x1000
 EXPORTS-NATIVE-NEXT: }
+EXPORTS-NATIVE:      HybridObject {
+EXPORTS-NATIVE:        ExportTableRVA: 0x0
+EXPORTS-NATIVE-NEXT:   ExportTableSize: 0x0
+EXPORTS-NATIVE-NOT:    Name: func
+
+# Export using the native .edata section.
+
+RUN: lld-link -machine:arm64x -dll -out:out-edata.dll arm64ec-func.obj arm64-func.obj \
+RUN:          loadconfig-arm64.obj loadconfig-arm64ec.obj arm64-edata.obj -noentry
+RUN: llvm-objdump -d out-edata.dll | FileCheck --check-prefix=DISASM-NATIVE %s
+RUN: llvm-readobj --headers --coff-exports out-edata.dll | FileCheck --check-prefix=EXPORTS-NATIVE %s
 
 # Export using both the native and EC .drectve sections.
 
@@ -99,6 +145,37 @@ EXPORTS-BOTH-NEXT:   Ordinal: 1
 EXPORTS-BOTH-NEXT:   Name: func
 EXPORTS-BOTH-NEXT:   RVA: 0x1000
 EXPORTS-BOTH-NEXT: }
+EXPORTS-BOTH:      HybridObject {
+EXPORTS-BOTH:        ExportTableRVA: 0x4{{.*}}
+EXPORTS-BOTH-NEXT:   ExportTableSize: 0x4{{.*}}
+EXPORTS-BOTH:        Export {
+EXPORTS-BOTH-NEXT:     Ordinal: 1
+EXPORTS-BOTH-NEXT:     Name: func
+EXPORTS-BOTH-NEXT:     RVA: 0x3000
+EXPORTS-BOTH-NEXT:   }
+EXPORTS-BOTH-NEXT: }
+
+# Export using both the native and EC .edata sections.
+
+RUN: lld-link -machine:arm64x -dll -out:out-edata-both.dll arm64ec-func.obj arm64-func.obj \
+RUN:          loadconfig-arm64.obj loadconfig-arm64ec.obj arm64-edata.obj arm64ec-edata.obj -noentry
+RUN: llvm-readobj --headers --coff-exports out-edata-both.dll | FileCheck --check-prefix=EXPORTS-EDATA-BOTH %s
+EXPORTS-EDATA-BOTH:      ExportTableRVA: 0x3{{.*}}
+EXPORTS-EDATA-BOTH-NEXT: ExportTableSize: 0x4{{.*}}
+EXPORTS-EDATA-BOTH:      Export {
+EXPORTS-EDATA-BOTH-NEXT:   Ordinal: 1
+EXPORTS-EDATA-BOTH-NEXT:   Name: func
+EXPORTS-EDATA-BOTH-NEXT:   RVA: 0x1000
+EXPORTS-EDATA-BOTH-NEXT: }
+EXPORTS-EDATA-BOTH:      HybridObject {
+EXPORTS-EDATA-BOTH:        ExportTableRVA: 0x3{{.*}}
+EXPORTS-EDATA-BOTH-NEXT:   ExportTableSize: 0x4{{.*}}
+EXPORTS-EDATA-BOTH:        Export {
+EXPORTS-EDATA-BOTH-NEXT:     Ordinal: 1
+EXPORTS-EDATA-BOTH-NEXT:     Name: func
+EXPORTS-EDATA-BOTH-NEXT:     RVA: 0x2000
+EXPORTS-EDATA-BOTH-NEXT:   }
+EXPORTS-EDATA-BOTH-NEXT: }
 
 #--- arm64-func.s
     .section .text,"xr",discard,func
@@ -119,3 +196,34 @@ func:
 #--- func-drectve.s
 .section .drectve
     .ascii "-export:func"
+
+#--- edata.s
+    .section .edata, "dr"
+    .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_func
+
+nameordinals:
+    .short 0
+
+functions:
+    .rva func
+    .long 0
+
+funcname_func:
+    .asciz "func"
+
+name:
+    .asciz "out-edata.dll"



More information about the llvm-commits mailing list