Created attachment 6520 [details]
Test case source
Delay import libraries contain stubs in the form of:
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 ....
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:
I've tested this with ld version 220.127.116.1191222 (ReactOS Build Environment), as well as MinGW's 2.22 and MinGW-w64's 18.104.22.16811217.
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.
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.