From 3bebb0fed9a1b75e89f380dea4abd134fffec27d Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Mon, 18 Apr 2005 09:53:39 +0000 Subject: [PATCH] - 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. --- documentation/architecture.sgml | 589 ++++++------------------------ documentation/winedev-kernel.sgml | 555 +++++++++++++++++++++++++--- 2 files changed, 620 insertions(+), 524 deletions(-) diff --git a/documentation/architecture.sgml b/documentation/architecture.sgml index a7174027720..9ec7cbff519 100644 --- a/documentation/architecture.sgml +++ b/documentation/architecture.sgml @@ -81,7 +81,7 @@ - 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 @@ DOS (.COM or .EXE) Win16 (NE) Win32 (PE) - WineLib + Winelib @@ -188,14 +188,12 @@ - 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 WOW - 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 WOW process (Windows on Windows), + referring to a similar mechanism used by Windows NT. 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. + + winevdm 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 winedos. + @@ -251,9 +258,12 @@ 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 + (NTDLL) which allows implementing + different subsystems (as win32); + kernel32 in NT architecture + implements the Win32 subsystem on top of + NTDLL. +---------------------+ \ | Windows EXE | } application @@ -371,12 +381,16 @@ 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. + (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. 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 .wine subdirectory (or wherever the - WINEPREFIX 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).) + WINEPREFIX 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). In earlier versions of Wine the master socket mentioned above was actually created in the configuration directory; either your home directory's /wine subdirectory or wherever the - WINEPREFIX environment variable - points>. Since that might not be possible the socket is - actually created within the /tmp - 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 + WINEPREFIX environment variable points>. + Since that might not be possible the socket is actually + created within the /tmp 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. @@ -544,9 +558,9 @@ automatically registered when the shared library is loaded - remember, registration call is put inside a shared library constructor - using the - PRELOAD environment variable - when running a Wine process can force the - registration of some DLL descriptors. + PRELOAD environment variable when + running a Wine process can force the registration of + some DLL descriptors. @@ -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 WINEDLLPATH environment - variable. + the WINEDLLPATH environment variable. @@ -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 + (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 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 - kernel32.dll or - system.dll will end up on the same + KERNEL32.DLL or + SYSTEM.DLL will end up on the same shared library. @@ -675,24 +692,26 @@ 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 + 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. 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 + SHELL DLL is loaded before the native + version of this library. SHELL 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 SHELL. @@ -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 GDI + library must be paired with a Windows display driver, which + of course is not present under Intel Unix and Wine. 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 + USER DLL. Should the native Windows + USER 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 @@ - 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 + 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. @@ -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 + NTDLL. 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 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. @@ -923,403 +945,8 @@ memory allocation and stack. - - - Implementation - - Wine (with a bit of black magic) is able to map all items - at the correct locations as depicted above. - - - Wine also implements the shared heap so native win9x DLLs - can be used. This heap is always created at the - SYSTEM_HEAP_BASE address or - 0x80000000 and defaults to 16 - megabytes in size. - - - 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. - - - - - Laying out the address space - - - 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. - - - - 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. - - - - 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. - - - - 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. - - - - 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. - - - - 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. - - - - 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. - - - - 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. - - - - Processes - - Let's take a closer look at the way Wine loads and run - processes in memory. - - - Starting a process from command line - - 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 - for the details) and will start the real Wine loader - corresponding to the choosen threading model. - - - Then Wine graps a few elements from the Unix world: the - environment, the program arguments. Then the - ntdll.dll.so is loaded into memory - using the standard shared library dynamic loader. When - loaded, NTDLL will mainly first create a decent Windows - environment: - - - create a PEB and a TEB - - - - set up the connection to the Wine server - and - eventually launching the Wine server if none runs - - - - create the process heap - - - - - Then Kernel32 is loaded (but now - using the Windows dynamic loading capabilities) and a Wine - specific entry point is called - __wine_kernel_init. This function - will actually handle all the logic of the process loading - and execution, and will never return from it's call. - - - __wine_kernel_init will undergo the - following tasks: - - - - initialization of program arguments from Unix - program arguments - - - - - lookup of executable in the file system - - - - - If the file is not found, then an error is printed - and the Wine loader stops. - - - - - 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. - - - - - 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. - - - - - Which this new stack, - ntdll.LdrInitializeThunk 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. - - - - - Control can now be passed to the - EntryPoint of the PE module, - which will let the executable run. - - - - - - - Creating a child process from a running process - - The steps used are closely link to what is done in the - previous case. - - - There are however a few points to look at a bit more - closely. The inner implementation creates the child - process using the fork() and - exec() 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. - - - 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). - - - The previously described loading mechanism will check in - the Wine server if such a chunk exists, and, if so, will - perform the relevant initialization. - - - 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. - - - - Starting a Winelib process - - 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 - foo.exe). The first one, named - foo will be a symbolic link to the - Wine loader (wine). The second one, - named foo.exe.so, is the equivalent - of the .dll.so 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. - - - When starting a Winelib application from the command line - (say with foo arg1 arg2), the Unix - shell will execute foo 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 wine but as - foo, and hence, will try to load (using - Unix shared library mechanism) the second file - foo.exe.so. 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. - - - 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 - (.init not to name it). All - constructors in this section are called before the - main 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: - - - - initialize the Wine infrastructure - - - - - load the executable into memory - - - - - handle the import sections for the executable - - - - - call the global object constructors (if any). They - now can properly call the Windows APIs - - - - - call the executable entry point - - - - - - 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 - .init 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. - - - - Starting a NE (Win16) process - - 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 winevdm. VDM stands for - Virtual DOS Machine. This winevdm - 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 - winevdm 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. - - - Note that several winevdm 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. winevdm - is built as Winelib application, and hence has access to - any facility a 32 bit application has. - - - The behaviour we just described also applies to DOS - executables, which are handled the same way by - winevdm. - - - Wine drivers @@ -1327,11 +954,13 @@ 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 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. In other words, Wine will only be able to provide access to diff --git a/documentation/winedev-kernel.sgml b/documentation/winedev-kernel.sgml index 28eae99ea91..7efd9d3ac73 100644 --- a/documentation/winedev-kernel.sgml +++ b/documentation/winedev-kernel.sgml @@ -202,6 +202,361 @@ ExitProcess( entry( peb ) ); + + Detailed memory management + + As already explained in previous chapter (see + 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. + + + + Implementation + + Wine (with a bit of black magic) is able to map the main module at + it's desired address (likely 0x400000), 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. + + + Wine also implements the shared heap so native win9x DLLs can be + used. This heap is always created at the + SYSTEM_HEAP_BASE address or + 0x80000000 and defaults to 16 megabytes in size. + + + 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. + + + + + Laying out the address space + + + 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. + + + + 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. + + + + 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. + + + + 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. + + + + 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. + + + + 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. + + + + 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. + + + + 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. + + + + + + Multi-processing in Wine + + Let's take a closer look at the way Wine loads and run processes in memory. + + + Starting a process from command line + + 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 + for the details) and will start the real + Wine loader corresponding to the choosen threading model. + + + Then Wine graps a few elements from the Unix world: the environment, + the program arguments. Then the ntdll.dll.so is + loaded into memory using the standard shared library dynamic + loader. When loaded, NTDLL will mainly first + create a decent Windows environment: + + + + create a PEB (Process Environment Block) and a TEB (Thread + Environment Block). + + + + + set up the connection to the Wine server - and eventually + launching the Wine server if none runs + + + + create the process heap + + + + + Then Kernel32 is loaded (but now using the + Windows dynamic loading capabilities) and a Wine specific entry point + is called __wine_kernel_init. This function will + actually handle all the logic of the process loading and execution, + and will never return from it's call. + + + __wine_kernel_init will undergo the following + tasks: + + + + initialization of program arguments from Unix program arguments + + + + lookup of executable in the file system + + + + If the file is not found, then an error is printed and the Wine + loader stops. + + + + + 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. + + + + + 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. + + + + + Which this new stack, + ntdll.LdrInitializeThunk 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. + + + + + Control can now be passed to the EntryPoint + of the PE module, which will let the executable run. + + + + + + + Creating a child process from a running process + + The steps used are closely link to what is done in the previous case. + + + There are however a few points to look at a bit more closely. The + inner implementation creates the child process using the + fork() and exec() + 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. + + + 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). + + + The previously described loading mechanism will check in the Wine + server if such a chunk exists, and, if so, will perform the relevant + initialization. + + + 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. + + + + Starting a Winelib process + + 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 foo.exe). The first + one, named foo will be a symbolic link to the + Wine loader (wine). The second one, named + foo.exe.so, is the equivalent of the + .dll.so 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. + + + When starting a Winelib application from the command line (say with + foo arg1 arg2), the Unix shell will execute + foo 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 wine but as foo, + and hence, will try to load (using Unix shared library mechanism) the + second file foo.exe.so. 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. + + + 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 + (.init not to name it). All constructors in this + section are called before the main() or + WinMain 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: + + + + initialize the Wine infrastructure + + + + + load the executable into memory + + + + + handle the import sections for the executable + + + + + call the global object constructors (if any). They now can + properly call the Windows APIs + + + + + call the executable entry point + + + + + + 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 .init 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. + + + + Multi-threading in Wine @@ -313,40 +668,6 @@ if (res != ERROR_SUCCESS) return res; - - SysLevels - - - 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 - USER mutex and level 3 is the - GDI mutex. - - - - When entering a syslevel, the code (in - dlls/kernel/syslevel.c) 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. - - - - Throughout the code you may see calls to - _ConfirmSysLevel() and - _CheckNotSysLevel(). 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, _CheckNotSysLevel() 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. - - - POSIX threading vs. kernel threading @@ -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. @@ -651,15 +972,16 @@ if (res != ERROR_SUCCESS) return res; Windows exceptions typically contain more information than the Unix standard APIs provide. For instance, a - STATUS_ACCESS_VIOLATION 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 SIGCONTEXT - 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. + STATUS_ACCESS_VIOLATION 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 SIGCONTEXT 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. @@ -1195,6 +1517,7 @@ if (res != ERROR_SUCCESS) return res; + Case sensitivity vs. preservation 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; + + Win16 processes support + + Starting a NE (Win16) process + + Wine is also able to run 16 bit processes, but this feature is only + supported on Intel IA-32 architectures. + + + 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 + winevdm. VDM stands for Virtual DOS + Machine. This winevdm 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. + + + Any new 16 bit process created by this executable (or its children) + will run into the same winevdm 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. + + + Note that several winevdm 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. winevdm is built as Winelib + application, and hence has access to any facility a 32 bit + application has. + + + Each Win16 application is implemented in + winevdm as a Win32 + thread. winevdm then implements its own + scheduling facilities (in fact, the code for this feature is in the + krnl386.exe DLL). Since the required Win16 + scheduling is non pre-emptive, this doesn't require any underlying + OS kernel support. + + + + SysLevels + + 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: + + + level 1 is the Win16 mutex, + + + level 2 is the USER mutex, + + + level 3 is the GDI mutex. + + + + + + When entering a syslevel, the code (in + dlls/kernel/syslevel.c) 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. + + + + Throughout the code you may see calls to + _ConfirmSysLevel() and + _CheckNotSysLevel(). 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, _CheckNotSysLevel() 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. + + + + Memory management + + 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. + + + 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. + + + + + DOS processes support + + The behaviour we just described also applies to DOS executables, which + are handled the same way by winevdm. This is only + supported on Intel IA-32 architectures. + + + Wine implements also most of the DOS support in a Wine specific DLL + (winedos). This DLL is called under certain + conditions, like: + + + + In winevdm, when trying to launch a DOS + application (.EXE or + .COM, .PIF). + + + + + In kernel32, when an attempt is made in the + binary code to call some DOS or BIOS interrupts (like Int 21h + for example). + + + + + + When winevdm runs a DOS program, this one runs in + real mode (in fact in V86 mode from the IA-32 point of view). + + + Wine also supports part of the DPMI (DOS Protected Mode Interface). + + + 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. + +