993 lines
38 KiB
Plaintext
993 lines
38 KiB
Plaintext
<chapter id="architecture">
|
|
<title>Overview</title>
|
|
<para>Brief overview of Wine's architecture...</para>
|
|
|
|
<sect1 id="basic-overview">
|
|
<title>Wine Overview</title>
|
|
|
|
<para>
|
|
With the fundamental architecture of Wine stabilizing, and
|
|
people starting to think that we might soon be ready to
|
|
actually release this thing, it may be time to take a look at
|
|
how Wine actually works and operates.
|
|
</para>
|
|
|
|
<sect2>
|
|
<title>Foreword</title>
|
|
<para>
|
|
Wine is often used as a recursive acronym, standing for
|
|
"Wine Is Not an Emulator". Sometimes it is also known to be
|
|
used for "Windows Emulator". In a way, both meanings are
|
|
correct, only seen from different perspectives. The first
|
|
meaning says that Wine is not a virtual machine, it does not
|
|
emulate a CPU, and you are not supposed to install
|
|
Windows nor any Windows device drivers on top of it; rather,
|
|
Wine is an implementation of the Windows API, and can be
|
|
used as a library to port Windows applications to Unix. The
|
|
second meaning, obviously, is that to Windows binaries
|
|
(<filename>.exe</filename> files), Wine does look like
|
|
Windows, and emulates its behaviour and quirks rather
|
|
closely.
|
|
</para>
|
|
<note>
|
|
<title>"Emulator"</title>
|
|
<para>
|
|
The "Emulator" perspective should not be thought of as if
|
|
Wine is a typical inefficient emulation layer that means
|
|
Wine can't be anything but slow - the faithfulness to the
|
|
badly designed Windows API may of course impose a minor
|
|
overhead in some cases, but this is both balanced out by
|
|
the higher efficiency of the Unix platforms Wine runs on,
|
|
and that other possible abstraction libraries (like Motif,
|
|
GTK+, CORBA, etc) has a runtime overhead typically
|
|
comparable to Wine's.
|
|
</para>
|
|
</note>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>Executables</title>
|
|
<para>
|
|
Wine's main task is to run Windows executables under non
|
|
Windows operating systems. It supports different types of
|
|
executables:
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
DOS executable. Those are even older programs, using
|
|
the DOS format (either <filename>.com</filename> or
|
|
<filename>.exe</filename> (the later being also called
|
|
MZ)).
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Windows NE executable, also called 16 bit. They were
|
|
the native processes run by Windows 2.x and 3.x. NE
|
|
stands for New Executable <g>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Windows PE executable. These are programs were
|
|
introduced in Windows 95 (and became the native
|
|
formats for all later Windows version), even if 16 bit
|
|
applications were still supported. PE stands for
|
|
Portable Executable, in a sense where the format of
|
|
the executable (as a file) is independent of the CPU
|
|
(even if the content of the file - the code - is CPU
|
|
dependent).
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Winelib executable. These are applications, written
|
|
using the Windows API, but compiled as a Unix
|
|
executable. Wine provides the tools to create such
|
|
executables.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</para>
|
|
<para>
|
|
Let's quickly review the main differences for the supported
|
|
executables:
|
|
<table>
|
|
<title>Wine executables</title>
|
|
<tgroup cols="5" align="left" colsep="1" rowsep="1">
|
|
<thead>
|
|
<row>
|
|
<entry></entry>
|
|
<entry>DOS (.COM or .EXE)</entry>
|
|
<entry>Win16 (NE)</entry>
|
|
<entry>Win32 (PE)</entry>
|
|
<entry>Winelib</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry>Multitasking</entry>
|
|
<entry>Only one application at a time (except for TSR)</entry>
|
|
<entry>Cooperative</entry>
|
|
<entry>Preemptive</entry>
|
|
<entry>Preemptive</entry>
|
|
</row>
|
|
<row>
|
|
<entry>Address space</entry>
|
|
<entry>
|
|
One MB of memory, where each application is loaded
|
|
and unloaded.
|
|
</entry>
|
|
<entry>
|
|
All 16 bit applications share a single address
|
|
space, protected mode.
|
|
</entry>
|
|
<entry>
|
|
Each application has it's own address
|
|
space. Requires MMU support from CPU.
|
|
</entry>
|
|
<entry>
|
|
Each application has it's own address
|
|
space. Requires MMU support from CPU.
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>Windows API</entry>
|
|
<entry>
|
|
No Windows API but the DOS API (like <function>Int
|
|
21h</function> traps).
|
|
</entry>
|
|
<entry>
|
|
Will call the 16 bit Windows API.
|
|
</entry>
|
|
<entry>
|
|
Will call the 32 bit Windows API.
|
|
</entry>
|
|
<entry>
|
|
Will call the 32 bit Windows API, and possibly
|
|
also the Unix APIs.
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>Code (CPU level)</entry>
|
|
<entry>
|
|
Only available on x86 in real mode. Code and data
|
|
are in segmented forms, with 16 bit
|
|
offsets. Processor is in real mode.
|
|
</entry>
|
|
<entry>
|
|
Only available on IA-32 architectures, code and
|
|
data are in segmented forms, with 16 bit offsets
|
|
(hence the 16 bit name). Processor is in protected
|
|
mode.
|
|
</entry>
|
|
<entry>
|
|
Available (with NT) on several CPUs, including
|
|
IA-32. On this CPU, uses a flat memory model with
|
|
32 bit offsets (hence the 32 bit name).
|
|
</entry>
|
|
<entry>
|
|
Flat model, with 32 bit addresses.
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>Multi-threading</entry>
|
|
<entry>Not available.</entry>
|
|
<entry>Not available.</entry>
|
|
<entry>
|
|
Available.
|
|
</entry>
|
|
<entry>
|
|
Available, but must use the Win32 APIs for
|
|
threading and synchronization, not the Unix ones.
|
|
</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</para>
|
|
|
|
<para>
|
|
Wine deals with this issue by launching a separate Wine process (which
|
|
is in fact a Unix process) for each Win32 process, but not for Win16
|
|
tasks. Win16 tasks are run as different intersynchronized Unix-threads
|
|
in the same dedicated Wine process; this Wine process is commonly
|
|
known as a <firstterm>WOW</firstterm> process (Windows on Windows),
|
|
referring to a similar mechanism used by Windows NT.
|
|
</para>
|
|
<para>
|
|
Synchronization between the Win16 tasks running in the WOW
|
|
process is normally done through the Win16 mutex - whenever
|
|
one of them is running, it holds the Win16 mutex, keeping
|
|
the others from running. When the task wishes to let the
|
|
other tasks run, the thread releases the Win16 mutex, and
|
|
one of the waiting threads will then acquire it and let its
|
|
task run.
|
|
</para>
|
|
<para>
|
|
<command>winevdm</command> is the Wine process dedicated to running the
|
|
Win16 processes. Note that several instances of this process could
|
|
exist, has Windows has support for different VDM (Virtual Dos
|
|
Machines) in order to have Win16 processes running in different
|
|
address spaces. Wine also uses the same architecture to run DOS
|
|
programs (in this case, the DOS emulation is provided by a Wine only
|
|
DLL called <filename>winedos</filename>.
|
|
</para>
|
|
</sect2>
|
|
</sect1>
|
|
|
|
<sect1>
|
|
<title>Standard Windows Architectures</title>
|
|
|
|
<sect2>
|
|
<title>Windows 9x architecture</title>
|
|
|
|
<para>
|
|
The windows architecture (Win 9x way) looks like this:
|
|
<screen>
|
|
+---------------------+ \
|
|
| Windows EXE | } application
|
|
+---------------------+ /
|
|
|
|
+---------+ +---------+ \
|
|
| Windows | | Windows | \ application & system DLLs
|
|
| DLL | | DLL | /
|
|
+---------+ +---------+ /
|
|
|
|
+---------+ +---------+ \
|
|
| GDI32 | | USER32 | \
|
|
| DLL | | DLL | \
|
|
+---------+ +---------+ } core system DLLs
|
|
+---------------------+ /
|
|
| Kernel32 DLL | /
|
|
+---------------------+ /
|
|
|
|
+---------------------+ \
|
|
| Win9x kernel | } kernel space
|
|
+---------------------+ /
|
|
|
|
+---------------------+ \
|
|
| Windows low-level | \ drivers (kernel space)
|
|
| drivers | /
|
|
+---------------------+ /
|
|
</screen>
|
|
</para>
|
|
</sect2>
|
|
<sect2>
|
|
<title>Windows NT architecture</title>
|
|
|
|
<para>
|
|
The windows architecture (Windows NT way) looks like the
|
|
following drawing. Note the new DLL
|
|
(<filename>NTDLL</filename>) which allows implementing
|
|
different subsystems (as win32);
|
|
<filename>kernel32</filename> in NT architecture
|
|
implements the Win32 subsystem on top of
|
|
<filename>NTDLL</filename>.
|
|
<screen>
|
|
+---------------------+ \
|
|
| Windows EXE | } application
|
|
+---------------------+ /
|
|
|
|
+---------+ +---------+ \
|
|
| Windows | | Windows | \ application & system DLLs
|
|
| DLL | | DLL | /
|
|
+---------+ +---------+ /
|
|
|
|
+---------+ +---------+ +-----------+ \
|
|
| GDI32 | | USER32 | | | \
|
|
| DLL | | DLL | | | \
|
|
+---------+ +---------+ | | \ core system DLLs
|
|
+---------------------+ | | / (on the left side)
|
|
| Kernel32 DLL | | Subsystem | /
|
|
| (Win32 subsystem) | |Posix, OS/2| /
|
|
+---------------------+ +-----------+ /
|
|
|
|
+---------------------------------------+
|
|
| NTDLL.DLL |
|
|
+---------------------------------------+
|
|
|
|
+---------------------------------------+ \
|
|
| NT kernel | } NT kernel (kernel space)
|
|
+---------------------------------------+ /
|
|
+---------------------------------------+ \
|
|
| Windows low-level drivers | } drivers (kernel space)
|
|
+---------------------------------------+ /
|
|
</screen>
|
|
</para>
|
|
<para>
|
|
Note also (not depicted in schema above) that the 16 bit
|
|
applications are supported in a specific subsystem.
|
|
Some basic differences between the Win9x and the NT
|
|
architectures include:
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
Several subsystems (Win32, Posix...) can be run on NT,
|
|
while not on Win 9x
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Win 9x roots its architecture in 16 bit systems, while
|
|
NT is truly a 32 bit system.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
The drivers model and interfaces in Win 9x and NT are
|
|
different (even if Microsoft tried to bridge the gap
|
|
with some support of WDM drivers in Win 98 and above).
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</para>
|
|
</sect2>
|
|
</sect1>
|
|
|
|
<sect1>
|
|
<title>Wine architecture</title>
|
|
|
|
<sect2>
|
|
<title>Global picture</title>
|
|
|
|
<para>
|
|
Wine implementation is closer to the Windows NT
|
|
architecture, even if several subsystems are not implemented
|
|
yet (remind also that 16bit support is implemented in a 32-bit
|
|
Windows EXE, not as a subsystem). Here's the overall picture:
|
|
<screen>
|
|
+---------------------+ \
|
|
| Windows EXE | } application
|
|
+---------------------+ /
|
|
|
|
+---------+ +---------+ \
|
|
| Windows | | Windows | \ application & system DLLs
|
|
| DLL | | DLL | /
|
|
+---------+ +---------+ /
|
|
|
|
+---------+ +---------+ +-----------+ +--------+ \
|
|
| GDI32 | | USER32 | | | | | \
|
|
| DLL | | DLL | | | | Wine | \
|
|
+---------+ +---------+ | | | Server | \ core system DLLs
|
|
+---------------------+ | | | | / (on the left side)
|
|
| Kernel32 DLL | | Subsystem | | NT-like| /
|
|
| (Win32 subsystem) | |Posix, OS/2| | Kernel | /
|
|
+---------------------+ +-----------+ | | /
|
|
| |
|
|
+---------------------------------------+ | |
|
|
| NTDLL | | |
|
|
+---------------------------------------+ +--------+
|
|
|
|
+---------------------------------------+ \
|
|
| Wine executable (wine-?thread) | } unix executable
|
|
+---------------------------------------+ /
|
|
+---------------------------------------------------+ \
|
|
| Wine drivers | } Wine specific DLLs
|
|
+---------------------------------------------------+ /
|
|
|
|
+------------+ +------------+ +--------------+ \
|
|
| libc | | libX11 | | other libs | } unix shared libraries
|
|
+------------+ +------------+ +--------------+ / (user space)
|
|
|
|
+---------------------------------------------------+ \
|
|
| Unix kernel (Linux,*BSD,Solaris,OS/X) | } (Unix) kernel space
|
|
+---------------------------------------------------+ /
|
|
+---------------------------------------------------+ \
|
|
| Unix device drivers | } Unix drivers (kernel space)
|
|
+---------------------------------------------------+ /
|
|
</screen>
|
|
</para>
|
|
|
|
<para>
|
|
Wine must at least completely replace the "Big Three" DLLs
|
|
(<filename>KERNEL</filename>/<filename>KERNEL32</filename>,
|
|
<filename>GDI</filename>/<filename>GDI32</filename>, and
|
|
<filename>USER</filename>/<filename>USER32</filename>),
|
|
which all other DLLs are layered on top of. But since Wine
|
|
is (for various reasons) leaning towards the NT way of
|
|
implementing things, the <filename>NTDLL</filename> is
|
|
another core DLL to be implemented in Wine, and many
|
|
<filename>KERNEL32</filename> and
|
|
<filename>ADVAPI32</filename> features will be
|
|
implemented through the <filename>NTDLL</filename>.
|
|
</para>
|
|
<para>
|
|
As of today, no real subsystem (apart the Win32 one) has
|
|
been implemented in Wine.
|
|
</para>
|
|
<para>
|
|
The Wine server provides the backbone for the implementation
|
|
of the core DLLs. It mainly implementents inter-process
|
|
synchronization and object sharing. It can be seen, from a
|
|
functional point of view, as a NT kernel (even if the APIs
|
|
and protocols used between Wine's DLL and the Wine server
|
|
are Wine specific).
|
|
</para>
|
|
<para>
|
|
Wine uses the Unix drivers to access the various hardware
|
|
pieces on the box. However, in some cases, Wine will
|
|
provide a driver (in Windows sense) to a physical hardware
|
|
device. This driver will be a proxy to the Unix driver
|
|
(this is the case, for example, for the graphical part
|
|
with X11 or SDL drivers, audio with OSS or ALSA drivers...).
|
|
</para>
|
|
<para>
|
|
All DLLs provided by Wine try to stick as much as possible
|
|
to the exported APIs from the Windows platforms. There are
|
|
rare cases where this is not the case, and have been
|
|
propertly documented (Wine DLLs export some Wine specific
|
|
APIs). Usually, those are prefixed with
|
|
<function>__wine</function>.
|
|
</para>
|
|
<para>
|
|
Let's now review in greater details all of those components.
|
|
</para>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>The Wine server</title>
|
|
<para>
|
|
The Wine server is among the most confusing concepts in
|
|
Wine. What is its function in Wine? Well, to be brief, it
|
|
provides Inter-Process Communication (IPC),
|
|
synchronization, and process/thread management. When the
|
|
Wine server launches, it creates a Unix socket for the
|
|
current host based on (see below) your home directory's
|
|
<filename>.wine</filename> subdirectory (or wherever the
|
|
<envar>WINEPREFIX</envar> environment variable points to)
|
|
- all Wine processes launched later connects to the Wine
|
|
server using this socket. If a Wine server was not
|
|
already running, the first Wine process will start up the
|
|
Wine server in auto-terminate mode (i.e. the Wine server
|
|
will then terminate itself once the last Wine process has
|
|
terminated).
|
|
</para>
|
|
<para>
|
|
In earlier versions of Wine the master socket mentioned
|
|
above was actually created in the configuration directory;
|
|
either your home directory's <filename>/wine</filename>
|
|
subdirectory or wherever the
|
|
<envar>WINEPREFIX</envar> environment variable points>.
|
|
Since that might not be possible the socket is actually
|
|
created within the <filename>/tmp</filename> directory
|
|
with a name that reflects the configuration directory.
|
|
This means that there can actually be several separate
|
|
copies of the Wine server running; one per combination of
|
|
user and configuration directory. Note that you should
|
|
not have several users using the same configuration
|
|
directory at the same time; they will have different
|
|
copies of the Wine server running and this could well
|
|
lead to problems with the registry information that
|
|
they are sharing.
|
|
</para>
|
|
<para>
|
|
Every thread in each Wine process has its own request
|
|
buffer, which is shared with the Wine server. When a
|
|
thread needs to synchronize or communicate with any other
|
|
thread or process, it fills out its request buffer, then
|
|
writes a command code through the socket. The Wine server
|
|
handles the command as appropriate, while the client
|
|
thread waits for a reply. In some cases, like with the
|
|
various <function>WaitFor???</function> synchronization
|
|
primitives, the server handles it by marking the client
|
|
thread as waiting and does not send it a reply before the
|
|
wait condition has been satisfied.
|
|
</para>
|
|
<para>
|
|
The Wine server itself is a single and separate Unix
|
|
process and does not have its own threading - instead, it
|
|
is built on top of a large <function>poll()</function>
|
|
loop that alerts the Wine server whenever anything
|
|
happens, such as a client having sent a command, or a wait
|
|
condition having been satisfied. There is thus no danger
|
|
of race conditions inside the Wine server itself - it is
|
|
often called upon to do operations that look completely
|
|
atomic to its clients.
|
|
</para>
|
|
<para>
|
|
Because the Wine server needs to manage processes,
|
|
threads, shared handles, synchronization, and any related
|
|
issues, all the clients' Win32 objects are also managed by
|
|
the Wine server, and the clients must send requests to the
|
|
Wine server whenever they need to know any Win32 object
|
|
handle's associated Unix file descriptor (in which case
|
|
the Wine server duplicates the file descriptor, transmits
|
|
it back to the client, and leaves it to the client to
|
|
close the duplicate when the client has finished with
|
|
it).
|
|
</para>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>
|
|
Wine builtin DLLs: about Relays, Thunks, and DLL
|
|
descriptors
|
|
</title>
|
|
<para>
|
|
This section mainly applies to builtin DLLs (DLLs provided
|
|
by Wine). See section <xref linkend="arch-dlls"> for the
|
|
details on native vs. builtin DLL handling.
|
|
</para>
|
|
<para>
|
|
Loading a Windows binary into memory isn't that hard by
|
|
itself, the hard part is all those various DLLs and entry
|
|
points it imports and expects to be there and function as
|
|
expected; this is, obviously, what the entire Wine
|
|
implementation is all about. Wine contains a range of DLL
|
|
implementations. You can find the DLLs implementation in the
|
|
<filename>dlls/</filename> directory.
|
|
</para>
|
|
<para>
|
|
Each DLL (at least, the 32 bit version, see below) is
|
|
implemented in a Unix shared library. The file name of this
|
|
shared library is the module name of the DLL with a
|
|
<filename>.dll.so</filename> suffix (or
|
|
<filename>.drv.so</filename> or any other relevant extension
|
|
depending on the DLL type). This shared library contains the
|
|
code itself for the DLL, as well as some more information,
|
|
as the DLL resources and a Wine specific DLL descriptor.
|
|
</para>
|
|
<para>
|
|
The DLL descriptor, when the DLL is instanciated, is used to
|
|
create an in-memory PE header, which will provide access to
|
|
various information about the DLL, including but not limited
|
|
to its entry point, its resources, its sections, its debug
|
|
information...
|
|
</para>
|
|
<para>
|
|
The DLL descriptor and entry point table is generated by
|
|
the <command>winebuild</command> tool (previously just
|
|
named <command>build</command>), taking DLL specification
|
|
files with the extension <filename>.spec</filename> as
|
|
input. Resources (after compilation by
|
|
<command>wrc</command>) or message tables (after
|
|
compilation by <command>wmc</command>) are also added to
|
|
the descriptor by <command>winebuild</command>.
|
|
</para>
|
|
<para>
|
|
Once an application module wants to import a DLL, Wine
|
|
will look at:
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
through its list of registered DLLs (in fact, both
|
|
the already loaded DLLs, and the already loaded
|
|
shared libraries which has registered a DLL
|
|
descriptor). Since, the DLL descriptor is
|
|
automatically registered when the shared library is
|
|
loaded - remember, registration call is put inside a
|
|
shared library constructor - using the
|
|
<envar>PRELOAD</envar> environment variable when
|
|
running a Wine process can force the registration of
|
|
some DLL descriptors.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
If it's not registered, Wine will look for it on
|
|
disk, building the shared library name from the DLL
|
|
module name. Directory searched for are specified by
|
|
the <envar>WINEDLLPATH</envar> environment variable.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Failing that, it will look for a real Windows
|
|
<filename>.DLL</filename> file to use, and look
|
|
through its imports, etc) and use the loading of
|
|
native DLLs.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</para>
|
|
<para>
|
|
After the DLL has been identified (assuming it's still a
|
|
native one), it's mapped into memory using a
|
|
<function>dlopen()</function> call. Note, that Wine doesn't
|
|
use the shared library mechanisms for resolving and/or
|
|
importing functions between two shared libraries (for two
|
|
DLLs). The shared library is only used for providing a way
|
|
to load a piece of code on demand. This piece of code,
|
|
thanks the DLL descriptor, will provide the same type of
|
|
information a native DLL would. Wine can then use the same
|
|
code for native and builtin DLL to handle imports/exports.
|
|
</para>
|
|
<para>
|
|
Wine also relies on the dynamic loading features of the Unix
|
|
shared libraries to relocate the DLLs if needed (the same
|
|
DLL can be loaded at different address in two different
|
|
processes, and even in two consecutive run of the same
|
|
executable if the order of loading the DLLs differ).
|
|
</para>
|
|
<para>
|
|
The DLL descriptor is registered in the Wine realm using
|
|
some tricks. The <command>winebuild</command> tool, while
|
|
creating the code for DLL descriptor, also creates a
|
|
constructor, that will be called when the shared library is
|
|
loaded into memory. This constructor will actually register
|
|
the descriptor to the Wine DLL loader. Hence, before the
|
|
<function>dlopen</function> call returns, the DLL descriptor
|
|
will be known and registered. This also helps to deal with
|
|
the cases where there's still dependencies (at the ELF
|
|
shared lib level, not at the embedded DLL level) between
|
|
different shared libraries: the embedded DLLs will be
|
|
properly registered, and even loaded (from a Windows point
|
|
of view).
|
|
</para>
|
|
<para>
|
|
Since Wine is 32-bit code itself, and if the compiler
|
|
supports Windows' calling convention, <type>stdcall</type>
|
|
(<command>gcc</command> does), Wine can resolve imports
|
|
into Win32 code by substituting the addresses of the Wine
|
|
handlers directly without any thunking layer in
|
|
between. This eliminates the overhead most people
|
|
associate with "emulation", and is what the applications
|
|
expect anyway.
|
|
</para>
|
|
<para>
|
|
However, if the user specified <parameter>WINEDEBUG=+relay
|
|
</parameter>, a thunk layer is inserted between the
|
|
application imports and the Wine handlers (actually the
|
|
export table of the DLL is modified, and a thunk is
|
|
inserted in the table); this layer is known as "relay"
|
|
because all it does is print out the arguments/return
|
|
values (by using the argument lists in the DLL
|
|
descriptor's entry point table), then pass the call on,
|
|
but it's invaluable for debugging misbehaving calls into
|
|
Wine code. A similar mechanism also exists between Windows
|
|
DLLs - Wine can optionally insert thunk layers between
|
|
them, by using <parameter>WINEDEBUG=+snoop</parameter>,
|
|
but since no DLL descriptor information exists for
|
|
non-Wine DLLs, this is less reliable and may lead to
|
|
crashes.
|
|
</para>
|
|
<para>
|
|
For Win16 code, there is no way around thunking - Wine
|
|
needs to relay between 16-bit and 32-bit code. These
|
|
thunks switch between the app's 16-bit stack and Wine's
|
|
32-bit stack, copies and converts arguments as appropriate
|
|
(an int is 16 bit 16-bit and 32 bits in 32-bit, pointers
|
|
are segmented in 16 bit (and also near or far) but are 32
|
|
bit linear values in 32 bit), and handles the Win16
|
|
mutex. Some finer control can be obtained on the
|
|
conversion, see <command>winebuild</command> reference
|
|
manual for the details. Suffice to say that the kind of
|
|
intricate stack content juggling this results in, is not
|
|
exactly suitable study material for beginners.
|
|
</para>
|
|
<para>
|
|
A DLL descriptor is also created for every 16 bit
|
|
DLL. However, this DLL normally paired with a 32 bit
|
|
DLL. Either, it's the 16 bit counterpart of the 16 bit DLL
|
|
(<filename>KRNL386.EXE</filename> for
|
|
<filename>KERNEL32</filename>, <filename>USER</filename>
|
|
for <filename>USER32</filename>...), or a 16
|
|
bit DLL directly linked to a 32 bit DLL (like
|
|
<filename>SYSTEM</filename> for <filename>KERNEL32</filename>,
|
|
or <filename>DDEML</filename> for
|
|
<filename>USER32</filename>). In those cases, the 16 bit
|
|
descriptor(s) is (are) inserted in the same shared library
|
|
as the the corresponding 32 bit DLL. Wine will also create
|
|
symbolic links between kernel32.dll.so and system.dll.so
|
|
so that loading of either
|
|
<filename>KERNEL32.DLL</filename> or
|
|
<filename>SYSTEM.DLL</filename> will end up on the same
|
|
shared library.
|
|
</para>
|
|
</sect2>
|
|
<sect2 id="arch-dlls">
|
|
<title>Wine/Windows DLLs</title>
|
|
|
|
<para>
|
|
This document mainly deals with the status of current DLL
|
|
support by Wine. The Wine ini file currently supports
|
|
settings to change the load order of DLLs. The load order
|
|
depends on several issues, which results in different settings
|
|
for various DLLs.
|
|
</para>
|
|
|
|
<sect3>
|
|
<title>Pros of Native DLLs</title>
|
|
|
|
<para>
|
|
Native DLLs of course guarantee 100% compatibility for
|
|
routines they implement. For example, using the native
|
|
<filename>USER</filename> DLL would maintain a virtually
|
|
perfect and Windows 95-like look for window borders,
|
|
dialog controls, and so on. Using the built-in Wine
|
|
version of this library, on the other hand, would produce
|
|
a display that does not precisely mimic that of Windows
|
|
95. Such subtle differences can be engendered in other
|
|
important DLLs, such as the common controls library
|
|
<filename>COMMCTRL</filename> or the common dialogs library
|
|
<filename>COMMDLG</filename>, when built-in Wine DLLs
|
|
outrank other types in load order.
|
|
</para>
|
|
<para>
|
|
More significant, less aesthetically-oriented problems can
|
|
result if the built-in Wine version of the
|
|
<filename>SHELL</filename> DLL is loaded before the native
|
|
version of this library. <filename>SHELL</filename>
|
|
contains routines such as those used by installer utilities
|
|
to create desktop shortcuts. Some installers might fail when
|
|
using Wine's built-in <filename>SHELL</filename>.
|
|
</para>
|
|
</sect3>
|
|
|
|
<sect3>
|
|
<title>Cons of Native DLLs</title>
|
|
|
|
<para>
|
|
Not every application performs better under native DLLs. If
|
|
a library tries to access features of the rest of the system
|
|
that are not fully implemented in Wine, the native DLL might
|
|
work much worse than the corresponding built-in one, if at
|
|
all. For example, the native Windows <filename>GDI</filename>
|
|
library must be paired with a Windows display driver, which
|
|
of course is not present under Intel Unix and Wine.
|
|
</para>
|
|
<para>
|
|
Finally, occasionally built-in Wine DLLs implement more
|
|
features than the corresponding native Windows DLLs.
|
|
Probably the most important example of such behavior is the
|
|
integration of Wine with X provided by Wine's built-in
|
|
<filename>USER</filename> DLL. Should the native Windows
|
|
<filename>USER</filename> library take load-order
|
|
precedence, such features as the ability to use the
|
|
clipboard or drag-and-drop between Wine windows and X
|
|
windows will be lost.
|
|
</para>
|
|
</sect3>
|
|
|
|
<sect3>
|
|
<title>Deciding Between Native and Built-In DLLs</title>
|
|
|
|
<para>
|
|
Clearly, there is no one rule-of-thumb regarding which
|
|
load-order to use. So, you must become familiar with
|
|
what specific DLLs do and which other DLLs or features
|
|
a given library interacts with, and use this information
|
|
to make a case-by-case decision.
|
|
</para>
|
|
</sect3>
|
|
|
|
<sect3>
|
|
<title>Load Order for DLLs</title>
|
|
|
|
<para>
|
|
Using the DLL sections from the wine configuration file, the
|
|
load order can be tweaked to a high degree. In general it is
|
|
advised not to change the settings of the configuration
|
|
file. The default configuration specifies the right load
|
|
order for the most important DLLs.
|
|
</para>
|
|
<para>
|
|
The default load order follows this algorithm: for all DLLs
|
|
which have a fully-functional Wine implementation, or where
|
|
the native DLL is known not to work, the built-in library
|
|
will be loaded first. In all other cases, the native DLL
|
|
takes load-order precedence.
|
|
</para>
|
|
<para>
|
|
The <varname>DefaultLoadOrder</varname> from the
|
|
[DllDefaults] section specifies for all DLLs which version
|
|
to try first. See manpage for explanation of the arguments.
|
|
</para>
|
|
<para>
|
|
The [DllOverrides] section deals with DLLs, which need a
|
|
different-from-default treatment.
|
|
</para>
|
|
<para>
|
|
The [DllPairs] section is for DLLs, which must be loaded in
|
|
pairs. In general, these are DLLs for either 16-bit or
|
|
32-bit applications. In most cases in Windows, the 32-bit
|
|
version cannot be used without its 16-bit counterpart. For
|
|
Wine, it is customary that the 16-bit implementations rely
|
|
on the 32-bit implementations and cast the results back to
|
|
16-bit arguments. Changing anything in this section is bound
|
|
to result in errors.
|
|
</para>
|
|
<para>
|
|
For the future, the Wine implementation of Windows DLL seems
|
|
to head towards unifying the 16 and 32 bit DLLs wherever
|
|
possible, resulting in larger DLLs. They are stored in the
|
|
<filename>dlls/</filename> subdirectory using the 32-bit
|
|
name.
|
|
</para>
|
|
</sect3>
|
|
</sect2>
|
|
|
|
<sect2 id="arch-mem">
|
|
<title>Memory management</title>
|
|
<para>
|
|
Every Win32 process in Wine has its own dedicated native
|
|
process on the host system, and therefore its own address
|
|
space. This section explores the layout of the Windows
|
|
address space and how it is emulated.
|
|
</para>
|
|
|
|
<para>
|
|
Firstly, a quick recap of how virtual memory works. Physical
|
|
memory in RAM chips is split into
|
|
<emphasis>frames</emphasis>, and the memory that each
|
|
process sees is split into <emphasis>pages</emphasis>. Each
|
|
process has its own 4 gigabytes of address space (4gig being
|
|
the maximum space addressable with a 32 bit pointer). Pages
|
|
can be mapped or unmapped: attempts to access an unmapped
|
|
page cause an
|
|
<constant>EXCEPTION_ACCESS_VIOLATION</constant> which has
|
|
the easily recognizable code of
|
|
<constant>0xC0000005</constant>. Any page can be mapped to
|
|
any frame, therefore you can have multiple addresses which
|
|
actually "contain" the same memory. Pages can also be mapped
|
|
to things like files or swap space, in which case accessing
|
|
that page will cause a disk access to read the contents into
|
|
a free frame.
|
|
</para>
|
|
|
|
<sect3>
|
|
<title>Initial layout (in Windows)</title>
|
|
<para>
|
|
When a Win32 process starts, it does not have a clear
|
|
address space to use as it pleases. Many pages are already
|
|
mapped by the operating system. In particular, the EXE
|
|
file itself and any DLLs it needs are mapped into memory,
|
|
and space has been reserved for the stack and a couple of
|
|
heaps (zones used to allocate memory to the app
|
|
from). Some of these things need to be at a fixed address,
|
|
and others can be placed anywhere.
|
|
</para>
|
|
|
|
<para>
|
|
The EXE file itself is usually mapped at address
|
|
<constant>0x400000</constant> and up: indeed, most EXEs have
|
|
their relocation records stripped which means they must be
|
|
loaded at their base address and cannot be loaded at any
|
|
other address.
|
|
</para>
|
|
|
|
<para>
|
|
DLLs are internally much the same as EXE files but they
|
|
have relocation records, which means that they can be
|
|
mapped at any address in the address space. Remember we
|
|
are not dealing with physical memory here, but rather
|
|
virtual memory which is different for each
|
|
process. Therefore <filename>OLEAUT32.DLL</filename> may
|
|
be loaded at one address in one process, and a totally
|
|
different one in another. Ensuring all the functions
|
|
loaded into memory can find each other is the job of the
|
|
Windows dynamic linker, which is a part of
|
|
<filename>NTDLL</filename>.
|
|
</para>
|
|
<para>
|
|
So, we have the EXE and its DLLs mapped into memory. Two
|
|
other very important regions also exist: the stack and the
|
|
process heap. The process heap is simply the equivalent of
|
|
the libc <function>malloc</function> arena on UNIX: it's a
|
|
region of memory managed by the OS which
|
|
<function>malloc</function>/<function>HeapAlloc</function>
|
|
partitions and hands out to the application. Windows
|
|
applications can create several heaps but the process heap
|
|
always exists.
|
|
</para>
|
|
<para>
|
|
Windows 9x also implements another kind of heap: the
|
|
shared heap. The shared heap is unusual in that
|
|
anything allocated from it will be visible in every other
|
|
process.
|
|
</para>
|
|
</sect3>
|
|
|
|
<sect3>
|
|
<title>Comparison</title>
|
|
<para>
|
|
So far we've assumed the entire 4 gigs of address space is
|
|
available for the application. In fact that's not so: only
|
|
the lower 2 gigs are available, the upper 2 gigs are on
|
|
Windows NT used by the operating system and hold the
|
|
kernel (from <constant>0x80000000</constant>). Why is the
|
|
kernel mapped into every address space? Mostly for
|
|
performance: while it's possible to give the kernel its own
|
|
address space too - this is what Ingo Molnars 4G/4G VM
|
|
split patch does for Linux - it requires that every system
|
|
call into the kernel switches address space. As that is a
|
|
fairly expensive operation (requires flushing the
|
|
translation lookaside buffers etc) and syscalls are made
|
|
frequently it's best avoided by keeping the kernel mapped
|
|
at a constant position in every processes address space.
|
|
</para>
|
|
|
|
<para>
|
|
Basically, the comparison of memory mappings looks as
|
|
follows:
|
|
<table>
|
|
<title>Memory layout (Windows and Wine)</title>
|
|
<tgroup cols="4" align="left" colsep="1" rowsep="1">
|
|
<thead>
|
|
<row>
|
|
<entry>Address</entry>
|
|
<entry>Windows 9x</entry>
|
|
<entry>Windows NT</entry>
|
|
<entry>Linux</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry>00000000-7fffffff</entry>
|
|
<entry>User</entry>
|
|
<entry>User</entry>
|
|
<entry>User</entry>
|
|
</row>
|
|
<row>
|
|
<entry>80000000-bfffffff</entry>
|
|
<entry>Shared</entry>
|
|
<entry>User</entry>
|
|
<entry>User</entry>
|
|
</row>
|
|
<row>
|
|
<entry>c0000000-ffffffff</entry>
|
|
<entry>Kernel</entry>
|
|
<entry>Kernel</entry>
|
|
<entry>Kernel</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</para>
|
|
|
|
<para>
|
|
On Windows 9x, in fact only the upper gigabyte
|
|
(<constant>0xC0000000</constant> and up) is used by the
|
|
kernel, the region from 2 to 3 gigs is a shared area used
|
|
for loading system DLLs and for file mappings. The bottom
|
|
2 gigs on both NT and 9x are available for the programs
|
|
memory allocation and stack.
|
|
</para>
|
|
</sect3>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>Wine drivers</title>
|
|
<para>
|
|
Wine will not allow running native Windows drivers under
|
|
Unix. This comes mainly because (look at the generic
|
|
architecture schemas) Wine doesn't implement the kernel
|
|
features of Windows (kernel here really means the kernel,
|
|
not the <filename>KERNEL32</filename> DLL), but rather
|
|
sets up a proxy layer on top of the Unix kernel to provide
|
|
the <filename>NTDLL</filename> and
|
|
<filename>KERNEL32</filename> features. This means that
|
|
Wine doesn't provide the inner infrastructure to run
|
|
native drivers, either from the Win9x family or from the
|
|
NT family.
|
|
</para>
|
|
<para>
|
|
In other words, Wine will only be able to provide access to
|
|
a specific device, if and only if, 1/ this device is
|
|
supported in Unix (there is Unix-driver to talk to it), 2/
|
|
Wine has implemented the proxy code to make the glue between
|
|
the API of a Windows driver, and the Unix interface of the
|
|
Unix driver.
|
|
</para>
|
|
<para>
|
|
Wine, however, tries to implement in the various DLLs
|
|
needing to access devices to do it through the standard
|
|
Windows APIs for device drivers in user space. This is for
|
|
example the case for the multimedia drivers, where Wine
|
|
loads Wine builtin DLLs to talk to the OSS interface, or the
|
|
ALSA interface. Those DLLs implement the same interface as
|
|
any user space audio driver in Windows.
|
|
</para>
|
|
</sect2>
|
|
</sect1>
|
|
</chapter>
|
|
|
|
|
|
<!-- Keep this comment at the end of the file
|
|
Local variables:
|
|
mode: sgml
|
|
sgml-parent-document:("wine-devel.sgml" "set" "book" "part" "chapter" "")
|
|
End:
|
|
-->
|