Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-cw
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-cw
Commits
b9c86719
Commit
b9c86719
authored
Jun 15, 2004
by
Mike Hearn
Committed by
Alexandre Julliard
Jun 15, 2004
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add documentation on the Wine initialization process.
parent
06a60621
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
148 additions
and
7 deletions
+148
-7
architecture.sgml
documentation/architecture.sgml
+143
-0
threading.sgml
documentation/threading.sgml
+3
-3
wine-devel.sgml
documentation/wine-devel.sgml
+2
-4
No files found.
documentation/architecture.sgml
View file @
b9c86719
...
...
@@ -1947,6 +1947,149 @@ WSOCK32.DLL: 32-bit sockets APIs
</sect1>
</chapter>
<chapter 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 main() 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>
<sect1>
<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>
</sect1>
<sect1>
<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>
</sect1>
</chapter>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
...
...
documentation/threading.sgml
View file @
b9c86719
...
...
@@ -19,8 +19,8 @@
<title> Threading support in Win32 </title>
<para>
Win32 is an unusually thread friendly API. Not only is i
n
entirely thread safe, but it provides
many different facilities
to
working with threads. These range from the basics such as starting
Win32 is an unusually thread friendly API. Not only is i
t
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>
...
...
@@ -33,7 +33,7 @@
<para>
Win32 provides many different ways you can make your code thread safe however the most common
are
the
<emphasis>critical section</emphasis> and the <emphasis>interlocked functions</emphasis>.
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
EnterCriticalSection and LeaveCriticalSection. The first call to EnterCriticalSection by a thread
...
...
documentation/wine-devel.sgml
View file @
b9c86719
...
...
@@ -26,9 +26,7 @@
<bookinfo>
<title>Wine Developer's Guide</title>
<!-- Until we learn how to format this thing nicely,
we can't really incude it -->
<!--authorgroup>
<authorgroup>
<author>
<firstname>Uwe</firstname>
<surname>Bonnes</surname>
...
...
@@ -109,7 +107,7 @@
<firstname>Morten</firstname>
<surname>Welinder</surname>
</author>
</authorgroup
--
>
</authorgroup>
</bookinfo>
<part id="part-one">
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment