From 5693678cae86ac433aa8bd9ed3920c8c93b5817b Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Tue, 21 May 2024 13:33:53 +0200 Subject: [LLD][COFF] Demangle ARM64EC export names. (#87068) --- lld/COFF/DriverUtils.cpp | 40 +++++++------ lld/test/COFF/arm64ec-exports.s | 121 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 145 insertions(+), 16 deletions(-) create mode 100644 lld/test/COFF/arm64ec-exports.s diff --git a/lld/COFF/DriverUtils.cpp b/lld/COFF/DriverUtils.cpp index b4ff31a..6e8f74c 100644 --- a/lld/COFF/DriverUtils.cpp +++ b/lld/COFF/DriverUtils.cpp @@ -21,6 +21,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/BinaryFormat/COFF.h" +#include "llvm/IR/Mangler.h" #include "llvm/Object/COFF.h" #include "llvm/Object/WindowsResource.h" #include "llvm/Option/Arg.h" @@ -39,6 +40,7 @@ #include using namespace llvm::COFF; +using namespace llvm::object; using namespace llvm::opt; using namespace llvm; using llvm::sys::Process; @@ -632,18 +634,6 @@ err: fatal("invalid /export: " + arg); } -static StringRef undecorate(COFFLinkerContext &ctx, StringRef sym) { - if (ctx.config.machine != I386) - return sym; - // In MSVC mode, a fully decorated stdcall function is exported - // as-is with the leading underscore (with type IMPORT_NAME). - // In MinGW mode, a decorated stdcall function gets the underscore - // removed, just like normal cdecl functions. - if (sym.starts_with("_") && sym.contains('@') && !ctx.config.mingw) - return sym; - return sym.starts_with("_") ? sym.substr(1) : sym; -} - // Convert stdcall/fastcall style symbols into unsuffixed symbols, // with or without a leading underscore. (MinGW specific.) static StringRef killAt(StringRef sym, bool prefix) { @@ -693,11 +683,29 @@ void LinkerDriver::fixupExports() { for (Export &e : ctx.config.exports) { if (!e.exportAs.empty()) { e.exportName = e.exportAs; - } else if (!e.forwardTo.empty()) { - e.exportName = undecorate(ctx, e.name); - } else { - e.exportName = undecorate(ctx, e.extName.empty() ? e.name : e.extName); + continue; + } + + StringRef sym = + !e.forwardTo.empty() || e.extName.empty() ? e.name : e.extName; + if (ctx.config.machine == I386 && sym.starts_with("_")) { + // In MSVC mode, a fully decorated stdcall function is exported + // as-is with the leading underscore (with type IMPORT_NAME). + // In MinGW mode, a decorated stdcall function gets the underscore + // removed, just like normal cdecl functions. + if (ctx.config.mingw || !sym.contains('@')) { + e.exportName = sym.substr(1); + continue; + } + } + if (isArm64EC(ctx.config.machine) && !e.data && !e.constant) { + if (std::optional demangledName = + getArm64ECDemangledFunctionName(sym)) { + e.exportName = saver().save(*demangledName); + continue; + } } + e.exportName = sym; } if (ctx.config.killAt && ctx.config.machine == I386) { diff --git a/lld/test/COFF/arm64ec-exports.s b/lld/test/COFF/arm64ec-exports.s new file mode 100644 index 0000000..a48211e --- /dev/null +++ b/lld/test/COFF/arm64ec-exports.s @@ -0,0 +1,121 @@ +; REQUIRES: aarch64 +; RUN: split-file %s %t.dir && cd %t.dir + +; RUN: llvm-mc -filetype=obj -triple=arm64ec-windows test.s -o test.obj +; RUN: llvm-mc -filetype=obj -triple=arm64ec-windows drectve.s -o drectve.obj +; RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64ec.obj + +; Check various forms of export directive and make sure that function export name is demangled. + +; RUN: lld-link -out:out.dll test.obj loadconfig-arm64ec.obj -dll -noentry -machine:arm64ec \ +; RUN: -export:unmangled_func '-export:#mangled_func' '-export:#exportas_func,EXPORTAS,exportas_func' \ +; RUN: '-export:?cxx_func@@$$hYAHXZ' -export:data_sym,DATA '-export:#mangled_data_sym,DATA' + + +; RUN: llvm-readobj --coff-exports out.dll | FileCheck --check-prefix=EXP %s +; EXP: Export { +; EXP-NEXT: Ordinal: 1 +; EXP-NEXT: Name: #mangled_data_sym +; EXP-NEXT: RVA: 0x3000 +; EXP-NEXT: } +; EXP-NEXT: Export { +; EXP-NEXT: Ordinal: 2 +; EXP-NEXT: Name: ?cxx_func@@YAHXZ +; EXP-NEXT: RVA: 0x1018 +; EXP-NEXT: } +; EXP-NEXT: Export { +; EXP-NEXT: Ordinal: 3 +; EXP-NEXT: Name: data_sym +; EXP-NEXT: RVA: 0x3004 +; EXP-NEXT: } +; EXP-NEXT: Export { +; EXP-NEXT: Ordinal: 4 +; EXP-NEXT: Name: exportas_func +; EXP-NEXT: RVA: 0x1010 +; EXP-NEXT: } +; EXP-NEXT: Export { +; EXP-NEXT: Ordinal: 5 +; EXP-NEXT: Name: mangled_func +; EXP-NEXT: RVA: 0x1008 +; EXP-NEXT: } +; EXP-NEXT: Export { +; EXP-NEXT: Ordinal: 6 +; EXP-NEXT: Name: unmangled_func +; EXP-NEXT: RVA: 0x1000 +; EXP-NEXT: } + +; RUN: llvm-nm --print-armap out.lib | FileCheck --check-prefix=IMPLIB %s +; IMPLIB: Archive EC map +; IMPLIB-NEXT: #exportas_func in out +; IMPLIB-NEXT: #mangled_func in out +; IMPLIB-NEXT: #unmangled_func in out +; IMPLIB-NEXT: ?cxx_func@@$$hYAHXZ in out +; IMPLIB-NEXT: ?cxx_func@@YAHXZ in out +; IMPLIB-NEXT: __IMPORT_DESCRIPTOR_out{{.*}} in out +; IMPLIB-NEXT: __NULL_IMPORT_DESCRIPTOR in out +; IMPLIB-NEXT: __imp_?cxx_func@@YAHXZ in out +; IMPLIB-NEXT: __imp_aux_?cxx_func@@YAHXZ in out +; IMPLIB-NEXT: __imp_aux_exportas_func in out +; IMPLIB-NEXT: __imp_aux_mangled_func in out +; IMPLIB-NEXT: __imp_aux_unmangled_func in out +; IMPLIB-NEXT: __imp_data_sym in out +; IMPLIB-NEXT: __imp_exportas_func in out +; IMPLIB-NEXT: __imp_mangled_data_sym in out +; IMPLIB-NEXT: __imp_mangled_func in out +; IMPLIB-NEXT: __imp_unmangled_func in out +; IMPLIB-NEXT: exportas_func in out +; IMPLIB-NEXT: mangled_func in out +; IMPLIB-NEXT: unmangled_func in out +; IMPLIB-NEXT: out{{.*}}_NULL_THUNK_DATA in out + + +; Check that using .drectve section has the same effect. + +; RUN: lld-link -out:out2.dll test.obj loadconfig-arm64ec.obj -dll -noentry -machine:arm64ec drectve.obj +; RUN: llvm-readobj --coff-exports out2.dll | FileCheck --check-prefix=EXP %s +; RUN: llvm-nm --print-armap out2.lib | FileCheck --check-prefix=IMPLIB %s + +#--- test.s + .text + .globl unmangled_func + .p2align 2, 0x0 +unmangled_func: + mov w0, #1 + ret + + .globl "#mangled_func" + .p2align 2, 0x0 +"#mangled_func": + mov w0, #2 + ret + + .globl "#exportas_func" + .p2align 2, 0x0 +"#exportas_func": + mov w0, #3 + ret + + .globl "?cxx_func@@$$hYAHXZ" + .p2align 2, 0x0 +"?cxx_func@@$$hYAHXZ": + mov w0, #4 + ret + + .data + .globl "#mangled_data_sym" + .p2align 2, 0x0 +"#mangled_data_sym": + .word 0x01010101 + .globl data_sym + .p2align 2, 0x0 +data_sym: + .word 0x01010101 + +#--- drectve.s + .section .drectve, "yn" + .ascii " -export:unmangled_func" + .ascii " -export:#mangled_func" + .ascii " -export:#exportas_func,EXPORTAS,exportas_func" + .ascii " -export:?cxx_func@@$$hYAHXZ" + .ascii " -export:data_sym,DATA" + .ascii " -export:#mangled_data_sym,DATA" -- cgit v1.1