From d766653534e0cff702e42a43b44d3057b6094fea Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Thu, 25 Jun 2015 02:21:44 +0000 Subject: [PATCH] COFF: Handle undefined symbols starting with __imp_ in a special way. MSVC linker is able to link an object file created from the following code. Note that __imp_hello is not defined anywhere. void hello() { printf("Hello\n"); } extern void (*__imp_hello)(); int main() { __imp_hello(); } Function symbols exported from DLLs are automatically mangled by appending __imp_ prefix, so they have two names (original one and with the prefix). This "feature" seems to simulate that behavior even for non-DLL symbols. This is in my opnion very odd feature. Even MSVC linker warns if you use this. I'm adding that anyway for the sake of compatibiltiy. llvm-svn: 240620 --- lld/COFF/SymbolTable.cpp | 13 ++++++++++-- lld/test/COFF/locally-imported.test | 41 +++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 lld/test/COFF/locally-imported.test diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp index 2bd2538..e76937f 100644 --- a/lld/COFF/SymbolTable.cpp +++ b/lld/COFF/SymbolTable.cpp @@ -70,17 +70,26 @@ bool SymbolTable::reportRemainingUndefines() { auto *Undef = dyn_cast(Sym->Body); if (!Undef) continue; + StringRef Name = Undef->getName(); if (SymbolBody *Alias = Undef->getWeakAlias()) { Sym->Body = Alias->getReplacement(); if (!isa(Sym->Body)) { // Aliases are yet another symbols pointed by other symbols // that could also remain undefined. - llvm::errs() << "undefined symbol: " << Undef->getName() << "\n"; + llvm::errs() << "undefined symbol: " << Name << "\n"; Ret = true; } continue; } - llvm::errs() << "undefined symbol: " << Undef->getName() << "\n"; + // If we can resolve a symbol by removing __imp_ prefix, do that. + // This odd rule is for compatibility with MSVC linker. + if (Name.startswith("__imp_")) { + if (Defined *Imp = find(Name.substr(strlen("__imp_")))) { + Sym->Body = Imp; + continue; + } + } + llvm::errs() << "undefined symbol: " << Name << "\n"; Ret = true; } return Ret; diff --git a/lld/test/COFF/locally-imported.test b/lld/test/COFF/locally-imported.test new file mode 100644 index 0000000..2d8e5323 --- /dev/null +++ b/lld/test/COFF/locally-imported.test @@ -0,0 +1,41 @@ +# RUN: yaml2obj < %s > %t.obj +# RUN: lld -flavor link2 /out:%t.exe %t.obj + +# The linker automatically removes __imp_ prefix if it helps to resolve all symbols. + +--- +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: B82A000000C3 +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 6 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + Selection: IMAGE_COMDAT_SELECT_ANY + - Name: mainCRTStartup + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: __imp_mainCRTStartup + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... -- 2.7.4