Commit 3bebb0fe authored by Eric Pouech's avatar Eric Pouech Committed by Alexandre Julliard

- Using uniform DocBook tags for DLLs, commands, environment vars...

- Moved detailed memory management from archi to kernel(s) part. - Enhanced process handling description. - Added section about 16 bit processes' support. - Added section about DOS support.
parent 81857b73
......@@ -81,7 +81,7 @@
</listitem>
<listitem>
<para>
WineLib executable. These are applications, written
Winelib executable. These are applications, written
using the Windows API, but compiled as a Unix
executable. Wine provides the tools to create such
executables.
......@@ -101,7 +101,7 @@
<entry>DOS (.COM or .EXE)</entry>
<entry>Win16 (NE)</entry>
<entry>Win32 (PE)</entry>
<entry>WineLib</entry>
<entry>Winelib</entry>
</row>
</thead>
<tbody>
......@@ -188,14 +188,12 @@
</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 (as well as
DOS programs) 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.
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
......@@ -206,6 +204,15 @@
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>
......@@ -251,9 +258,12 @@
<para>
The windows architecture (Windows NT way) looks like the
following drawing. Note the new DLL (NTDLL) which allows
implementing different subsystems (as win32); kernel32 in NT
architecture implements the Win32 subsystem on top of NTDLL.
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
......@@ -371,12 +381,16 @@
<para>
Wine must at least completely replace the "Big Three" DLLs
(KERNEL/KERNEL32, GDI/GDI32, and USER/USER32), 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 NTDLL is another core DLL to be implemented in
Wine, and many KERNEL32 and ADVAPI32 features will be
implemented through the NTDLL.
(<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
......@@ -421,30 +435,30 @@
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
<constant>WINEPREFIX</constant> 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).)
<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
<constant>WINEPREFIX</constant> 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
<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>
......@@ -544,9 +558,9 @@
automatically registered when the shared library is
loaded - remember, registration call is put inside a
shared library constructor - using the
<constant>PRELOAD</constant> environment variable
when running a Wine process can force the
registration of some DLL descriptors.
<envar>PRELOAD</envar> environment variable when
running a Wine process can force the registration of
some DLL descriptors.
</para>
</listitem>
<listitem>
......@@ -554,8 +568,7 @@
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 <constant>WINEDLLPATH</constant> environment
variable.
the <envar>WINEDLLPATH</envar> environment variable.
</para>
</listitem>
<listitem>
......@@ -647,15 +660,19 @@
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
(KRNL386.EXE for KERNEL32, USER for USER32...), or a 16
bit DLL directly linked to a 32 bit DLL (like SYSTEM for
KERNEL32, or DDEML for USER32). In those cases, the 16 bit
(<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
<filename>KERNEL32.DLL</filename> or
<filename>SYSTEM.DLL</filename> will end up on the same
shared library.
</para>
</sect2>
......@@ -675,24 +692,26 @@
<para>
Native DLLs of course guarantee 100% compatibility for
routines they implement. For example, using the native USER
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 COMMCTRL or the common dialogs library
COMMDLG, when built-in Wine DLLs outrank other types in load
order.
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 SHELL DLL is
loaded before the native version of this library. SHELL
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 SHELL.
using Wine's built-in <filename>SHELL</filename>.
</para>
</sect3>
......@@ -704,16 +723,17 @@
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 GDI library must be
paired with a Windows display driver, which of course is not
present under Intel Unix and Wine.
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 USER
DLL. Should the native Windows USER library take load-order
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.
......@@ -820,10 +840,11 @@
</para>
<para>
The EXE file itself is usually mapped at address 0x400000
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.
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>
......@@ -836,7 +857,8 @@
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 NTDLL.
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
......@@ -864,16 +886,16 @@
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 0x80000000). 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.
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>
......@@ -923,415 +945,22 @@
memory allocation and stack.
</para>
</sect3>
<sect3>
<title>Implementation</title>
<para>
Wine (with a bit of black magic) is able to map all items
at the correct locations as depicted above.
</para>
<para>
Wine also implements the shared heap so native win9x DLLs
can be used. This heap is always created at the
<constant>SYSTEM_HEAP_BASE</constant> address or
<constant>0x80000000</constant> and defaults to 16
megabytes in size.
</para>
<para>
There are a few other magic locations. The bottom 64k of
memory is deliberately left unmapped to catch null pointer
dereferences. The region from 64k to 1mb+64k are reserved
for DOS compatibility and contain various DOS data
structures. Finally, the address space also contains
mappings for the Wine binary itself, any native libaries
Wine is using, the glibc malloc arena and so on.
</para>
</sect3>
<sect3 id="address-space">
<title>Laying out the address space</title>
<para>
Up until about the start of 2004, the Linux address space
very much resembled the Windows 9x layout: the kernel sat
in the top gigabyte, the bottom pages were unmapped to
catch null pointer dereferences, and the rest was
free. The kernels mmap algorithm was predictable: it would
start by mapping files at low addresses and work up from
there.
</para>
<para>
The development of a series of new low level patches
violated many of these assumptions, and resulted in Wine
needing to force the Win32 address space layout upon the
system. This section looks at why and how this is done.
</para>
<para>
The exec-shield patch increases security by randomizing
the kernels mmap algorithms. Rather than consistently
choosing the same addresses given the same sequence of
requests, the kernel will now choose randomized
addresses. Because the Linux dynamic linker
(ld-linux.so.2) loads DSOs into memory by using mmap, this
means that DSOs are no longer loaded at predictable
addresses, so making it harder to attack software by using
buffer overflows. It also attempts to relocate certain
binaries into a special low area of memory known as the
ASCII armor so making it harder to jump into them when
using string based attacks.
</para>
<para>
Prelink is a technology that enhances startup times by
precalculating ELF global offset tables then saving the
results inside the native binaries themselves. By grid
fitting each DSO into the address space, the dynamic
linker does not have to perform as many relocations so
allowing applications that heavily rely on dynamic linkage
to be loaded into memory much quicker. Complex C++
applications such as Mozilla, OpenOffice and KDE can
especially benefit from this technique.
</para>
<para>
The 4G VM split patch was developed by Ingo Molnar. It
gives the Linux kernel its own address space, thereby
allowing processes to access the maximum addressable
amount of memory on a 32-bit machine: 4 gigabytes. It
allows people with lots of RAM to fully utilise that in
any given process at the cost of performance: the reason
behind giving the kernel a part of each processes address
space was to avoid the overhead of switching on each
syscall.
</para>
<para>
Each of these changes alter the address space in a way
incompatible with Windows. Prelink and exec-shield mean
that the libraries Wine uses can be placed at any point in
the address space: typically this meant that a library was
sitting in the region that the EXE you wanted to run had
to be loaded (remember that unlike DLLs, EXE files cannot
be moved around in memory). The 4G VM split means that
programs could receive pointers to the top gigabyte of
address space which some are not prepared for (they may
store extra information in the high bits of a pointer, for
instance). In particular, in combination with exec-shield
this one is especially deadly as it's possible the process
heap could be allocated beyond ADDRESS_SPACE_LIMIT which
causes Wine initialization to fail.
</para>
<para>
The solution to these problems is for Wine to reserve
particular parts of the address space so that areas that
we don't want the system to use will be avoided. We later
on (re/de)allocate those areas as needed. One problem is
that some of these mappings are put in place automatically
by the dynamic linker: for instance any libraries that
Wine is linked to (like libc, libwine, libpthread etc)
will be mapped into memory before Wine even gets
control. In order to solve that, Wine overrides the
default ELF initialization sequence at a low level and
reserves the needed areas by using direct syscalls into
the kernel (ie without linking against any other code to
do it) before restarting the standard initialization and
letting the dynamic linker continue. This is referred to
as the preloader and is found in loader/preloader.c.
</para>
<para>
Once the usual ELF boot sequence has been completed, some
native libraries may well have been mapped above the 3gig
limit: however, this doesn't matter as 3G is a Windows
limit, not a Linux limit. We still have to prevent the
system from allocating anything else above there (like the
heap or other DLLs) though so Wine performs a binary
search over the upper gig of address space in order to
iteratively fill in the holes with MAP_NORESERVE mappings
so the address space is allocated but the memory to
actually back it is not. This code can be found in libs/wine/mmap.c:reserve_area.
</para>
</sect3>
</sect2>
<sect2>
<title>Processes</title>
<para>
Let's take a closer look at the way Wine loads and run
processes in memory.
</para>
<sect3>
<title>Starting a process from command line</title>
<para>
When starting a Wine process from command line (we'll get
later on to the differences between NE, PE and Winelib
executables), there are a couple of things Wine need to do
first. A first executable is run to check the threading
model of the underlying OS (see <xref linkend="threading">
for the details) and will start the real Wine loader
corresponding to the choosen threading model.
</para>
<para>
Then Wine graps a few elements from the Unix world: the
environment, the program arguments. Then the
<filename>ntdll.dll.so</filename> is loaded into memory
using the standard shared library dynamic loader. When
loaded, NTDLL will mainly first create a decent Windows
environment:
<itemizedlist>
<listitem>
<para>create a PEB and a TEB</para>
</listitem>
<listitem>
<para>
set up the connection to the Wine server - and
eventually launching the Wine server if none runs
</para>
</listitem>
<listitem>
<para>create the process heap</para>
</listitem>
</itemizedlist>
</para>
<para>
Then <filename>Kernel32</filename> is loaded (but now
using the Windows dynamic loading capabilities) and a Wine
specific entry point is called
<function>__wine_kernel_init</function>. This function
will actually handle all the logic of the process loading
and execution, and will never return from it's call.
</para>
<para>
<function>__wine_kernel_init</function> will undergo the
following tasks:
<itemizedlist>
<listitem>
<para>
initialization of program arguments from Unix
program arguments
</para>
</listitem>
<listitem>
<para>
lookup of executable in the file system
</para>
</listitem>
<listitem>
<para>
If the file is not found, then an error is printed
and the Wine loader stops.
</para>
</listitem>
<listitem>
<para>
We'll cover the non-PE file type later on, so assume
for now it's a PE file. The PE module is loaded in
memory using the Windows shared library
mechanism. Note that the dependencies on the module
are not resolved at this point.
</para>
</listitem>
<listitem>
<para>
A new stack is created, which size is given in the
PE header, and this stack is made the one of the
running thread (which is still the only one in the
process). The stack used at startup will no longer
be used.
</para>
</listitem>
<listitem>
<para>
Which this new stack,
<function>ntdll.LdrInitializeThunk</function> is
called which performs the remaining initialization
parts, including resolving all the DLL imports on
the PE module, and doing the init of the TLS slots.
</para>
</listitem>
<listitem>
<para>
Control can now be passed to the
<function>EntryPoint</function> of the PE module,
which will let the executable run.
</para>
</listitem>
</itemizedlist>
</para>
</sect3>
<sect3>
<title>Creating a child process from a running process</title>
<para>
The steps used are closely link to what is done in the
previous case.
</para>
<para>
There are however a few points to look at a bit more
closely. The inner implementation creates the child
process using the <function>fork()</function> and
<function>exec()</function> calls. This means that we
don't need to check again for the threading model, we can
use what the parent (or the grand-parent process...)
started from command line has found.
</para>
<para>
The Win32 process creation allows to pass a lot of
information between the parent and the child. This
includes object handles, windows title, console
parameters, environment strings... Wine makes use of both
the standard Unix inheritance mechanisms (for environment
for example) and the Wine server (to pass from parent to
child a chunk of data containing the relevant information).
</para>
<para>
The previously described loading mechanism will check in
the Wine server if such a chunk exists, and, if so, will
perform the relevant initialization.
</para>
<para>
Some further synchronization is also put in place: a
parent will wait until the child has started, or has
failed. The Wine server is also used to perform those
tasks.
</para>
</sect3>
<sect3>
<title>Starting a Winelib process</title>
<para>
Before going into the gory details, let's first go back to
what a Winelib application is. It can be either a regular
Unix executable, or a more specific Wine beast. This later
form in fact creates two files for a given executable (say
<filename>foo.exe</filename>). The first one, named
<filename>foo</filename> will be a symbolic link to the
Wine loader (<filename>wine</filename>). The second one,
named <filename>foo.exe.so</filename>, is the equivalent
of the <filename>.dll.so</filename> files we've already
described for DLLs. As in Windows, an executable is, among
other things, a module with its import and export
information, as any DLL, it makes sense Wine uses the same
mechanisms for loading native executables and DLLs.
</para>
<para>
When starting a Winelib application from the command line
(say with <command>foo arg1 arg2</command>), the Unix
shell will execute <command>foo</command> as a Unix
executable. Since this is in fact the Wine loader, Wine
will fire up. However, will notice that it hasn't been
started as <command>wine</command> but as
<command>foo</command>, and hence, will try to load (using
Unix shared library mechanism) the second file
<filename>foo.exe.so</filename>. Wine will recognize a 32
bit module (with its descriptor) embedded in the shared
library, and once the shared library loaded, it will
proceed the same path as when loading a standard native PE
executable.
</para>
<para>
Wine needs to implement this second form of executable in
order to maintain the order of initialization of some
elements in the executable. One particular issue is when
dealing with global C++ objects. In standard Unix
executable, the call of the constructor to such objects is
stored in the specific section of the executable
(<function>.init</function> not to name it). All
constructors in this section are called before the
<function>main</function> function is called. Creating a
Wine executable using the first form mentionned above will
let those constructors being called before Wine gets a
chance to initialize itself. So, any constructor using a
Windows API will fail, because Wine infrastructure isn't
in place. The use of the second form for Winelib
executables ensures that we do the initialization using
the following steps:
<itemizedlist>
<listitem>
<para>
initialize the Wine infrastructure
</para>
</listitem>
<listitem>
<para>
load the executable into memory
</para>
</listitem>
<listitem>
<para>
handle the import sections for the executable
</para>
</listitem>
<listitem>
<para>
call the global object constructors (if any). They
now can properly call the Windows APIs
</para>
</listitem>
<listitem>
<para>
call the executable entry point
</para>
</listitem>
</itemizedlist>
</para>
<para>
The attentive reader would have noted that the resolution
of imports for the executable is done, as for a DLL, when
the executable/DLL descriptor is registered. However, this
is done also by adding a specific constructor in the
<function>.init</function> section. For the above describe
scheme to function properly, this constructor must be the
first constructor to be called, before all the other
constructors, generated by the executable itself. The Wine
build chain takes care of that, and also generating the
executable/DLL descriptor for the Winelib executable.
</para>
</sect3>
<sect3>
<title>Starting a NE (Win16) process</title>
<para>
When Wine is requested to run a NE (Win 16 process), it
will in fact hand over the execution of it to a specific
executable <filename>winevdm</filename>. VDM stands for
Virtual DOS Machine. This <filename>winevdm</filename>
will in fact set up the correct 16 bit environment to run
the executable. Any new 16 bit process created by this
executable (or its children) will run into the same
<filename>winevdm</filename> instance. Among one instance,
several functionalities will be provided to those 16 bit
processes, including the cooperative multitasking, sharing
the same address space, managing the selectors for the 16
bit segments needed for code, data and stack.
</para>
<para>
Note that several <filename>winevdm</filename> instances
can run in the same Wine session, but the functionalities
described above are only shared among a given instance,
not among all the instances. <filename>winevdm</filename>
is built as Winelib application, and hence has access to
any facility a 32 bit application has.
</para>
<para>
The behaviour we just described also applies to DOS
executables, which are handled the same way by
<filename>winevdm</filename>.
</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 KERNEL32 DLL), but rather sets up a proxy layer on
top of the Unix kernel to provide the NTDLL and KERNEL32
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.
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
......
......@@ -202,6 +202,361 @@ ExitProcess( entry( peb ) );
</sect2>
</sect1>
<sect1>
<title>Detailed memory management</title>
<para>
As already explained in previous chapter (see <xref linkend="arch-mem">
for the details), Wine creates every 32-bit Windows process in its own
32 address space. Wine also tries to map at the relevant addresses what
Windows would do. There are however a few nasty bits to look at.
</para>
<sect2>
<title>Implementation</title>
<para>
Wine (with a bit of black magic) is able to map the main module at
it's desired address (likely <constant>0x400000</constant>), to create
the process heap, its stack (as a Windows executable can ask for a
specific stack size), Wine simply use the initial stack of the ELF
executable for its initialisation, but creates a new stack (as a Win32
one) for the main thread of the executable. Wine also tries to map all
native DLLs at their desired address, so that no relocation has to be
performed.
</para>
<para>
Wine also implements the shared heap so native win9x DLLs can be
used. This heap is always created at the
<constant>SYSTEM_HEAP_BASE</constant> address or
<constant>0x80000000</constant> and defaults to 16 megabytes in size.
</para>
<para>
There are a few other magic locations. The bottom 64k of memory is
deliberately left unmapped to catch null pointer dereferences. The
region from 64k to 1mb+64k are reserved for DOS compatibility and
contain various DOS data structures. Finally, the address space also
contains mappings for the Wine binary itself, any native libaries
Wine is using, the glibc malloc arena and so on.
</para>
</sect2>
<sect2 id="address-space">
<title>Laying out the address space</title>
<para>
Up until about the start of 2004, the Linux address space very much
resembled the Windows 9x layout: the kernel sat in the top gigabyte,
the bottom pages were unmapped to catch null pointer dereferences, and
the rest was free. The kernels mmap algorithm was predictable: it
would start by mapping files at low addresses and work up from there.
</para>
<para>
The development of a series of new low level patches violated many of
these assumptions, and resulted in Wine needing to force the Win32
address space layout upon the system. This section looks at why and
how this is done.
</para>
<para>
The exec-shield patch increases security by randomizing the kernels
mmap algorithms. Rather than consistently choosing the same addresses
given the same sequence of requests, the kernel will now choose
randomized addresses. Because the Linux dynamic linker
(<filename>ld-linux.so.2</filename>) loads DSOs into memory by using
mmap, this means that DSOs are no longer loaded at predictable
addresses, so making it harder to attack software by using buffer
overflows. It also attempts to relocate certain binaries into a
special low area of memory known as the ASCII armor so making it
harder to jump into them when using string based attacks.
</para>
<para>
Prelink is a technology that enhances startup times by precalculating
ELF global offset tables then saving the results inside the native
binaries themselves. By grid fitting each DSO into the address space,
the dynamic linker does not have to perform as many relocations so
allowing applications that heavily rely on dynamic linkage to be
loaded into memory much quicker. Complex C++ applications such as
Mozilla, OpenOffice and KDE can especially benefit from this
technique.
</para>
<para>
The 4G VM split patch was developed by Ingo Molnar. It gives the Linux
kernel its own address space, thereby allowing processes to access the
maximum addressable amount of memory on a 32-bit machine: 4
gigabytes. It allows people with lots of RAM to fully utilise that in
any given process at the cost of performance: the reason behind giving
the kernel a part of each processes address space was to avoid the
overhead of switching on each syscall.
</para>
<para>
Each of these changes alter the address space in a way incompatible
with Windows. Prelink and exec-shield mean that the libraries Wine
uses can be placed at any point in the address space: typically this
meant that a library was sitting in the region that the EXE you wanted
to run had to be loaded (remember that unlike DLLs, EXE files cannot
be moved around in memory). The 4G VM split means that programs could
receive pointers to the top gigabyte of address space which some are
not prepared for (they may store extra information in the high bits of
a pointer, for instance). In particular, in combination with
exec-shield this one is especially deadly as it's possible the process
heap could be allocated beyond
<constant>ADDRESS_SPACE_LIMIT</constant> which causes Wine
initialization to fail.
</para>
<para>
The solution to these problems is for Wine to reserve particular parts
of the address space so that areas that we don't want the system to
use will be avoided. We later on (re/de)allocate those areas as
needed. One problem is that some of these mappings are put in place
automatically by the dynamic linker: for instance any libraries that
Wine is linked to (like <filename>libc</filename>,
<filename>libwine</filename>, <filename>libpthread</filename> etc)
will be mapped into memory before Wine even gets control. In order to
solve that, Wine overrides the default ELF initialization sequence at
a low level and reserves the needed areas by using direct syscalls
into the kernel (ie without linking against any other code to do it)
before restarting the standard initialization and letting the dynamic
linker continue. This is referred to as the preloader and is found in
<filename>loader/preloader.c</filename>.
</para>
<para>
Once the usual ELF boot sequence has been completed, some native
libraries may well have been mapped above the 3gig limit: however,
this doesn't matter as 3G is a Windows limit, not a Linux limit. We
still have to prevent the system from allocating anything else above
there (like the heap or other DLLs) though so Wine performs a binary
search over the upper gig of address space in order to iteratively
fill in the holes with <constant>MAP_NORESERVE</constant> mappings so
the address space is allocated but the memory to actually back it is
not. This code can be found in
<filename>libs/wine/mmap.c</filename>:<function>reserve_area</function>.
</para>
</sect2>
</sect1>
<sect1>
<title>Multi-processing in Wine</title>
<para>
Let's take a closer look at the way Wine loads and run processes in memory.
</para>
<sect2>
<title>Starting a process from command line</title>
<para>
When starting a Wine process from command line (we'll get later on to
the differences between NE, PE and Winelib executables), there are a
couple of things Wine need to do first. A first executable is run to
check the threading model of the underlying OS (see
<xref linkend="threading"> for the details) and will start the real
Wine loader corresponding to the choosen threading model.
</para>
<para>
Then Wine graps a few elements from the Unix world: the environment,
the program arguments. Then the <filename>ntdll.dll.so</filename> is
loaded into memory using the standard shared library dynamic
loader. When loaded, <filename>NTDLL</filename> will mainly first
create a decent Windows environment:
<itemizedlist>
<listitem>
<para>
create a PEB (Process Environment Block) and a TEB (Thread
Environment Block).
</para>
</listitem>
<listitem>
<para>
set up the connection to the Wine server - and eventually
launching the Wine server if none runs
</para>
</listitem>
<listitem>
<para>create the process heap</para>
</listitem>
</itemizedlist>
</para>
<para>
Then <filename>Kernel32</filename> is loaded (but now using the
Windows dynamic loading capabilities) and a Wine specific entry point
is called <function>__wine_kernel_init</function>. This function will
actually handle all the logic of the process loading and execution,
and will never return from it's call.
</para>
<para>
<function>__wine_kernel_init</function> will undergo the following
tasks:
<itemizedlist>
<listitem>
<para>
initialization of program arguments from Unix program arguments
</para>
</listitem>
<listitem>
<para>lookup of executable in the file system</para>
</listitem>
<listitem>
<para>
If the file is not found, then an error is printed and the Wine
loader stops.
</para>
</listitem>
<listitem>
<para>
We'll cover the non-PE file type later on, so assume for now
it's a PE file. The PE module is loaded in memory using the
same mechanisms as for a native DLLs (mainly mapping the file
data and code sections into memory, and handling relocation if
needed). Note that the dependencies on the module are not
resolved at this point.
</para>
</listitem>
<listitem>
<para>
A new stack is created, which size is given in the PE header,
and this stack is made the one of the running thread (which is
still the only one in the process). The stack used at startup
will no longer be used.
</para>
</listitem>
<listitem>
<para>
Which this new stack,
<function>ntdll.LdrInitializeThunk</function> is called which
performs the remaining initialization parts, including resolving
all the DLL imports on the PE module, and doing the init of the
TLS slots.
</para>
</listitem>
<listitem>
<para>
Control can now be passed to the <function>EntryPoint</function>
of the PE module, which will let the executable run.
</para>
</listitem>
</itemizedlist>
</para>
</sect2>
<sect2>
<title>Creating a child process from a running process</title>
<para>
The steps used are closely link to what is done in the previous case.
</para>
<para>
There are however a few points to look at a bit more closely. The
inner implementation creates the child process using the
<function>fork()</function> and <function>exec()</function>
calls. This means that we don't need to check again for the threading
model, we can use what the parent (or the grand-parent process...)
started from command line has found.
</para>
<para>
The Win32 process creation allows to pass a lot of information between
the parent and the child. This includes object handles, windows title,
console parameters, environment strings... Wine makes use of both the
standard Unix inheritance mechanisms (for environment for example) and
the Wine server (to pass from parent to child a chunk of data
containing the relevant information).
</para>
<para>
The previously described loading mechanism will check in the Wine
server if such a chunk exists, and, if so, will perform the relevant
initialization.
</para>
<para>
Some further synchronization is also put in place: a parent will wait
until the child has started, or has failed. The Wine server is also
used to perform those tasks.
</para>
</sect2>
<sect2>
<title>Starting a Winelib process</title>
<para>
Before going into the gory details, let's first go back to what a
Winelib application is. It can be either a regular Unix executable, or
a more specific Wine beast. This later form in fact creates two files
for a given executable (say <filename>foo.exe</filename>). The first
one, named <filename>foo</filename> will be a symbolic link to the
Wine loader (<filename>wine</filename>). The second one, named
<filename>foo.exe.so</filename>, is the equivalent of the
<filename>.dll.so</filename> files we've already described for
DLLs. As in Windows, an executable is, among other things, a module
with its import and export information, as any DLL, it makes sense
Wine uses the same mechanisms for loading native executables and
DLLs.
</para>
<para>
When starting a Winelib application from the command line (say with
<command>foo arg1 arg2</command>), the Unix shell will execute
<command>foo</command> as a Unix executable. Since this is in fact the
Wine loader, Wine will fire up. However, will notice that it hasn't
been started as <command>wine</command> but as <command>foo</command>,
and hence, will try to load (using Unix shared library mechanism) the
second file <filename>foo.exe.so</filename>. Wine will recognize a 32
bit module (with its descriptor) embedded in the shared library, and
once the shared library loaded, it will proceed the same path as when
loading a standard native PE executable.
</para>
<para>
Wine needs to implement this second form of executable in order to
maintain the order of initialization of some elements in the
executable. One particular issue is when dealing with global C++
objects. In standard Unix executable, the call of the constructor to
such objects is stored in the specific section of the executable
(<function>.init</function> not to name it). All constructors in this
section are called before the <function>main()</function> or
<function>WinMain</function> function is called. Creating a Wine
executable using the first form mentionned above will let those
constructors being called before Wine gets a chance to initialize
itself. So, any constructor using a Windows API will fail, because
Wine infrastructure isn't in place. The use of the second form for
Winelib executables ensures that we do the initialization using the
following steps:
<itemizedlist>
<listitem>
<para>
initialize the Wine infrastructure
</para>
</listitem>
<listitem>
<para>
load the executable into memory
</para>
</listitem>
<listitem>
<para>
handle the import sections for the executable
</para>
</listitem>
<listitem>
<para>
call the global object constructors (if any). They now can
properly call the Windows APIs
</para>
</listitem>
<listitem>
<para>
call the executable entry point
</para>
</listitem>
</itemizedlist>
</para>
<para>
The attentive reader would have noted that the resolution of imports
for the executable is done, as for a DLL, when the executable/DLL
descriptor is registered. However, this is done also by adding a
specific constructor in the <function>.init</function> section. For
the above describe scheme to function properly, this constructor must
be the first constructor to be called, before all the other
constructors, generated by the executable itself. The Wine build chain
takes care of that, and also generating the executable/DLL descriptor
for the Winelib executable.
</para>
</sect2>
</sect1>
<sect1 id="threading">
<title>Multi-threading in Wine</title>
......@@ -314,40 +669,6 @@ if (res != ERROR_SUCCESS) return res;
</sect2>
<sect2>
<title>SysLevels</title>
<para>
SysLevels are an undocumented Windows-internal thread-safety
system. They are basically critical sections which must be taken in a
particular order. The mechanism is generic but there are always three
syslevels: level 1 is the Win16 mutex, level 2 is the
<filename>USER</filename> mutex and level 3 is the
<filename>GDI</filename> mutex.
</para>
<para>
When entering a syslevel, the code (in
<filename>dlls/kernel/syslevel.c</filename>) will check that a higher
syslevel is not already held and produce an error if so. This is
because it's not legal to enter level 2 while holding level 3 - first,
you must leave level 3.
</para>
<para>
Throughout the code you may see calls to
<function>_ConfirmSysLevel()</function> and
<function>_CheckNotSysLevel()</function>. These functions are
essentially assertions about the syslevel states and can be used to
check that the rules have not been accidentally violated. In
particular, <function>_CheckNotSysLevel()</function> will break
probably into the debugger) if the check fails. If this happens the
solution is to get a backtrace and find out, by reading the source of
the wine functions called along the way, how Wine got into the invalid
state.
</para>
</sect2>
<sect2>
<title>POSIX threading vs. kernel threading</title>
<para>
......@@ -393,7 +714,7 @@ if (res != ERROR_SUCCESS) return res;
glibc, for instance. Worse, pthreads and pure kernel threads had
strange interactions when run in the same process yet some libraries
used by Wine used pthreads internally. Throw in source code porting
using WineLib - where you have both UNIX and Win32 code in the same
using Winelib - where you have both UNIX and Win32 code in the same
process - and chaos was the result.
</para>
......@@ -651,15 +972,16 @@ if (res != ERROR_SUCCESS) return res;
<para>
Windows exceptions typically contain more information than the Unix
standard APIs provide. For instance, a
<constant>STATUS_ACCESS_VIOLATION</constant> exception (0xC0000005)
structure contains the faulting address, whereas a standard Unix
SIGSEGV just tells the app that it crashed. Usually this information
is passed as an extra parameter to the signal handler, however its
location and contents vary between kernels (BSD, Solaris,
etc). This data is provided in a <structname>SIGCONTEXT</structname>
structure, and on entry to the signal handler it contains the register
state of the CPU before the signal was sent. Modifying it will cause
the kernel to adjust the context before restarting the thread.
<constant>STATUS_ACCESS_VIOLATION</constant> exception
(<constant>0xC0000005</constant>) structure contains the faulting
address, whereas a standard Unix <constant>SIGSEGV</constant> just
tells the app that it crashed. Usually this information is passed as
an extra parameter to the signal handler, however its location and
contents vary between kernels (BSD, Solaris, etc). This data is
provided in a <structname>SIGCONTEXT</structname> structure, and on
entry to the signal handler it contains the register state of the CPU
before the signal was sent. Modifying it will cause the kernel to
adjust the context before restarting the thread.
</para>
</sect2>
</sect1>
......@@ -1195,6 +1517,7 @@ if (res != ERROR_SUCCESS) return res;
</para>
<para>
<note>
<title>Case sensitivity vs. preservation</title>
<para>
When we say that most systems in NT are case insensitive, this
has to be understood for looking up for a file, where the
......@@ -2125,6 +2448,150 @@ if (res != ERROR_SUCCESS) return res;
</para>
</sect3>
</sect2>
<sect2>
<title>Win16 processes support</title>
<sect3>
<title>Starting a NE (Win16) process</title>
<para>
Wine is also able to run 16 bit processes, but this feature is only
supported on Intel IA-32 architectures.
</para>
<para>
When Wine is requested to run a NE (Win 16 process), it will in fact
hand over the execution of it to a specific executable
<command>winevdm</command>. VDM stands for Virtual DOS
Machine. This <command>winevdm</command> is a Winelib application,
but will in fact set up the correct 16 bit environment to run the
executable. We will get back later on in details to what this means.
</para>
<para>
Any new 16 bit process created by this executable (or its children)
will run into the same <command>winevdm</command> instance. Among
one instance, several functionalities will be provided to those 16
bit processes, including the cooperative multitasking, sharing the
same address space, managing the selectors for the 16 bit segments
needed for code, data and stack.
</para>
<para>
Note that several <command>winevdm</command> instances can run in
the same Wine session, but the functionalities described above are
only shared among a given instance, not among all the
instances. <command>winevdm</command> is built as Winelib
application, and hence has access to any facility a 32 bit
application has.
</para>
<para>
Each Win16 application is implemented in
<command>winevdm</command> as a Win32
thread. <command>winevdm</command> then implements its own
scheduling facilities (in fact, the code for this feature is in the
<filename>krnl386.exe</filename> DLL). Since the required Win16
scheduling is non pre-emptive, this doesn't require any underlying
OS kernel support.
</para>
</sect3>
<sect3>
<title>SysLevels</title>
<para>
SysLevels are an undocumented Windows-internal thread-safety system
dedicated to 16 bit applications (or 32 bit applications that call -
directly or indirectly - 16 bit code). They are basically critical
sections which must be taken in a particular order. The mechanism is
generic but there are always three syslevels:
<itemizedlist>
<listitem>
<para>level 1 is the Win16 mutex,</para>
</listitem>
<listitem>
<para>level 2 is the <filename>USER</filename> mutex,</para>
</listitem>
<listitem>
<para>level 3 is the <filename>GDI</filename> mutex.</para>
</listitem>
</itemizedlist>
</para>
<para>
When entering a syslevel, the code (in
<filename>dlls/kernel/syslevel.c</filename>) will check that a
higher syslevel is not already held and produce an error if so. This
is because it's not legal to enter level 2 while holding level 3 -
first, you must leave level 3.
</para>
<para>
Throughout the code you may see calls to
<function>_ConfirmSysLevel()</function> and
<function>_CheckNotSysLevel()</function>. These functions are
essentially assertions about the syslevel states and can be used to
check that the rules have not been accidentally violated. In
particular, <function>_CheckNotSysLevel()</function> will break
probably into the debugger) if the check fails. If this happens the
solution is to get a backtrace and find out, by reading the source
of the wine functions called along the way, how Wine got into the
invalid state.
</para>
</sect3>
<sect3>
<title>Memory management</title>
<para>
Every Win16 address is expressed in the form of selector:offset. The
selector is an entry in the LDT, but a 16 bit entry, limiting each
offset to 64 KB. Hence, the maximum available memory to a Win16
process is 512 MB. Note, that the processor runs in protected mode,
but using 16 bit selectors.
</para>
<para>
Windows, for a 16 bit process, defines a few selectors to access the
"real" memory (the one provided) by DOS. Basically, Wine also
provides this area of memory.
</para>
</sect3>
</sect2>
<sect2>
<title>DOS processes support</title>
<para>
The behaviour we just described also applies to DOS executables, which
are handled the same way by <command>winevdm</command>. This is only
supported on Intel IA-32 architectures.
</para>
<para>
Wine implements also most of the DOS support in a Wine specific DLL
(<filename>winedos</filename>). This DLL is called under certain
conditions, like:
<itemizedlist>
<listitem>
<para>
In <command>winevdm</command>, when trying to launch a DOS
application (<filename>.EXE</filename> or
<filename>.COM</filename>, <filename>.PIF</filename>).
</para>
</listitem>
<listitem>
<para>
In <filename>kernel32</filename>, when an attempt is made in the
binary code to call some DOS or BIOS interrupts (like Int 21h
for example).
</para>
</listitem>
</itemizedlist>
</para>
<para>
When <command>winevdm</command> runs a DOS program, this one runs in
real mode (in fact in V86 mode from the IA-32 point of view).
</para>
<para>
Wine also supports part of the DPMI (DOS Protected Mode Interface).
</para>
<para>
Wine, when running a DOS programs, needs to map the 1 MB of virtual
memory to the real memory (as seen by the DOS program). When this is
not possible (like when someone else is already using this area), the
DOS support is not possible. Not also that by doing so, access to
linear address 0 is enabled (as it's also real mode address 0 which is
valid). Hence, NULL pointer derefence faults are no longer catched.
</para>
</sect2>
</sect1>
</chapter>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment