<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> |