-
Notifications
You must be signed in to change notification settings - Fork 12.1k
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
[LLD][COFF] Add support for EXPORTAS import name type. #86541
Conversation
@llvm/pr-subscribers-platform-windows @llvm/pr-subscribers-lld Author: Jacek Caban (cjacek) ChangesThis depends on #86535. #78772 added similar support for .def file parser and import library writer. This PR adds missing bits in LLD to propagate EXPORTAS name and allow it in Full diff: https://github.com/llvm/llvm-project/pull/86541.diff 5 Files Affected:
diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h
index 8f85929f1bea7f..917f88fc28280b 100644
--- a/lld/COFF/Config.h
+++ b/lld/COFF/Config.h
@@ -54,6 +54,7 @@ enum class EmitKind { Obj, LLVM, ASM };
struct Export {
StringRef name; // N in /export:N or /export:E=N
StringRef extName; // E in /export:E=N
+ StringRef exportAs; // E in /export:N,EXPORTAS,E
StringRef aliasTarget; // GNU specific: N in "alias == N"
Symbol *sym = nullptr;
uint16_t ordinal = 0;
@@ -73,10 +74,9 @@ struct Export {
StringRef exportName; // Name in DLL
bool operator==(const Export &e) const {
- return (name == e.name && extName == e.extName &&
- aliasTarget == e.aliasTarget &&
- ordinal == e.ordinal && noname == e.noname &&
- data == e.data && isPrivate == e.isPrivate);
+ return (name == e.name && extName == e.extName && exportAs == e.exportAs &&
+ aliasTarget == e.aliasTarget && ordinal == e.ordinal &&
+ noname == e.noname && data == e.data && isPrivate == e.isPrivate);
}
};
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index 1b075389325a91..3596d891fbceb5 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -945,6 +945,7 @@ void LinkerDriver::createImportLibrary(bool asLib) {
e2.Name = std::string(e1.name);
e2.SymbolName = std::string(e1.symbolName);
e2.ExtName = std::string(e1.extName);
+ e2.ExportAs = std::string(e1.exportAs);
e2.AliasTarget = std::string(e1.aliasTarget);
e2.Ordinal = e1.ordinal;
e2.Noname = e1.noname;
@@ -1039,12 +1040,14 @@ void LinkerDriver::parseModuleDefs(StringRef path) {
if (!e1.ExtName.empty() && e1.ExtName != e1.Name &&
StringRef(e1.Name).contains('.')) {
e2.name = saver().save(e1.ExtName);
+ e2.exportAs = saver().save(e1.ExportAs);
e2.forwardTo = saver().save(e1.Name);
ctx.config.exports.push_back(e2);
continue;
}
e2.name = saver().save(e1.Name);
e2.extName = saver().save(e1.ExtName);
+ e2.exportAs = saver().save(e1.ExportAs);
e2.aliasTarget = saver().save(e1.AliasTarget);
e2.ordinal = e1.Ordinal;
e2.noname = e1.Noname;
diff --git a/lld/COFF/DriverUtils.cpp b/lld/COFF/DriverUtils.cpp
index fc8eb327be49bd..33ab9cb12d0050 100644
--- a/lld/COFF/DriverUtils.cpp
+++ b/lld/COFF/DriverUtils.cpp
@@ -577,16 +577,16 @@ Export LinkerDriver::parseExport(StringRef arg) {
if (y.contains(".")) {
e.name = x;
e.forwardTo = y;
- return e;
+ } else {
+ e.extName = x;
+ e.name = y;
+ if (e.name.empty())
+ goto err;
}
-
- e.extName = x;
- e.name = y;
- if (e.name.empty())
- goto err;
}
- // If "<name>=<internalname>[,@ordinal[,NONAME]][,DATA][,PRIVATE]"
+ // Optional parameters
+ // "[,@ordinal[,NONAME]][,DATA][,PRIVATE][,EXPORTAS,exportname]"
while (!rest.empty()) {
StringRef tok;
std::tie(tok, rest) = rest.split(",");
@@ -608,6 +608,12 @@ Export LinkerDriver::parseExport(StringRef arg) {
e.isPrivate = true;
continue;
}
+ if (tok.equals_insensitive("exportas")) {
+ if (rest.empty() || rest.contains(','))
+ goto err;
+ e.exportAs = rest;
+ break;
+ }
if (tok.starts_with("@")) {
int32_t ord;
if (tok.substr(1).getAsInteger(0, ord))
@@ -684,7 +690,9 @@ void LinkerDriver::fixupExports() {
}
for (Export &e : ctx.config.exports) {
- if (!e.forwardTo.empty()) {
+ 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);
diff --git a/lld/test/COFF/export.test b/lld/test/COFF/export.test
index d340e0174b563e..7b804852e6d34a 100644
--- a/lld/test/COFF/export.test
+++ b/lld/test/COFF/export.test
@@ -76,18 +76,45 @@ SYMTAB: exportfn3 in export.test.tmp.DLL
# RUN: lld-link /out:%t.dll /dll %t.obj /export:foo=kernel32.foobar
# RUN: llvm-objdump -p %t.dll | FileCheck --check-prefix=FORWARDER %s
+# RUN: llvm-nm -M %t.lib | FileCheck --check-prefix=SYMTAB-FWD %s
# RUN: echo "EXPORTS foo=kernel32.foobar" > %t.def
-# RUN: lld-link /out:%t.dll /dll %t.obj /def:%t.def
-# RUN: llvm-objdump -p %t.dll | FileCheck --check-prefix=FORWARDER %s
+# RUN: lld-link /out:%t-def.dll /dll %t.obj /def:%t.def
+# RUN: llvm-objdump -p %t-def.dll | FileCheck --check-prefix=FORWARDER %s
+# RUN: llvm-nm -M %t-def.lib | FileCheck --check-prefix=SYMTAB-FWD %s
FORWARDER: Export Table:
-FORWARDER: DLL name: export.test.tmp.dll
+FORWARDER: DLL name: export.test.tmp
FORWARDER: Ordinal base: 1
FORWARDER: Ordinal RVA Name
FORWARDER: 1 0x1010 exportfn
FORWARDER: 2 foo (forwarded to kernel32.foobar)
+SYMTAB-FWD: __imp_exportfn3 in export.test.tmp
+SYMTAB-FWD: __imp_foo in export.test.tmp
+SYMTAB-FWD: exportfn3 in export.test.tmp
+SYMTAB-FWD: foo in export.test.tmp
+
+# RUN: lld-link /out:%t-fwd-priv.dll /dll %t.obj /export:foo=kernel32.foobar,DATA,PRIVATE
+# RUN: llvm-objdump -p %t-fwd-priv.dll | FileCheck --check-prefix=FORWARDER %s
+# RUN: llvm-nm -M %t-fwd-priv.lib | FileCheck --check-prefix=SYMTAB-FWD-PRIV %s
+
+SYMTAB-FWD-PRIV: __imp_exportfn3 in export.test.tmp-fwd-priv
+SYMTAB-FWD-PRIV-NOT: __imp_foo
+SYMTAB-FWD-PRIV: exportfn3 in export.test.tmp-fwd-priv
+SYMTAB-FWD-PRIV-NOT: foo
+
+# RUN: lld-link /out:%t-fwd-ord.dll /dll %t.obj /export:foo=kernel32.foobar,@3,NONAME
+# RUN: llvm-objdump -p %t-fwd-ord.dll | FileCheck --check-prefix=FORWARDER-ORD %s
+# RUN: llvm-nm -M %t-fwd-ord.lib | FileCheck --check-prefix=SYMTAB-FWD %s
+
+FORWARDER-ORD: Export Table:
+FORWARDER-ORD: DLL name: export.test.tmp-fwd-ord.dll
+FORWARDER-ORD: Ordinal base: 3
+FORWARDER-ORD: Ordinal RVA Name
+FORWARDER-ORD: 3 (forwarded to kernel32.foobar)
+FORWARDER-ORD: 4 0x1010 exportfn3
+
# RUN: lld-link /out:%t.dll /dll %t.obj /merge:.rdata=.text /export:exportfn1 /export:exportfn2
# RUN: llvm-objdump -p %t.dll | FileCheck --check-prefix=MERGE --match-full-lines %s
diff --git a/lld/test/COFF/exportas.test b/lld/test/COFF/exportas.test
index c0295c3d7fb76d..9674471ecdf533 100644
--- a/lld/test/COFF/exportas.test
+++ b/lld/test/COFF/exportas.test
@@ -9,6 +9,72 @@ RUN: lld-link -out:out1.dll -dll -noentry test.obj test.lib
RUN: llvm-readobj --coff-imports out1.dll | FileCheck --check-prefix=IMPORT %s
IMPORT: Symbol: expfunc
+Pass -export argument with EXPORTAS.
+
+RUN: llvm-mc -filetype=obj -triple=x86_64-windows func.s -o func.obj
+RUN: lld-link -out:out2.dll -dll -noentry func.obj -export:func,EXPORTAS,expfunc
+RUN: llvm-readobj --coff-exports out2.dll | FileCheck --check-prefix=EXPORT %s
+EXPORT: Name: expfunc
+
+RUN: llvm-readobj out2.lib | FileCheck --check-prefix=IMPLIB %s
+IMPLIB: Name type: export as
+IMPLIB-NEXT: Export name: expfunc
+IMPLIB-NEXT: Symbol: __imp_func
+IMPLIB-NEXT: Symbol: func
+
+Use .drectve section with EXPORTAS.
+
+RUN: llvm-mc -filetype=obj -triple=x86_64-windows drectve.s -o drectve.obj
+RUN: lld-link -out:out3.dll -dll -noentry func.obj drectve.obj
+RUN: llvm-readobj --coff-exports out3.dll | FileCheck --check-prefix=EXPORT %s
+RUN: llvm-readobj out3.lib | FileCheck --check-prefix=IMPLIB %s
+
+Use a .def file with EXPORTAS.
+
+RUN: lld-link -out:out4.dll -dll -noentry func.obj -def:test.def
+RUN: llvm-readobj --coff-exports out4.dll | FileCheck --check-prefix=EXPORT %s
+RUN: llvm-readobj out4.lib | FileCheck --check-prefix=IMPLIB %s
+
+Use a .def file with EXPORTAS in a forwarding export.
+
+RUN: lld-link -out:out5.dll -dll -noentry func.obj -def:test2.def
+RUN: llvm-readobj --coff-exports out5.dll | FileCheck --check-prefix=FORWARD-EXPORT %s
+FORWARD-EXPORT: Export {
+FORWARD-EXPORT-NEXT: Ordinal: 1
+FORWARD-EXPORT-NEXT: Name: expfunc
+FORWARD-EXPORT-NEXT: ForwardedTo: otherdll.otherfunc
+FORWARD-EXPORT-NEXT: }
+
+RUN: llvm-readobj out5.lib | FileCheck --check-prefix=FORWARD-IMPLIB %s
+FORWARD-IMPLIB: Name type: export as
+FORWARD-IMPLIB-NEXT: Export name: expfunc
+FORWARD-IMPLIB-NEXT: Symbol: __imp_func
+FORWARD-IMPLIB-NEXT: Symbol: func
+
+Pass -export argument with EXPORTAS in a forwarding export.
+
+RUN: lld-link -out:out6.dll -dll -noentry func.obj -export:func=otherdll.otherfunc,EXPORTAS,expfunc
+RUN: llvm-readobj --coff-exports out6.dll | FileCheck --check-prefix=FORWARD-EXPORT %s
+RUN: llvm-readobj out6.lib | FileCheck --check-prefix=FORWARD-IMPLIB %s
+
+Pass -export argument with EXPORTAS in a data export.
+
+RUN: lld-link -out:out7.dll -dll -noentry func.obj -export:func,DATA,@5,EXPORTAS,expfunc
+RUN: llvm-readobj --coff-exports out7.dll | FileCheck --check-prefix=ORD %s
+ORD: Ordinal: 5
+ORD-NEXT: Name: expfunc
+
+RUN: llvm-readobj out7.lib | FileCheck --check-prefix=ORD-IMPLIB %s
+ORD-IMPLIB: Type: data
+ORD-IMPLIB-NEXT: Name type: export as
+ORD-IMPLIB-NEXT: Export name: expfunc
+ORD-IMPLIB-NEXT: Symbol: __imp_func
+
+Check invalid EXPORTAS syntax.
+
+RUN: not lld-link -out:err1.dll -dll -noentry func.obj -export:func,EXPORTAS,
+RUN: not lld-link -out:err2.dll -dll -noentry func.obj -export:func,EXPORTAS,expfunc,DATA
+
#--- test.s
.section ".test", "rd"
.rva __imp_func
@@ -17,3 +83,20 @@ IMPORT: Symbol: expfunc
LIBRARY test.dll
EXPORTS
func EXPORTAS expfunc
+
+#--- test2.def
+LIBRARY test.dll
+EXPORTS
+ func=otherdll.otherfunc EXPORTAS expfunc
+
+#--- func.s
+ .text
+ .globl func
+ .p2align 2, 0x0
+func:
+ movl $1, %eax
+ retq
+
+#--- drectve.s
+ .section .drectve, "yn"
+ .ascii " -export:func,EXPORTAS,expfunc"
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
✅ With the latest revision this PR passed the Python code formatter. |
This depends on #86535.
#78772 added similar support for .def file parser and import library writer. This PR adds missing bits in LLD to propagate EXPORTAS name and allow it in
/export
parser. This is syntax is used by MSVC for ARM64EC__declspec(dllexport)
handling.