92 lines
5.0 KiB
Plaintext
92 lines
5.0 KiB
Plaintext
<chapter id="address-space">
|
|
<title> Address space management </title>
|
|
|
|
<para>
|
|
A good understanding of memory layout in Unix and Windows is
|
|
required before reading the next section (<xref
|
|
linkend="arch-mem"> gives some basic insight).
|
|
</para>
|
|
|
|
<sect1>
|
|
<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>
|
|
|
|
</sect1>
|
|
|
|
</chapter>
|