[Bug 53402] New: fake dlls such as OPENGL32.dll won't load when their unix lib is linked by LLVM lld
WineHQ Bugzilla
wine-bugs at winehq.org
Sat Jul 23 06:37:48 CDT 2022
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 at winehq.org
Reporter: w12101111 at 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.
--
Do not reply to this email, post in Bugzilla using the
above URL to reply.
You are receiving this mail because:
You are watching all bug changes.
More information about the wine-bugs
mailing list