Skip to content

Commit 5693678

Browse files
authored
[LLD][COFF] Demangle ARM64EC export names. (#87068)
1 parent 18e7bcb commit 5693678

File tree

2 files changed

+145
-16
lines changed

2 files changed

+145
-16
lines changed

lld/COFF/DriverUtils.cpp

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "llvm/ADT/StringExtras.h"
2222
#include "llvm/ADT/StringSwitch.h"
2323
#include "llvm/BinaryFormat/COFF.h"
24+
#include "llvm/IR/Mangler.h"
2425
#include "llvm/Object/COFF.h"
2526
#include "llvm/Object/WindowsResource.h"
2627
#include "llvm/Option/Arg.h"
@@ -39,6 +40,7 @@
3940
#include <optional>
4041

4142
using namespace llvm::COFF;
43+
using namespace llvm::object;
4244
using namespace llvm::opt;
4345
using namespace llvm;
4446
using llvm::sys::Process;
@@ -632,18 +634,6 @@ Export LinkerDriver::parseExport(StringRef arg) {
632634
fatal("invalid /export: " + arg);
633635
}
634636

635-
static StringRef undecorate(COFFLinkerContext &ctx, StringRef sym) {
636-
if (ctx.config.machine != I386)
637-
return sym;
638-
// In MSVC mode, a fully decorated stdcall function is exported
639-
// as-is with the leading underscore (with type IMPORT_NAME).
640-
// In MinGW mode, a decorated stdcall function gets the underscore
641-
// removed, just like normal cdecl functions.
642-
if (sym.starts_with("_") && sym.contains('@') && !ctx.config.mingw)
643-
return sym;
644-
return sym.starts_with("_") ? sym.substr(1) : sym;
645-
}
646-
647637
// Convert stdcall/fastcall style symbols into unsuffixed symbols,
648638
// with or without a leading underscore. (MinGW specific.)
649639
static StringRef killAt(StringRef sym, bool prefix) {
@@ -693,11 +683,29 @@ void LinkerDriver::fixupExports() {
693683
for (Export &e : ctx.config.exports) {
694684
if (!e.exportAs.empty()) {
695685
e.exportName = e.exportAs;
696-
} else if (!e.forwardTo.empty()) {
697-
e.exportName = undecorate(ctx, e.name);
698-
} else {
699-
e.exportName = undecorate(ctx, e.extName.empty() ? e.name : e.extName);
686+
continue;
687+
}
688+
689+
StringRef sym =
690+
!e.forwardTo.empty() || e.extName.empty() ? e.name : e.extName;
691+
if (ctx.config.machine == I386 && sym.starts_with("_")) {
692+
// In MSVC mode, a fully decorated stdcall function is exported
693+
// as-is with the leading underscore (with type IMPORT_NAME).
694+
// In MinGW mode, a decorated stdcall function gets the underscore
695+
// removed, just like normal cdecl functions.
696+
if (ctx.config.mingw || !sym.contains('@')) {
697+
e.exportName = sym.substr(1);
698+
continue;
699+
}
700+
}
701+
if (isArm64EC(ctx.config.machine) && !e.data && !e.constant) {
702+
if (std::optional<std::string> demangledName =
703+
getArm64ECDemangledFunctionName(sym)) {
704+
e.exportName = saver().save(*demangledName);
705+
continue;
706+
}
700707
}
708+
e.exportName = sym;
701709
}
702710

703711
if (ctx.config.killAt && ctx.config.machine == I386) {

lld/test/COFF/arm64ec-exports.s

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
; REQUIRES: aarch64
2+
; RUN: split-file %s %t.dir && cd %t.dir
3+
4+
; RUN: llvm-mc -filetype=obj -triple=arm64ec-windows test.s -o test.obj
5+
; RUN: llvm-mc -filetype=obj -triple=arm64ec-windows drectve.s -o drectve.obj
6+
; RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64ec.obj
7+
8+
; Check various forms of export directive and make sure that function export name is demangled.
9+
10+
; RUN: lld-link -out:out.dll test.obj loadconfig-arm64ec.obj -dll -noentry -machine:arm64ec \
11+
; RUN: -export:unmangled_func '-export:#mangled_func' '-export:#exportas_func,EXPORTAS,exportas_func' \
12+
; RUN: '-export:?cxx_func@@$$hYAHXZ' -export:data_sym,DATA '-export:#mangled_data_sym,DATA'
13+
14+
15+
; RUN: llvm-readobj --coff-exports out.dll | FileCheck --check-prefix=EXP %s
16+
; EXP: Export {
17+
; EXP-NEXT: Ordinal: 1
18+
; EXP-NEXT: Name: #mangled_data_sym
19+
; EXP-NEXT: RVA: 0x3000
20+
; EXP-NEXT: }
21+
; EXP-NEXT: Export {
22+
; EXP-NEXT: Ordinal: 2
23+
; EXP-NEXT: Name: ?cxx_func@@YAHXZ
24+
; EXP-NEXT: RVA: 0x1018
25+
; EXP-NEXT: }
26+
; EXP-NEXT: Export {
27+
; EXP-NEXT: Ordinal: 3
28+
; EXP-NEXT: Name: data_sym
29+
; EXP-NEXT: RVA: 0x3004
30+
; EXP-NEXT: }
31+
; EXP-NEXT: Export {
32+
; EXP-NEXT: Ordinal: 4
33+
; EXP-NEXT: Name: exportas_func
34+
; EXP-NEXT: RVA: 0x1010
35+
; EXP-NEXT: }
36+
; EXP-NEXT: Export {
37+
; EXP-NEXT: Ordinal: 5
38+
; EXP-NEXT: Name: mangled_func
39+
; EXP-NEXT: RVA: 0x1008
40+
; EXP-NEXT: }
41+
; EXP-NEXT: Export {
42+
; EXP-NEXT: Ordinal: 6
43+
; EXP-NEXT: Name: unmangled_func
44+
; EXP-NEXT: RVA: 0x1000
45+
; EXP-NEXT: }
46+
47+
; RUN: llvm-nm --print-armap out.lib | FileCheck --check-prefix=IMPLIB %s
48+
; IMPLIB: Archive EC map
49+
; IMPLIB-NEXT: #exportas_func in out
50+
; IMPLIB-NEXT: #mangled_func in out
51+
; IMPLIB-NEXT: #unmangled_func in out
52+
; IMPLIB-NEXT: ?cxx_func@@$$hYAHXZ in out
53+
; IMPLIB-NEXT: ?cxx_func@@YAHXZ in out
54+
; IMPLIB-NEXT: __IMPORT_DESCRIPTOR_out{{.*}} in out
55+
; IMPLIB-NEXT: __NULL_IMPORT_DESCRIPTOR in out
56+
; IMPLIB-NEXT: __imp_?cxx_func@@YAHXZ in out
57+
; IMPLIB-NEXT: __imp_aux_?cxx_func@@YAHXZ in out
58+
; IMPLIB-NEXT: __imp_aux_exportas_func in out
59+
; IMPLIB-NEXT: __imp_aux_mangled_func in out
60+
; IMPLIB-NEXT: __imp_aux_unmangled_func in out
61+
; IMPLIB-NEXT: __imp_data_sym in out
62+
; IMPLIB-NEXT: __imp_exportas_func in out
63+
; IMPLIB-NEXT: __imp_mangled_data_sym in out
64+
; IMPLIB-NEXT: __imp_mangled_func in out
65+
; IMPLIB-NEXT: __imp_unmangled_func in out
66+
; IMPLIB-NEXT: exportas_func in out
67+
; IMPLIB-NEXT: mangled_func in out
68+
; IMPLIB-NEXT: unmangled_func in out
69+
; IMPLIB-NEXT: out{{.*}}_NULL_THUNK_DATA in out
70+
71+
72+
; Check that using .drectve section has the same effect.
73+
74+
; RUN: lld-link -out:out2.dll test.obj loadconfig-arm64ec.obj -dll -noentry -machine:arm64ec drectve.obj
75+
; RUN: llvm-readobj --coff-exports out2.dll | FileCheck --check-prefix=EXP %s
76+
; RUN: llvm-nm --print-armap out2.lib | FileCheck --check-prefix=IMPLIB %s
77+
78+
#--- test.s
79+
.text
80+
.globl unmangled_func
81+
.p2align 2, 0x0
82+
unmangled_func:
83+
mov w0, #1
84+
ret
85+
86+
.globl "#mangled_func"
87+
.p2align 2, 0x0
88+
"#mangled_func":
89+
mov w0, #2
90+
ret
91+
92+
.globl "#exportas_func"
93+
.p2align 2, 0x0
94+
"#exportas_func":
95+
mov w0, #3
96+
ret
97+
98+
.globl "?cxx_func@@$$hYAHXZ"
99+
.p2align 2, 0x0
100+
"?cxx_func@@$$hYAHXZ":
101+
mov w0, #4
102+
ret
103+
104+
.data
105+
.globl "#mangled_data_sym"
106+
.p2align 2, 0x0
107+
"#mangled_data_sym":
108+
.word 0x01010101
109+
.globl data_sym
110+
.p2align 2, 0x0
111+
data_sym:
112+
.word 0x01010101
113+
114+
#--- drectve.s
115+
.section .drectve, "yn"
116+
.ascii " -export:unmangled_func"
117+
.ascii " -export:#mangled_func"
118+
.ascii " -export:#exportas_func,EXPORTAS,exportas_func"
119+
.ascii " -export:?cxx_func@@$$hYAHXZ"
120+
.ascii " -export:data_sym,DATA"
121+
.ascii " -export:#mangled_data_sym,DATA"

0 commit comments

Comments
 (0)