| <chapter> |
| <title>Kernel modules</title> |
| <para> |
| This section cover the kernel modules. As already stated, Wine |
| implements the NT architecture, hence provides NTDLL for the |
| core kernel functions, and KERNEL32, which is the |
| implementation of the basis of the Win32 subsystem, on top of |
| NTDLL. |
| </para> |
| <sect1 id="ntdll"> |
| <title>NTDLL</title> |
| <para> |
| NTDLL provides most of the services you'd expect from a |
| kernel. |
| </para> |
| <para> |
| Process and thread management are part of them (even if |
| process management is still mainly done in KERNEL32, unlike |
| NT). A Windows process runs as a Unix process, and a Windows |
| thread runs as a Unix thread. |
| </para> |
| <para> |
| Wine also provide fibers (which is the Windows name of |
| co-routines). |
| </para> |
| <para> |
| Most of the Windows memory handling (Heap, Global and Local |
| functions, virtual memory...) are easily mapped upon their |
| Unix equivalents. Note the NTDLL doesn't know about 16 bit |
| memory, which is only handled in KERNEL32/KRNL386.EXE (and |
| also the DOS routines). |
| </para> |
| |
| <sect2> |
| <title>File management</title> |
| <para> |
| Wine uses some configuration in order to map Windows |
| filenames (either defined with drive letters, or as UNC |
| names) to the unix filenames. Wine also uses some |
| incantation so that most of file related APIs can also |
| take full unix names. This is handy when passing filenames |
| on the command line. |
| </para> |
| <para> |
| File handles can be waitable objects, as Windows define |
| them. |
| </para> |
| <para> |
| Asynchronous I/O is implemented on file handles by |
| queueing pseudo APC. They are not real APC in the sense |
| that they have the same priority as the threads in the |
| considered process (while APCs on NT have normally a |
| higher priority). These APCs get called when invoking |
| Wine server (which should lead to correct behavior when the |
| program ends up waiting on some object - waiting always |
| implies calling Wine server). |
| </para> |
| <para> |
| FIXME: this should be enhanced and updated to latest work |
| on FS. |
| </para> |
| </sect2> |
| |
| <sect2> |
| <title>Synchronization</title> |
| <para> |
| Most of the synchronization (between threads or processes) |
| is done in Wine server, which handles both the waiting |
| operation (on a single object or a set of objects) and the |
| signaling of objects. |
| </para> |
| </sect2> |
| |
| <sect2> |
| <title>Module (DLL) loading</title> |
| <para> |
| Wine is able to load any NE and PE module. In all cases, |
| the module's binary code is directly executed by the |
| processor. |
| </para> |
| </sect2> |
| |
| <sect2> |
| <title>Device management</title> |
| <para> |
| Wine allows usage a wide variety of devices: |
| <itemizedlist> |
| <listitem> |
| <para> |
| Communication ports are mapped to Unix |
| communication ports (if they have sufficient |
| permissions). |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| Parallel ports are mapped to Unix parallel ports (if |
| they have sufficient permissions). |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| CDROM: the Windows device I/O control calls are |
| mapped onto Unix <function>ioctl()</function>. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| Some Win9x VxDs are supported, by rewriting some of |
| their internal behavior. But this support is |
| limited. Portable programs to Windows NT shouldn't |
| need them. |
| </para> |
| <para> |
| Wine will not support native VxD. |
| </para> |
| </listitem> |
| </itemizedlist> |
| </para> |
| </sect2> |
| <sect2 id="threading"> |
| <title>Multi-threading in Wine</title> |
| |
| <para> |
| This section will assume you understand the basics of |
| multithreading. If not there are plenty of good tutorials |
| available on the net to get you started. |
| </para> |
| |
| <para> |
| Threading in Wine is somewhat complex due to several |
| factors. The first is the advanced level of multithreading |
| support provided by Windows - there are far more threading |
| related constructs available in Win32 than the Linux |
| equivalent (pthreads). The second is the need to be able to |
| map Win32 threads to native Linux threads which provides us |
| with benefits like having the kernel schedule them without |
| our intervention. While it's possible to implement threading |
| entirely without kernel support, doing so is not desirable |
| on most platforms that Wine runs on. |
| </para> |
| |
| <sect3> |
| <title> Threading support in Win32 </title> |
| |
| <para> |
| Win32 is an unusually thread friendly API. Not only is it |
| entirely thread safe, but it provides many different |
| facilities for working with threads. These range from the |
| basics such as starting and stopping threads, to the |
| extremely complex such as injecting threads into other |
| processes and COM inter-thread marshalling. |
| </para> |
| |
| <para> |
| One of the primary challenges of writing Wine code |
| therefore is ensuring that all our DLLs are thread safe, |
| free of race conditions and so on. This isn't simple - |
| don't be afraid to ask if you aren't sure whether a piece |
| of code is thread safe or not! |
| </para> |
| |
| <para> |
| Win32 provides many different ways you can make your code |
| thread safe however the most common are <emphasis>critical |
| section</emphasis> and the <emphasis>interlocked |
| functions</emphasis>. Critical sections are a type of |
| mutex designed to protect a geographic area of code. If |
| you don't want multiple threads running in a piece of code |
| at once, you can protect them with calls to |
| <function>EnterCriticalSection</function> and |
| <function>LeaveCriticalSection</function>. The first call |
| to <function>EnterCriticalSection</function> by a thread |
| will lock the section and continue without stopping. If |
| another thread calls it then it will block until the |
| original thread calls |
| <function>LeaveCriticalSection</function> again. |
| </para> |
| |
| <para> |
| It is therefore vitally important that if you use critical |
| sections to make some code thread-safe, that you check |
| every possible codepath out of the code to ensure that any |
| held sections are left. Code like this: |
| </para> |
| |
| <programlisting> |
| if (res != ERROR_SUCCESS) return res; |
| </programlisting> |
| |
| <para> |
| is extremely suspect in a function that also contains a |
| call to <function>EnterCriticalSection</function>. Be |
| careful. |
| </para> |
| |
| <para> |
| If a thread blocks while waiting for another thread to |
| leave a critical section, you will see an error from the |
| <function>RtlpWaitForCriticalSection</function> function, |
| along with a note of which thread is holding the |
| lock. This only appears after a certain timeout, normally |
| a few seconds. It's possible the thread holding the lock |
| is just being really slow which is why Wine won't |
| terminate the app like a non-checked build of Windows |
| would, but the most common cause is that for some reason a |
| thread forgot to call |
| <function>LeaveCriticalSection</function>, or died while |
| holding the lock (perhaps because it was in turn waiting |
| for another lock). This doesn't just happen in Wine code: |
| a deadlock while waiting for a critical section could be |
| due to a bug in the app triggered by a slight difference |
| in the emulation. |
| </para> |
| |
| <para> |
| Another popular mechanism available is the use of |
| functions like <function>InterlockedIncrement</function> |
| and <function>InterlockedExchange</function>. These make |
| use of native CPU abilities to execute a single |
| instruction while ensuring any other processors on the |
| system cannot access memory, and allow you to do common |
| operations like add/remove/check a variable in thread-safe |
| code without holding a mutex. These are useful for |
| reference counting especially in free-threaded (thread |
| safe) COM objects. |
| </para> |
| |
| <para> |
| Finally, the usage of TLS slots are also popular. TLS |
| stands for thread-local storage, and is a set of slots |
| scoped local to a thread which you can store pointers |
| in. Look on MSDN for the <function>TlsAlloc</function> |
| function to learn more about the Win32 implementation of |
| this. Essentially, the contents of a given slot will be |
| different in each thread, so you can use this to store |
| data that is only meaningful in the context of a single |
| thread. On recent versions of Linux the __thread keyword |
| provides a convenient interface to this functionality - a |
| more portable API is exposed in the pthread |
| library. However, these facilities is not used by Wine, |
| rather, we implement Win32 TLS entirely ourselves. |
| </para> |
| </sect3> |
| |
| <sect3> |
| <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 USER mutex and level 3 |
| is the GDI 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> |
| |
| </sect3> |
| |
| <sect3> |
| <title> POSIX threading vs kernel threading </title> |
| |
| <para> |
| Wine runs in one of two modes: either pthreads (posix |
| threading) or kthreads (kernel threading). This section |
| explains the differences between them. The one that is |
| used is automatically selected on startup by a small test |
| program which then execs the correct binary, either |
| wine-kthread or wine-pthread. On NPTL-enabled systems |
| pthreads will be used, and on older non-NPTL systems |
| kthreads is selected. |
| </para> |
| |
| <para> |
| Let's start with a bit of history. Back in the dark ages |
| when Wines threading support was first implemented a |
| problem was faced - Windows had much more capable |
| threading APIs than Linux did. This presented a problem - |
| Wine works either by reimplementing an API entirely or by |
| mapping it onto the underlying systems equivalent. How |
| could Win32 threading be implemented using a library which |
| did not have all the neeed features? The answer, of |
| course, was that it couldn't be. |
| </para> |
| |
| <para> |
| On Linux the pthreads interface is used to start, stop and |
| control threads. The pthreads library in turn is based on |
| top of so-called "kernel threads" which are created using |
| the <function>clone(2)</function> syscall. Pthreads |
| provides a nicer (more portable) interface to this |
| functionality and also provides APIs for controlling |
| mutexes. There is a <ulink |
| url="http://www.llnl.gov/computing/tutorials/pthreads/"> |
| good tutorial on pthreads </ulink> available if you want |
| to learn more. |
| </para> |
| |
| <para> |
| As pthreads did not provide the necessary semantics to |
| implement Win32 threading, the decision was made to |
| implement Win32 threading on top of the underlying kernel |
| threads by using syscalls like <function>clone</function> |
| directly. This provided maximum flexibility and allowed a |
| correct implementation but caused some bad side |
| effects. Most notably, all the userland Linux APIs assumed |
| that the user was utilising the pthreads library. Some |
| only enabled thread safety when they detected that |
| pthreads was in use - this is true of 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 process - and chaos was |
| the result. |
| </para> |
| |
| <para> |
| The solution was simple yet ingenius: Wine would provide |
| its own implementation of the pthread library |
| <emphasis>inside</emphasis> its own binary. Due to the |
| semantics of ELF symbol scoping, this would cause Wines |
| own implementations to override any implementation loaded |
| later on (like the real libpthread.so). Therefore, any |
| calls to the pthread APIs in external libraries would be |
| linked to Wines instead of the systems pthreads library, |
| and Wine implemented pthreads by using the standard |
| Windows threading APIs it in turn implemented itself. |
| </para> |
| |
| <para> |
| As a result, libraries that only became thread-safe in the |
| presence of a loaded pthreads implementation would now do |
| so, and any external code that used pthreads would |
| actually end up creating Win32 threads that Wine was aware |
| of and controlled. This worked quite nicely for a long |
| time, even though it required doing some extremely |
| un-kosher things like overriding internal libc structures |
| and functions. That is, it worked until NPTL was developed |
| at which point the underlying thread implementation on |
| Linux changed dramatically. |
| </para> |
| |
| <para> |
| The fake pthread implementation can be found in |
| <filename>loader/kthread.c</filename>, which is used to |
| produce to wine-kthread binary. In contrast, |
| loader/pthread.c produces the wine-pthread binary which is |
| used on newer NPTL systems. |
| </para> |
| |
| <para> |
| NPTL is a new threading subsystem for Linux that hugely |
| improves its performance and flexibility. By allowing |
| threads to become much more scalable and adding new |
| pthread APIs, NPTL made Linux competitive with Windows in |
| the multi-threaded world. Unfortunately it also broke many |
| assumptions made by Wine (as well as other applications |
| such as the Sun JVM and RealPlayer) in the process. |
| </para> |
| |
| <para> |
| There was, however, some good news. NPTL made Linux |
| threading powerful enough that Win32 threads could now be |
| implemented on top of pthreads like any other normal |
| application. There would no longer be problems with mixing |
| win32-kthreads and pthreads created by external libraries, |
| and no need to override glibc internals. As you can see |
| from the relative sizes of the |
| <filename>loader/kthread.c</filename> and |
| <filename>loader/pthread.c</filename> files, the |
| difference in code complexity is considerable. NPTL also |
| made several other semantic changes to things such as |
| signal delivery so changes were required in many different |
| places in Wine. |
| </para> |
| |
| <para> |
| On non-Linux systems the threading interface is typically |
| not powerful enough to replicate the semantics Win32 |
| applications expect and so kthreads with the pthread |
| overrides are used. |
| </para> |
| </sect3> |
| |
| <sect3> |
| <title> The Win32 thread environment </title> |
| |
| <para> |
| All Win32 code, whether from a native EXE/DLL or in Wine |
| itself, expects certain constructs to be present in its |
| environment. This section explores what those constructs |
| are and how Wine sets them up. The lack of this |
| environment is one thing that makes it hard to use Wine |
| code directly from standard Linux applications - in order |
| to interact with Win32 code a thread must first be |
| "adopted" by Wine. |
| </para> |
| |
| <para> |
| The first thing Win32 code requires is the |
| <emphasis>TEB</emphasis> or "Thread Environment |
| Block". This is an internal (undocumented) Windows |
| structure associated with every thread which stores a |
| variety of things such as TLS slots, a pointer to the |
| threads message queue, the last error code and so on. You |
| can see the definition of the TEB in |
| <filename>include/thread.h</filename>, or at least what we |
| know of it so far. Being internal and subject to change, |
| the layout of the TEB has had to be reverse engineered |
| from scratch. |
| </para> |
| |
| <para> |
| A pointer to the TEB is stored in the %fs register and can |
| be accessed using <function>NtCurrentTeb()</function> from |
| within Wine code. %fs actually stores a selector, and |
| setting it therefore requires modifying the processes |
| local descriptor table (LDT) - the code to do this is in |
| <filename>lib/wine/ldt.c</filename>. |
| </para> |
| |
| <para> |
| The TEB is required by nearly all Win32 code run in the |
| Wine environment, as any wineserver RPC will use it, which |
| in turn implies that any code which could possibly block |
| (for instance by using a critical section) needs it. The |
| TEB also holds the SEH exception handler chain as the |
| first element, so if when disassembling you see code like |
| this: |
| </para> |
| |
| <programlisting> movl %esp, %fs:0 </programlisting> |
| |
| <para> |
| ... then you are seeing the program set up an SEH handler |
| frame. All threads must have at least one SEH entry, which |
| normally points to the backstop handler which is |
| ultimately responsible for popping up the all-too-familiar |
| "This program has performed an illegal operation and will |
| be terminated" message. On Wine we just drop straight into |
| the debugger. A full description of SEH is out of the |
| scope of this section, however there are some good |
| articles in MSJ if you are interested. |
| </para> |
| |
| <para> |
| All Win32-aware threads must have a wineserver |
| connection. Many different APIs require the ability to |
| communicate with the wineserver. In turn, the wineserver |
| must be aware of Win32 threads in order to be able to |
| accurately report information to other parts of the program |
| and do things like route inter-thread messages, dispatch |
| APCs (asynchronous procedure calls) and so on. Therefore a |
| part of thread initialization is initializing the thread |
| serverside. The result is not only correct information in |
| the server, but a set of file descriptors the thread can use |
| to communicate with the server - the request fd, reply fd |
| and wait fd (used for blocking). |
| </para> |
| </sect3> |
| </sect2> |
| </sect1> |
| |
| <sect1> |
| <title>KERNEL Module</title> |
| |
| <para> |
| FIXME: Needs some content... |
| </para> |
| <sect2 id="consoles"> |
| <title>Consoles in Wine</title> |
| <para> |
| As described in the Wine User Guide's CUI section, Wine |
| manipulates three kinds of "consoles" in order to support |
| properly the Win32 CUI API. |
| </para> |
| <para> |
| The following table describes the main implementation |
| differences between the three approaches. |
| <table> |
| <title>Function consoles implementation comparison</title> |
| <tgroup cols="4" align="left"> |
| <thead> |
| <row> |
| <entry>Function</entry> |
| <entry>Bare streams</entry> |
| <entry>Wineconsole & user backend</entry> |
| <entry>Wineconsole & curses backend</entry> |
| </row> |
| </thead> |
| <tbody> |
| <row> |
| <entry> |
| Console as a Win32 Object (and associated |
| handles) |
| </entry> |
| <entry> |
| No specific Win32 object is used in this |
| case. The handles manipulated for the standard |
| Win32 streams are in fact "bare handles" to |
| their corresponding Unix streams. The mode |
| manipulation functions |
| (<function>GetConsoleMode</function> / |
| <function>SetConsoleMode</function>) are not |
| supported. |
| </entry> |
| <entry> |
| Implemented in server, and a specific Winelib |
| program (wineconsole) is in charge of the |
| rendering and user input. The mode manipulation |
| functions behave as expected. |
| </entry> |
| <entry> |
| Implemented in server, and a specific Winelib |
| program (wineconsole) is in charge of the |
| rendering and user input. The mode manipulation |
| functions behave as expected. |
| </entry> |
| </row> |
| <row> |
| <entry> |
| Inheritance (including handling in |
| <function>CreateProcess</function> of |
| <constant>CREATE_DETACHED</constant>, |
| <constant>CREATE_NEW_CONSOLE</constant> flags). |
| </entry> |
| <entry> |
| Not supported. Every process child of a process |
| will inherit the Unix streams, so will also |
| inherit the Win32 standard streams. |
| </entry> |
| <entry> |
| Fully supported (each new console creation will |
| be handled by the creation of a new USER32 |
| window) |
| </entry> |
| <entry> |
| Fully supported, except for the creation of a |
| new console, which will be rendered on the same |
| Unix terminal as the previous one, leading to |
| unpredictable results. |
| </entry> |
| </row> |
| <row> |
| <entry> |
| <function>ReadFile</function> / |
| <function>WriteFile</function> |
| operations |
| </entry> |
| <entry>Fully supported</entry> |
| <entry>Fully supported</entry> |
| <entry>Fully supported</entry> |
| </row> |
| <row> |
| <entry> |
| Screen-buffer manipulation (creation, deletion, |
| resizing...) |
| </entry> |
| <entry>Not supported</entry> |
| <entry>Fully supported</entry> |
| <entry> |
| Partly supported (this won't work too well as we |
| don't control (so far) the size of underlying |
| Unix terminal |
| </entry> |
| </row> |
| <row> |
| <entry> |
| APIs for reading/writing screen-buffer content, |
| cursor position |
| </entry> |
| <entry>Not supported</entry> |
| <entry>Fully supported</entry> |
| <entry>Fully supported</entry> |
| </row> |
| <row> |
| <entry> |
| APIs for manipulating the rendering window size |
| </entry> |
| <entry>Not supported</entry> |
| <entry>Fully supported</entry> |
| <entry> |
| Partly supported (this won't work too well as we |
| don't control (so far) the size of underlying |
| Unix terminal |
| </entry> |
| </row> |
| <row> |
| <entry> |
| Signaling (in particular, Ctrl-C handling) |
| </entry> |
| <entry> |
| Nothing is done, which means that Ctrl-C will |
| generate (as usual) a |
| <constant>SIGINT</constant> which will terminate |
| the program. |
| </entry> |
| <entry> |
| Partly supported (Ctrl-C behaves as expected, |
| however the other Win32 CUI signaling isn't |
| properly implemented). |
| </entry> |
| <entry> |
| Partly supported (Ctrl-C behaves as expected, |
| however the other Win32 CUI signaling isn't |
| properly implemented). |
| </entry> |
| </row> |
| </tbody> |
| </tgroup> |
| </table> |
| </para> |
| |
| <para> |
| The Win32 objects behind a console can be created in |
| several occasions: |
| <itemizedlist> |
| <listitem> |
| <para> |
| When the program is started from wineconsole, a new |
| console object is created and will be used |
| (inherited) by the process launched from |
| wineconsole. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| When a program, which isn't attached to a console, |
| calls <function>AllocConsole</function>, Wine then |
| launches wineconsole, and attaches the current |
| program to this console. In this mode, the USER32 |
| mode is always selected as Wine cannot tell the |
| current state of the Unix console. |
| </para> |
| </listitem> |
| </itemizedlist> |
| </para> |
| <para> |
| Please also note, that starting a child process with the |
| <constant>CREATE_NEW_CONSOLE</constant> flag, will end-up |
| calling <function>AllocConsole</function> in the child |
| process, hence creating a wineconsole with the USER32 |
| backend. |
| </para> |
| </sect2> |
| </sect1> |
| |
| <sect1 id="initialization"> |
| |
| <title> The Wine initialization process </title> |
| |
| <para> |
| Wine has a rather complex startup procedure, so unlike many |
| programs the best place to begin exploring the code-base is |
| <emphasis>not</emphasis> in fact at the |
| <function>main()</function> function but instead at some of the |
| more straightforward DLLs that exist on the periphery such as |
| MSI, the widget library (in USER and COMCTL32) etc. The purpose |
| of this section is to document and explain how Wine starts up |
| from the moment the user runs "wine myprogram.exe" to the point |
| at which myprogram gets control. |
| </para> |
| |
| <sect2> |
| <title> First Steps </title> |
| |
| <para> |
| The actual wine binary that the user runs does not do very much, in fact it is only |
| responsible for checking the threading model in use (NPTL vs LinuxThreads) and then invoking |
| a new binary which performs the next stage in the startup sequence. See the threading chapter |
| for more information on this check and why it's necessary. You can find this code in |
| <filename>loader/glibc.c</filename>. The result of this check is an exec of either |
| wine-pthread or wine-kthread, potentially (on Linux) via |
| the <emphasis>preloader</emphasis>. We need to use separate binaries here because overriding |
| the native pthreads library requires us to exploit a property of ELF symbol fixup semantics: |
| it's not possible to do this without starting a new process. |
| </para> |
| |
| <para> |
| The Wine preloader is found in <filename>loader/preloader.c</filename>, and is required in |
| order to impose a Win32 style address space layout upon the newly created Win32 process. The |
| details of what this does is covered in the address space layout chapter. The preloader is a |
| statically linked ELF binary which is passed the name of the actual Wine binary to run (either |
| wine-kthread or wine-pthread) along with the arguments the user passed in from the command |
| line. The preloader is an unusual program: it does not have a main() function. In standard ELF |
| applications, the entry point is actually at a symbol named _start: this is provided by the |
| standard gcc infrastructure and normally jumps to <function>__libc_start_main</function> which |
| initializes glibc before passing control to the main function as defined by the programmer. |
| </para> |
| |
| <para> |
| The preloader takes control direct from the entry point for a few reasons. Firstly, it is |
| required that glibc is not initialized twice: the result of such behaviour is undefined and |
| subject to change without notice. Secondly, it's possible that as part of initializing glibc, |
| the address space layout could be changed - for instance, any call to malloc will initialize a |
| heap arena which modifies the VM mappings. Finally, glibc does not return to _start at any |
| point, so by reusing it we avoid the need to recreate the ELF bootstrap stack (env, argv, |
| auxiliary array etc). |
| </para> |
| |
| <para> |
| The preloader is responsible for two things: protecting important regions of the address |
| space so the dynamic linker does not map shared libraries into them, and once that is done |
| loading the real Wine binary off disk, linking it and starting it up. Normally all this is |
| done automatically by glibc and the kernel but as we intercepted this process by using a |
| static binary it's up to us to restart the process. The bulk of the code in the preloader is |
| about loading wine-[pk]thread and ld-linux.so.2 off disk, linking them together, then |
| starting the dynamic linking process. |
| </para> |
| |
| <para> |
| One of the last things the preloader does before jumping into the dynamic linker is scan the |
| symbol table of the loaded Wine binary and set the value of a global variable directly: this |
| is a more efficient way of passing information to the main Wine program than flattening the |
| data structures into an environment variable or command line parameter then unpacking it on |
| the other side, but it achieves pretty much the same thing. The global variable set points to |
| the preload descriptor table, which contains the VMA regions protected by the preloader. This |
| allows Wine to unmap them once the dynamic linker has been run, so leaving gaps we can |
| initialize properly later on. |
| </para> |
| |
| </sect2> |
| |
| <sect2> |
| <title> Starting the emulator </title> |
| |
| <para> |
| The process of starting up the emulator itself is mostly one of chaining through various |
| initializer functions defined in the core libraries and DLLs: libwine, then NTDLL, then kernel32. |
| </para> |
| |
| <para> |
| Both the wine-pthread and wine-kthread binaries share a common <function>main</function> |
| function, defined in <filename>loader/main.c</filename>, so no matter which binary is selected |
| after the preloader has run we start here. This passes the information provided by the |
| preloader into libwine and then calls wine_init, defined |
| in <filename>libs/wine/loader.c</filename>. This is where the emulation really starts: |
| <function>wine_init</function> can, with the correct preparation, |
| be called from programs other than the wine loader itself. |
| </para> |
| |
| <para> |
| <function>wine_init</function> does some very basic setup tasks such as initializing the |
| debugging infrastructure, yet more address space manipulation (see the information on the |
| 4G/4G VM split in the address space chapter), before loading NTDLL - the core of both Wine and |
| the Windows NT series - and jumping to the <function>__wine_process_init</function> function defined |
| in <filename>dlls/ntdll/loader.c</filename> |
| </para> |
| |
| <para> |
| This function is responsible for initializing the primary Win32 environment. In thread_init(), |
| it sets up the TEB, the wineserver connection for the main thread and the process heap. See |
| the threading chapter for more information on this. |
| </para> |
| |
| <para> |
| Finally, it loads and jumps to <function>__wine_kernel_init</function> in kernel32.dll: this |
| is defined in <filename>dlls/kernel32/process.c</filename>. This is where the bulk of the work |
| is done. The kernel32 initialization code retrieves the startup info for the process from the |
| server, initializes the registry, sets up the drive mapping system and locale data, then |
| begins loading the requested application itself. Each process has a STARTUPINFO block that can |
| be passed into <function>CreateProcess</function> specifying various things like how the first |
| window should be displayed: this is sent to the new process via the wineserver. |
| </para> |
| |
| <para> |
| After determining the type of file given to Wine by the user (a Win32 EXE file, a Win16 EXE, a |
| Winelib app etc), the program is loaded into memory (which may involve loading and |
| initializing other DLLs, the bulk of Wines startup code), before control reaches the end of |
| <function>__wine_kernel_init</function>. This function ends with the new process stack being |
| initialized, and start_process being called on the new stack. Nearly there! |
| </para> |
| |
| <para> |
| The final element of initializing Wine is starting the newly loaded program |
| itself. <function>start_process</function> sets up the SEH backstop handler, calls |
| <function>LdrInitializeThunk</function> which performs the last part of the process |
| initialization (such as performing relocations and calling the DllMains with PROCESS_ATTACH), |
| grabs the entry point of the executable and then on this line: |
| </para> |
| |
| <programlisting> |
| ExitProcess( entry( peb ) ); |
| </programlisting> |
| |
| <para> |
| ... jumps to the entry point of the program. At this point the users program is running and |
| the API provided by Wine is ready to be used. When entry returns, |
| the <function>ExitProcess</function> API will be used to initialize a graceful shutdown. |
| </para> |
| </sect2> |
| </sect1> |
| </chapter> |
| |
| <!-- Keep this comment at the end of the file |
| Local variables: |
| mode: sgml |
| sgml-parent-document:("wine-devel.sgml" "set" "book" "part" "chapter" "") |
| End: |
| --> |