diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index 22ee2f133be98..091aa0df20741 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -939,7 +939,7 @@ std::string LinkerDriver::getImportName(bool asLib) { void LinkerDriver::createImportLibrary(bool asLib) { llvm::TimeTraceScope timeScope("Create import library"); - std::vector exports; + std::vector exports, nativeExports; for (Export &e1 : ctx.config.exports) { COFFShortExport e2; e2.Name = std::string(e1.name); @@ -958,8 +958,8 @@ void LinkerDriver::createImportLibrary(bool asLib) { std::string path = getImplibPath(); if (!ctx.config.incremental) { - checkError(writeImportLibrary(libName, path, exports, ctx.config.machine, - ctx.config.mingw)); + checkError(writeImportLibrary(libName, path, exports, nativeExports, + ctx.config.machine, ctx.config.mingw)); return; } @@ -968,8 +968,8 @@ void LinkerDriver::createImportLibrary(bool asLib) { ErrorOr> oldBuf = MemoryBuffer::getFile( path, /*IsText=*/false, /*RequiresNullTerminator=*/false); if (!oldBuf) { - checkError(writeImportLibrary(libName, path, exports, ctx.config.machine, - ctx.config.mingw)); + checkError(writeImportLibrary(libName, path, exports, nativeExports, + ctx.config.machine, ctx.config.mingw)); return; } @@ -979,7 +979,7 @@ void LinkerDriver::createImportLibrary(bool asLib) { fatal("cannot create temporary file for import library " + path + ": " + ec.message()); - if (Error e = writeImportLibrary(libName, tmpName, exports, + if (Error e = writeImportLibrary(libName, tmpName, exports, nativeExports, ctx.config.machine, ctx.config.mingw)) { checkError(std::move(e)); return; diff --git a/llvm/include/llvm/Object/COFFImportFile.h b/llvm/include/llvm/Object/COFFImportFile.h index 46a982ddb7eee..23c3e6a1f0784 100644 --- a/llvm/include/llvm/Object/COFFImportFile.h +++ b/llvm/include/llvm/Object/COFFImportFile.h @@ -137,6 +137,7 @@ struct COFFShortExport { Error writeImportLibrary(StringRef ImportName, StringRef Path, ArrayRef Exports, + ArrayRef NativeExports, COFF::MachineTypes Machine, bool MinGW); } // namespace object diff --git a/llvm/lib/Object/COFFImportFile.cpp b/llvm/lib/Object/COFFImportFile.cpp index a3e5e78952c16..9175c3ee2a2c4 100644 --- a/llvm/lib/Object/COFFImportFile.cpp +++ b/llvm/lib/Object/COFFImportFile.cpp @@ -625,6 +625,7 @@ NewArchiveMember ObjectFactory::createWeakExternal(StringRef Sym, Error writeImportLibrary(StringRef ImportName, StringRef Path, ArrayRef Exports, + ArrayRef NativeExports, MachineTypes Machine, bool MinGW) { MachineTypes NativeMachine = @@ -642,66 +643,73 @@ Error writeImportLibrary(StringRef ImportName, StringRef Path, std::vector NullThunk; Members.push_back(OF.createNullThunk(NullThunk)); - for (const COFFShortExport &E : Exports) { - if (E.Private) - continue; - - ImportType ImportType = IMPORT_CODE; - if (E.Data) - ImportType = IMPORT_DATA; - if (E.Constant) - ImportType = IMPORT_CONST; - - StringRef SymbolName = E.SymbolName.empty() ? E.Name : E.SymbolName; - std::string Name; - - if (E.ExtName.empty()) { - Name = std::string(SymbolName); - } else { - Expected ReplacedName = - replace(SymbolName, E.Name, E.ExtName); - if (!ReplacedName) - return ReplacedName.takeError(); - Name.swap(*ReplacedName); - } + auto addExports = [&](ArrayRef Exp, + MachineTypes M) -> Error { + for (const COFFShortExport &E : Exp) { + if (E.Private) + continue; + + ImportType ImportType = IMPORT_CODE; + if (E.Data) + ImportType = IMPORT_DATA; + if (E.Constant) + ImportType = IMPORT_CONST; + + StringRef SymbolName = E.SymbolName.empty() ? E.Name : E.SymbolName; + std::string Name; + + if (E.ExtName.empty()) { + Name = std::string(SymbolName); + } else { + Expected ReplacedName = + replace(SymbolName, E.Name, E.ExtName); + if (!ReplacedName) + return ReplacedName.takeError(); + Name.swap(*ReplacedName); + } - if (!E.AliasTarget.empty() && Name != E.AliasTarget) { - Members.push_back( - OF.createWeakExternal(E.AliasTarget, Name, false, Machine)); - Members.push_back( - OF.createWeakExternal(E.AliasTarget, Name, true, Machine)); - continue; - } + if (!E.AliasTarget.empty() && Name != E.AliasTarget) { + Members.push_back(OF.createWeakExternal(E.AliasTarget, Name, false, M)); + Members.push_back(OF.createWeakExternal(E.AliasTarget, Name, true, M)); + continue; + } - ImportNameType NameType; - std::string ExportName; - if (E.Noname) { - NameType = IMPORT_ORDINAL; - } else if (!E.ExportAs.empty()) { - NameType = IMPORT_NAME_EXPORTAS; - ExportName = E.ExportAs; - } else { - NameType = getNameType(SymbolName, E.Name, Machine, MinGW); - } + ImportNameType NameType; + std::string ExportName; + if (E.Noname) { + NameType = IMPORT_ORDINAL; + } else if (!E.ExportAs.empty()) { + NameType = IMPORT_NAME_EXPORTAS; + ExportName = E.ExportAs; + } else { + NameType = getNameType(SymbolName, E.Name, M, MinGW); + } - // On ARM64EC, use EXPORTAS to import demangled name for mangled symbols. - if (ImportType == IMPORT_CODE && isArm64EC(Machine)) { - if (std::optional MangledName = - getArm64ECMangledFunctionName(Name)) { - if (ExportName.empty()) { + // On ARM64EC, use EXPORTAS to import demangled name for mangled symbols. + if (ImportType == IMPORT_CODE && isArm64EC(M)) { + if (std::optional MangledName = + getArm64ECMangledFunctionName(Name)) { + if (ExportName.empty()) { + NameType = IMPORT_NAME_EXPORTAS; + ExportName.swap(Name); + } + Name = std::move(*MangledName); + } else if (ExportName.empty()) { NameType = IMPORT_NAME_EXPORTAS; - ExportName.swap(Name); + ExportName = std::move(*getArm64ECDemangledFunctionName(Name)); } - Name = std::move(*MangledName); - } else if (ExportName.empty()) { - NameType = IMPORT_NAME_EXPORTAS; - ExportName = std::move(*getArm64ECDemangledFunctionName(Name)); } + + Members.push_back(OF.createShortImport(Name, E.Ordinal, ImportType, + NameType, ExportName, M)); } + return Error::success(); + }; - Members.push_back(OF.createShortImport(Name, E.Ordinal, ImportType, - NameType, ExportName, Machine)); - } + if (Error e = addExports(Exports, Machine)) + return e; + if (Error e = addExports(NativeExports, NativeMachine)) + return e; return writeArchive(Path, Members, SymtabWritingMode::NormalSymtab, MinGW ? object::Archive::K_GNU : object::Archive::K_COFF, diff --git a/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp b/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp index 834903857a88e..0749580c78a57 100644 --- a/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp +++ b/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp @@ -215,8 +215,9 @@ int llvm::dlltoolDriverMain(llvm::ArrayRef ArgsArr) { } } - if (!Path.empty() && writeImportLibrary(Def->OutputFile, Path, Def->Exports, - Machine, /*MinGW=*/true)) + if (!Path.empty() && + writeImportLibrary(Def->OutputFile, Path, Def->Exports, std::nullopt, + Machine, /*MinGW=*/true)) return 1; return 0; } diff --git a/llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp b/llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp index 5d7ec0fb03098..3baa0a08c73d1 100644 --- a/llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp +++ b/llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp @@ -392,8 +392,34 @@ int llvm::libDriverMain(ArrayRef ArgsArr) { return 1; } - return writeImportLibrary(Def->OutputFile, OutputPath, Def->Exports, - LibMachine, + std::vector NativeExports; + std::string OutputFile = Def->OutputFile; + + if (isArm64EC(LibMachine) && Args.hasArg(OPT_nativedeffile)) { + std::unique_ptr NativeMB = + openFile(Args.getLastArg(OPT_nativedeffile)->getValue()); + if (!NativeMB) + return 1; + + if (!NativeMB->getBufferSize()) { + llvm::errs() << "native definition file empty\n"; + return 1; + } + + Expected NativeDef = + parseCOFFModuleDefinition(*NativeMB, COFF::IMAGE_FILE_MACHINE_ARM64); + + if (!NativeDef) { + llvm::errs() << "error parsing native definition\n" + << errorToErrorCode(NativeDef.takeError()).message(); + return 1; + } + NativeExports = std::move(NativeDef->Exports); + OutputFile = std::move(NativeDef->OutputFile); + } + + return writeImportLibrary(OutputFile, OutputPath, Def->Exports, + NativeExports, LibMachine, /*MinGW=*/false) ? 1 : 0; diff --git a/llvm/lib/ToolDrivers/llvm-lib/Options.td b/llvm/lib/ToolDrivers/llvm-lib/Options.td index 22ac1fb842e4d..a3d901d77054a 100644 --- a/llvm/lib/ToolDrivers/llvm-lib/Options.td +++ b/llvm/lib/ToolDrivers/llvm-lib/Options.td @@ -23,6 +23,7 @@ def libpath: P<"libpath", "Object file search path">; def lst : F<"list">, HelpText<"List contents of .lib file on stdout">; def out : P<"out", "Path to file to write output">; def deffile : P<"def", "def file to use to generate import library">; +def nativedeffile : P<"defArm64Native", "def file to use to generate native ARM64 symbols in ARM64EC import library">; def llvmlibthin : F<"llvmlibthin">, HelpText<"Make .lib point to .obj files instead of copying their contents">; diff --git a/llvm/test/tools/llvm-lib/arm64ec-implib.test b/llvm/test/tools/llvm-lib/arm64ec-implib.test index c583ef75b2b0a..77bdc23589fd2 100644 --- a/llvm/test/tools/llvm-lib/arm64ec-implib.test +++ b/llvm/test/tools/llvm-lib/arm64ec-implib.test @@ -98,6 +98,208 @@ RUN: llvm-lib -machine:arm64ec test.lib -out:test2.lib RUN: llvm-nm --print-armap test2.lib | FileCheck -check-prefix=ARMAP %s +RUN: llvm-lib -machine:arm64ec -def:test.def -defArm64Native:test.def -out:testx.lib + +RUN: llvm-nm --print-armap testx.lib | FileCheck -check-prefix=ARMAPX %s + +ARMAPX: Archive map +ARMAPX-NEXT: #mangledfunc in test.dll +ARMAPX-NEXT: ?test_cpp_func@@YAHPEAX@Z in test.dll +ARMAPX-NEXT: __IMPORT_DESCRIPTOR_test in test.dll +ARMAPX-NEXT: __NULL_IMPORT_DESCRIPTOR in test.dll +ARMAPX-NEXT: __imp_#mangledfunc in test.dll +ARMAPX-NEXT: __imp_?test_cpp_func@@YAHPEAX@Z in test.dll +ARMAPX-NEXT: __imp_dataexp in test.dll +ARMAPX-NEXT: __imp_expname in test.dll +ARMAPX-NEXT: __imp_funcexp in test.dll +ARMAPX-NEXT: expname in test.dll +ARMAPX-NEXT: funcexp in test.dll +ARMAPX-NEXT: test_NULL_THUNK_DATA in test.dll +ARMAPX-EMPTY: +ARMAPX-NEXT: Archive EC map +ARMAPX-NEXT: #expname in test.dll +ARMAPX-NEXT: #funcexp in test.dll +ARMAPX-NEXT: #mangledfunc in test.dll +ARMAPX-NEXT: ?test_cpp_func@@$$hYAHPEAX@Z in test.dll +ARMAPX-NEXT: ?test_cpp_func@@YAHPEAX@Z in test.dll +ARMAPX-NEXT: __imp_?test_cpp_func@@YAHPEAX@Z in test.dll +ARMAPX-NEXT: __imp_aux_?test_cpp_func@@YAHPEAX@Z in test.dll +ARMAPX-NEXT: __imp_aux_expname in test.dll +ARMAPX-NEXT: __imp_aux_funcexp in test.dll +ARMAPX-NEXT: __imp_aux_mangledfunc in test.dll +ARMAPX-NEXT: __imp_dataexp in test.dll +ARMAPX-NEXT: __imp_expname in test.dll +ARMAPX-NEXT: __imp_funcexp in test.dll +ARMAPX-NEXT: __imp_mangledfunc in test.dll +ARMAPX-NEXT: expname in test.dll +ARMAPX-NEXT: funcexp in test.dll +ARMAPX-NEXT: mangledfunc in test.dll + +RUN: llvm-readobj testx.lib | FileCheck -check-prefix=READOBJX %s + +READOBJX: File: testx.lib(test.dll) +READOBJX-NEXT: Format: COFF-ARM64 +READOBJX-NEXT: Arch: aarch64 +READOBJX-NEXT: AddressSize: 64bit +READOBJX-EMPTY: +READOBJX-NEXT: File: testx.lib(test.dll) +READOBJX-NEXT: Format: COFF-ARM64 +READOBJX-NEXT: Arch: aarch64 +READOBJX-NEXT: AddressSize: 64bit +READOBJX-EMPTY: +READOBJX-NEXT: File: testx.lib(test.dll) +READOBJX-NEXT: Format: COFF-ARM64 +READOBJX-NEXT: Arch: aarch64 +READOBJX-NEXT: AddressSize: 64bit +READOBJX-EMPTY: +READOBJX-NEXT: File: test.dll +READOBJX-NEXT: Format: COFF-import-file-ARM64EC +READOBJX-NEXT: Type: code +READOBJX-NEXT: Name type: export as +READOBJX-NEXT: Export name: funcexp +READOBJX-NEXT: Symbol: __imp_funcexp +READOBJX-NEXT: Symbol: funcexp +READOBJX-NEXT: Symbol: __imp_aux_funcexp +READOBJX-NEXT: Symbol: #funcexp +READOBJX-EMPTY: +READOBJX-NEXT: File: test.dll +READOBJX-NEXT: Format: COFF-import-file-ARM64EC +READOBJX-NEXT: Type: code +READOBJX-NEXT: Name type: export as +READOBJX-NEXT: Export name: mangledfunc +READOBJX-NEXT: Symbol: __imp_mangledfunc +READOBJX-NEXT: Symbol: mangledfunc +READOBJX-NEXT: Symbol: __imp_aux_mangledfunc +READOBJX-NEXT: Symbol: #mangledfunc +READOBJX-EMPTY: +READOBJX-NEXT: File: test.dll +READOBJX-NEXT: Format: COFF-import-file-ARM64EC +READOBJX-NEXT: Type: code +READOBJX-NEXT: Name type: export as +READOBJX-NEXT: Export name: ?test_cpp_func@@YAHPEAX@Z +READOBJX-NEXT: Symbol: __imp_?test_cpp_func@@YAHPEAX@Z +READOBJX-NEXT: Symbol: ?test_cpp_func@@YAHPEAX@Z +READOBJX-NEXT: Symbol: __imp_aux_?test_cpp_func@@YAHPEAX@Z +READOBJX-NEXT: Symbol: ?test_cpp_func@@$$hYAHPEAX@Z +READOBJX-EMPTY: +READOBJX-NEXT: File: test.dll +READOBJX-NEXT: Format: COFF-import-file-ARM64EC +READOBJX-NEXT: Type: code +READOBJX-NEXT: Name type: export as +READOBJX-NEXT: Export name: expname +READOBJX-NEXT: Symbol: __imp_expname +READOBJX-NEXT: Symbol: expname +READOBJX-NEXT: Symbol: __imp_aux_expname +READOBJX-NEXT: Symbol: #expname +READOBJX-EMPTY: +READOBJX-NEXT: File: test.dll +READOBJX-NEXT: Format: COFF-import-file-ARM64EC +READOBJX-NEXT: Type: data +READOBJX-NEXT: Name type: name +READOBJX-NEXT: Export name: dataexp +READOBJX-NEXT: Symbol: __imp_dataexp +READOBJX-EMPTY: +READOBJX-NEXT: File: test.dll +READOBJX-NEXT: Format: COFF-import-file-ARM64 +READOBJX-NEXT: Type: code +READOBJX-NEXT: Name type: name +READOBJX-NEXT: Export name: funcexp +READOBJX-NEXT: Symbol: __imp_funcexp +READOBJX-NEXT: Symbol: funcexp +READOBJX-EMPTY: +READOBJX-NEXT: File: test.dll +READOBJX-NEXT: Format: COFF-import-file-ARM64 +READOBJX-NEXT: Type: code +READOBJX-NEXT: Name type: name +READOBJX-NEXT: Export name: #mangledfunc +READOBJX-NEXT: Symbol: __imp_#mangledfunc +READOBJX-NEXT: Symbol: #mangledfunc +READOBJX-EMPTY: +READOBJX-NEXT: File: test.dll +READOBJX-NEXT: Format: COFF-import-file-ARM64 +READOBJX-NEXT: Type: code +READOBJX-NEXT: Name type: name +READOBJX-NEXT: Export name: ?test_cpp_func@@YAHPEAX@Z +READOBJX-NEXT: Symbol: __imp_?test_cpp_func@@YAHPEAX@Z +READOBJX-NEXT: Symbol: ?test_cpp_func@@YAHPEAX@Z +READOBJX-EMPTY: +READOBJX-NEXT: File: test.dll +READOBJX-NEXT: Format: COFF-import-file-ARM64 +READOBJX-NEXT: Type: code +READOBJX-NEXT: Name type: name +READOBJX-NEXT: Export name: expname +READOBJX-NEXT: Symbol: __imp_expname +READOBJX-NEXT: Symbol: expname +READOBJX-EMPTY: +READOBJX-NEXT: File: test.dll +READOBJX-NEXT: Format: COFF-import-file-ARM64 +READOBJX-NEXT: Type: data +READOBJX-NEXT: Name type: name +READOBJX-NEXT: Export name: dataexp +READOBJX-NEXT: Symbol: __imp_dataexp + + +RUN: llvm-lib -machine:arm64ec -def:test.def -defArm64Native:test2.def -out:test2.lib +RUN: llvm-nm --print-armap test2.lib | FileCheck -check-prefix=ARMAPX2 %s + +ARMAPX2: Archive map +ARMAPX2-NEXT: __IMPORT_DESCRIPTOR_test2 in test2.dll +ARMAPX2-NEXT: __NULL_IMPORT_DESCRIPTOR in test2.dll +ARMAPX2-NEXT: __imp_otherfunc in test2.dll +ARMAPX2-NEXT: otherfunc in test2.dll +ARMAPX2-NEXT: test2_NULL_THUNK_DATA in test2.dll +ARMAPX2-EMPTY: +ARMAPX2-NEXT: Archive EC map +ARMAPX2-NEXT: #expname in test2.dll +ARMAPX2-NEXT: #funcexp in test2.dll +ARMAPX2-NEXT: #mangledfunc in test2.dll +ARMAPX2-NEXT: ?test_cpp_func@@$$hYAHPEAX@Z in test2.dll +ARMAPX2-NEXT: ?test_cpp_func@@YAHPEAX@Z in test2.dll +ARMAPX2-NEXT: __imp_?test_cpp_func@@YAHPEAX@Z in test2.dll +ARMAPX2-NEXT: __imp_aux_?test_cpp_func@@YAHPEAX@Z in test2.dll +ARMAPX2-NEXT: __imp_aux_expname in test2.dll +ARMAPX2-NEXT: __imp_aux_funcexp in test2.dll +ARMAPX2-NEXT: __imp_aux_mangledfunc in test2.dll +ARMAPX2-NEXT: __imp_dataexp in test2.dll +ARMAPX2-NEXT: __imp_expname in test2.dll +ARMAPX2-NEXT: __imp_funcexp in test2.dll +ARMAPX2-NEXT: __imp_mangledfunc in test2.dll +ARMAPX2-NEXT: expname in test2.dll +ARMAPX2-NEXT: funcexp in test2.dll +ARMAPX2-NEXT: mangledfunc in test2.dll + +ARMAPX2: test2.dll: +ARMAPX2: 00000000 T #funcexp +ARMAPX2-NEXT: 00000000 T __imp_aux_funcexp +ARMAPX2-NEXT: 00000000 T __imp_funcexp +ARMAPX2-NEXT: 00000000 T funcexp +ARMAPX2-EMPTY: +ARMAPX2-NEXT: test2.dll: +ARMAPX2-NEXT: 00000000 T #mangledfunc +ARMAPX2-NEXT: 00000000 T __imp_aux_mangledfunc +ARMAPX2-NEXT: 00000000 T __imp_mangledfunc +ARMAPX2-NEXT: 00000000 T mangledfunc +ARMAPX2-EMPTY: +ARMAPX2-NEXT: test2.dll: +ARMAPX2-NEXT: 00000000 T ?test_cpp_func@@$$hYAHPEAX@Z +ARMAPX2-NEXT: 00000000 T ?test_cpp_func@@YAHPEAX@Z +ARMAPX2-NEXT: 00000000 T __imp_?test_cpp_func@@YAHPEAX@Z +ARMAPX2-NEXT: 00000000 T __imp_aux_?test_cpp_func@@YAHPEAX@Z +ARMAPX2-EMPTY: +ARMAPX2-NEXT: test2.dll: +ARMAPX2-NEXT: 00000000 T #expname +ARMAPX2-NEXT: 00000000 T __imp_aux_expname +ARMAPX2-NEXT: 00000000 T __imp_expname +ARMAPX2-NEXT: 00000000 T expname +ARMAPX2-EMPTY: +ARMAPX2-NEXT: test2.dll: +ARMAPX2-NEXT: 00000000 D __imp_dataexp +ARMAPX2-EMPTY: +ARMAPX2-NEXT: test2.dll: +ARMAPX2-NEXT: 00000000 T __imp_otherfunc +ARMAPX2-NEXT: 00000000 T otherfunc + + RUN: llvm-lib -machine:arm64ec -def:exportas.def -out:exportas.lib RUN: llvm-nm --print-armap exportas.lib | FileCheck -check-prefix=EXPAS-ARMAP %s RUN: llvm-readobj exportas.lib | FileCheck -check-prefix=EXPAS-READOBJ %s @@ -186,6 +388,11 @@ EXPORTS expname=impname dataexp DATA +#--- test2.def +LIBRARY test2.dll +EXPORTS + otherfunc + #--- exportas.def LIBRARY test.dll EXPORTS