[lld] [LLD][COFF] Add support for CHPE code ranges metadata. (PR #105741)

via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 22 14:51:36 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lld

Author: Jacek Caban (cjacek)

<details>
<summary>Changes</summary>

This is part of CHPE metadata containing a sorted list of x86_64 export thunks RVAs and sizes.

---
Full diff: https://github.com/llvm/llvm-project/pull/105741.diff


7 Files Affected:

- (modified) lld/COFF/Chunks.cpp (+29) 
- (modified) lld/COFF/Chunks.h (+22) 
- (modified) lld/COFF/Driver.cpp (+4) 
- (modified) lld/COFF/Writer.cpp (+35-1) 
- (modified) lld/test/COFF/Inputs/loadconfig-arm64ec.s (+4-4) 
- (modified) lld/test/COFF/arm64ec-export-thunks.test (+32-2) 
- (modified) lld/test/COFF/arm64ec-patchable-thunks.test (+7-1) 


``````````diff
diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp
index be44950a1720e3..72a9ad05ca11c1 100644
--- a/lld/COFF/Chunks.cpp
+++ b/lld/COFF/Chunks.cpp
@@ -1078,4 +1078,33 @@ void ECExportThunkChunk::writeTo(uint8_t *buf) const {
   write32le(buf + 10, target->getRVA() - rva - 14);
 }
 
+size_t CHPECodeRangesChunk::getSize() const {
+  return exportThunks.size() * sizeof(chpe_code_range_entry);
+}
+
+void CHPECodeRangesChunk::writeTo(uint8_t *buf) const {
+  auto ranges = reinterpret_cast<chpe_code_range_entry *>(buf);
+
+  for (uint32_t i = 0; i < exportThunks.size(); i++) {
+    Chunk *thunk = exportThunks[i].first;
+    uint32_t start = thunk->getRVA();
+    ranges[i].StartRva = start;
+    ranges[i].EndRva = start + thunk->getSize();
+    ranges[i].EntryPoint = start;
+  }
+}
+
+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..fe202008971a54 100644
--- a/lld/COFF/Chunks.h
+++ b/lld/COFF/Chunks.h
@@ -749,6 +749,28 @@ class ECCodeMapChunk : public NonSectionChunk {
   std::vector<ECCodeMapEntry> ↦
 };
 
+class CHPECodeRangesChunk : public NonSectionChunk {
+public:
+  CHPECodeRangesChunk(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;
+};
+
+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..3ef9fa3f65c6a6 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -2440,8 +2440,12 @@ 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);
+    ctx.symtab.addAbsolute("__x64_code_ranges_to_entry_points", 0);
+    ctx.symtab.addAbsolute("__x64_code_ranges_to_entry_points_count", 0);
   }
 
   if (config->pseudoRelocs) {
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index 776595d98c391d..0360e186ecf0cf 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,19 @@ void Writer::createECChunks() {
   Symbol *codeMapSym = ctx.symtab.findUnderscore("__hybrid_code_map");
   replaceSymbol<DefinedSynthetic>(codeMapSym, codeMapSym->getName(),
                                   codeMapChunk);
+
+  CHPECodeRangesChunk *ranges = make<CHPECodeRangesChunk>(exportThunks);
+  rdataSec->addChunk(ranges);
+  Symbol *rangesSym =
+      ctx.symtab.findUnderscore("__x64_code_ranges_to_entry_points");
+  replaceSymbol<DefinedSynthetic>(rangesSym, rangesSym->getName(), ranges);
+
+  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 +2175,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 +2191,14 @@ void Writer::setECSymbols() {
         ->setVA(pdata.last->getRVA() + pdata.last->getSize() -
                 pdata.first->getRVA());
   }
+
+  Symbol *rangesCountSym =
+      ctx.symtab.findUnderscore("__x64_code_ranges_to_entry_points_count");
+  cast<DefinedAbsolute>(rangesCountSym)->setVA(exportThunks.size());
+
+  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..78e7fba43a0a4d 100644
--- a/lld/test/COFF/Inputs/loadconfig-arm64ec.s
+++ b/lld/test/COFF/Inputs/loadconfig-arm64ec.s
@@ -66,8 +66,8 @@ __chpe_metadata:
         .word 1
         .rva __hybrid_code_map
         .word __hybrid_code_map_count
-        .word 0 // __x64_code_ranges_to_entry_points
-        .word 0 //__arm64x_redirection_metadata
+        .rva __x64_code_ranges_to_entry_points
+        .rva __arm64x_redirection_metadata
         .rva __os_arm64x_dispatch_call_no_redirect
         .rva __os_arm64x_dispatch_ret
         .rva __os_arm64x_check_call
@@ -75,8 +75,8 @@ __chpe_metadata:
         .rva __os_arm64x_check_icall_cfg
         .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 __x64_code_ranges_to_entry_points_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..809fac1f24a7dc 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,33 @@ EXP-CHPE:       CodeMap [
 EXP-CHPE-NEXT:    0x1000 - 0x100C  ARM64EC
 EXP-CHPE-NEXT:    0x2000 - 0x3020  X64
 EXP-CHPE-NEXT:  ]
+EXP-CHPE-NEXT:  CodeRangesToEntryPoints [
+EXP-CHPE-NEXT:    0x3000 - 0x3010 -> 0x3000
+EXP-CHPE-NEXT:    0x3010 - 0x3020 -> 0x3010
+EXP-CHPE-NEXT:  ]
+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 +124,12 @@ ENTRY-CHPE:       CodeMap [
 ENTRY-CHPE-NEXT:    0x1000 - 0x100C  ARM64EC
 ENTRY-CHPE-NEXT:    0x2000 - 0x2010  X64
 ENTRY-CHPE-NEXT:  ]
+ENTRY-CHPE-NEXT:  CodeRangesToEntryPoints [
+ENTRY-CHPE-NEXT:    0x2000 - 0x2010 -> 0x2000
+ENTRY-CHPE-NEXT:  ]
+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..5cebe7cc27ad63 100644
--- a/lld/test/COFF/arm64ec-patchable-thunks.test
+++ b/lld/test/COFF/arm64ec-patchable-thunks.test
@@ -27,13 +27,19 @@ 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 [
+PATCH-CHPE-NEXT:    0x2000 - 0x2010 -> 0x2000
+PATCH-CHPE-NEXT:  ]
+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

``````````

</details>


https://github.com/llvm/llvm-project/pull/105741


More information about the llvm-commits mailing list