https://bugs.winehq.org/show_bug.cgi?id=53402
Bug ID: 53402 Summary: fake dlls such as OPENGL32.dll won't load when their unix lib is linked by LLVM lld Product: Wine Version: 7.13 Hardware: x86-64 OS: Linux Status: UNCONFIRMED Severity: normal Priority: P2 Component: ntdll Assignee: wine-bugs@winehq.org Reporter: w12101111@outlook.com Distribution: ---
I build wine 7.13 using Gentoo Linux ebuild (app-emulation/wine-vanilla-7.13) with clang & ld.lld and x86_64-w64-mingw32.
In wine 7.13, opengl32.dll is a wine fake dll, and I found that any program require opengl failed to launch (take https://github.com/gkv311/wglinfo as an example):
0024:err:module:LdrInitializeThunk "OPENGL32.dll" failed to initialize, aborting 0024:err:module:LdrInitializeThunk Initializing dlls for L"Z:\home\han\Downloads\wglinfo64.exe" failed, status c0000005
Use gdb to debug this, I found that the real address of DllMain is 0x7a9be8e0, but ntdll try to call 0x17a9be8e0:
#0 0x000000017a9be8e0 in ?? () #1 0x0000000170032ac7 in call_dll_entry_point (proc=0x17a9be8e0, module=0x7a9d0000 <__wine_spec_pe_header+65274>, reason=1, reserved=0x11fb00) at /tmp/portage/app-emulation/wine-vanilla-7.13/work/wine-7.13/dlls/ntdll/loader.c:305
(gdb) x /6i 0x000000017a9be8e0 => 0x17a9be8e0: Cannot access memory at address 0x17a9be8e0 (gdb) x /6i 0x000000007a9be8e0 0x7a9be8e0 <DllMain>: push %rbp 0x7a9be8e1 <DllMain+1>: mov %rsp,%rbp 0x7a9be8e4 <DllMain+4>: and $0xfffffffffffffff8,%rsp 0x7a9be8e8 <DllMain+8>: sub $0x30,%rsp 0x7a9be8ec <DllMain+12>: mov %rcx,0x18(%rsp) 0x7a9be8f1 <DllMain+17>: mov %edx,0x14(%rsp)
The address of `module` (0x7a9d0000) is calculated by dlopen_dll ( dlls/ntdll/unix/loader.c:1294 ):
nt = dlsym( handle, "__wine_spec_nt_header" ) module = (HMODULE)((nt->OptionalHeader.ImageBase + 0xffff) & ~0xffff); map_so_dll( nt, module )
And in function static NTSTATUS map_so_dll( const IMAGE_NT_HEADERS *nt_descr, HMODULE module ):
BYTE *addr = (BYTE *)module; fixup_rva_ptrs( &nt->OptionalHeader.AddressOfEntryPoint, addr, 1 );
static inline void fixup_rva_ptrs( void *array, BYTE *base, unsigned int count ) { BYTE **src = array; DWORD *dst = array;
for ( ; count; count--, src++, dst++) *dst = *src ? *src - base : 0; }
This code is equal to
nt->OptionalHeader.AddressOfEntryPoint = (DWORD)((BYTE*)nt->OptionalHeader.AddressOfEntryPoint - (BYTE *)module);
Note that nt->OptionalHeader.AddressOfEntryPoint is DWORD, this code implies that nt->OptionalHeader.AddressOfEntryPoint is greater than (nt->OptionalHeader.ImageBase + 0xffff) & ~0xffff), otherwise it will overflow.
This header is write by output_module ( tools/winebuild/spec32.c:699 ), nt->OptionalHeader.AddressOfEntryPoint is the address of DllMain, and nt->OptionalHeader.ImageBase is the address of __wine_spec_pe_header
Read opengl32.dll.so using readelf:
readelf -S /usr/lib/wine-vanilla-7.13/wine/x86_64-unix/opengl32.dll.so
There are 31 section headers, starting at offset 0x386b20:
Section Headers: [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 [ 1] .dynsym DYNSYM 000000007a800238 000238 002370 18 A 4 1 8 [ 2] .gnu.hash GNU_HASH 000000007a8025a8 0025a8 000b30 00 A 1 0 8 [ 3] .hash HASH 000000007a8030d8 0030d8 000bd8 04 A 1 0 4 [ 4] .dynstr STRTAB 000000007a803cb0 003cb0 00133a 00 A 0 0 1 [ 5] .rela.dyn RELA 000000007a804ff0 004ff0 043890 18 A 1 0 8 [ 6] .rela.plt RELA 000000007a848880 048880 000120 18 AI 1 20 8 [ 7] .rodata PROGBITS 000000007a8489a0 0489a0 0140d0 00 AMS 0 0 16 [ 8] .eh_frame_hdr PROGBITS 000000007a85ca70 05ca70 00cc7c 00 A 0 0 4 [ 9] .eh_frame PROGBITS 000000007a8696f0 0696f0 045d24 00 A 0 0 8 [10] .text PROGBITS 000000007a8b0420 0af420 10fce0 00 AX 0 0 32 [11] .init PROGBITS 000000007a9c0100 1bf100 011008 00 AX 0 0 1 [12] .fini PROGBITS 000000007a9d1108 1d0108 000003 00 AX 0 0 1 [13] .plt PROGBITS 000000007a9d1110 1d0110 0000d0 00 AX 0 0 16 [14] .init_array INIT_ARRAY 000000007a9d21e0 1d01e0 000008 00 WA 0 0 8 [15] .fini_array FINI_ARRAY 000000007a9d21e8 1d01e8 000010 00 WA 0 0 8 [16] .data.rel.ro PROGBITS 000000007a9d2200 1d0200 00fcb0 00 WA 0 0 16 [17] .dynamic DYNAMIC 000000007a9e1eb0 1dfeb0 000170 10 WA 4 0 8 [18] .got PROGBITS 000000007a9e2020 1e0020 000018 00 WA 0 0 8 [19] .data PROGBITS 000000007a9e3038 1e0038 009120 00 WA 0 0 8 [20] .got.plt PROGBITS 000000007a9ec158 1e9158 000078 00 WA 0 0 8 [21] .bss NOBITS 000000007a9ec1d0 1e91d0 006090 00 WA 0 0 16 [22] .debug_line PROGBITS 0000000000000000 1e91d0 039046 00 0 0 1 [23] .debug_line_str PROGBITS 0000000000000000 222216 00004e 01 MS 0 0 1 [24] .comment PROGBITS 0000000000000000 222264 00003e 01 MS 0 0 1 [25] .debug_abbrev PROGBITS 0000000000000000 2222a2 000c02 00 0 0 1 [26] .debug_info PROGBITS 0000000000000000 222ea4 0ed62d 00 0 0 1 [27] .debug_str PROGBITS 0000000000000000 3104d1 028720 01 MS 0 0 1 [28] .symtab SYMTAB 0000000000000000 338bf8 026d30 18 30 6249 8 [29] .shstrtab STRTAB 0000000000000000 35f928 000117 00 0 0 1 [30] .strtab STRTAB 0000000000000000 35fa3f 0270de 00 0 0 1 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), C (compressed), x (unknown), o (OS specific), E (exclude), R (retain), l (large), p (processor specific)
readelf -s /usr/lib/wine-vanilla-7.13/wine/x86_64-unix/opengl32.dll.so | grep __wine_spec_pe_header
1: 000000007a9c0106 0 NOTYPE LOCAL DEFAULT 11 __wine_spec_pe_header
readelf -s /usr/lib/wine-vanilla-7.13/wine/x86_64-unix/opengl32.dll.so | grep DllMain
6227: 000000007a9be8e0 147 FUNC LOCAL HIDDEN 10 DllMain
In output_module, __wine_spec_pe_header is put into .init section:
.section ".init","ax" jmp 1f __wine_spec_pe_header: .skip 69632 1:
DllMain is in .text section
But LLVM lld put .text before .init, so the assumption in map_so_dll is not valid, and the address has a extra 2^32 because of the subtraction overflow and cast to DWORD.
If I change function output_module, put __wine_spec_pe_header in .text just like PLATFORM_SOLARIS, then OPENGL32.DLL will load without any issue.
https://bugs.winehq.org/show_bug.cgi?id=53402
w12101111@outlook.com w12101111@outlook.com changed:
What |Removed |Added ---------------------------------------------------------------------------- Status|UNCONFIRMED |RESOLVED Resolution|--- |FIXED
--- Comment #1 from w12101111@outlook.com w12101111@outlook.com --- Close as opengl32 is not fake dll now.
https://bugs.winehq.org/show_bug.cgi?id=53402
Alexandre Julliard julliard@winehq.org changed:
What |Removed |Added ---------------------------------------------------------------------------- Status|RESOLVED |CLOSED
--- Comment #2 from Alexandre Julliard julliard@winehq.org --- Closing bugs fixed in 7.22.
https://bugs.winehq.org/show_bug.cgi?id=53402
Fabian Maurer dark.shadow4@web.de changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |Alexander88207@Protonmail.c | |om
--- Comment #3 from Fabian Maurer dark.shadow4@web.de --- *** Bug 54134 has been marked as a duplicate of this bug. ***