From 1a6ec906fb3781c2fc98979ec37a2a76479b0b08 Mon Sep 17 00:00:00 2001 From: Daniel Paoliello Date: Tue, 12 Mar 2024 14:10:49 -0700 Subject: [Arm64EC] Copy import descriptors to the EC Map (#84834) As noted in , MSVC places import descriptors in both the EC and regular map - that PR moved the descriptors to ONLY the regular map, however this causes linking errors when linking as Arm64EC: ``` bcryptprimitives.lib(bcryptprimitives.dll) : error LNK2001: unresolved external symbol __IMPORT_DESCRIPTOR_bcryptprimitives (EC Symbol) ``` This change copies import descriptors from the regular map to the EC map, which fixes this linking error. --- llvm/include/llvm/Object/COFFImportFile.h | 6 ++++++ llvm/lib/Object/ArchiveWriter.cpp | 11 +++++++++++ llvm/lib/Object/COFFImportFile.cpp | 10 ++++------ llvm/test/tools/llvm-dlltool/arm64ec.test | 6 ++++++ llvm/test/tools/llvm-lib/arm64ec-implib.test | 12 ++++++++++++ 5 files changed, 39 insertions(+), 6 deletions(-) diff --git a/llvm/include/llvm/Object/COFFImportFile.h b/llvm/include/llvm/Object/COFFImportFile.h index 402ded0..7268faa 100644 --- a/llvm/include/llvm/Object/COFFImportFile.h +++ b/llvm/include/llvm/Object/COFFImportFile.h @@ -26,6 +26,12 @@ namespace llvm { namespace object { +constexpr std::string_view ImportDescriptorPrefix = "__IMPORT_DESCRIPTOR_"; +constexpr std::string_view NullImportDescriptorSymbolName = + "__NULL_IMPORT_DESCRIPTOR"; +constexpr std::string_view NullThunkDataPrefix = "\x7f"; +constexpr std::string_view NullThunkDataSuffix = "_NULL_THUNK_DATA"; + class COFFImportFile : public SymbolicFile { private: enum SymbolIndex { ImpSymbol, ThunkSymbol, ECAuxSymbol, ECThunkSymbol }; diff --git a/llvm/lib/Object/ArchiveWriter.cpp b/llvm/lib/Object/ArchiveWriter.cpp index be51093..e062974 100644 --- a/llvm/lib/Object/ArchiveWriter.cpp +++ b/llvm/lib/Object/ArchiveWriter.cpp @@ -677,6 +677,13 @@ static bool isECObject(object::SymbolicFile &Obj) { return false; } +bool isImportDescriptor(StringRef Name) { + return Name.starts_with(ImportDescriptorPrefix) || + Name == StringRef{NullImportDescriptorSymbolName} || + (Name.starts_with(NullThunkDataPrefix) && + Name.ends_with(NullThunkDataSuffix)); +} + static Expected> getSymbols(SymbolicFile *Obj, uint16_t Index, raw_ostream &SymNames, @@ -704,6 +711,10 @@ static Expected> getSymbols(SymbolicFile *Obj, if (Map == &SymMap->Map) { Ret.push_back(SymNames.tell()); SymNames << Name << '\0'; + // If EC is enabled, then the import descriptors are NOT put into EC + // objects so we need to copy them to the EC map manually. + if (SymMap->UseECMap && isImportDescriptor(Name)) + SymMap->ECMap[Name] = Index; } } else { Ret.push_back(SymNames.tell()); diff --git a/llvm/lib/Object/COFFImportFile.cpp b/llvm/lib/Object/COFFImportFile.cpp index 376dd12..46c8e70 100644 --- a/llvm/lib/Object/COFFImportFile.cpp +++ b/llvm/lib/Object/COFFImportFile.cpp @@ -108,7 +108,7 @@ template static void append(std::vector &B, const T &Data) { } static void writeStringTable(std::vector &B, - ArrayRef Strings) { + ArrayRef Strings) { // The COFF string table consists of a 4-byte value which is the size of the // table, including the length field itself. This value is followed by the // string content itself, which is an array of null-terminated C-style @@ -171,9 +171,6 @@ static Expected replace(StringRef S, StringRef From, return (Twine(S.substr(0, Pos)) + To + S.substr(Pos + From.size())).str(); } -static const std::string NullImportDescriptorSymbolName = - "__NULL_IMPORT_DESCRIPTOR"; - namespace { // This class constructs various small object files necessary to support linking // symbols imported from a DLL. The contents are pretty strictly defined and @@ -192,8 +189,9 @@ class ObjectFactory { public: ObjectFactory(StringRef S, MachineTypes M) : NativeMachine(M), ImportName(S), Library(llvm::sys::path::stem(S)), - ImportDescriptorSymbolName(("__IMPORT_DESCRIPTOR_" + Library).str()), - NullThunkSymbolName(("\x7f" + Library + "_NULL_THUNK_DATA").str()) {} + ImportDescriptorSymbolName((ImportDescriptorPrefix + Library).str()), + NullThunkSymbolName( + (NullThunkDataPrefix + Library + NullThunkDataSuffix).str()) {} // Creates an Import Descriptor. This is a small object file which contains a // reference to the terminators and contains the library name (entry) for the diff --git a/llvm/test/tools/llvm-dlltool/arm64ec.test b/llvm/test/tools/llvm-dlltool/arm64ec.test index e742a77..b03b4ea 100644 --- a/llvm/test/tools/llvm-dlltool/arm64ec.test +++ b/llvm/test/tools/llvm-dlltool/arm64ec.test @@ -12,9 +12,12 @@ ARMAP-NEXT: test_NULL_THUNK_DATA in test.dll ARMAP-EMPTY: ARMAP-NEXT: Archive EC map ARMAP-NEXT: #func in test.dll +ARMAP-NEXT: __IMPORT_DESCRIPTOR_test in test.dll +ARMAP-NEXT: __NULL_IMPORT_DESCRIPTOR in test.dll ARMAP-NEXT: __imp_aux_func in test.dll ARMAP-NEXT: __imp_func in test.dll ARMAP-NEXT: func in test.dll +ARMAP-NEXT: test_NULL_THUNK_DATA in test.dll RUN: llvm-dlltool -m arm64ec -d test.def -N test2.def -l test2.lib RUN: llvm-nm --print-armap test2.lib | FileCheck --check-prefix=ARMAP2 %s @@ -28,9 +31,12 @@ ARMAP2-NEXT: test_NULL_THUNK_DATA in test.dll ARMAP2-EMPTY: ARMAP2-NEXT: Archive EC map ARMAP2-NEXT: #func in test.dll +ARMAP2-NEXT: __IMPORT_DESCRIPTOR_test in test.dll +ARMAP2-NEXT: __NULL_IMPORT_DESCRIPTOR in test.dll ARMAP2-NEXT: __imp_aux_func in test.dll ARMAP2-NEXT: __imp_func in test.dll ARMAP2-NEXT: func in test.dll +ARMAP2-NEXT: test_NULL_THUNK_DATA in test.dll RUN: llvm-dlltool -m arm64ec -d test.def --input-native-def test2.def -l test3.lib RUN: llvm-nm --print-armap test3.lib | FileCheck --check-prefix=ARMAP2 %s diff --git a/llvm/test/tools/llvm-lib/arm64ec-implib.test b/llvm/test/tools/llvm-lib/arm64ec-implib.test index 77bdc23..00eddd2 100644 --- a/llvm/test/tools/llvm-lib/arm64ec-implib.test +++ b/llvm/test/tools/llvm-lib/arm64ec-implib.test @@ -16,6 +16,8 @@ ARMAP-NEXT: #funcexp in test.dll ARMAP-NEXT: #mangledfunc in test.dll ARMAP-NEXT: ?test_cpp_func@@$$hYAHPEAX@Z in test.dll ARMAP-NEXT: ?test_cpp_func@@YAHPEAX@Z in test.dll +ARMAP-NEXT: __IMPORT_DESCRIPTOR_test in test.dll +ARMAP-NEXT: __NULL_IMPORT_DESCRIPTOR in test.dll ARMAP-NEXT: __imp_?test_cpp_func@@YAHPEAX@Z in test.dll ARMAP-NEXT: __imp_aux_?test_cpp_func@@YAHPEAX@Z in test.dll ARMAP-NEXT: __imp_aux_expname in test.dll @@ -28,6 +30,7 @@ ARMAP-NEXT: __imp_mangledfunc in test.dll ARMAP-NEXT: expname in test.dll ARMAP-NEXT: funcexp in test.dll ARMAP-NEXT: mangledfunc in test.dll +ARMAP-NEXT: test_NULL_THUNK_DATA in test.dll RUN: llvm-readobj test.lib | FileCheck -check-prefix=READOBJ %s @@ -122,6 +125,8 @@ 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: __IMPORT_DESCRIPTOR_test in test.dll +ARMAPX-NEXT: __NULL_IMPORT_DESCRIPTOR 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 @@ -134,6 +139,7 @@ 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 +ARMAPX-NEXT: test_NULL_THUNK_DATA in test.dll RUN: llvm-readobj testx.lib | FileCheck -check-prefix=READOBJX %s @@ -255,6 +261,8 @@ 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: __IMPORT_DESCRIPTOR_test2 in test2.dll +ARMAPX2-NEXT: __NULL_IMPORT_DESCRIPTOR 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 @@ -267,6 +275,7 @@ 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-NEXT: test2_NULL_THUNK_DATA in test2.dll ARMAPX2: test2.dll: ARMAPX2: 00000000 T #funcexp @@ -309,6 +318,8 @@ EXPAS-ARMAP-NEXT: #func1 in test.dll EXPAS-ARMAP-NEXT: #func2 in test.dll EXPAS-ARMAP-NEXT: #func3 in test.dll EXPAS-ARMAP-NEXT: #func4 in test.dll +EXPAS-ARMAP-NEXT: __IMPORT_DESCRIPTOR_test in test.dll +EXPAS-ARMAP-NEXT: __NULL_IMPORT_DESCRIPTOR in test.dll EXPAS-ARMAP-NEXT: __imp_aux_func1 in test.dll EXPAS-ARMAP-NEXT: __imp_aux_func2 in test.dll EXPAS-ARMAP-NEXT: __imp_aux_func3 in test.dll @@ -323,6 +334,7 @@ EXPAS-ARMAP-NEXT: func1 in test.dll EXPAS-ARMAP-NEXT: func2 in test.dll EXPAS-ARMAP-NEXT: func3 in test.dll EXPAS-ARMAP-NEXT: func4 in test.dll +EXPAS-ARMAP-NEXT: test_NULL_THUNK_DATA in test.dll EXPAS-READOBJ: File: test.dll EXPAS-READOBJ-NEXT: Format: COFF-import-file-ARM64EC -- cgit v1.1