[lld] caa844e - [LLD][COFF] Add support for CHPE redirection metadata. (#105739)

via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 23 11:29:22 PDT 2024


Author: Jacek Caban
Date: 2024-08-23T20:29:19+02:00
New Revision: caa844e67cbb5e4f5f20a237d713a227ce65b5b9

URL: https://github.com/llvm/llvm-project/commit/caa844e67cbb5e4f5f20a237d713a227ce65b5b9
DIFF: https://github.com/llvm/llvm-project/commit/caa844e67cbb5e4f5f20a237d713a227ce65b5b9.diff

LOG: [LLD][COFF] Add support for CHPE redirection metadata. (#105739)

This is part of CHPE metadata containing a sorted list of x86_64 export
thunks RVAs and RVAs of ARM64EC functions associated with them. It's
stored in a dedicated .a64xrm section.

Added: 
    

Modified: 
    lld/COFF/Chunks.cpp
    lld/COFF/Chunks.h
    lld/COFF/Driver.cpp
    lld/COFF/Writer.cpp
    lld/test/COFF/Inputs/loadconfig-arm64ec.s
    lld/test/COFF/arm64ec-export-thunks.test
    lld/test/COFF/arm64ec-patchable-thunks.test

Removed: 
    


################################################################################
diff  --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp
index be44950a1720e3..4e3a564ebacd87 100644
--- a/lld/COFF/Chunks.cpp
+++ b/lld/COFF/Chunks.cpp
@@ -1078,4 +1078,17 @@ void ECExportThunkChunk::writeTo(uint8_t *buf) const {
   write32le(buf + 10, target->getRVA() - rva - 14);
 }
 
+size_t CHPERedirectionChunk::getSize() const {
+  return exportThunks.size() * sizeof(chpe_redirection_entry);
+}
+
+void CHPERedirectionChunk::writeTo(uint8_t *buf) const {
+  auto entries = reinterpret_cast<chpe_redirection_entry *>(buf);
+
+  for (uint32_t i = 0; i < exportThunks.size(); i++) {
+    entries[i].Source = exportThunks[i].first->getRVA();
+    entries[i].Destination = exportThunks[i].second->getRVA();
+  }
+}
+
 } // namespace lld::coff

diff  --git a/lld/COFF/Chunks.h b/lld/COFF/Chunks.h
index 5443d4619a977e..015df41b04c67d 100644
--- a/lld/COFF/Chunks.h
+++ b/lld/COFF/Chunks.h
@@ -749,6 +749,17 @@ class ECCodeMapChunk : public NonSectionChunk {
   std::vector<ECCodeMapEntry> ↦
 };
 
+class CHPERedirectionChunk : public NonSectionChunk {
+public:
+  CHPERedirectionChunk(std::vector<std::pair<Chunk *, Defined *>> &exportThunks)
+      : exportThunks(exportThunks) {}
+  size_t getSize() const override;
+  void writeTo(uint8_t *buf) const override;
+
+private:
+  std::vector<std::pair<Chunk *, Defined *>> &exportThunks;
+};
+
 static const uint8_t ECExportThunkCode[] = {
     0x48, 0x8b, 0xc4,          // movq    %rsp, %rax
     0x48, 0x89, 0x58, 0x20,    // movq    %rbx, 0x20(%rax)

diff  --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index c09c91fe4b1719..472f5074ba8b8c 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -2440,6 +2440,8 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
   if (isArm64EC(config->machine)) {
     ctx.symtab.addAbsolute("__arm64x_extra_rfe_table", 0);
     ctx.symtab.addAbsolute("__arm64x_extra_rfe_table_size", 0);
+    ctx.symtab.addAbsolute("__arm64x_redirection_metadata", 0);
+    ctx.symtab.addAbsolute("__arm64x_redirection_metadata_count", 0);
     ctx.symtab.addAbsolute("__hybrid_code_map", 0);
     ctx.symtab.addAbsolute("__hybrid_code_map_count", 0);
   }

diff  --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index 776595d98c391d..358d16fe330cea 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -298,6 +298,9 @@ class Writer {
   CVDebugRecordChunk *buildId = nullptr;
   ArrayRef<uint8_t> sectionTable;
 
+  // List of Arm64EC export thunks.
+  std::vector<std::pair<Chunk *, Defined *>> exportThunks;
+
   uint64_t fileSize;
   uint32_t pointerToSymbolTable = 0;
   uint64_t sizeOfImage;
@@ -312,6 +315,7 @@ class Writer {
   OutputSection *idataSec;
   OutputSection *edataSec;
   OutputSection *didatSec;
+  OutputSection *a64xrmSec;
   OutputSection *rsrcSec;
   OutputSection *relocSec;
   OutputSection *ctorsSec;
@@ -995,6 +999,8 @@ void Writer::createSections() {
   idataSec = createSection(".idata", data | r);
   edataSec = createSection(".edata", data | r);
   didatSec = createSection(".didat", data | r);
+  if (isArm64EC(ctx.config.machine))
+    a64xrmSec = createSection(".a64xrm", data | r);
   rsrcSec = createSection(".rsrc", data | r);
   relocSec = createSection(".reloc", data | discardable | r);
   ctorsSec = createSection(".ctors", data | r | w);
@@ -2053,8 +2059,10 @@ void Writer::createECChunks() {
     auto sym = dyn_cast<Defined>(s);
     if (!sym || !sym->getChunk())
       continue;
-    if (auto thunk = dyn_cast<ECExportThunkChunk>(sym->getChunk()))
+    if (auto thunk = dyn_cast<ECExportThunkChunk>(sym->getChunk())) {
       hexpthkSec->addChunk(thunk);
+      exportThunks.push_back({thunk, thunk->target});
+    }
   }
 
   auto codeMapChunk = make<ECCodeMapChunk>(codeMap);
@@ -2062,6 +2070,13 @@ void Writer::createECChunks() {
   Symbol *codeMapSym = ctx.symtab.findUnderscore("__hybrid_code_map");
   replaceSymbol<DefinedSynthetic>(codeMapSym, codeMapSym->getName(),
                                   codeMapChunk);
+
+  CHPERedirectionChunk *entryPoints = make<CHPERedirectionChunk>(exportThunks);
+  a64xrmSec->addChunk(entryPoints);
+  Symbol *entryPointsSym =
+      ctx.symtab.findUnderscore("__arm64x_redirection_metadata");
+  replaceSymbol<DefinedSynthetic>(entryPointsSym, entryPointsSym->getName(),
+                                  entryPoints);
 }
 
 // MinGW specific. Gather all relocations that are imported from a DLL even
@@ -2154,6 +2169,11 @@ void Writer::setECSymbols() {
   if (!isArm64EC(ctx.config.machine))
     return;
 
+  llvm::stable_sort(exportThunks, [](const std::pair<Chunk *, Defined *> &a,
+                                     const std::pair<Chunk *, Defined *> &b) {
+    return a.first->getRVA() < b.first->getRVA();
+  });
+
   Symbol *rfeTableSym = ctx.symtab.findUnderscore("__arm64x_extra_rfe_table");
   replaceSymbol<DefinedSynthetic>(rfeTableSym, "__arm64x_extra_rfe_table",
                                   pdata.first);
@@ -2165,6 +2185,10 @@ void Writer::setECSymbols() {
         ->setVA(pdata.last->getRVA() + pdata.last->getSize() -
                 pdata.first->getRVA());
   }
+
+  Symbol *entryPointCountSym =
+      ctx.symtab.findUnderscore("__arm64x_redirection_metadata_count");
+  cast<DefinedAbsolute>(entryPointCountSym)->setVA(exportThunks.size());
 }
 
 // Write section contents to a mmap'ed file.

diff  --git a/lld/test/COFF/Inputs/loadconfig-arm64ec.s b/lld/test/COFF/Inputs/loadconfig-arm64ec.s
index a270d281095dd6..62a6d0cab642e9 100644
--- a/lld/test/COFF/Inputs/loadconfig-arm64ec.s
+++ b/lld/test/COFF/Inputs/loadconfig-arm64ec.s
@@ -67,7 +67,7 @@ __chpe_metadata:
         .rva __hybrid_code_map
         .word __hybrid_code_map_count
         .word 0 // __x64_code_ranges_to_entry_points
-        .word 0 //__arm64x_redirection_metadata
+        .rva __arm64x_redirection_metadata
         .rva __os_arm64x_dispatch_call_no_redirect
         .rva __os_arm64x_dispatch_ret
         .rva __os_arm64x_check_call
@@ -76,7 +76,7 @@ __chpe_metadata:
         .word 0 // __arm64x_native_entrypoint
         .word 0 // __hybrid_auxiliary_iat
         .word 0 // __x64_code_ranges_to_entry_points_count
-        .word 0 // __arm64x_redirection_metadata_count
+        .word __arm64x_redirection_metadata_count
         .rva __os_arm64x_get_x64_information
         .rva __os_arm64x_set_x64_information
         .rva __arm64x_extra_rfe_table

diff  --git a/lld/test/COFF/arm64ec-export-thunks.test b/lld/test/COFF/arm64ec-export-thunks.test
index 6ed0514d4b17f3..2e4cfd6203b751 100644
--- a/lld/test/COFF/arm64ec-export-thunks.test
+++ b/lld/test/COFF/arm64ec-export-thunks.test
@@ -49,7 +49,7 @@ EXP-DISASM-NEXT: 18000301f: cc                           int3
 RUN: llvm-objdump -p exports.dll | FileCheck -check-prefix=EXP-EXPORT %s
 EXP-EXPORT:      Ordinal      RVA  Name
 EXP-EXPORT-NEXT:       1   0x3010  arm64ec_func
-EXP-EXPORT-NEXT:       2   0x6000  data_sym
+EXP-EXPORT-NEXT:       2   0x7000  data_sym
 EXP-EXPORT-NEXT:       3   0x3000  func
 EXP-EXPORT-NEXT:       4   0x2000  x86_64_func
 
@@ -58,9 +58,30 @@ EXP-CHPE:       CodeMap [
 EXP-CHPE-NEXT:    0x1000 - 0x100C  ARM64EC
 EXP-CHPE-NEXT:    0x2000 - 0x3020  X64
 EXP-CHPE-NEXT:  ]
+EXP-CHPE-NEXT:  CodeRangesToEntryPoints: 0
+EXP-CHPE-NEXT:  RedirectionMetadata [
+EXP-CHPE-NEXT:    0x3000 -> 0x1000
+EXP-CHPE-NEXT:    0x3010 -> 0x1000
+EXP-CHPE-NEXT:  ]
+
+RUN: llvm-readobj --sections exports.dll | FileCheck --check-prefix=A64XRM %s
+
+A64XRM:      Name: .a64xrm (2E 61 36 34 78 72 6D 00)
+A64XRM-NEXT: VirtualSize: 0x10
+A64XRM-NEXT: VirtualAddress: 0x6000
+A64XRM-NEXT: RawDataSize: 512
+A64XRM-NEXT: PointerToRawData:
+A64XRM-NEXT: PointerToRelocations: 0x0
+A64XRM-NEXT: PointerToLineNumbers: 0x0
+A64XRM-NEXT: RelocationCount: 0
+A64XRM-NEXT: LineNumberCount: 0
+A64XRM-NEXT: Characteristics [ (0x40000040)
+A64XRM-NEXT:   IMAGE_SCN_CNT_INITIALIZED_DATA (0x40)
+A64XRM-NEXT:   IMAGE_SCN_MEM_READ (0x40000000)
+A64XRM-NEXT: ]
 
 RUN: llvm-objdump -s --section=.test exports.dll | FileCheck --check-prefix=EXP-DATA %s
-EXP-DATA: 180006000 00300000 10300000
+EXP-DATA: 180007000 00300000 10300000
 
 RUN: lld-link -out:exports2.dll -machine:arm64ec antidep-func.obj x86_64-func.obj loadconfig-arm64ec.obj \
 RUN:          arm64ec-data.obj -dll -noentry -export:arm64ec_func -export:func=arm64ec_func \
@@ -100,6 +121,10 @@ ENTRY-CHPE:       CodeMap [
 ENTRY-CHPE-NEXT:    0x1000 - 0x100C  ARM64EC
 ENTRY-CHPE-NEXT:    0x2000 - 0x2010  X64
 ENTRY-CHPE-NEXT:  ]
+ENTRY-CHPE-NEXT:  CodeRangesToEntryPoints: 0
+ENTRY-CHPE-NEXT:  RedirectionMetadata [
+ENTRY-CHPE-NEXT:    0x2000 -> 0x1000
+ENTRY-CHPE-NEXT:  ]
 
 
 Test exporting data symbol as a function:

diff  --git a/lld/test/COFF/arm64ec-patchable-thunks.test b/lld/test/COFF/arm64ec-patchable-thunks.test
index cccd42eebfd367..044f3c7cebdf8e 100644
--- a/lld/test/COFF/arm64ec-patchable-thunks.test
+++ b/lld/test/COFF/arm64ec-patchable-thunks.test
@@ -27,13 +27,17 @@ PATCH-DISASM-NEXT: 18000200e: cc                           int3
 PATCH-DISASM-NEXT: 18000200f: cc                           int3
 
 RUN: llvm-readobj --hex-dump=.test test.dll | FileCheck -check-prefix=RVA %s
-RVA: 0x180005000 00200000
+RVA: 0x180006000 00200000
 
 RUN: llvm-readobj --coff-load-config test.dll | FileCheck -check-prefix=PATCH-CHPE %s
 PATCH-CHPE:       CodeMap [
 PATCH-CHPE-NEXT:    0x1000 - 0x1008  ARM64EC
 PATCH-CHPE-NEXT:    0x2000 - 0x2010  X64
 PATCH-CHPE-NEXT:  ]
+PATCH-CHPE-NEXT:  CodeRangesToEntryPoints: 0
+PATCH-CHPE-NEXT:  RedirectionMetadata [
+PATCH-CHPE-NEXT:    0x2000 -> 0x1000
+PATCH-CHPE-NEXT:  ]
 
 
 RUN: lld-link -out:test2.dll -machine:arm64ec arm64ec-alias.obj test-sec.obj loadconfig-arm64ec.obj -dll -noentry


        


More information about the llvm-commits mailing list