Skip to content

[LLD][COFF] Add support for EXPORTAS import name type. #86541

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

Merged
merged 1 commit into from
Mar 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions lld/COFF/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
}
};

Expand Down
2 changes: 2 additions & 0 deletions lld/COFF/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
14 changes: 12 additions & 2 deletions lld/COFF/DriverUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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(",");
Expand All @@ -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))
Expand Down Expand Up @@ -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);
Expand Down
88 changes: 88 additions & 0 deletions lld/test/COFF/exportas.test
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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"