-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[LLD][COFF] Use EC symbol table for CHPE metadata #120328
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Depends on #120326. According to my testing, MSVC handles this by copying the value from the EC load configuration to the native one. This approach allows tests to be updated to use load configurations correctly on ARM64X by relying on a regular native ARM64 load configuration without CHPE metadata. |
@llvm/pr-subscribers-platform-windows @llvm/pr-subscribers-lld Author: Jacek Caban (cjacek) ChangesCopy CHPE metadata pointer from EC load config to native configuration. Patch is 30.83 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/120328.diff 14 Files Affected:
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index bef55abb7f856e..d5f84cfe36e133 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -2548,7 +2548,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
symtab.addAbsolute(mangle("__guard_eh_cont_count"), 0);
symtab.addAbsolute(mangle("__guard_eh_cont_table"), 0);
- if (isArm64EC(ctx.config.machine)) {
+ if (symtab.isEC()) {
symtab.addAbsolute("__arm64x_extra_rfe_table", 0);
symtab.addAbsolute("__arm64x_extra_rfe_table_size", 0);
symtab.addAbsolute("__arm64x_redirection_metadata", 0);
@@ -2822,6 +2822,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
if (ctx.symtabEC)
ctx.symtabEC->initializeECThunks();
+ ctx.forEachSymtab([](SymbolTable &symtab) { symtab.initializeLoadConfig(); });
// Identify unreferenced COMDAT sections.
if (config->doGC) {
diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp
index 6b3375e13e8393..7e243fc626d38d 100644
--- a/lld/COFF/SymbolTable.cpp
+++ b/lld/COFF/SymbolTable.cpp
@@ -27,6 +27,7 @@
#include <utility>
using namespace llvm;
+using namespace llvm::support;
namespace lld::coff {
@@ -595,6 +596,52 @@ std::pair<Symbol *, bool> SymbolTable::insert(StringRef name, InputFile *file) {
return result;
}
+void SymbolTable::initializeLoadConfig() {
+ auto sym =
+ dyn_cast_or_null<DefinedRegular>(findUnderscore("_load_config_used"));
+ if (!sym) {
+ if (ctx.config.guardCF != GuardCFLevel::Off)
+ Warn(ctx)
+ << "Control Flow Guard is enabled but '_load_config_used' is missing";
+ if (ctx.config.dependentLoadFlags)
+ Warn(ctx) << "_load_config_used not found, /dependentloadflag will have "
+ "no effect";
+ return;
+ }
+
+ SectionChunk *sc = sym->getChunk();
+ if (!sc->hasData) {
+ Err(ctx) << "_load_config_used points to uninitialized data";
+ return;
+ }
+ uint64_t offsetInChunk = sym->getValue();
+ if (offsetInChunk + 4 > sc->getSize()) {
+ Err(ctx) << "_load_config_used section chunk is too small";
+ return;
+ }
+
+ ArrayRef<uint8_t> secContents = sc->getContents();
+ loadConfigSize =
+ *reinterpret_cast<const ulittle32_t *>(&secContents[offsetInChunk]);
+ if (offsetInChunk + loadConfigSize > sc->getSize()) {
+ Err(ctx) << "_load_config_used specifies a size larger than its containing "
+ "section chunk";
+ return;
+ }
+
+ uint32_t expectedAlign = ctx.config.is64() ? 8 : 4;
+ if (sc->getAlignment() < expectedAlign)
+ Warn(ctx) << "'_load_config_used' is misaligned (expected alignment to be "
+ << expectedAlign << " bytes, got " << sc->getAlignment()
+ << " instead)";
+ else if (!isAligned(Align(expectedAlign), offsetInChunk))
+ Warn(ctx) << "'_load_config_used' is misaligned (section offset is 0x"
+ << Twine::utohexstr(sym->getValue()) << " not aligned to "
+ << expectedAlign << " bytes)";
+
+ loadConfigSym = sym;
+}
+
void SymbolTable::addEntryThunk(Symbol *from, Symbol *to) {
entryThunks.push_back({from, to});
}
diff --git a/lld/COFF/SymbolTable.h b/lld/COFF/SymbolTable.h
index b694893b903aa3..8548a6d036a9db 100644
--- a/lld/COFF/SymbolTable.h
+++ b/lld/COFF/SymbolTable.h
@@ -138,6 +138,10 @@ class SymbolTable {
callback(pair.second);
}
+ DefinedRegular *loadConfigSym = nullptr;
+ uint32_t loadConfigSize = 0;
+ void initializeLoadConfig();
+
private:
/// Given a name without "__imp_" prefix, returns a defined symbol
/// with the "__imp_" prefix, if it exists.
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index 3c6112b7fc89ad..7952ad5474ec4e 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -282,7 +282,8 @@ class Writer {
uint32_t getSizeOfInitializedData();
void prepareLoadConfig();
- template <typename T> void prepareLoadConfig(T *loadConfig);
+ template <typename T>
+ void prepareLoadConfig(SymbolTable &symtab, T *loadConfig);
std::unique_ptr<FileOutputBuffer> &buffer;
std::map<PartialSectionKey, PartialSection *> partialSections;
@@ -574,7 +575,7 @@ bool Writer::createThunks(OutputSection *os, int margin) {
// Create a code map for CHPE metadata.
void Writer::createECCodeMap() {
- if (!isArm64EC(ctx.config.machine))
+ if (!ctx.symtabEC)
return;
// Clear the map in case we were're recomputing the map after adding
@@ -610,7 +611,8 @@ void Writer::createECCodeMap() {
closeRange();
- Symbol *tableCountSym = ctx.symtab.findUnderscore("__hybrid_code_map_count");
+ Symbol *tableCountSym =
+ ctx.symtabEC->findUnderscore("__hybrid_code_map_count");
cast<DefinedAbsolute>(tableCountSym)->setVA(codeMap.size());
}
@@ -1228,8 +1230,7 @@ void Writer::createMiscChunks() {
// Create /guard:cf tables if requested.
createGuardCFTables();
- if (isArm64EC(config->machine))
- createECChunks();
+ createECChunks();
if (config->autoImport)
createRuntimePseudoRelocs();
@@ -1837,22 +1838,10 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
dir[DEBUG_DIRECTORY].RelativeVirtualAddress = debugDirectory->getRVA();
dir[DEBUG_DIRECTORY].Size = debugDirectory->getSize();
}
- if (Symbol *sym = ctx.symtab.findUnderscore("_load_config_used")) {
- if (auto *b = dyn_cast<DefinedRegular>(sym)) {
- SectionChunk *sc = b->getChunk();
- assert(b->getRVA() >= sc->getRVA());
- uint64_t offsetInChunk = b->getRVA() - sc->getRVA();
- if (!sc->hasData || offsetInChunk + 4 > sc->getSize())
- Fatal(ctx) << "_load_config_used is malformed";
-
- ArrayRef<uint8_t> secContents = sc->getContents();
- uint32_t loadConfigSize =
- *reinterpret_cast<const ulittle32_t *>(&secContents[offsetInChunk]);
- if (offsetInChunk + loadConfigSize > sc->getSize())
- Fatal(ctx) << "_load_config_used is too large";
- dir[LOAD_CONFIG_TABLE].RelativeVirtualAddress = b->getRVA();
- dir[LOAD_CONFIG_TABLE].Size = loadConfigSize;
- }
+ if (ctx.symtab.loadConfigSym) {
+ dir[LOAD_CONFIG_TABLE].RelativeVirtualAddress =
+ ctx.symtab.loadConfigSym->getRVA();
+ dir[LOAD_CONFIG_TABLE].Size = ctx.symtab.loadConfigSize;
}
if (!delayIdata.empty()) {
dir[DELAY_IMPORT_DESCRIPTOR].RelativeVirtualAddress =
@@ -2169,7 +2158,11 @@ void Writer::maybeAddRVATable(SymbolRVASet tableSymbols, StringRef tableSym,
// Create CHPE metadata chunks.
void Writer::createECChunks() {
- for (Symbol *s : ctx.symtab.expSymbols) {
+ SymbolTable *symtab = ctx.symtabEC;
+ if (!symtab)
+ return;
+
+ for (Symbol *s : symtab->expSymbols) {
auto sym = dyn_cast<Defined>(s);
if (!sym || !sym->getChunk())
continue;
@@ -2188,9 +2181,9 @@ void Writer::createECChunks() {
// we should use the #foo$hp_target symbol as the redirection target.
// First, try to look up the $hp_target symbol. If it can't be found,
// assume it's a regular function and look for #foo instead.
- Symbol *targetSym = ctx.symtab.find((targetName + "$hp_target").str());
+ Symbol *targetSym = symtab->find((targetName + "$hp_target").str());
if (!targetSym)
- targetSym = ctx.symtab.find(targetName);
+ targetSym = symtab->find(targetName);
Defined *t = dyn_cast_or_null<Defined>(targetSym);
if (t && isArm64EC(t->getChunk()->getMachine()))
exportThunks.push_back({chunk, t});
@@ -2199,20 +2192,20 @@ void Writer::createECChunks() {
auto codeMapChunk = make<ECCodeMapChunk>(codeMap);
rdataSec->addChunk(codeMapChunk);
- Symbol *codeMapSym = ctx.symtab.findUnderscore("__hybrid_code_map");
+ Symbol *codeMapSym = 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");
+ 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");
+ symtab->findUnderscore("__arm64x_redirection_metadata");
replaceSymbol<DefinedSynthetic>(entryPointsSym, entryPointsSym->getName(),
entryPoints);
}
@@ -2305,7 +2298,8 @@ void Writer::setSectionPermissions() {
// Set symbols used by ARM64EC metadata.
void Writer::setECSymbols() {
- if (!isArm64EC(ctx.config.machine))
+ SymbolTable *symtab = ctx.symtabEC;
+ if (!symtab)
return;
llvm::stable_sort(exportThunks, [](const std::pair<Chunk *, Defined *> &a,
@@ -2313,45 +2307,45 @@ void Writer::setECSymbols() {
return a.first->getRVA() < b.first->getRVA();
});
- Symbol *rfeTableSym = ctx.symtab.findUnderscore("__arm64x_extra_rfe_table");
+ Symbol *rfeTableSym = symtab->findUnderscore("__arm64x_extra_rfe_table");
replaceSymbol<DefinedSynthetic>(rfeTableSym, "__arm64x_extra_rfe_table",
pdata.first);
if (pdata.first) {
Symbol *rfeSizeSym =
- ctx.symtab.findUnderscore("__arm64x_extra_rfe_table_size");
+ symtab->findUnderscore("__arm64x_extra_rfe_table_size");
cast<DefinedAbsolute>(rfeSizeSym)
->setVA(pdata.last->getRVA() + pdata.last->getSize() -
pdata.first->getRVA());
}
Symbol *rangesCountSym =
- ctx.symtab.findUnderscore("__x64_code_ranges_to_entry_points_count");
+ symtab->findUnderscore("__x64_code_ranges_to_entry_points_count");
cast<DefinedAbsolute>(rangesCountSym)->setVA(exportThunks.size());
Symbol *entryPointCountSym =
- ctx.symtab.findUnderscore("__arm64x_redirection_metadata_count");
+ symtab->findUnderscore("__arm64x_redirection_metadata_count");
cast<DefinedAbsolute>(entryPointCountSym)->setVA(exportThunks.size());
- Symbol *iatSym = ctx.symtab.findUnderscore("__hybrid_auxiliary_iat");
+ Symbol *iatSym = symtab->findUnderscore("__hybrid_auxiliary_iat");
replaceSymbol<DefinedSynthetic>(iatSym, "__hybrid_auxiliary_iat",
idata.auxIat.empty() ? nullptr
: idata.auxIat.front());
- Symbol *iatCopySym = ctx.symtab.findUnderscore("__hybrid_auxiliary_iat_copy");
+ Symbol *iatCopySym = symtab->findUnderscore("__hybrid_auxiliary_iat_copy");
replaceSymbol<DefinedSynthetic>(
iatCopySym, "__hybrid_auxiliary_iat_copy",
idata.auxIatCopy.empty() ? nullptr : idata.auxIatCopy.front());
Symbol *delayIatSym =
- ctx.symtab.findUnderscore("__hybrid_auxiliary_delayload_iat");
+ symtab->findUnderscore("__hybrid_auxiliary_delayload_iat");
replaceSymbol<DefinedSynthetic>(
delayIatSym, "__hybrid_auxiliary_delayload_iat",
delayIdata.getAuxIat().empty() ? nullptr
: delayIdata.getAuxIat().front());
Symbol *delayIatCopySym =
- ctx.symtab.findUnderscore("__hybrid_auxiliary_delayload_iat_copy");
+ symtab->findUnderscore("__hybrid_auxiliary_delayload_iat_copy");
replaceSymbol<DefinedSynthetic>(
delayIatCopySym, "__hybrid_auxiliary_delayload_iat_copy",
delayIdata.getAuxIatCopy().empty() ? nullptr
@@ -2649,39 +2643,25 @@ void Writer::fixTlsAlignment() {
}
void Writer::prepareLoadConfig() {
- Symbol *sym = ctx.symtab.findUnderscore("_load_config_used");
- auto *b = cast_if_present<DefinedRegular>(sym);
- if (!b) {
- if (ctx.config.guardCF != GuardCFLevel::Off)
- Warn(ctx)
- << "Control Flow Guard is enabled but '_load_config_used' is missing";
- if (ctx.config.dependentLoadFlags)
- Warn(ctx) << "_load_config_used not found, /dependentloadflag will have "
- "no effect";
- return;
- }
+ ctx.forEachSymtab([&](SymbolTable &symtab) {
+ if (!symtab.loadConfigSym)
+ return;
- OutputSection *sec = ctx.getOutputSection(b->getChunk());
- uint8_t *buf = buffer->getBufferStart();
- uint8_t *secBuf = buf + sec->getFileOff();
- uint8_t *symBuf = secBuf + (b->getRVA() - sec->getRVA());
- uint32_t expectedAlign = ctx.config.is64() ? 8 : 4;
- if (b->getChunk()->getAlignment() < expectedAlign)
- Warn(ctx) << "'_load_config_used' is misaligned (expected alignment to be "
- << expectedAlign << " bytes, got "
- << b->getChunk()->getAlignment() << " instead)";
- else if (!isAligned(Align(expectedAlign), b->getRVA()))
- Warn(ctx) << "'_load_config_used' is misaligned (RVA is 0x"
- << Twine::utohexstr(b->getRVA()) << " not aligned to "
- << expectedAlign << " bytes)";
-
- if (ctx.config.is64())
- prepareLoadConfig(reinterpret_cast<coff_load_configuration64 *>(symBuf));
- else
- prepareLoadConfig(reinterpret_cast<coff_load_configuration32 *>(symBuf));
+ OutputSection *sec = ctx.getOutputSection(symtab.loadConfigSym->getChunk());
+ uint8_t *secBuf = buffer->getBufferStart() + sec->getFileOff();
+ uint8_t *symBuf = secBuf + (symtab.loadConfigSym->getRVA() - sec->getRVA());
+
+ if (ctx.config.is64())
+ prepareLoadConfig(symtab,
+ reinterpret_cast<coff_load_configuration64 *>(symBuf));
+ else
+ prepareLoadConfig(symtab,
+ reinterpret_cast<coff_load_configuration32 *>(symBuf));
+ });
}
-template <typename T> void Writer::prepareLoadConfig(T *loadConfig) {
+template <typename T>
+void Writer::prepareLoadConfig(SymbolTable &symtab, T *loadConfig) {
size_t loadConfigSize = loadConfig->Size;
#define RETURN_IF_NOT_CONTAINS(field) \
@@ -2694,12 +2674,12 @@ template <typename T> void Writer::prepareLoadConfig(T *loadConfig) {
if (loadConfigSize >= offsetof(T, field) + sizeof(T::field))
#define CHECK_VA(field, sym) \
- if (auto *s = dyn_cast<DefinedSynthetic>(ctx.symtab.findUnderscore(sym))) \
+ if (auto *s = dyn_cast<DefinedSynthetic>(symtab.findUnderscore(sym))) \
if (loadConfig->field != ctx.config.imageBase + s->getRVA()) \
Warn(ctx) << #field " not set correctly in '_load_config_used'";
#define CHECK_ABSOLUTE(field, sym) \
- if (auto *s = dyn_cast<DefinedAbsolute>(ctx.symtab.findUnderscore(sym))) \
+ if (auto *s = dyn_cast<DefinedAbsolute>(symtab.findUnderscore(sym))) \
if (loadConfig->field != s->getVA()) \
Warn(ctx) << #field " not set correctly in '_load_config_used'";
@@ -2713,6 +2693,21 @@ template <typename T> void Writer::prepareLoadConfig(T *loadConfig) {
loadConfig->DynamicValueRelocTableSection = relocSec->sectionIndex;
loadConfig->DynamicValueRelocTableOffset =
ctx.dynamicRelocs->getRVA() - relocSec->getRVA();
+
+ // On ARM64X, only the EC version of the load config contains
+ // CHPEMetadataPointer. Copy its value to the native load config.
+ if (!symtab.isEC() && ctx.hybridSymtab->loadConfigSize >=
+ offsetof(T, CHPEMetadataPointer) +
+ sizeof(T::CHPEMetadataPointer)) {
+ OutputSection *sec =
+ ctx.getOutputSection(ctx.hybridSymtab->loadConfigSym->getChunk());
+ uint8_t *secBuf = buffer->getBufferStart() + sec->getFileOff();
+ auto hybridLoadConfig =
+ reinterpret_cast<const coff_load_configuration64 *>(
+ secBuf +
+ (ctx.hybridSymtab->loadConfigSym->getRVA() - sec->getRVA()));
+ loadConfig->CHPEMetadataPointer = hybridLoadConfig->CHPEMetadataPointer;
+ }
}
else {
Warn(ctx) << "'_load_config_used' structure too small to include dynamic "
diff --git a/lld/test/COFF/Inputs/loadconfig-arm64.s b/lld/test/COFF/Inputs/loadconfig-arm64.s
new file mode 100644
index 00000000000000..67d1a0aea50e47
--- /dev/null
+++ b/lld/test/COFF/Inputs/loadconfig-arm64.s
@@ -0,0 +1,15 @@
+ .section .rdata,"dr"
+ .globl _load_config_used
+ .p2align 3, 0
+_load_config_used:
+ .word 0x140
+ .fill 0x7c,1,0
+ .xword __guard_fids_table
+ .xword __guard_fids_count
+ .xword __guard_flags
+ .xword 0
+ .xword __guard_iat_table
+ .xword __guard_iat_count
+ .xword __guard_longjmp_table
+ .xword __guard_longjmp_count
+ .fill 0x80,1,0
diff --git a/lld/test/COFF/arm64ec-codemap.test b/lld/test/COFF/arm64ec-codemap.test
index 2d79538f0a7ebc..050261117be2ec 100644
--- a/lld/test/COFF/arm64ec-codemap.test
+++ b/lld/test/COFF/arm64ec-codemap.test
@@ -9,7 +9,7 @@ RUN: llvm-mc -filetype=obj -triple=arm64ec-windows data-sec2.s -o data-sec2.obj
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows empty-sec.s -o arm64ec-empty-sec.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=x86_64-windows empty-sec.s -o x86_64-empty-sec.obj
-RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64.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 %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64ec.obj
Link ARM64EC DLL and verify that the code is arranged as expected.
diff --git a/lld/test/COFF/arm64ec-entry-thunk.s b/lld/test/COFF/arm64ec-entry-thunk.s
index bf5cb42755b62a..b31d315eeb7a8d 100644
--- a/lld/test/COFF/arm64ec-entry-thunk.s
+++ b/lld/test/COFF/arm64ec-entry-thunk.s
@@ -27,7 +27,7 @@ thunk:
.rva func
// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %S/Inputs/loadconfig-arm64ec.s -o loadcfg.obj
-// RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64ec.s -o native-loadcfg.obj
+// RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64.s -o native-loadcfg.obj
// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows test-simple.s -o test-simple.obj
// RUN: lld-link -machine:arm64ec -dll -noentry -out:out-simple.dll loadcfg.obj test-simple.obj
// RUN: llvm-objdump -d out-simple.dll | FileCheck --check-prefix=DISASM %s
diff --git a/lld/test/COFF/arm64ec-lib.test b/lld/test/COFF/arm64ec-lib.test
index ea07d28f1a411b..8698a5ceccbe7a 100644
--- a/lld/test/COFF/arm64ec-lib.test
+++ b/lld/test/COFF/arm64ec-lib.test
@@ -11,7 +11,7 @@ RUN: llvm-mc -filetype=obj -triple=arm64ec-windows ref-alias.s -o ref-alias.obj
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows ref-thunk.s -o ref-thunk.obj
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows func.s -o func.obj
RUN: llvm-mc -filetype=obj -triple=x86_64-windows func-x86_64.s -o func-x86_64.obj
-RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64.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 %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64ec.obj
RUN: llvm-lib -machine:arm64ec -out:sym-arm64ec.lib sym-arm64ec.obj nsym-aarch64.obj
diff --git a/lld/test/COFF/arm64ec-range-thunks.s b/lld/test/COFF/arm64ec-range-thunks.s
index 09d9b013f97a5b..dcfa6365b4e3a4 100644
--- a/lld/test/COFF/arm64ec-range-thunks.s
+++ b/lld/test/COFF/arm64ec-range-thunks.s
@@ -5,7 +5,7 @@
# RUN: llvm-mc -filetype=obj -triple=aarch64-windows native-funcs.s -o funcs-aarch64.obj
# RUN: llvm-mc -filetype=obj -triple=x86_64-windows space.s -o space-x86_64.obj
# RUN: llvm-mc -filetype=obj -triple=aarch64-windows space.s -o space-aarch64.obj
-# RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64.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 %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64ec.obj
diff --git a/lld/test/COFF/arm64x-loadconfig.s b/lld/test/COFF/arm64x-loadconfig.s
index 0d4fe0ed...
[truncated]
|
@llvm/pr-subscribers-lld-coff Author: Jacek Caban (cjacek) ChangesCopy CHPE metadata pointer from EC load config to native configuration. Patch is 30.83 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/120328.diff 14 Files Affected:
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index bef55abb7f856e..d5f84cfe36e133 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -2548,7 +2548,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
symtab.addAbsolute(mangle("__guard_eh_cont_count"), 0);
symtab.addAbsolute(mangle("__guard_eh_cont_table"), 0);
- if (isArm64EC(ctx.config.machine)) {
+ if (symtab.isEC()) {
symtab.addAbsolute("__arm64x_extra_rfe_table", 0);
symtab.addAbsolute("__arm64x_extra_rfe_table_size", 0);
symtab.addAbsolute("__arm64x_redirection_metadata", 0);
@@ -2822,6 +2822,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
if (ctx.symtabEC)
ctx.symtabEC->initializeECThunks();
+ ctx.forEachSymtab([](SymbolTable &symtab) { symtab.initializeLoadConfig(); });
// Identify unreferenced COMDAT sections.
if (config->doGC) {
diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp
index 6b3375e13e8393..7e243fc626d38d 100644
--- a/lld/COFF/SymbolTable.cpp
+++ b/lld/COFF/SymbolTable.cpp
@@ -27,6 +27,7 @@
#include <utility>
using namespace llvm;
+using namespace llvm::support;
namespace lld::coff {
@@ -595,6 +596,52 @@ std::pair<Symbol *, bool> SymbolTable::insert(StringRef name, InputFile *file) {
return result;
}
+void SymbolTable::initializeLoadConfig() {
+ auto sym =
+ dyn_cast_or_null<DefinedRegular>(findUnderscore("_load_config_used"));
+ if (!sym) {
+ if (ctx.config.guardCF != GuardCFLevel::Off)
+ Warn(ctx)
+ << "Control Flow Guard is enabled but '_load_config_used' is missing";
+ if (ctx.config.dependentLoadFlags)
+ Warn(ctx) << "_load_config_used not found, /dependentloadflag will have "
+ "no effect";
+ return;
+ }
+
+ SectionChunk *sc = sym->getChunk();
+ if (!sc->hasData) {
+ Err(ctx) << "_load_config_used points to uninitialized data";
+ return;
+ }
+ uint64_t offsetInChunk = sym->getValue();
+ if (offsetInChunk + 4 > sc->getSize()) {
+ Err(ctx) << "_load_config_used section chunk is too small";
+ return;
+ }
+
+ ArrayRef<uint8_t> secContents = sc->getContents();
+ loadConfigSize =
+ *reinterpret_cast<const ulittle32_t *>(&secContents[offsetInChunk]);
+ if (offsetInChunk + loadConfigSize > sc->getSize()) {
+ Err(ctx) << "_load_config_used specifies a size larger than its containing "
+ "section chunk";
+ return;
+ }
+
+ uint32_t expectedAlign = ctx.config.is64() ? 8 : 4;
+ if (sc->getAlignment() < expectedAlign)
+ Warn(ctx) << "'_load_config_used' is misaligned (expected alignment to be "
+ << expectedAlign << " bytes, got " << sc->getAlignment()
+ << " instead)";
+ else if (!isAligned(Align(expectedAlign), offsetInChunk))
+ Warn(ctx) << "'_load_config_used' is misaligned (section offset is 0x"
+ << Twine::utohexstr(sym->getValue()) << " not aligned to "
+ << expectedAlign << " bytes)";
+
+ loadConfigSym = sym;
+}
+
void SymbolTable::addEntryThunk(Symbol *from, Symbol *to) {
entryThunks.push_back({from, to});
}
diff --git a/lld/COFF/SymbolTable.h b/lld/COFF/SymbolTable.h
index b694893b903aa3..8548a6d036a9db 100644
--- a/lld/COFF/SymbolTable.h
+++ b/lld/COFF/SymbolTable.h
@@ -138,6 +138,10 @@ class SymbolTable {
callback(pair.second);
}
+ DefinedRegular *loadConfigSym = nullptr;
+ uint32_t loadConfigSize = 0;
+ void initializeLoadConfig();
+
private:
/// Given a name without "__imp_" prefix, returns a defined symbol
/// with the "__imp_" prefix, if it exists.
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index 3c6112b7fc89ad..7952ad5474ec4e 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -282,7 +282,8 @@ class Writer {
uint32_t getSizeOfInitializedData();
void prepareLoadConfig();
- template <typename T> void prepareLoadConfig(T *loadConfig);
+ template <typename T>
+ void prepareLoadConfig(SymbolTable &symtab, T *loadConfig);
std::unique_ptr<FileOutputBuffer> &buffer;
std::map<PartialSectionKey, PartialSection *> partialSections;
@@ -574,7 +575,7 @@ bool Writer::createThunks(OutputSection *os, int margin) {
// Create a code map for CHPE metadata.
void Writer::createECCodeMap() {
- if (!isArm64EC(ctx.config.machine))
+ if (!ctx.symtabEC)
return;
// Clear the map in case we were're recomputing the map after adding
@@ -610,7 +611,8 @@ void Writer::createECCodeMap() {
closeRange();
- Symbol *tableCountSym = ctx.symtab.findUnderscore("__hybrid_code_map_count");
+ Symbol *tableCountSym =
+ ctx.symtabEC->findUnderscore("__hybrid_code_map_count");
cast<DefinedAbsolute>(tableCountSym)->setVA(codeMap.size());
}
@@ -1228,8 +1230,7 @@ void Writer::createMiscChunks() {
// Create /guard:cf tables if requested.
createGuardCFTables();
- if (isArm64EC(config->machine))
- createECChunks();
+ createECChunks();
if (config->autoImport)
createRuntimePseudoRelocs();
@@ -1837,22 +1838,10 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
dir[DEBUG_DIRECTORY].RelativeVirtualAddress = debugDirectory->getRVA();
dir[DEBUG_DIRECTORY].Size = debugDirectory->getSize();
}
- if (Symbol *sym = ctx.symtab.findUnderscore("_load_config_used")) {
- if (auto *b = dyn_cast<DefinedRegular>(sym)) {
- SectionChunk *sc = b->getChunk();
- assert(b->getRVA() >= sc->getRVA());
- uint64_t offsetInChunk = b->getRVA() - sc->getRVA();
- if (!sc->hasData || offsetInChunk + 4 > sc->getSize())
- Fatal(ctx) << "_load_config_used is malformed";
-
- ArrayRef<uint8_t> secContents = sc->getContents();
- uint32_t loadConfigSize =
- *reinterpret_cast<const ulittle32_t *>(&secContents[offsetInChunk]);
- if (offsetInChunk + loadConfigSize > sc->getSize())
- Fatal(ctx) << "_load_config_used is too large";
- dir[LOAD_CONFIG_TABLE].RelativeVirtualAddress = b->getRVA();
- dir[LOAD_CONFIG_TABLE].Size = loadConfigSize;
- }
+ if (ctx.symtab.loadConfigSym) {
+ dir[LOAD_CONFIG_TABLE].RelativeVirtualAddress =
+ ctx.symtab.loadConfigSym->getRVA();
+ dir[LOAD_CONFIG_TABLE].Size = ctx.symtab.loadConfigSize;
}
if (!delayIdata.empty()) {
dir[DELAY_IMPORT_DESCRIPTOR].RelativeVirtualAddress =
@@ -2169,7 +2158,11 @@ void Writer::maybeAddRVATable(SymbolRVASet tableSymbols, StringRef tableSym,
// Create CHPE metadata chunks.
void Writer::createECChunks() {
- for (Symbol *s : ctx.symtab.expSymbols) {
+ SymbolTable *symtab = ctx.symtabEC;
+ if (!symtab)
+ return;
+
+ for (Symbol *s : symtab->expSymbols) {
auto sym = dyn_cast<Defined>(s);
if (!sym || !sym->getChunk())
continue;
@@ -2188,9 +2181,9 @@ void Writer::createECChunks() {
// we should use the #foo$hp_target symbol as the redirection target.
// First, try to look up the $hp_target symbol. If it can't be found,
// assume it's a regular function and look for #foo instead.
- Symbol *targetSym = ctx.symtab.find((targetName + "$hp_target").str());
+ Symbol *targetSym = symtab->find((targetName + "$hp_target").str());
if (!targetSym)
- targetSym = ctx.symtab.find(targetName);
+ targetSym = symtab->find(targetName);
Defined *t = dyn_cast_or_null<Defined>(targetSym);
if (t && isArm64EC(t->getChunk()->getMachine()))
exportThunks.push_back({chunk, t});
@@ -2199,20 +2192,20 @@ void Writer::createECChunks() {
auto codeMapChunk = make<ECCodeMapChunk>(codeMap);
rdataSec->addChunk(codeMapChunk);
- Symbol *codeMapSym = ctx.symtab.findUnderscore("__hybrid_code_map");
+ Symbol *codeMapSym = 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");
+ 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");
+ symtab->findUnderscore("__arm64x_redirection_metadata");
replaceSymbol<DefinedSynthetic>(entryPointsSym, entryPointsSym->getName(),
entryPoints);
}
@@ -2305,7 +2298,8 @@ void Writer::setSectionPermissions() {
// Set symbols used by ARM64EC metadata.
void Writer::setECSymbols() {
- if (!isArm64EC(ctx.config.machine))
+ SymbolTable *symtab = ctx.symtabEC;
+ if (!symtab)
return;
llvm::stable_sort(exportThunks, [](const std::pair<Chunk *, Defined *> &a,
@@ -2313,45 +2307,45 @@ void Writer::setECSymbols() {
return a.first->getRVA() < b.first->getRVA();
});
- Symbol *rfeTableSym = ctx.symtab.findUnderscore("__arm64x_extra_rfe_table");
+ Symbol *rfeTableSym = symtab->findUnderscore("__arm64x_extra_rfe_table");
replaceSymbol<DefinedSynthetic>(rfeTableSym, "__arm64x_extra_rfe_table",
pdata.first);
if (pdata.first) {
Symbol *rfeSizeSym =
- ctx.symtab.findUnderscore("__arm64x_extra_rfe_table_size");
+ symtab->findUnderscore("__arm64x_extra_rfe_table_size");
cast<DefinedAbsolute>(rfeSizeSym)
->setVA(pdata.last->getRVA() + pdata.last->getSize() -
pdata.first->getRVA());
}
Symbol *rangesCountSym =
- ctx.symtab.findUnderscore("__x64_code_ranges_to_entry_points_count");
+ symtab->findUnderscore("__x64_code_ranges_to_entry_points_count");
cast<DefinedAbsolute>(rangesCountSym)->setVA(exportThunks.size());
Symbol *entryPointCountSym =
- ctx.symtab.findUnderscore("__arm64x_redirection_metadata_count");
+ symtab->findUnderscore("__arm64x_redirection_metadata_count");
cast<DefinedAbsolute>(entryPointCountSym)->setVA(exportThunks.size());
- Symbol *iatSym = ctx.symtab.findUnderscore("__hybrid_auxiliary_iat");
+ Symbol *iatSym = symtab->findUnderscore("__hybrid_auxiliary_iat");
replaceSymbol<DefinedSynthetic>(iatSym, "__hybrid_auxiliary_iat",
idata.auxIat.empty() ? nullptr
: idata.auxIat.front());
- Symbol *iatCopySym = ctx.symtab.findUnderscore("__hybrid_auxiliary_iat_copy");
+ Symbol *iatCopySym = symtab->findUnderscore("__hybrid_auxiliary_iat_copy");
replaceSymbol<DefinedSynthetic>(
iatCopySym, "__hybrid_auxiliary_iat_copy",
idata.auxIatCopy.empty() ? nullptr : idata.auxIatCopy.front());
Symbol *delayIatSym =
- ctx.symtab.findUnderscore("__hybrid_auxiliary_delayload_iat");
+ symtab->findUnderscore("__hybrid_auxiliary_delayload_iat");
replaceSymbol<DefinedSynthetic>(
delayIatSym, "__hybrid_auxiliary_delayload_iat",
delayIdata.getAuxIat().empty() ? nullptr
: delayIdata.getAuxIat().front());
Symbol *delayIatCopySym =
- ctx.symtab.findUnderscore("__hybrid_auxiliary_delayload_iat_copy");
+ symtab->findUnderscore("__hybrid_auxiliary_delayload_iat_copy");
replaceSymbol<DefinedSynthetic>(
delayIatCopySym, "__hybrid_auxiliary_delayload_iat_copy",
delayIdata.getAuxIatCopy().empty() ? nullptr
@@ -2649,39 +2643,25 @@ void Writer::fixTlsAlignment() {
}
void Writer::prepareLoadConfig() {
- Symbol *sym = ctx.symtab.findUnderscore("_load_config_used");
- auto *b = cast_if_present<DefinedRegular>(sym);
- if (!b) {
- if (ctx.config.guardCF != GuardCFLevel::Off)
- Warn(ctx)
- << "Control Flow Guard is enabled but '_load_config_used' is missing";
- if (ctx.config.dependentLoadFlags)
- Warn(ctx) << "_load_config_used not found, /dependentloadflag will have "
- "no effect";
- return;
- }
+ ctx.forEachSymtab([&](SymbolTable &symtab) {
+ if (!symtab.loadConfigSym)
+ return;
- OutputSection *sec = ctx.getOutputSection(b->getChunk());
- uint8_t *buf = buffer->getBufferStart();
- uint8_t *secBuf = buf + sec->getFileOff();
- uint8_t *symBuf = secBuf + (b->getRVA() - sec->getRVA());
- uint32_t expectedAlign = ctx.config.is64() ? 8 : 4;
- if (b->getChunk()->getAlignment() < expectedAlign)
- Warn(ctx) << "'_load_config_used' is misaligned (expected alignment to be "
- << expectedAlign << " bytes, got "
- << b->getChunk()->getAlignment() << " instead)";
- else if (!isAligned(Align(expectedAlign), b->getRVA()))
- Warn(ctx) << "'_load_config_used' is misaligned (RVA is 0x"
- << Twine::utohexstr(b->getRVA()) << " not aligned to "
- << expectedAlign << " bytes)";
-
- if (ctx.config.is64())
- prepareLoadConfig(reinterpret_cast<coff_load_configuration64 *>(symBuf));
- else
- prepareLoadConfig(reinterpret_cast<coff_load_configuration32 *>(symBuf));
+ OutputSection *sec = ctx.getOutputSection(symtab.loadConfigSym->getChunk());
+ uint8_t *secBuf = buffer->getBufferStart() + sec->getFileOff();
+ uint8_t *symBuf = secBuf + (symtab.loadConfigSym->getRVA() - sec->getRVA());
+
+ if (ctx.config.is64())
+ prepareLoadConfig(symtab,
+ reinterpret_cast<coff_load_configuration64 *>(symBuf));
+ else
+ prepareLoadConfig(symtab,
+ reinterpret_cast<coff_load_configuration32 *>(symBuf));
+ });
}
-template <typename T> void Writer::prepareLoadConfig(T *loadConfig) {
+template <typename T>
+void Writer::prepareLoadConfig(SymbolTable &symtab, T *loadConfig) {
size_t loadConfigSize = loadConfig->Size;
#define RETURN_IF_NOT_CONTAINS(field) \
@@ -2694,12 +2674,12 @@ template <typename T> void Writer::prepareLoadConfig(T *loadConfig) {
if (loadConfigSize >= offsetof(T, field) + sizeof(T::field))
#define CHECK_VA(field, sym) \
- if (auto *s = dyn_cast<DefinedSynthetic>(ctx.symtab.findUnderscore(sym))) \
+ if (auto *s = dyn_cast<DefinedSynthetic>(symtab.findUnderscore(sym))) \
if (loadConfig->field != ctx.config.imageBase + s->getRVA()) \
Warn(ctx) << #field " not set correctly in '_load_config_used'";
#define CHECK_ABSOLUTE(field, sym) \
- if (auto *s = dyn_cast<DefinedAbsolute>(ctx.symtab.findUnderscore(sym))) \
+ if (auto *s = dyn_cast<DefinedAbsolute>(symtab.findUnderscore(sym))) \
if (loadConfig->field != s->getVA()) \
Warn(ctx) << #field " not set correctly in '_load_config_used'";
@@ -2713,6 +2693,21 @@ template <typename T> void Writer::prepareLoadConfig(T *loadConfig) {
loadConfig->DynamicValueRelocTableSection = relocSec->sectionIndex;
loadConfig->DynamicValueRelocTableOffset =
ctx.dynamicRelocs->getRVA() - relocSec->getRVA();
+
+ // On ARM64X, only the EC version of the load config contains
+ // CHPEMetadataPointer. Copy its value to the native load config.
+ if (!symtab.isEC() && ctx.hybridSymtab->loadConfigSize >=
+ offsetof(T, CHPEMetadataPointer) +
+ sizeof(T::CHPEMetadataPointer)) {
+ OutputSection *sec =
+ ctx.getOutputSection(ctx.hybridSymtab->loadConfigSym->getChunk());
+ uint8_t *secBuf = buffer->getBufferStart() + sec->getFileOff();
+ auto hybridLoadConfig =
+ reinterpret_cast<const coff_load_configuration64 *>(
+ secBuf +
+ (ctx.hybridSymtab->loadConfigSym->getRVA() - sec->getRVA()));
+ loadConfig->CHPEMetadataPointer = hybridLoadConfig->CHPEMetadataPointer;
+ }
}
else {
Warn(ctx) << "'_load_config_used' structure too small to include dynamic "
diff --git a/lld/test/COFF/Inputs/loadconfig-arm64.s b/lld/test/COFF/Inputs/loadconfig-arm64.s
new file mode 100644
index 00000000000000..67d1a0aea50e47
--- /dev/null
+++ b/lld/test/COFF/Inputs/loadconfig-arm64.s
@@ -0,0 +1,15 @@
+ .section .rdata,"dr"
+ .globl _load_config_used
+ .p2align 3, 0
+_load_config_used:
+ .word 0x140
+ .fill 0x7c,1,0
+ .xword __guard_fids_table
+ .xword __guard_fids_count
+ .xword __guard_flags
+ .xword 0
+ .xword __guard_iat_table
+ .xword __guard_iat_count
+ .xword __guard_longjmp_table
+ .xword __guard_longjmp_count
+ .fill 0x80,1,0
diff --git a/lld/test/COFF/arm64ec-codemap.test b/lld/test/COFF/arm64ec-codemap.test
index 2d79538f0a7ebc..050261117be2ec 100644
--- a/lld/test/COFF/arm64ec-codemap.test
+++ b/lld/test/COFF/arm64ec-codemap.test
@@ -9,7 +9,7 @@ RUN: llvm-mc -filetype=obj -triple=arm64ec-windows data-sec2.s -o data-sec2.obj
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows empty-sec.s -o arm64ec-empty-sec.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=x86_64-windows empty-sec.s -o x86_64-empty-sec.obj
-RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64.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 %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64ec.obj
Link ARM64EC DLL and verify that the code is arranged as expected.
diff --git a/lld/test/COFF/arm64ec-entry-thunk.s b/lld/test/COFF/arm64ec-entry-thunk.s
index bf5cb42755b62a..b31d315eeb7a8d 100644
--- a/lld/test/COFF/arm64ec-entry-thunk.s
+++ b/lld/test/COFF/arm64ec-entry-thunk.s
@@ -27,7 +27,7 @@ thunk:
.rva func
// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %S/Inputs/loadconfig-arm64ec.s -o loadcfg.obj
-// RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64ec.s -o native-loadcfg.obj
+// RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64.s -o native-loadcfg.obj
// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows test-simple.s -o test-simple.obj
// RUN: lld-link -machine:arm64ec -dll -noentry -out:out-simple.dll loadcfg.obj test-simple.obj
// RUN: llvm-objdump -d out-simple.dll | FileCheck --check-prefix=DISASM %s
diff --git a/lld/test/COFF/arm64ec-lib.test b/lld/test/COFF/arm64ec-lib.test
index ea07d28f1a411b..8698a5ceccbe7a 100644
--- a/lld/test/COFF/arm64ec-lib.test
+++ b/lld/test/COFF/arm64ec-lib.test
@@ -11,7 +11,7 @@ RUN: llvm-mc -filetype=obj -triple=arm64ec-windows ref-alias.s -o ref-alias.obj
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows ref-thunk.s -o ref-thunk.obj
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows func.s -o func.obj
RUN: llvm-mc -filetype=obj -triple=x86_64-windows func-x86_64.s -o func-x86_64.obj
-RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64.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 %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64ec.obj
RUN: llvm-lib -machine:arm64ec -out:sym-arm64ec.lib sym-arm64ec.obj nsym-aarch64.obj
diff --git a/lld/test/COFF/arm64ec-range-thunks.s b/lld/test/COFF/arm64ec-range-thunks.s
index 09d9b013f97a5b..dcfa6365b4e3a4 100644
--- a/lld/test/COFF/arm64ec-range-thunks.s
+++ b/lld/test/COFF/arm64ec-range-thunks.s
@@ -5,7 +5,7 @@
# RUN: llvm-mc -filetype=obj -triple=aarch64-windows native-funcs.s -o funcs-aarch64.obj
# RUN: llvm-mc -filetype=obj -triple=x86_64-windows space.s -o space-x86_64.obj
# RUN: llvm-mc -filetype=obj -triple=aarch64-windows space.s -o space-aarch64.obj
-# RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64.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 %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64ec.obj
diff --git a/lld/test/COFF/arm64x-loadconfig.s b/lld/test/COFF/arm64x-loadconfig.s
index 0d4fe0ed...
[truncated]
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this looks mostly ok, but one comment about a potentially missing condition.
Copy CHPE metadata pointer from EC load config to native configuration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Copy CHPE metadata pointer from EC load config to native configuration.