Created attachment 6520 [details] Test case source Delay import libraries contain stubs in the form of: _WSAStartup@8: 00000000: FF 25 00 00 00 00 jmp dword ptr [.idata$5] 00000006: B8 00 00 00 00 mov eax,offset .idata$5 0000000B: E9 00 00 00 00 jmp ___tailMerge_libws2_32_delayed_a These are then referenced in the corresponding .idata section à la: RAW DATA #5 00000000: 06 00 00 00 .... RELOCATIONS #5 Symbol Symbol Offset Type Applied To Index Name -------- ---------------- ----------------- -------- ------ 00000000 DIR32 00000006 0 .text When using __declspec(dllimport), only the symbol in .idata$5 (__imp__WSAStartup@8) is referenced, not _WSAStartup@8 in the .text section. This apparently causes the linker to omit the stub, and turn the corresponding relocation into a no-op (i.e. the application will call the address 6). --whole-archive has no effect on this, the stubs are still omitted. Linking the individual object files as extracted from the library DOES produce correct output, though. Adding '-u _WSAStartup@8' to the command line also seems to work. I've made a small test case including an analysis of the generated code. The source for this test case is attached. It can also (including compiled binaries and disassembly) be found at: http://thfabba.ath.cx/~thfabba/pub/delaylib/ I've tested this with ld version 2.20.51.20091222 (ReactOS Build Environment), as well as MinGW's 2.22 and MinGW-w64's 2.22.51.20111217. Possibly, but not necessarily related to bug 12614.
At https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=blob;f=ld/emultempl/pe.em;h=8f41f27709a11c5b3bc4f028c05f7915ce540a86;hb=HEAD#l1768 is this: /* The following chunk of code tries to identify jump stubs in import libraries which are dead code and eliminates them from the final link. For each exported symbol <sym>, there is a object file in the import library with a .text section and several .idata\$* sections. The .text section contains the symbol definition for <sym> which is a jump stub of the form jmp *__imp_<sym>. The .idata\$5 contains the symbol definition for __imp_<sym> which is the address of the slot for <sym> in the import address table. When a symbol is imported explicitly using __declspec(dllimport) declaration, the compiler generates a reference to __imp_<sym> which directly resolves to the symbol in .idata\$5, in which case the jump stub code is not needed. The following code tries to identify jump stub sections in import libraries which are not referred to by anyone and marks them for exclusion from the final link. */ This code removes the delay-loading stubs as well. My simple fix/workaround was to check if the last symbol name starts with "___tailMerge_", and in this case not exclude it from the final link.
Domani Hannes, This seems like the correct place for the fix, however not an 100% correct fix. I do believe that in this case, we have to check if someone references any of the parts of the delayload chain, the entire chain should be included.
I've also hit this issue and removing the __declspec(dllimport) resolved it. In the documentation provided by Microsoft it does mention a compiler optimisation that is performed when this is added as noted in a previous comment. Documentation is here https://docs.microsoft.com/en-us/cpp/build/importing-into-an-application-using-declspec-dllimport?view=msvc-170. Maybe something could be put into the generated assembly of the static wrapper library to disable compile optimisation for that block.
I've also found that adding the WINAPI macro (__stdcall) is also problematic. It allows the library to load and it fails after the dliNotePreGetProcAddress query stage and doesn't hit dliNoteEndProcessing. BTW this ticket (https://www.sourceware.org/bugzilla/show_bug.cgi?id=22676) will be related as it has the __declspec(dllimport).