OSDN Git Service

* autoload.cc (WSAIoctl): Reintroduce.
[pf3gnuchains/pf3gnuchains4x.git] / winsup / cygwin / autoload.cc
1 /* autoload.cc: all dynamic load stuff.
2
3    Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Red Hat, Inc.
4
5 This file is part of Cygwin.
6
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
9 details. */
10
11 #include "winsup.h"
12 #include "miscfuncs.h"
13 #define USE_SYS_TYPES_FD_SET
14 #include <winsock2.h>
15
16 bool NO_COPY wsock_started;
17
18 /* Macro for defining "auto-load" functions.
19  * Note that this is self-modifying code *gasp*.
20  * The first invocation of a routine will trigger the loading of
21  * the DLL.  This will then be followed by the discovery of
22  * the procedure's entry point, which is placed into the location
23  * pointed to by the stack pointer.  This code then changes
24  * the "call" operand which invoked it to a "jmp" which will
25  * transfer directly to the DLL function on the next invocation.
26  *
27  * Subsequent calls to routines whose transfer address has not been
28  * determined will skip the "load the dll" step, starting at the
29  * "discovery of the entry point" step.
30  *
31  * So, immediately following the the call to one of the above routines
32  * we have:
33  *  DLL info (4 bytes)   Pointer to a block of information concerning
34  *                       the DLL (see below).
35  *  DLL args (4 bytes)   The number of arguments pushed on the stack by
36  *                       the call.  If this is an odd value then this
37  *                       is a flag that non-existence of this function
38  *                       is not a fatal error
39  *  func name (n bytes)  asciz string containing the name of the function
40  *                       to be loaded.
41  *
42  * The DLL info block consists of the following
43  *  load_state (4 bytes) Pointer to a word containing the routine used
44  *                       to eventually invoke the function.  Initially
45  *                       points to an init function which loads the
46  *                       DLL, gets the process's load address,
47  *                       changes the contents here to point to the
48  *                       function address, and changes the call *(%eax)
49  *                       to a jmp func.  If the initialization has been
50  *                       done, only the load part is done.
51  *  DLL handle (4 bytes) The handle to use when loading the DLL.
52  *  DLL locker (4 bytes) Word to use to avoid multi-thread access during
53  *                       initialization.
54  *  extra init (4 bytes) Extra initialization function.
55  *  DLL name (n bytes)   asciz string containing the name of the DLL.
56  */
57
58 /* LoadDLLprime is used to prime the DLL info information, providing an
59    additional initialization routine to call prior to calling the first
60    function.  */
61 #define LoadDLLprime(dllname, init_also) __asm__ ("     \n\
62 .ifndef " #dllname "_primed                             \n\
63   .section      .data_cygwin_nocopy,\"w\"               \n\
64   .align        4                                       \n\
65 ."#dllname "_info:                                      \n\
66   .long         _std_dll_init                           \n\
67   .long         0                                       \n\
68   .long         -1                                      \n\
69   .long         " #init_also "                          \n\
70   .asciz        \"" #dllname "\"                        \n\
71   .text                                                 \n\
72   .set          " #dllname "_primed, 1                  \n\
73 .endif                                                  \n\
74 ");
75
76 /* Create a "decorated" name */
77 #define mangle(name, n) #name "@" #n
78
79 /* Standard DLL load macro.  May invoke a fatal error if the function isn't
80    found. */
81 #define LoadDLLfunc(name, n, dllname) \
82   LoadDLLfuncEx (name, n, dllname, 0)
83 #define LoadDLLfuncEx(name, n, dllname, notimp) \
84   LoadDLLfuncEx2(name, n, dllname, notimp, 0)
85 #define LoadDLLfuncEx2(name, n, dllname, notimp, err) \
86   LoadDLLfuncEx3(name, n, dllname, notimp, err, 0)
87
88 /* Main DLL setup stuff. */
89 #define LoadDLLfuncEx3(name, n, dllname, notimp, err, fn) \
90   LoadDLLprime (dllname, dll_func_load)                 \
91   __asm__ ("                                            \n\
92   .section      ." #dllname "_autoload_text,\"wx\"      \n\
93   .global       _" mangle (name, n) "                   \n\
94   .global       _win32_" mangle (name, n) "             \n\
95   .align        8                                       \n\
96 _" mangle (name, n) ":                                  \n\
97 _win32_" mangle (name, n) ":                            \n\
98   .byte         0xe9                                    \n\
99   .long         -4 + 1f - .                             \n\
100 1:movl          (2f),%eax                               \n\
101    call         *(%eax)                                 \n\
102 2:.long         ." #dllname "_info                      \n\
103    .long                (" #n "+" #notimp ") | (((" #err ") & 0xff) <<16) | (((" #fn ") & 0xff) << 24)  \n\
104    .asciz       \"" #name "\"                           \n\
105    .text                                                        \n\
106 ");
107
108 /* DLL loader helper functions used during initialization. */
109
110 /* The function which finds the address, given the name and overwrites
111    the call so that future invocations go straight to the function in
112    the DLL. */
113 extern "C" void dll_func_load () __asm__ ("dll_func_load");
114
115 /* Called by the primary initialization function "init_std_dll" to
116    setup the stack and eliminate future calls to init_std_dll for other
117    functions from this DLL.  */
118 extern "C" void dll_chain () __asm__ ("dll_chain");
119
120 extern "C" {
121
122 __asm__ ("                                                              \n\
123          .text                                                          \n\
124 msg1:                                                                   \n\
125         .ascii  \"couldn't dynamically determine load address for '%s' (handle %p), %E\\0\"\n\
126                                                                         \n\
127         .align  32                                                      \n\
128 noload:                                                                 \n\
129         popl    %edx            # Get the address of the information block\n\
130         movl    4(%edx),%eax    # Should we 'ignore' the lack           \n\
131         test    $1,%eax         #  of this function?                    \n\
132         jz      1f              # Nope.                                 \n\
133         decl    %eax            # Yes.  This is the # of bytes + 1      \n\
134         popl    %edx            # Caller's caller                       \n\
135         addl    %eax,%esp       # Pop off bytes                         \n\
136         andl    $0xffff0000,%eax# upper word                            \n\
137         subl    %eax,%esp       # adjust for possible return value      \n\
138         pushl   %eax            # Save for later                        \n\
139         movl    $127,%eax       # ERROR_PROC_NOT_FOUND                  \n\
140         pushl   %eax            # First argument                        \n\
141         call    _SetLastError@4 # Set it                                \n\
142         popl    %eax            # Get back argument                     \n\
143         sarl    $16,%eax        # return value in high order word       \n\
144         jmp     *%edx           # Return                                \n\
145 1:                                                                      \n\
146         movl    (%edx),%eax     # Handle value                          \n\
147         pushl   4(%eax)                                                 \n\
148         leal    8(%edx),%eax    # Location of name of function          \n\
149         push    %eax                                                    \n\
150         push    $msg1           # The message                           \n\
151         call    ___api_fatal    # Print message. Never returns          \n\
152                                                                         \n\
153         .globl  dll_func_load                                           \n\
154 dll_func_load:                                                          \n\
155         movl    (%esp),%eax     # 'Return address' contains load info   \n\
156         addl    $8,%eax         # Address of name of function to load   \n\
157         pushl   %eax            # Second argument                       \n\
158         movl    -8(%eax),%eax   # Where handle lives                    \n\
159         movl    4(%eax),%eax    # Address of Handle to DLL              \n\
160         pushl   %eax            # Handle to DLL                         \n\
161         call    _GetProcAddress@8# Load it                              \n\
162         test    %eax,%eax       # Success?                              \n\
163         jne     gotit           # Yes                                   \n\
164         jmp     noload          # Issue an error or return              \n\
165 gotit:                                                                  \n\
166         popl    %edx            # Pointer to 'return address'           \n\
167         subl    %edx,%eax       # Make it relative                      \n\
168         addl    $7,%eax         # Tweak                                 \n\
169         subl    $12,%edx        # Point to jmp                          \n\
170         movl    %eax,1(%edx)    # Move relative address after jump      \n\
171         jmp     *%edx           # Jump to actual function               \n\
172                                                                         \n\
173         .global dll_chain                                               \n\
174 dll_chain:                                                              \n\
175         pushl   %eax            # Restore 'return address'              \n\
176         jmp     *%edx           # Jump to next init function            \n\
177 ");
178
179 /* C representations of the two info blocks described above.
180    FIXME: These structures confuse gdb for some reason.  GDB can print
181    the whole structure but has problems with the name field? */
182 struct dll_info
183 {
184   DWORD load_state;
185   HANDLE handle;
186   LONG here;
187   void (*init) ();
188   char name[];
189 };
190
191 struct func_info
192 {
193   struct dll_info *dll;
194   LONG decoration;
195   char name[];
196 };
197
198 /* Mechanism for setting up info for passing to dll_chain routines. */
199 union retchain
200 {
201   struct {long high; long low;};
202   long long ll;
203 };
204
205 /* The standard DLL initialization routine. */
206 __attribute__ ((used, noinline)) static long long
207 std_dll_init ()
208 {
209   HANDLE h;
210   struct func_info *func = (struct func_info *) __builtin_return_address (0);
211   struct dll_info *dll = func->dll;
212   retchain ret;
213
214   if (InterlockedIncrement (&dll->here))
215     do
216       {
217         InterlockedDecrement (&dll->here);
218         low_priority_sleep (0);
219       }
220     while (InterlockedIncrement (&dll->here));
221   else if (!dll->handle)
222     {
223       unsigned fpu_control = 0;
224       __asm__ __volatile__ ("fnstcw %0": "=m" (fpu_control));
225       if ((h = LoadLibrary (dll->name)) != NULL)
226         {
227           __asm__ __volatile__ ("fldcw %0": : "m" (fpu_control));
228           dll->handle = h;
229         }
230       else if (!(func->decoration & 1))
231         api_fatal ("could not load %s, %E", dll->name);
232       else
233         dll->handle = INVALID_HANDLE_VALUE;
234     }
235
236   InterlockedDecrement (&dll->here);
237
238   /* Kludge alert.  Redirects the return address to dll_chain. */
239   __asm__ __volatile__ ("               \n\
240         movl    $dll_chain,4(%ebp)      \n\
241   ");
242
243   /* Set "arguments for dll_chain. */
244   ret.low = (long) dll->init;
245   ret.high = (long) func;
246   return ret.ll;
247 }
248
249 /* Initialization function for winsock stuff. */
250 WSADATA NO_COPY wsadata;
251 __attribute__ ((used, noinline, regparm(1))) static long long
252 wsock_init ()
253 {
254   static LONG NO_COPY here = -1L;
255   struct func_info *func = (struct func_info *) __builtin_return_address (0);
256   struct dll_info *dll = func->dll;
257
258   while (InterlockedIncrement (&here))
259     {
260       InterlockedDecrement (&here);
261       low_priority_sleep (0);
262     }
263
264   if (!wsock_started)
265     {
266       int (*wsastartup) (int, WSADATA *);
267
268       /* Don't use autoload to load WSAStartup to eliminate recursion. */
269       wsastartup = (int (*)(int, WSADATA *))
270                    GetProcAddress ((HMODULE) (dll->handle), "WSAStartup");
271       if (wsastartup)
272         {
273           int res = wsastartup ((2<<8) | 2, &wsadata);
274
275           debug_printf ("res %d", res);
276           debug_printf ("wVersion %d", wsadata.wVersion);
277           debug_printf ("wHighVersion %d", wsadata.wHighVersion);
278           debug_printf ("szDescription %s", wsadata.szDescription);
279           debug_printf ("szSystemStatus %s", wsadata.szSystemStatus);
280           debug_printf ("iMaxSockets %d", wsadata.iMaxSockets);
281           debug_printf ("iMaxUdpDg %d", wsadata.iMaxUdpDg);
282           debug_printf ("lpVendorInfo %d", wsadata.lpVendorInfo);
283
284           wsock_started = 1;
285         }
286     }
287
288   /* Kludge alert.  Redirects the return address to dll_chain. */
289   __asm__ __volatile__ ("               \n\
290         movl    $dll_chain,4(%ebp)      \n\
291   ");
292
293   InterlockedDecrement (&here);
294
295   volatile retchain ret;
296   /* Set "arguments for dll_chain. */
297   ret.low = (long) dll_func_load;
298   ret.high = (long) func;
299   return ret.ll;
300 }
301
302 LoadDLLprime (ws2_32, _wsock_init)
303
304 /* 127 == ERROR_PROC_NOT_FOUND */
305 LoadDLLfuncEx2 (DsGetDcNameW, 24, netapi32, 1, 127)
306 LoadDLLfunc (NetApiBufferFree, 4, netapi32)
307 LoadDLLfuncEx (NetGetAnyDCName, 12, netapi32, 1)
308 LoadDLLfuncEx (NetGetDCName, 12, netapi32, 1)
309 LoadDLLfunc (NetLocalGroupEnum, 28, netapi32)
310 LoadDLLfunc (NetLocalGroupGetMembers, 32, netapi32)
311 LoadDLLfunc (NetUserGetGroups, 28, netapi32)
312 LoadDLLfunc (NetUserGetInfo, 16, netapi32)
313
314 /* 0xc000007a == STATUS_PROCEDURE_NOT_FOUND */
315 #define LoadDLLfuncNt(name, n, dllname) \
316   LoadDLLfuncEx2(name, n, dllname, 1, 0xc000007a)
317 LoadDLLfuncNt (NtCommitTransaction, 8, ntdll)
318 LoadDLLfuncNt (NtCreateTransaction, 40, ntdll)
319 LoadDLLfuncNt (NtRollbackTransaction, 8, ntdll)
320 LoadDLLfuncNt (RtlGetCurrentTransaction, 0, ntdll)
321 LoadDLLfuncNt (RtlSetCurrentTransaction, 4, ntdll)
322
323 LoadDLLfuncEx (EnumProcessModules, 16, psapi, 1)
324 LoadDLLfuncEx (GetModuleFileNameExW, 16, psapi, 1)
325 LoadDLLfuncEx (GetModuleInformation, 16, psapi, 1)
326 LoadDLLfuncEx (GetProcessMemoryInfo, 12, psapi, 1)
327 LoadDLLfuncEx (QueryWorkingSet, 12, psapi, 1)
328
329 LoadDLLfuncEx (LsaDeregisterLogonProcess, 4, secur32, 1)
330 LoadDLLfuncEx (LsaFreeReturnBuffer, 4, secur32, 1)
331 LoadDLLfuncEx (LsaLogonUser, 56, secur32, 1)
332 LoadDLLfuncEx (LsaLookupAuthenticationPackage, 12, secur32, 1)
333 LoadDLLfuncEx (LsaRegisterLogonProcess, 12, secur32, 1)
334
335 LoadDLLfunc (CharNextExA, 12, user32)
336 LoadDLLfunc (CloseClipboard, 0, user32)
337 LoadDLLfunc (CloseDesktop, 4, user32)
338 LoadDLLfunc (CloseWindowStation, 4, user32)
339 LoadDLLfunc (CreateDesktopW, 24, user32)
340 LoadDLLfunc (CreateWindowExA, 48, user32)
341 LoadDLLfunc (CreateWindowStationW, 16, user32)
342 LoadDLLfunc (DefWindowProcA, 16, user32)
343 LoadDLLfunc (DispatchMessageA, 4, user32)
344 LoadDLLfunc (EmptyClipboard, 0, user32)
345 LoadDLLfunc (FindWindowA, 8, user32)
346 LoadDLLfunc (GetClipboardData, 4, user32)
347 LoadDLLfunc (GetForegroundWindow, 0, user32)
348 LoadDLLfunc (GetKeyboardLayout, 4, user32)
349 LoadDLLfunc (GetMessageA, 16, user32)
350 LoadDLLfunc (GetPriorityClipboardFormat, 8, user32)
351 LoadDLLfunc (GetProcessWindowStation, 0, user32)
352 LoadDLLfunc (GetThreadDesktop, 4, user32)
353 LoadDLLfunc (GetWindowThreadProcessId, 8, user32)
354 LoadDLLfunc (GetUserObjectInformationW, 20, user32)
355 LoadDLLfunc (MessageBeep, 4, user32)
356 LoadDLLfunc (MessageBoxA, 16, user32)
357 LoadDLLfunc (MsgWaitForMultipleObjects, 20, user32)
358 LoadDLLfunc (OpenClipboard, 4, user32)
359 LoadDLLfunc (PeekMessageA, 20, user32)
360 LoadDLLfunc (PostMessageA, 16, user32)
361 LoadDLLfunc (PostQuitMessage, 4, user32)
362 LoadDLLfunc (RegisterClassA, 4, user32)
363 LoadDLLfunc (RegisterClipboardFormatA, 4, user32)
364 LoadDLLfunc (SendMessageA, 16, user32)
365 LoadDLLfunc (SetClipboardData, 8, user32)
366 LoadDLLfunc (SetThreadDesktop, 4, user32)
367 LoadDLLfunc (SetProcessWindowStation, 4, user32)
368
369 LoadDLLfunc (accept, 12, ws2_32)
370 LoadDLLfunc (bind, 12, ws2_32)
371 LoadDLLfunc (closesocket, 4, ws2_32)
372 LoadDLLfunc (connect, 12, ws2_32)
373 LoadDLLfunc (gethostbyaddr, 12, ws2_32)
374 LoadDLLfunc (gethostbyname, 4, ws2_32)
375 LoadDLLfuncEx2 (gethostname, 8, ws2_32, 1, 1)
376 LoadDLLfunc (getpeername, 12, ws2_32)
377 LoadDLLfunc (getprotobyname, 4, ws2_32)
378 LoadDLLfunc (getprotobynumber, 4, ws2_32)
379 LoadDLLfunc (getservbyname, 8, ws2_32)
380 LoadDLLfunc (getservbyport, 8, ws2_32)
381 LoadDLLfunc (getsockname, 12, ws2_32)
382 LoadDLLfunc (getsockopt, 20, ws2_32)
383 LoadDLLfunc (ioctlsocket, 12, ws2_32)
384 LoadDLLfunc (listen, 8, ws2_32)
385 LoadDLLfunc (setsockopt, 20, ws2_32)
386 LoadDLLfunc (shutdown, 8, ws2_32)
387 LoadDLLfunc (socket, 12, ws2_32)
388 LoadDLLfunc (WSAAsyncSelect, 16, ws2_32)
389 LoadDLLfunc (WSAEnumNetworkEvents, 12, ws2_32)
390 LoadDLLfunc (WSAEventSelect, 12, ws2_32)
391 LoadDLLfunc (WSAGetLastError, 0, ws2_32)
392 LoadDLLfunc (WSAIoctl, 36, ws2_32)
393 LoadDLLfunc (WSARecvFrom, 36, ws2_32)
394 LoadDLLfunc (WSASendMsg, 24, ws2_32)
395 LoadDLLfunc (WSASendTo, 36, ws2_32)
396 LoadDLLfunc (WSASetLastError, 4, ws2_32)
397 // LoadDLLfunc (WSAStartup, 8, ws2_32)
398 LoadDLLfunc (WSAWaitForMultipleEvents, 20, ws2_32)
399
400 // 50 = ERROR_NOT_SUPPORTED.  Returned if OS doesn't supprot iphlpapi funcs
401 LoadDLLfuncEx2 (GetAdaptersAddresses, 20, iphlpapi, 1, 50)
402 LoadDLLfuncEx2 (GetExtendedTcpTable, 24, iphlpapi, 1, 50)
403 LoadDLLfuncEx2 (GetIfEntry, 4, iphlpapi, 1, 50)
404 LoadDLLfuncEx2 (GetIpAddrTable, 12, iphlpapi, 1, 50)
405 LoadDLLfuncEx2 (GetIpForwardTable, 12, iphlpapi, 1, 50)
406 LoadDLLfuncEx2 (GetNetworkParams, 8, iphlpapi, 1, 50)
407 LoadDLLfuncEx2 (GetTcpTable, 12, iphlpapi, 1, 50)
408 LoadDLLfuncEx2 (SendARP, 16, iphlpapi, 1, 50)
409
410 LoadDLLfunc (CoTaskMemFree, 4, ole32)
411
412 LoadDLLfuncEx (FindFirstVolumeA, 8, kernel32, 1)
413 LoadDLLfuncEx (FindNextVolumeA, 12, kernel32, 1)
414 LoadDLLfuncEx (FindVolumeClose, 4, kernel32, 1)
415 LoadDLLfuncEx (GetConsoleWindow, 0, kernel32, 1)
416 LoadDLLfuncEx (GetSystemWindowsDirectoryW, 8, kernel32, 1)
417 LoadDLLfuncEx (GetVolumeNameForVolumeMountPointA, 12, kernel32, 1)
418 LoadDLLfuncEx (GetSystemDEPPolicy, 0, kernel32, 1)
419 LoadDLLfuncEx (GetProcessDEPPolicy, 12, kernel32, 1)
420 LoadDLLfuncEx (SetProcessDEPPolicy, 4, kernel32, 1)
421
422 LoadDLLfunc (SHGetDesktopFolder, 4, shell32)
423
424 LoadDLLfuncEx (waveOutGetNumDevs, 0, winmm, 1)
425 LoadDLLfuncEx (waveOutOpen, 24, winmm, 1)
426 LoadDLLfuncEx (waveOutReset, 4, winmm, 1)
427 LoadDLLfuncEx (waveOutClose, 4, winmm, 1)
428 LoadDLLfuncEx (waveOutGetVolume, 8, winmm, 1)
429 LoadDLLfuncEx (waveOutSetVolume, 8, winmm, 1)
430 LoadDLLfuncEx (waveOutUnprepareHeader, 12, winmm, 1)
431 LoadDLLfuncEx (waveOutPrepareHeader, 12, winmm, 1)
432 LoadDLLfuncEx (waveOutWrite, 12, winmm, 1)
433 LoadDLLfuncEx (timeGetDevCaps, 8, winmm, 1)
434 LoadDLLfuncEx (timeGetTime, 0, winmm, 1)
435 LoadDLLfuncEx (timeBeginPeriod, 4, winmm, 1)
436 LoadDLLfuncEx (timeEndPeriod, 4, winmm, 1)
437
438 LoadDLLfuncEx (waveInGetNumDevs, 0, winmm, 1)
439 LoadDLLfuncEx (waveInOpen, 24, winmm, 1)
440 LoadDLLfuncEx (waveInUnprepareHeader, 12, winmm, 1)
441 LoadDLLfuncEx (waveInPrepareHeader, 12, winmm, 1)
442 LoadDLLfuncEx (waveInAddBuffer, 12, winmm, 1)
443 LoadDLLfuncEx (waveInStart, 4, winmm, 1)
444 LoadDLLfuncEx (waveInReset, 4, winmm, 1)
445 LoadDLLfuncEx (waveInClose, 4, winmm, 1)
446
447 LoadDLLfunc (WNetGetProviderNameA, 12, mpr)
448 LoadDLLfunc (WNetGetResourceInformationA, 16, mpr)
449 LoadDLLfunc (WNetOpenEnumA, 20, mpr)
450 LoadDLLfunc (WNetEnumResourceA, 16, mpr)
451 LoadDLLfunc (WNetCloseEnum, 4, mpr)
452
453 LoadDLLfuncEx (UuidCreate, 4, rpcrt4, 1)
454 LoadDLLfuncEx (UuidCreateSequential, 4, rpcrt4, 1)
455
456 LoadDLLfuncEx2 (DnsQuery_A, 24, dnsapi, 1, 127) // ERROR_PROC_NOT_FOUND
457 LoadDLLfuncEx (DnsRecordListFree, 8, dnsapi, 1)
458 }