[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