mirror of
https://github.com/intel/llvm.git
synced 2026-01-26 21:53:12 +08:00
[LLD][COFF] Add support for EXPORTAS import name type. (#86541)
#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.
This commit is contained in:
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -1044,6 +1045,7 @@ void LinkerDriver::parseModuleDefs(StringRef path) {
|
||||
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;
|
||||
|
||||
@@ -585,7 +585,8 @@ Export LinkerDriver::parseExport(StringRef arg) {
|
||||
}
|
||||
}
|
||||
|
||||
// Optional parameters "[,@ordinal[,NONAME]][,DATA][,PRIVATE]"
|
||||
// Optional parameters
|
||||
// "[,@ordinal[,NONAME]][,DATA][,PRIVATE][,EXPORTAS,exportname]"
|
||||
while (!rest.empty()) {
|
||||
StringRef tok;
|
||||
std::tie(tok, rest) = rest.split(",");
|
||||
@@ -607,6 +608,13 @@ Export LinkerDriver::parseExport(StringRef arg) {
|
||||
e.isPrivate = true;
|
||||
continue;
|
||||
}
|
||||
if (tok.equals_insensitive("exportas")) {
|
||||
if (!rest.empty() && !rest.contains(','))
|
||||
e.exportAs = rest;
|
||||
else
|
||||
error("invalid EXPORTAS value: " + rest);
|
||||
break;
|
||||
}
|
||||
if (tok.starts_with("@")) {
|
||||
int32_t ord;
|
||||
if (tok.substr(1).getAsInteger(0, ord))
|
||||
@@ -683,7 +691,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);
|
||||
|
||||
@@ -9,6 +9,77 @@ 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, 2>&1 | \
|
||||
RUN: FileCheck --check-prefix=ERR1 %s
|
||||
ERR1: error: invalid EXPORTAS value: {{$}}
|
||||
|
||||
RUN: not lld-link -out:err2.dll -dll -noentry func.obj -export:func,EXPORTAS,expfunc,DATA 2>&1 | \
|
||||
RUN: FileCheck --check-prefix=ERR2 %s
|
||||
ERR2: error: invalid EXPORTAS value: expfunc,DATA
|
||||
|
||||
#--- test.s
|
||||
.section ".test", "rd"
|
||||
.rva __imp_func
|
||||
@@ -17,3 +88,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"
|
||||
|
||||
Reference in New Issue
Block a user