I tried to write down what I grasped for the current modules' evolution
since there's always questions floating around this subject, might be worthwhile to document it a bit
it's likely full of errors, shortcuts, misconceptions... so don't hesitate to comment/amend
Wine "old" module model: ----------------------- Wine used to generate a module (DLL or EXE) as: - an .so (ELF) module, compiled with a native compiler - this .so module embeds also PE module information, so that Wine's loader exposes to Windows application the PE module only.
+--------------------------+ | FOOBAR.dll.so (ELF) | | +----------------------+ | | | PE information | | | +----------------------+ | +--------------------------+
Wine loader is also able to load "pure" PE modules from .dll/.exe files.
A built-in module (FOOBAR.dll.so) can use standard ELF dynamic linking to load also ELF libraries (eg winepulse needs to loads libpulse.so). This is needed to implement in Wine most of the integration into the Unix world; e.g: graphical (X11 or image coding/decoding jpeg...), audio/video (pulse, gstreamer), and other utilities (xml/xslt, database connectivity...) to name a few.
+--------------------------+ +-----------+ | FOOBAR.dll.so (ELF) | -------------> | helper.so | | +----------------------+ | ELF dyn link +-----------+ | | PE information | | | +----------------------+ | +--------------------------+
But, this had some limitations: some applications (version checking, anti-crack...) were trying to open directly the FOOBAR.dll file (as it exists on Windows) to read some elements inside. Wine implemented "fake" files to mimic that PE file content.
+--------------------------+ +-----------+ | FOOBAR.dll.so (ELF) | -------------> | helper.so | | +----------------------+ | ELF dyn link +-----------+ | | PE information | | | +----------------------+ | +--------------------------+
+--------------------------+ | FOOBAR.dll (Fake PE) | +--------------------------+
But this doesn't take into account 32 vs 64 bit applications (letting aside the 16bit part). So in fact, the global picture is closer to this:
+------------------------------+ +-----------+ | FOOBAR.dll.so (ELF 64bit) | -------------> | helper.so | | +------------------------+ | ELF dyn link | (64 bit) | | | PE information (64bit) | | +-----------+ | +------------------------+ | +------------------------------+
+------------------------------+ | FOOBAR.dll (Fake 64 bit PE) | +------------------------------+
+------------------------------+ +-----------+ | FOOBAR.dll.so (ELF 32bit) | -------------> | helper.so | | +------------------------+ | ELF dyn link | (32 bit) | | | PE information (32bit) | | +-----------+ | +------------------------+ | +------------------------------+
+------------------------------+ | FOOBAR.dll (Fake 32 bit PE) | +------------------------------+
This requires that both 32 and 64bit .so libraries to be installed on the host.
But again, this started to show some limitations: - some Linux distros and Apple are willing to drop the 32bit support from their packages, so the 32 bit helper.so libraries might not be available in the future - Apple evolution to support M1 family chip also adds another dimension to the above picture (as a an application can either be compiled for ARM/M1 or Intel chip, so there's also a need to support invocation from both processors (the ABI is different, to start with).
Wine "new" PE model: (PE migration...) ------------------- In this model, Wine requires a cross-compiler to generate directly a PE file for each module.
+-----------------+ | FOOBAR.dll (PE) | +-----------------+
One of interesting benefit of this choice, is that the PE module can now simply link with Window's libc implementation (either msvcrt or ucrt). In the "old" model, the default was to use the unix libc libraries, yet providing some other potential differences.
For modules not requiring system .so files, this migration is rather simple. There are still some elements to look at [1]. But most of the hard job is done by the compiler and the Wine infrastructure.
For modules requiring linking to .so files, the scheme has to be extended by generating an additional ELF library, tied to the PE module. +-----------------+ +-----------------+ +-----------+ | FOOBAR.dll (PE) | | FOOBAR.so (ELF) | -------------> | helper.so | | | --------> | (unixlib) | ELF dyn link +-----------+ | | | | +-----------------+ +-----------------+
Addind this extra module in the middle allows to: - do the translation from a entities defined in PE world into entities defined in the ELF world (ABI are different, structures layout are different) - this provides an abstraction of the library for the PE world. - decide what to migrate from the existing code into the PE part (remember existing library in old model lives in the ELF world)
One can see the FOOBAR.so like a Wine-"system driver" for providing the required support from the host.
But, it brings constraints too. The ELF part cannot call back into the PE part of the module, nor into other PE modules. If this ELF parts requires some Wine "kernel features", the it can (using ELF dynamic linking) use the APIs provided by ntdll.so ELF library.
+-----------------+ +-----------------+ +-----------+ | FOOBAR.dll (PE) | | FOOBAR.so (ELF) | -------------> | ntdll.so | | | --------> | (unixlib) | ELF dyn link +-----------+ | | | | -------------> | helper.so | +-----------------+ +-----------------+ +-----------+
Note: likely some other modules .so should be available too (like win32u) (to be confirmed)
Currently, the 32 <> 64 bit is still duplicated:
+-----------------+ +------------------------+ +--------------------+ | FOOBAR.dll (PE) | | FOOBAR.so (ELF 64 bit) | -------------> | ntdll.so (64 bit) | | 64 bit | --------> | (unixlib 64 bit) | ELF dyn link +--------------------+ | | | | -------------> | helper.so (64 bit) | +-----------------+ +------------------------+ +--------------------+
+-----------------+ +------------------------+ +--------------------+ | FOOBAR.dll (PE) | | FOOBAR.so (ELF 32 bit) | -------------> | ntdll.so (32 bit) | | 32 bit | --------> | (unixlib 32 bit) | ELF dyn link +--------------------+ | | | | -------------> | helper.so (32 bit) | +-----------------+ +------------------------+ +--------------------+
When all modules are converted to the new scheme, this shall look like:
+-----------------+ +------------------------+ +--------------------+ | FOOBAR.dll (PE) | | FOOBAR.so (ELF 64 bit) | -------------> | ntdll.so (64 bit) | | 64 bit | --------> | (unixlib ) | ELF dyn link +--------------------+ | | +----> | (64 + 32 bit) | -------------> | helper.so (64 bit) | +-----------------+ | +------------------------+ +--------------------+ | +-----------------+ | | FOOBAR.dll (PE) | | | 32 bit | ---+ | | +-----------------+
This will require that FOOBAR.so correctly handles the "syscall" for both 32 bit and 64 bit unixlib calls. When this is in place, no support for 32-bit .so files will be necessary (both the packages that provide the .so files, but also for the development packages.
Unixlib in a nutshell --------------------- A unixlib interface is just a table of entry points. Both ends (calling PE side, and callee on ELF side) share: - the semantic attached to an entry point a given index in the table (usually defined as a value inside an enum) - the signature of each entry point is always the same: NTSTATUS the_func(void *args); - args is a pointer to a structure containing input and output parameters to this very entry point. There's a specific structure for each function (in some rare cases, several functions can use the same structure).
Invoking on PE side looks like: | struct xxx_yyy arg; | /* fill in arg */ | NTSTATUS status = __wine_unixlib_callinto(foobar.so, /* pseudo code <g> */ | 23 /* index of entry */, | &arg);
An on ELF side: | static NTSTATUS my_func_23(void* parg) | { | struct xxx_yyy *arg = parg; | /* do the hard work */ | } | | /* other functions */ | | entry_point_table[] = { | /* ... */ | my_func_23, /* index 23 */ | /* ... */ | }; | | /* a bit of black magic to register the entry_point_table */
Keep in mind: - the same structure can have different sizes for fields, and different layouts when compiled for PE or ELF, 32 or 64 bit, or different CPUs. So the ELF part must handle those discrepancies if any. - pointers will be of different sizes... - allocation of memory can be harder to implement on ELF side (as one must ensure that allocated memory can be accessed from 32 bit PE part) - exception handling?
Actually, there will be two distinct tables: - one used for the invocation from 64 bit PE side, - the second one used for the invocation from 32 bit PE side.
Upon invocation, their argument will be mapped to the 32 bit or the 64 bit layout of the argument structure. This allows either to adapt the implementation to any difference between the 32 and 64 bit worlds.
So the interface between the PE module and its .so counterpart has to be designed with care: + as already stated, no callback from ELF part into PE part is available, + some objects can be defined differently from both sides: - integers (int) doesn't have the same size - pointers are either 32 bit or 64 bit entities... so if memory has to be returned to PE side, it must be in lower part of memory (at least for 32 bit "syscalls") - ...
So the migration of a module from the "old" model to this PE model requires to: - define the API between the PE and the ELF parts - ensure that code in the ELF doesn't call back into PE APIs - call through the Unixlib mechanism between the PE and ELF part. - the Unixlib call mechanism is available even if the module is generated in the old model, hence allowing to put the unixlib API in place still using the old model. When all is migrated to the Unixlib interface, module can be generated using the new module. (it may be that after reading this you need either/or a) a break, b) a deep breath, c) check your aspirin stock and d) restart from the beginning)
TODO: - debugging - sketch the ARM/Intel on Darwin
Additional bits: --------------- From the .so files that Wine used to link to, some of them are not tied to the physical system, and can be available directly as PE modules (eg. JPEG decoder, XML reader/writer...). The most important of those libraries are cross-compiled, and their source code inserted into Wine tree (see libs/). It's also possible to load the system-wide equivalent PE modules when installed.
It's still not clear to me how the new module wow64 will be activated.
[1]: on 64 bit, Windows chose the LLP64 integer model, while Unix chose the LP64 one (sur. The main difference is that long is 32 bit on Windows and 64 bit on Unix. In the old model, as compilation was native, the Windows types were redefined to fit the LP64 model (like DWORD was an unsigned int to get the right size). With the migration to the new model, as compilation of PE modules is done on LLP64 models, DWORD (and friends) are now defined as on Windows as an unsigned long. This is called the migration to long types (90% of modules migrated) and takes place along side the PE migration.
Great summary, a few clarifications from my understanding
On 14.04.22 11:26, Eric Pouech wrote:
Keep in mind:
- the same structure can have different sizes for fields, and
different layouts when compiled for PE or ELF, 32 or 64 bit, or different CPUs. So the ELF part must handle those discrepancies if any.
- pointers will be of different sizes...
- allocation of memory can be harder to implement on ELF side (as one
must ensure that allocated memory can be accessed from 32 bit PE part)
Even on the 64-bit side, memory existing on the PE side should have been allocated through wine's system, with valid information reflected from calls to functions like NtQueryVirtualMemory.
- exception handling?
All unixlib entries have an implicit stack exception handler around them, that, when caught, returns the exception code NTSTATUS from the function to the PE side.
Actually, there will be two distinct tables:
- one used for the invocation from 64 bit PE side,
- the second one used for the invocation from 32 bit PE side.
Upon invocation, their argument will be mapped to the 32 bit or the 64 bit layout of the argument structure. This allows either to adapt the implementation to any difference between the 32 and 64 bit worlds.
This is a bit confusingly worded, the second table "__wine_unix_call_wow64_funcs" will map the incoming 32-bit ABI argument structure to the 64 bit ABI, call the 64 bit handler, then map the outgoing 64bit ABI argument structure, (the same structure is used both for input and output parameters) into the equivalent 32-bit ABI structure again.
It's still not clear to me how the new module wow64 will be activated.
As far as I understand it, wow64.dll is simply a 64-bit PE that is loaded by the 64-bit ntdll.dll in a wow64 process. 64-bit ntdll.dll also loads 32-bit ntdll.dll, which, when used on wow64, will call into wow64.dll for system calls, by means of using wow64cpu.dll to perform a context switch to the 64-bit CPU mode.
Very nice sum up of the whole situation. Sounds perfect for the wiki.
Bernhard
Eric Pouech eric.pouech@orange.fr schrieb am Do., 14. Apr. 2022, 17:26:
I tried to write down what I grasped for the current modules' evolution
since there's always questions floating around this subject, might be worthwhile to document it a bit
it's likely full of errors, shortcuts, misconceptions... so don't hesitate to comment/amend
Wine "old" module model:
Wine used to generate a module (DLL or EXE) as:
an .so (ELF) module, compiled with a native compiler
this .so module embeds also PE module information, so that Wine's loader exposes to Windows application the PE module only.
+--------------------------+ | FOOBAR.dll.so (ELF) | | +----------------------+ | | | PE information | | | +----------------------+ | +--------------------------+
Wine loader is also able to load "pure" PE modules from .dll/.exe files.
A built-in module (FOOBAR.dll.so) can use standard ELF dynamic linking to load also ELF libraries (eg winepulse needs to loads libpulse.so). This is needed to implement in Wine most of the integration into the Unix world; e.g: graphical (X11 or image coding/decoding jpeg...), audio/video (pulse, gstreamer), and other utilities (xml/xslt, database connectivity...) to name a few.
+--------------------------+ +-----------+ | FOOBAR.dll.so (ELF) | -------------> | helper.so | | +----------------------+ | ELF dyn link +-----------+ | | PE information | | | +----------------------+ | +--------------------------+
But, this had some limitations: some applications (version checking, anti-crack...) were trying to open directly the FOOBAR.dll file (as it exists on Windows) to read some elements inside. Wine implemented "fake" files to mimic that PE file content.
+--------------------------+ +-----------+ | FOOBAR.dll.so (ELF) | -------------> | helper.so | | +----------------------+ | ELF dyn link +-----------+ | | PE information | | | +----------------------+ | +--------------------------+
+--------------------------+ | FOOBAR.dll (Fake PE) | +--------------------------+
But this doesn't take into account 32 vs 64 bit applications (letting aside the 16bit part). So in fact, the global picture is closer to this:
+------------------------------+ +-----------+ | FOOBAR.dll.so (ELF 64bit) | -------------> | helper.so | | +------------------------+ | ELF dyn link | (64 bit) | | | PE information (64bit) | | +-----------+ | +------------------------+ | +------------------------------+
+------------------------------+ | FOOBAR.dll (Fake 64 bit PE) | +------------------------------+
+------------------------------+ +-----------+ | FOOBAR.dll.so (ELF 32bit) | -------------> | helper.so | | +------------------------+ | ELF dyn link | (32 bit) | | | PE information (32bit) | | +-----------+ | +------------------------+ | +------------------------------+
+------------------------------+ | FOOBAR.dll (Fake 32 bit PE) | +------------------------------+
This requires that both 32 and 64bit .so libraries to be installed on the host.
But again, this started to show some limitations:
- some Linux distros and Apple are willing to drop the 32bit support from
their packages, so the 32 bit helper.so libraries might not be available in the future
- Apple evolution to support M1 family chip also adds another dimension to
the above picture (as a an application can either be compiled for ARM/M1 or Intel chip, so there's also a need to support invocation from both processors (the ABI is different, to start with).
Wine "new" PE model: (PE migration...)
In this model, Wine requires a cross-compiler to generate directly a PE file for each module.
+-----------------+ | FOOBAR.dll (PE) | +-----------------+
One of interesting benefit of this choice, is that the PE module can now simply link with Window's libc implementation (either msvcrt or ucrt). In the "old" model, the default was to use the unix libc libraries, yet providing some other potential differences.
For modules not requiring system .so files, this migration is rather simple. There are still some elements to look at [1]. But most of the hard job is done by the compiler and the Wine infrastructure.
For modules requiring linking to .so files, the scheme has to be extended by generating an additional ELF library, tied to the PE module. +-----------------+ +-----------------+ +-----------+ | FOOBAR.dll (PE) | | FOOBAR.so (ELF) | -------------> | helper.so | | | --------> | (unixlib) | ELF dyn link +-----------+ | | | | +-----------------+ +-----------------+
Addind this extra module in the middle allows to:
- do the translation from a entities defined in PE world into entities defined in the ELF world (ABI are different, structures layout are
different)
- this provides an abstraction of the library for the PE world.
- decide what to migrate from the existing code into the PE part (remember existing library in old model lives in the ELF world)
One can see the FOOBAR.so like a Wine-"system driver" for providing the required support from the host.
But, it brings constraints too. The ELF part cannot call back into the PE part of the module, nor into other PE modules. If this ELF parts requires some Wine "kernel features", the it can (using ELF dynamic linking) use the APIs provided by ntdll.so ELF library.
+-----------------+ +-----------------+ +-----------+ | FOOBAR.dll (PE) | | FOOBAR.so (ELF) | -------------> | ntdll.so | | | --------> | (unixlib) | ELF dyn link +-----------+ | | | | -------------> | helper.so | +-----------------+ +-----------------+ +-----------+
Note: likely some other modules .so should be available too (like win32u) (to be confirmed)
Currently, the 32 <> 64 bit is still duplicated:
+-----------------+ +------------------------+ +--------------------+ | FOOBAR.dll (PE) | | FOOBAR.so (ELF 64 bit) | -------------> | ntdll.so (64 bit) | | 64 bit | --------> | (unixlib 64 bit) | ELF dyn link +--------------------+ | | | | -------------> | helper.so (64 bit) | +-----------------+ +------------------------+ +--------------------+
+-----------------+ +------------------------+ +--------------------+ | FOOBAR.dll (PE) | | FOOBAR.so (ELF 32 bit) | -------------> | ntdll.so (32 bit) | | 32 bit | --------> | (unixlib 32 bit) | ELF dyn link +--------------------+ | | | | -------------> | helper.so (32 bit) | +-----------------+ +------------------------+ +--------------------+
When all modules are converted to the new scheme, this shall look like:
+-----------------+ +------------------------+ +--------------------+ | FOOBAR.dll (PE) | | FOOBAR.so (ELF 64 bit) | -------------> | ntdll.so (64 bit) | | 64 bit | --------> | (unixlib ) | ELF dyn link +--------------------+ | | +----> | (64 + 32 bit) | -------------> | helper.so (64 bit) | +-----------------+ | +------------------------+ +--------------------+ | +-----------------+ | | FOOBAR.dll (PE) | | | 32 bit | ---+ | | +-----------------+
This will require that FOOBAR.so correctly handles the "syscall" for both 32 bit and 64 bit unixlib calls. When this is in place, no support for 32-bit .so files will be necessary (both the packages that provide the .so files, but also for the development packages.
Unixlib in a nutshell
A unixlib interface is just a table of entry points. Both ends (calling PE side, and callee on ELF side) share:
- the semantic attached to an entry point a given index in the table (usually defined as a value inside an enum)
- the signature of each entry point is always the same: NTSTATUS the_func(void *args);
- args is a pointer to a structure containing input and output parameters to this very entry point. There's a specific structure for each function (in some rare cases,
several functions can use the same structure).
Invoking on PE side looks like: | struct xxx_yyy arg; | /* fill in arg */ | NTSTATUS status = __wine_unixlib_callinto(foobar.so, /* pseudo code <g> */ | 23 /* index of entry */, | &arg);
An on ELF side: | static NTSTATUS my_func_23(void* parg) | { | struct xxx_yyy *arg = parg; | /* do the hard work */ | } | | /* other functions */ | | entry_point_table[] = { | /* ... */ | my_func_23, /* index 23 */ | /* ... */ | }; | | /* a bit of black magic to register the entry_point_table */
Keep in mind:
- the same structure can have different sizes for fields, and different
layouts when compiled for PE or ELF, 32 or 64 bit, or different CPUs. So the ELF part must handle those discrepancies if any.
- pointers will be of different sizes...
- allocation of memory can be harder to implement on ELF side (as one must ensure that allocated memory can be accessed from 32 bit PE part)
- exception handling?
Actually, there will be two distinct tables:
- one used for the invocation from 64 bit PE side,
- the second one used for the invocation from 32 bit PE side.
Upon invocation, their argument will be mapped to the 32 bit or the 64 bit layout of the argument structure. This allows either to adapt the implementation to any difference between the 32 and 64 bit worlds.
So the interface between the PE module and its .so counterpart has to be designed with care:
- as already stated, no callback from ELF part into PE part is available,
- some objects can be defined differently from both sides:
- integers (int) doesn't have the same size
- pointers are either 32 bit or 64 bit entities... so if memory has to be returned to PE side, it must be in lower part of memory (at least for
32 bit "syscalls")
- ...
So the migration of a module from the "old" model to this PE model requires to:
- define the API between the PE and the ELF parts
- ensure that code in the ELF doesn't call back into PE APIs
- call through the Unixlib mechanism between the PE and ELF part.
- the Unixlib call mechanism is available even if the module is generated
in the old model, hence allowing to put the unixlib API in place still using the old model. When all is migrated to the Unixlib interface, module can be generated using the new module. (it may be that after reading this you need either/or a) a break, b) a deep breath, c) check your aspirin stock and d) restart from the beginning)
TODO:
- debugging
- sketch the ARM/Intel on Darwin
Additional bits:
From the .so files that Wine used to link to, some of them are not tied to the physical system, and can be available directly as PE modules (eg. JPEG decoder, XML reader/writer...). The most important of those libraries are cross-compiled, and their source code inserted into Wine tree (see libs/). It's also possible to load the system-wide equivalent PE modules when installed.
It's still not clear to me how the new module wow64 will be activated.
[1]: on 64 bit, Windows chose the LLP64 integer model, while Unix chose the LP64 one (sur. The main difference is that long is 32 bit on Windows and 64 bit on Unix. In the old model, as compilation was native, the Windows types were redefined to fit the LP64 model (like DWORD was an unsigned int to get the right size). With the migration to the new model, as compilation of PE modules is done on LLP64 models, DWORD (and friends) are now defined as on Windows as an unsigned long. This is called the migration to long types (90% of modules migrated) and takes place along side the PE migration.
On 4/15/22 00:26, Eric Pouech wrote:
For modules requiring linking to .so files, the scheme has to be extended by generating an additional ELF library, tied to the PE module. +-----------------+ +-----------------+ +-----------+ | FOOBAR.dll (PE) | | FOOBAR.so (ELF) | -------------> | helper.so | | | --------> | (unixlib) | ELF dyn link +-----------+ | | | | +-----------------+ +-----------------+
Addind this extra module in the middle allows to:
- do the translation from a entities defined in PE world into entities
defined in the ELF world (ABI are different, structures layout are different)
- this provides an abstraction of the library for the PE world.
- decide what to migrate from the existing code into the PE part (remember
existing library in old model lives in the ELF world)
One can see the FOOBAR.so like a Wine-"system driver" for providing the required support from the host.
But, it brings constraints too. The ELF part cannot call back into the PE part of the module, nor into other PE modules.
To clarify: the ELF part cannot call back into PE modules *without performance penalty or interference with stack unwinding*.
ELF modules calls back into user-supplied functions just fine, think e.g. window procedures. This however involves KeUserModeCallback(), accompanied by its context-switching overhead.
Perhaps we intend to say: "The ELF part cannot link directly to dlls. Also, calling back to the PE side comes with performance penalty or interferes with stack unwinding, depending on which callback approach is used."
If this ELF parts requires some Wine "kernel features", the it can (using ELF dynamic linking) use the APIs provided by ntdll.so ELF library.
+-----------------+ +-----------------+ +-----------+ | FOOBAR.dll (PE) | | FOOBAR.so (ELF) | -------------> | ntdll.so | | | --------> | (unixlib) | ELF dyn link +-----------+ | | | | -------------> | helper.so | +-----------------+ +-----------------+ +-----------+
Note: likely some other modules .so should be available too (like win32u) (to be confirmed)
I confirm that win32u.so also exists.
Here is a list of other Unixlibs:
avicap32.so, bcrypt.so, capi2032.so, crypt32.so, ctapi32.so, dnsapi.so, dwrite.so, gphoto2.so, kerberos.so, mountmgr.so, msv1_0.so, netapi32.so, nsiproxy.so, odbc32.so, opencl.so, qcap.so, sane.so, secur32.so, winealsa.so, winebus.so, winecoreaudio.so, winegstreamer.so, wineoss.so, winepulse.so, winevulkan.so, winspool.so, wldap32.so, wpcap.so, ws2_32.so
Currently, the 32 <> 64 bit is still duplicated:
+-----------------+ +------------------------+ +--------------------+ | FOOBAR.dll (PE) | | FOOBAR.so (ELF 64 bit) | -------------> | ntdll.so (64 bit) | | 64 bit | --------> | (unixlib 64 bit) | ELF dyn link +--------------------+ | | | | -------------> | helper.so (64 bit) | +-----------------+ +------------------------+ +--------------------+
+-----------------+ +------------------------+ +--------------------+ | FOOBAR.dll (PE) | | FOOBAR.so (ELF 32 bit) | -------------> | ntdll.so (32 bit) | | 32 bit | --------> | (unixlib 32 bit) | ELF dyn link +--------------------+ | | | | -------------> | helper.so (32 bit) | +-----------------+ +------------------------+ +--------------------+
When all modules are converted to the new scheme, this shall look like:
+-----------------+ +------------------------+ +--------------------+ | FOOBAR.dll (PE) | | FOOBAR.so (ELF 64 bit) | -------------> | ntdll.so (64 bit) | | 64 bit | --------> | (unixlib ) | ELF dyn link +--------------------+ | | +----> | (64 + 32 bit) | -------------> | helper.so (64 bit) | +-----------------+ | +------------------------+ +--------------------+ | +-----------------+ | | FOOBAR.dll (PE) | | | 32 bit | ---+ | | +-----------------+
This will require that FOOBAR.so correctly handles the "syscall" for both 32 bit and 64 bit unixlib calls. When this is in place, no support for 32-bit .so files will be necessary (both the packages that provide the .so files, but also for the development packages.
Unixlib in a nutshell
A unixlib interface is just a table of entry points. Both ends (calling PE side, and callee on ELF side) share:
- the semantic attached to an entry point a given index in the table
(usually defined as a value inside an enum)
- the signature of each entry point is always the same:
NTSTATUS the_func(void *args);
- args is a pointer to a structure containing input and output
parameters to this very entry point. There's a specific structure for each function (in some rare cases, several functions can use the same structure).
It's also worth noting that some DLLs (e.g. win32u.so) have not yet fully migrated to the new __wine_unix_call interface. They will eventually, though.
Invoking on PE side looks like: | struct xxx_yyy arg; | /* fill in arg */ | NTSTATUS status = __wine_unixlib_callinto(foobar.so, /* pseudo code <g> */ | 23 /* index of entry */, | &arg);
__wine_unix_call*
An on ELF side: | static NTSTATUS my_func_23(void* parg) | { | struct xxx_yyy *arg = parg; | /* do the hard work */ | } | | /* other functions */ | | entry_point_table[] = { | /* ... */ | my_func_23, /* index 23 */ | /* ... */ | }; | | /* a bit of black magic to register the entry_point_table */
Keep in mind:
- the same structure can have different sizes for fields, and different layouts
when compiled for PE or ELF, 32 or 64 bit, or different CPUs. So the ELF part must handle those discrepancies if any.
- pointers will be of different sizes...
Yes, hence __wine_unix_call_wow64_funcs.
- allocation of memory can be harder to implement on ELF side (as one must
ensure that allocated memory can be accessed from 32 bit PE part)
Ideally, all memory allocation should be done in PE side (userspace), which has access to HeapAlloc(). Failing that, we can use NtAllocateVirtualMemory.
- exception handling?
To accurately mimic stack unwinding as it happens on Windows, one should stick to the syscall interface instead of the unixlib interface. This way, unix-side stack frames will never appear in RtlVirtualUnwind() output (since they are effectively kernel-mode frames, not user-mode ones).
Actually, there will be two distinct tables:
- one used for the invocation from 64 bit PE side,
- the second one used for the invocation from 32 bit PE side.
(yes, assuming 64-bit wine build with wow64 support)
Upon invocation, their argument will be mapped to the 32 bit or the 64 bit layout of the argument structure. This allows either to adapt the implementation to any difference between the 32 and 64 bit worlds.
So the interface between the PE module and its .so counterpart has to be designed with care:
- as already stated, no callback from ELF part into PE part is available,
- some objects can be defined differently from both sides:
- integers (int) doesn't have the same size - pointers are either 32 bit or 64 bit entities... so if memory has to be returned to PE side, it must be in lower part of memory (at least for 32 bit "syscalls") - ...
So the migration of a module from the "old" model to this PE model requires to:
- define the API between the PE and the ELF parts
- ensure that code in the ELF doesn't call back into PE APIs
- call through the Unixlib mechanism between the PE and ELF part.
- the Unixlib call mechanism is available even if the module is generated in the
old model, hence allowing to put the unixlib API in place still using the old model. When all is migrated to the Unixlib interface, module can be generated using the new module.
Gradual migration is one of the explicit goals of the unixlib infrastructure, yes.
(it may be that after reading this you need either/or a) a break, b) a deep breath, c) check your aspirin stock and d) restart from the beginning)
TODO:
- debugging
- sketch the ARM/Intel on Darwin
Additional bits:
From the .so files that Wine used to link to, some of them are not tied to the physical system, and can be available directly as PE modules (eg. JPEG decoder, XML reader/writer...). The most important of those libraries are cross-compiled, and their source code inserted into Wine tree (see libs/). It's also possible to load the system-wide equivalent PE modules when installed.
It's still not clear to me how the new module wow64 will be activated.
See https://www.winehq.org/pipermail/wine-devel/2022-April/213620.html
[1]: on 64 bit, Windows chose the LLP64 integer model, while Unix chose the LP64 one (sur. The main difference is that long is 32 bit on Windows and 64 bit on Unix. In the old model, as compilation was native, the Windows types were redefined to fit the LP64 model (like DWORD was an unsigned int to get the right size). With the migration to the new model, as compilation of PE modules is done on LLP64 models, DWORD (and friends) are now defined as on Windows as an unsigned long. This is called the migration to long types (90% of modules migrated) and takes place along side the PE migration.
On 16.04.22 03:58, Jinoh Kang wrote:
On 4/15/22 00:26, Eric Pouech wrote:
For modules requiring linking to .so files, the scheme has to be extended by generating an additional ELF library, tied to the PE module. +-----------------+ +-----------------+ +-----------+ | FOOBAR.dll (PE) | | FOOBAR.so (ELF) | -------------> | helper.so | | | --------> | (unixlib) | ELF dyn link +-----------+ | | | | +-----------------+ +-----------------+
Addind this extra module in the middle allows to:
- do the translation from a entities defined in PE world into entities
defined in the ELF world (ABI are different, structures layout are different)
- this provides an abstraction of the library for the PE world.
- decide what to migrate from the existing code into the PE part (remember
existing library in old model lives in the ELF world)
One can see the FOOBAR.so like a Wine-"system driver" for providing the required support from the host.
But, it brings constraints too. The ELF part cannot call back into the PE part of the module, nor into other PE modules.
To clarify: the ELF part cannot call back into PE modules *without performance penalty or interference with stack unwinding*.
ELF modules calls back into user-supplied functions just fine, think e.g. window procedures. This however involves KeUserModeCallback(), accompanied by its context-switching overhead.
Perhaps we intend to say: "The ELF part cannot link directly to dlls. Also, calling back to the PE side comes with performance penalty or interferes with stack unwinding, depending on which callback approach is used."
Can you describe the two approaches you're referring to? I'm aware of KeUserModeCallback, and I assume the other method is to create a win32 PE thread which waits on callbacks from the unixlib? As far as I know, KeUserModeCallback doesn't involve context switching, just the usual context saving/restoring required for syscalls in general.
If this ELF parts requires some Wine "kernel features", the it can (using ELF dynamic linking) use the APIs provided by ntdll.so ELF library.
+-----------------+ +-----------------+ +-----------+ | FOOBAR.dll (PE) | | FOOBAR.so (ELF) | -------------> | ntdll.so | | | --------> | (unixlib) | ELF dyn link +-----------+ | | | | -------------> | helper.so | +-----------------+ +-----------------+ +-----------+
Note: likely some other modules .so should be available too (like win32u) (to be confirmed)
I confirm that win32u.so also exists.
Here is a list of other Unixlibs:
I think what Eric was getting at here was what base unix libraries all other unix libraries can be linked against. (For example, using win32u.so from winevulkan.so).
avicap32.so, bcrypt.so, capi2032.so, crypt32.so, ctapi32.so, dnsapi.so, dwrite.so, gphoto2.so, kerberos.so, mountmgr.so, msv1_0.so, netapi32.so, nsiproxy.so, odbc32.so, opencl.so, qcap.so, sane.so, secur32.so, winealsa.so, winebus.so, winecoreaudio.so, winegstreamer.so, wineoss.so, winepulse.so, winevulkan.so, winspool.so, wldap32.so, wpcap.so, ws2_32.so
- exception handling?
To accurately mimic stack unwinding as it happens on Windows, one should stick to the syscall interface instead of the unixlib interface.
Assuming you're referring to the __wine_init_unix_lib approach, the unixlib interface doesn't even exist anymore. (Was removed right before wine 7.0-rc1)
This way, unix-side stack frames will never appear in RtlVirtualUnwind() output (since they are effectively kernel-mode frames, not user-mode ones).
On 4/18/22 22:37, Derek Lesho wrote:
On 16.04.22 03:58, Jinoh Kang wrote:
On 4/15/22 00:26, Eric Pouech wrote:
For modules requiring linking to .so files, the scheme has to be extended by generating an additional ELF library, tied to the PE module. +-----------------+ +-----------------+ +-----------+ | FOOBAR.dll (PE) | | FOOBAR.so (ELF) | -------------> | helper.so | | | --------> | (unixlib) | ELF dyn link +-----------+ | | | | +-----------------+ +-----------------+
Addind this extra module in the middle allows to:
- do the translation from a entities defined in PE world into entities
defined in the ELF world (ABI are different, structures layout are different)
- this provides an abstraction of the library for the PE world.
- decide what to migrate from the existing code into the PE part (remember
existing library in old model lives in the ELF world)
One can see the FOOBAR.so like a Wine-"system driver" for providing the required support from the host.
But, it brings constraints too. The ELF part cannot call back into the PE part of the module, nor into other PE modules.
To clarify: the ELF part cannot call back into PE modules *without performance penalty or interference with stack unwinding*.
ELF modules calls back into user-supplied functions just fine, think e.g. window procedures. This however involves KeUserModeCallback(), accompanied by its context-switching overhead.
Perhaps we intend to say: "The ELF part cannot link directly to dlls. Also, calling back to the PE side comes with performance penalty or interferes with stack unwinding, depending on which callback approach is used."
Can you describe the two approaches you're referring to? I'm aware of KeUserModeCallback, and I assume the other method is to create a win32 PE thread which waits on callbacks from the unixlib?
I meant calling it directly. Which (kind of) messes with syscall frame state.
As far as I know, KeUserModeCallback doesn't involve context switching, just the usual context saving/restoring required for syscalls in general.
Oh, maybe not a context switch per se. It's actually:
1. __wine_setjmp: save Unix-side state 2. emulated syscall return: divert into KiUserCallbackDispatcher 3. syscall: call into NtCallbackReturn 4. __wine_longjmp: restore Unix-side state
So it's still a lot of work.
If this ELF parts requires some Wine "kernel features", the it can (using ELF dynamic linking) use the APIs provided by ntdll.so ELF library.
+-----------------+ +-----------------+ +-----------+ | FOOBAR.dll (PE) | | FOOBAR.so (ELF) | -------------> | ntdll.so | | | --------> | (unixlib) | ELF dyn link +-----------+ | | | | -------------> | helper.so | +-----------------+ +-----------------+ +-----------+
Note: likely some other modules .so should be available too (like win32u) (to be confirmed)
I confirm that win32u.so also exists.
Here is a list of other Unixlibs:
I think what Eric was getting at here was what base unix libraries all other unix libraries can be linked against. (For example, using win32u.so from winevulkan.so).
Pretty much every Unix library can link to one another if they want to, barring abstraction layer issues. I think this aligns with what Eric is trying to convey.
avicap32.so, bcrypt.so, capi2032.so, crypt32.so, ctapi32.so, dnsapi.so, dwrite.so, gphoto2.so, kerberos.so, mountmgr.so, msv1_0.so, netapi32.so, nsiproxy.so, odbc32.so, opencl.so, qcap.so, sane.so, secur32.so, winealsa.so, winebus.so, winecoreaudio.so, winegstreamer.so, wineoss.so, winepulse.so, winevulkan.so, winspool.so, wldap32.so, wpcap.so, ws2_32.so
- exception handling?
To accurately mimic stack unwinding as it happens on Windows, one should stick to the syscall interface instead of the unixlib interface.
Assuming you're referring to the __wine_init_unix_lib approach, the unixlib interface doesn't even exist anymore. (Was removed right before wine 7.0-rc1)
I really meant __wine_unix_call. There's no syscall gate in-between, exposing DWARF frames that could confuse Win32 debuggers/monitors (probably as part of some DRM/obfuscation/anti-RE)
This way, unix-side stack frames will never appear in RtlVirtualUnwind() output (since they are effectively kernel-mode frames, not user-mode ones).
On 18.04.22 12:35, Jinoh Kang wrote:
On 4/18/22 22:37, Derek Lesho wrote:
On 16.04.22 03:58, Jinoh Kang wrote:
On 4/15/22 00:26, Eric Pouech wrote:
For modules requiring linking to .so files, the scheme has to be extended by generating an additional ELF library, tied to the PE module. +-----------------+ +-----------------+ +-----------+ | FOOBAR.dll (PE) | | FOOBAR.so (ELF) | -------------> | helper.so | | | --------> | (unixlib) | ELF dyn link +-----------+ | | | | +-----------------+ +-----------------+
Addind this extra module in the middle allows to:
- do the translation from a entities defined in PE world into entities
defined in the ELF world (ABI are different, structures layout are different)
- this provides an abstraction of the library for the PE world.
- decide what to migrate from the existing code into the PE part (remember
existing library in old model lives in the ELF world)
One can see the FOOBAR.so like a Wine-"system driver" for providing the required support from the host.
But, it brings constraints too. The ELF part cannot call back into the PE part of the module, nor into other PE modules.
To clarify: the ELF part cannot call back into PE modules *without performance penalty or interference with stack unwinding*.
ELF modules calls back into user-supplied functions just fine, think e.g. window procedures. This however involves KeUserModeCallback(), accompanied by its context-switching overhead.
Perhaps we intend to say: "The ELF part cannot link directly to dlls. Also, calling back to the PE side comes with performance penalty or interferes with stack unwinding, depending on which callback approach is used."
Can you describe the two approaches you're referring to? I'm aware of KeUserModeCallback, and I assume the other method is to create a win32 PE thread which waits on callbacks from the unixlib?
I meant calling it directly. Which (kind of) messes with syscall frame state.
Is this allowed in upstream wine, even as an intermediate step in the transition?
As far as I know, KeUserModeCallback doesn't involve context switching, just the usual context saving/restoring required for syscalls in general.
Oh, maybe not a context switch per se. It's actually:
- __wine_setjmp: save Unix-side state
- emulated syscall return: divert into KiUserCallbackDispatcher
- syscall: call into NtCallbackReturn
- __wine_longjmp: restore Unix-side state
So it's still a lot of work.
Yeah, and of course it should be noted that this only works on threads created by wine.
If this ELF parts requires some Wine "kernel features", the it can (using ELF dynamic linking) use the APIs provided by ntdll.so ELF library.
+-----------------+ +-----------------+ +-----------+ | FOOBAR.dll (PE) | | FOOBAR.so (ELF) | -------------> | ntdll.so | | | --------> | (unixlib) | ELF dyn link +-----------+ | | | | -------------> | helper.so | +-----------------+ +-----------------+ +-----------+
Note: likely some other modules .so should be available too (like win32u) (to be confirmed)
I confirm that win32u.so also exists.
Here is a list of other Unixlibs:
I think what Eric was getting at here was what base unix libraries all other unix libraries can be linked against. (For example, using win32u.so from winevulkan.so).
Pretty much every Unix library can link to one another if they want to, barring abstraction layer issues. I think this aligns with what Eric is trying to convey.
Yeah, it's definitely possible to link to any unix library you want, but in terms of making sense of the system, it's possibly useful to clearly differentiate between unix libraries which in addition to their primary purpose can also be used as helper libraries for other unix libraries (like ntdll, win32u), and which unix libraries have the sole purpose of providing a link to the unix world for an optional PE dll (bcrypt, gphoto2, winegstreamer, winepulse, etc).
The former category would be those providing what Eric referred to as "kernel features".
avicap32.so, bcrypt.so, capi2032.so, crypt32.so, ctapi32.so, dnsapi.so, dwrite.so, gphoto2.so, kerberos.so, mountmgr.so, msv1_0.so, netapi32.so, nsiproxy.so, odbc32.so, opencl.so, qcap.so, sane.so, secur32.so, winealsa.so, winebus.so, winecoreaudio.so, winegstreamer.so, wineoss.so, winepulse.so, winevulkan.so, winspool.so, wldap32.so, wpcap.so, ws2_32.so
- exception handling?
To accurately mimic stack unwinding as it happens on Windows, one should stick to the syscall interface instead of the unixlib interface.
Assuming you're referring to the __wine_init_unix_lib approach, the unixlib interface doesn't even exist anymore. (Was removed right before wine 7.0-rc1)
I really meant __wine_unix_call. There's no syscall gate in-between, exposing DWARF frames that could confuse Win32 debuggers/monitors (probably as part of some DRM/obfuscation/anti-RE)
__wine_unix_call is part of the syscall interface, so you won't run into the problems mentioned by using it.
https://source.winehq.org/git/wine.git/blob/HEAD:/dlls/ntdll/ntdll.spec#l164... :
@ stdcall -syscall __wine_unix_call(int64 long ptr)
This way, unix-side stack frames will never appear in RtlVirtualUnwind() output (since they are effectively kernel-mode frames, not user-mode ones).
On Tue, Apr 19, 2022, 2:03 AM Derek Lesho dlesho@codeweavers.com wrote:
On 18.04.22 12:35, Jinoh Kang wrote:
On 4/18/22 22:37, Derek Lesho wrote:
On 16.04.22 03:58, Jinoh Kang wrote:
On 4/15/22 00:26, Eric Pouech wrote:
For modules requiring linking to .so files, the scheme has to be extended by generating an additional ELF library, tied to the PE module. +-----------------+ +-----------------+ +-----------+ | FOOBAR.dll (PE) | | FOOBAR.so (ELF) | -------------> | helper.so | | | --------> | (unixlib) | ELF dyn link +-----------+ | | | | +-----------------+ +-----------------+
Addind this extra module in the middle allows to:
- do the translation from a entities defined in PE world into entities defined in the ELF world (ABI are different, structures layout are different)
- this provides an abstraction of the library for the PE world.
- decide what to migrate from the existing code into the PE part (remember existing library in old model lives in the ELF world)
One can see the FOOBAR.so like a Wine-"system driver" for providing the required support from the host.
But, it brings constraints too. The ELF part cannot call back into the PE part of the module, nor into other PE modules.
To clarify: the ELF part cannot call back into PE modules *without performance penalty or interference with stack unwinding*.
ELF modules calls back into user-supplied functions just fine, think e.g. window procedures. This however involves KeUserModeCallback(), accompanied by its context-switching overhead.
Perhaps we intend to say: "The ELF part cannot link directly to dlls. Also, calling back to the PE side comes with performance penalty or interferes with stack unwinding, depending on which callback approach is used."
Can you describe the two approaches you're referring to? I'm aware of KeUserModeCallback, and I assume the other method is to create a win32 PE thread which waits on callbacks from the unixlib?
I meant calling it directly. Which (kind of) messes with syscall frame state.
Is this allowed in upstream wine, even as an intermediate step in the transition?
I was only suggesting a possibility, not necessarily what is allowed in upstream codebase policy.
As far as I know, KeUserModeCallback doesn't involve context switching, just the usual context saving/restoring required for syscalls in general.
Oh, maybe not a context switch per se. It's actually:
- __wine_setjmp: save Unix-side state
- emulated syscall return: divert into KiUserCallbackDispatcher
- syscall: call into NtCallbackReturn
- __wine_longjmp: restore Unix-side state
So it's still a lot of work.
Yeah, and of course it should be noted that this only works on threads created by wine.
If this ELF parts requires some Wine "kernel features", the it can (using ELF dynamic linking) use the APIs provided by ntdll.so ELF library.
+-----------------+ +-----------------+ +-----------+ | FOOBAR.dll (PE) | | FOOBAR.so (ELF) | -------------> | ntdll.so | | | --------> | (unixlib) | ELF dyn link +-----------+ | | | | -------------> | helper.so | +-----------------+ +-----------------+ +-----------+
Note: likely some other modules .so should be available too (like win32u) (to be confirmed)
I confirm that win32u.so also exists.
Here is a list of other Unixlibs:
I think what Eric was getting at here was what base unix libraries all other unix libraries can be linked against. (For example, using win32u.so from winevulkan.so).
Pretty much every Unix library can link to one another if they want to, barring abstraction layer issues. I think this aligns with what Eric is trying to convey.
Yeah, it's definitely possible to link to any unix library you want, but in terms of making sense of the system, it's possibly useful to clearly differentiate between unix libraries which in addition to their primary purpose can also be used as helper libraries for other unix libraries (like ntdll, win32u), and which unix libraries have the sole purpose of providing a link to the unix world for an optional PE dll (bcrypt, gphoto2, winegstreamer, winepulse, etc).
The former category would be those providing what Eric referred to as "kernel features".
You're right. Maybe I wasn't reading this thoroughly...
avicap32.so, bcrypt.so, capi2032.so, crypt32.so, ctapi32.so, dnsapi.so, dwrite.so, gphoto2.so, kerberos.so, mountmgr.so, msv1_0.so, netapi32.so, nsiproxy.so, odbc32.so, opencl.so, qcap.so, sane.so, secur32.so, winealsa.so, winebus.so, winecoreaudio.so, winegstreamer.so, wineoss.so, winepulse.so, winevulkan.so, winspool.so, wldap32.so, wpcap.so, ws2_32.so
- exception handling?
To accurately mimic stack unwinding as it happens on Windows, one should stick to the syscall interface instead of the unixlib interface.
Assuming you're referring to the __wine_init_unix_lib approach, the unixlib interface doesn't even exist anymore. (Was removed right before wine 7.0-rc1)
I really meant __wine_unix_call. There's no syscall gate in-between, exposing DWARF frames that could confuse Win32 debuggers/monitors (probably as part of some DRM/obfuscation/anti-RE)
__wine_unix_call is part of the syscall interface, so you won't run into the problems mentioned by using it.
https://source.winehq.org/git/wine.git/blob/HEAD:/dlls/ntdll/ntdll.spec#l164... :
@ stdcall -syscall __wine_unix_call(int64 long ptr)
I stand corrected.
This way, unix-side stack frames will never appear in RtlVirtualUnwind() output (since they are effectively kernel-mode frames, not user-mode ones).
On Thu, Apr 14, 2022 at 9:26 AM Eric Pouech eric.pouech@orange.fr wrote:
I tried to write down what I grasped for the current modules' evolution
since there's always questions floating around this subject, might be worthwhile to document it a bit
Thank you very much for the documentation! Please be sure to put it on the wiki.
Currently, the 32 <> 64 bit is still duplicated:
+-----------------+ +------------------------+ +--------------------+ | FOOBAR.dll (PE) | | FOOBAR.so (ELF 64 bit) | -------------> | ntdll.so (64 bit) | | 64 bit | --------> | (unixlib 64 bit) | ELF dyn link +--------------------+ | | | | -------------> | helper.so (64 bit) | +-----------------+ +------------------------+ +--------------------+
+-----------------+ +------------------------+ +--------------------+ | FOOBAR.dll (PE) | | FOOBAR.so (ELF 32 bit) | -------------> | ntdll.so (32 bit) | | 32 bit | --------> | (unixlib 32 bit) | ELF dyn link +--------------------+ | | | | -------------> | helper.so (32 bit) | +-----------------+ +------------------------+ +--------------------+
When all modules are converted to the new scheme, this shall look like:
+-----------------+ +------------------------+ +--------------------+ | FOOBAR.dll (PE) | | FOOBAR.so (ELF 64 bit) | -------------> | ntdll.so (64 bit) | | 64 bit | --------> | (unixlib ) | ELF dyn link +--------------------+ | | +----> | (64 + 32 bit) | -------------> | helper.so (64 bit) | +-----------------+ | +------------------------+ +--------------------+ | +-----------------+ | | FOOBAR.dll (PE) | | | 32 bit | ---+ | | +-----------------+
This will require that FOOBAR.so correctly handles the "syscall" for both 32 bit and 64 bit unixlib calls. When this is in place, no support for 32-bit .so files will be necessary (both the packages that provide the .so files, but also for the development packages.
This part is still confusing to me. Do any DLLs currently use the new scheme? How can I know which of the two schemes a DLL uses?
-Alex
On 18.04.22 12:33, Alex Henrie wrote:
On Thu, Apr 14, 2022 at 9:26 AM Eric Pouech eric.pouech@orange.fr wrote:
I tried to write down what I grasped for the current modules' evolution
since there's always questions floating around this subject, might be worthwhile to document it a bit
Thank you very much for the documentation! Please be sure to put it on the wiki.
Currently, the 32 <> 64 bit is still duplicated:
+-----------------+ +------------------------+ +--------------------+ | FOOBAR.dll (PE) | | FOOBAR.so (ELF 64 bit) | -------------> | ntdll.so (64 bit) | | 64 bit | --------> | (unixlib 64 bit) | ELF dyn link +--------------------+ | | | | -------------> | helper.so (64 bit) | +-----------------+ +------------------------+ +--------------------+
+-----------------+ +------------------------+ +--------------------+ | FOOBAR.dll (PE) | | FOOBAR.so (ELF 32 bit) | -------------> | ntdll.so (32 bit) | | 32 bit | --------> | (unixlib 32 bit) | ELF dyn link +--------------------+ | | | | -------------> | helper.so (32 bit) | +-----------------+ +------------------------+ +--------------------+
When all modules are converted to the new scheme, this shall look like:
+-----------------+ +------------------------+ +--------------------+ | FOOBAR.dll (PE) | | FOOBAR.so (ELF 64 bit) | -------------> | ntdll.so (64 bit) | | 64 bit | --------> | (unixlib ) | ELF dyn link +--------------------+ | | +----> | (64 + 32 bit) | -------------> | helper.so (64 bit) | +-----------------+ | +------------------------+ +--------------------+ | +-----------------+ | | FOOBAR.dll (PE) | | | 32 bit | ---+ | | +-----------------+
This will require that FOOBAR.so correctly handles the "syscall" for both 32 bit and 64 bit unixlib calls. When this is in place, no support for 32-bit .so files will be necessary (both the packages that provide the .so files, but also for the development packages.
This part is still confusing to me. Do any DLLs currently use the new scheme? How can I know which of the two schemes a DLL uses?
Right now in upstream wine, this codepath is locked behind some gates, meaning that all DLLs use the former system, but some DLLs have already implemented support to prepare for when the path is unlocked.
To see whether a DLL supports the wow64 path already, check if it defines "__wine_unix_call_wow64_funcs" somewhere in its source:
https://source.winehq.org/git/wine.git/?a=search&h=HEAD&st=grep&...
-Alex