From eecab63d96c57b8ed4293c1d1b95aa37806965ce Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Mon, 27 Jan 2025 23:36:13 +0100 Subject: [PATCH] [LLD][COFF] Add MinGW auto-export support for ARM64X Export all symbols from both EC and native symbol tables. If an explicit export is present in either symbol table, auto-export is disabled for both. --- lld/COFF/Driver.cpp | 57 ++++++++++--------- lld/COFF/MinGW.cpp | 9 ++- lld/COFF/MinGW.h | 4 +- lld/test/COFF/arm64x-export-all.s | 93 +++++++++++++++++++++++++++++++ 4 files changed, 129 insertions(+), 34 deletions(-) create mode 100644 lld/test/COFF/arm64x-export-all.s diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index 979c0ae496273..281510b7ac6ea 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -1382,43 +1382,46 @@ void LinkerDriver::maybeExportMinGWSymbols(const opt::InputArgList &args) { if (!ctx.config.dll) return; - if (!ctx.symtab.exports.empty()) + if (ctx.symtab.hadExplicitExports || + (ctx.hybridSymtab && ctx.hybridSymtab->hadExplicitExports)) return; if (args.hasArg(OPT_exclude_all_symbols)) return; } - AutoExporter exporter(ctx, excludedSymbols); + ctx.forEachSymtab([&](SymbolTable &symtab) { + AutoExporter exporter(symtab, excludedSymbols); - for (auto *arg : args.filtered(OPT_wholearchive_file)) - if (std::optional path = findFile(arg->getValue())) - exporter.addWholeArchive(*path); + for (auto *arg : args.filtered(OPT_wholearchive_file)) + if (std::optional path = findFile(arg->getValue())) + exporter.addWholeArchive(*path); - for (auto *arg : args.filtered(OPT_exclude_symbols)) { - SmallVector vec; - StringRef(arg->getValue()).split(vec, ','); - for (StringRef sym : vec) - exporter.addExcludedSymbol(ctx.symtab.mangle(sym)); - } + for (auto *arg : args.filtered(OPT_exclude_symbols)) { + SmallVector vec; + StringRef(arg->getValue()).split(vec, ','); + for (StringRef sym : vec) + exporter.addExcludedSymbol(symtab.mangle(sym)); + } - ctx.symtab.forEachSymbol([&](Symbol *s) { - auto *def = dyn_cast(s); - if (!exporter.shouldExport(def)) - return; + symtab.forEachSymbol([&](Symbol *s) { + auto *def = dyn_cast(s); + if (!exporter.shouldExport(def)) + return; - if (!def->isGCRoot) { - def->isGCRoot = true; - ctx.config.gcroot.push_back(def); - } + if (!def->isGCRoot) { + def->isGCRoot = true; + ctx.config.gcroot.push_back(def); + } - Export e; - e.name = def->getName(); - e.sym = def; - if (Chunk *c = def->getChunk()) - if (!(c->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE)) - e.data = true; - s->isUsedInRegularObj = true; - ctx.symtab.exports.push_back(e); + Export e; + e.name = def->getName(); + e.sym = def; + if (Chunk *c = def->getChunk()) + if (!(c->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE)) + e.data = true; + s->isUsedInRegularObj = true; + symtab.exports.push_back(e); + }); }); } diff --git a/lld/COFF/MinGW.cpp b/lld/COFF/MinGW.cpp index 76f5a0a7500b9..a6407bc279200 100644 --- a/lld/COFF/MinGW.cpp +++ b/lld/COFF/MinGW.cpp @@ -25,9 +25,8 @@ using namespace lld; using namespace lld::coff; AutoExporter::AutoExporter( - COFFLinkerContext &ctx, - const llvm::DenseSet &manualExcludeSymbols) - : manualExcludeSymbols(manualExcludeSymbols), ctx(ctx) { + SymbolTable &symtab, const llvm::DenseSet &manualExcludeSymbols) + : manualExcludeSymbols(manualExcludeSymbols), symtab(symtab) { excludeLibs = { "libgcc", "libgcc_s", @@ -84,7 +83,7 @@ AutoExporter::AutoExporter( "_NULL_THUNK_DATA", }; - if (ctx.config.machine == I386) { + if (symtab.machine == I386) { excludeSymbols = { "__NULL_IMPORT_DESCRIPTOR", "__pei386_runtime_relocator", @@ -151,7 +150,7 @@ bool AutoExporter::shouldExport(Defined *sym) const { return false; // If a corresponding __imp_ symbol exists and is defined, don't export it. - if (ctx.symtab.find(("__imp_" + sym->getName()).str())) + if (symtab.find(("__imp_" + sym->getName()).str())) return false; // Check that file is non-null before dereferencing it, symbols not diff --git a/lld/COFF/MinGW.h b/lld/COFF/MinGW.h index ffa500b234777..265beb315c9a7 100644 --- a/lld/COFF/MinGW.h +++ b/lld/COFF/MinGW.h @@ -25,7 +25,7 @@ class COFFLinkerContext; // symbols for MinGW. class AutoExporter { public: - AutoExporter(COFFLinkerContext &ctx, + AutoExporter(SymbolTable &symtab, const llvm::DenseSet &manualExcludeSymbols); void addWholeArchive(StringRef path); @@ -42,7 +42,7 @@ class AutoExporter { bool shouldExport(Defined *sym) const; private: - COFFLinkerContext &ctx; + SymbolTable &symtab; }; void writeDefFile(COFFLinkerContext &, StringRef name, diff --git a/lld/test/COFF/arm64x-export-all.s b/lld/test/COFF/arm64x-export-all.s new file mode 100644 index 0000000000000..831edfe0b6f88 --- /dev/null +++ b/lld/test/COFF/arm64x-export-all.s @@ -0,0 +1,93 @@ +// REQUIRES: aarch64 + +// RUN: llvm-mc -filetype=obj -triple=aarch64-windows %s -o %t.arm64.obj +// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %s -o %t.arm64ec.obj +// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %S/Inputs/loadconfig-arm64ec.s -o %t-loadconfig-arm64ec.obj +// RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64.s -o %t-loadconfig-arm64.obj + +// Check that all symbols are exported in both EC and native views. + +// RUN: lld-link -machine:arm64x -lldmingw -dll -noentry -out:%t.dll %t.arm64.obj %t.arm64ec.obj %t-loadconfig-arm64.obj %t-loadconfig-arm64ec.obj + +// RUN: llvm-readobj --coff-exports %t.dll | FileCheck --check-prefix=EXP %s +// EXP: Format: COFF-ARM64X +// EXP-NEXT: Arch: aarch64 +// EXP-NEXT: AddressSize: 64bit +// EXP-NEXT: Export { +// EXP-NEXT: Ordinal: 1 +// EXP-NEXT: Name: _load_config_used +// EXP-NEXT: RVA: +// EXP-NEXT: } +// EXP-NEXT: Export { +// EXP-NEXT: Ordinal: 2 +// EXP-NEXT: Name: sym +// EXP-NEXT: RVA: 0x2000 +// EXP-NEXT: } +// EXP-NEXT: Export { +// EXP-NEXT: Ordinal: 3 +// EXP-NEXT: Name: sym2 +// EXP-NEXT: RVA: 0x2004 +// EXP-NEXT: } +// EXP-NEXT: HybridObject { +// EXP-NEXT: Format: COFF-ARM64EC +// EXP-NEXT: Arch: aarch64 +// EXP-NEXT: AddressSize: 64bit +// EXP-NEXT: Export { +// EXP-NEXT: Ordinal: 1 +// EXP-NEXT: Name: __chpe_metadata +// EXP-NEXT: RVA: +// EXP-NEXT: } +// EXP-NEXT: Export { +// EXP-NEXT: Ordinal: 2 +// EXP-NEXT: Name: __os_arm64x_dispatch_icall +// EXP-NEXT: RVA: 0x12B0 +// EXP-NEXT: } +// EXP-NEXT: Export { +// EXP-NEXT: Ordinal: 3 +// EXP-NEXT: Name: __os_arm64x_dispatch_ret +// EXP-NEXT: RVA: +// EXP-NEXT: } +// EXP-NEXT: Export { +// EXP-NEXT: Ordinal: 4 +// EXP-NEXT: Name: _load_config_used +// EXP-NEXT: RVA: +// EXP-NEXT: } +// EXP-NEXT: Export { +// EXP-NEXT: Ordinal: 5 +// EXP-NEXT: Name: sym +// EXP-NEXT: RVA: 0x2008 +// EXP-NEXT: } +// EXP-NEXT: Export { +// EXP-NEXT: Ordinal: 6 +// EXP-NEXT: Name: sym2 +// EXP-NEXT: RVA: 0x200C +// EXP-NEXT: } +// EXP-NEXT: } + +// Check that an explicit export in the EC view is respected, preventing symbols from being auto-exported in both EC and native views. + +// RUN: lld-link -machine:arm64x -lldmingw -dll -noentry -out:%t2.dll %t.arm64.obj %t.arm64ec.obj -export:sym \ +// RUN: %t-loadconfig-arm64.obj %t-loadconfig-arm64ec.obj + +// RUN: llvm-readobj --coff-exports %t2.dll | FileCheck --check-prefix=EXP2 %s +// EXP2: Format: COFF-ARM64X +// EXP2-NEXT: Arch: aarch64 +// EXP2-NEXT: AddressSize: 64bit +// EXP2-NEXT: HybridObject { +// EXP2-NEXT: Format: COFF-ARM64EC +// EXP2-NEXT: Arch: aarch64 +// EXP2-NEXT: AddressSize: 64bit +// EXP2-NEXT: Export { +// EXP2-NEXT: Ordinal: 1 +// EXP2-NEXT: Name: sym +// EXP2-NEXT: RVA: 0x2008 +// EXP2-NEXT: } +// EXP2-NEXT: } + + .data + .globl sym +sym: + .word 0 + .globl sym2 +sym2: + .word 0