1 /* autoload.cc: all dynamic load stuff.
3 Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Red Hat, Inc.
5 This file is part of Cygwin.
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
12 #include "miscfuncs.h"
13 #define USE_SYS_TYPES_FD_SET
16 bool NO_COPY wsock_started;
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.
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.
31 * So, immediately following the the call to one of the above routines
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
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
54 * extra init (4 bytes) Extra initialization function.
55 * DLL name (n bytes) asciz string containing the name of the DLL.
58 /* LoadDLLprime is used to prime the DLL info information, providing an
59 additional initialization routine to call prior to calling the first
61 #define LoadDLLprime(dllname, init_also) __asm__ (" \n\
62 .ifndef " #dllname "_primed \n\
63 .section .data_cygwin_nocopy,\"w\" \n\
65 ."#dllname "_info: \n\
66 .long _std_dll_init \n\
69 .long " #init_also " \n\
70 .asciz \"" #dllname "\" \n\
72 .set " #dllname "_primed, 1 \n\
76 /* Create a "decorated" name */
77 #define mangle(name, n) #name "@" #n
79 /* Standard DLL load macro. May invoke a fatal error if the function isn't
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)
88 /* Main DLL setup stuff. */
89 #define LoadDLLfuncEx3(name, n, dllname, notimp, err, fn) \
90 LoadDLLprime (dllname, dll_func_load) \
92 .section ." #dllname "_autoload_text,\"wx\" \n\
93 .global _" mangle (name, n) " \n\
94 .global _win32_" mangle (name, n) " \n\
96 _" mangle (name, n) ": \n\
97 _win32_" mangle (name, n) ": \n\
102 2:.long ." #dllname "_info \n\
103 .long (" #n "+" #notimp ") | (((" #err ") & 0xff) <<16) | (((" #fn ") & 0xff) << 24) \n\
104 .asciz \"" #name "\" \n\
108 /* DLL loader helper functions used during initialization. */
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
113 extern "C" void dll_func_load () __asm__ ("dll_func_load");
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");
125 .ascii \"couldn't dynamically determine load address for '%s' (handle %p), %E\\0\"\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\
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\
146 movl (%edx),%eax # Handle value \n\
148 leal 8(%edx),%eax # Location of name of function \n\
150 push $msg1 # The message \n\
151 call ___api_fatal # Print message. Never returns \n\
153 .globl 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\
164 jmp noload # Issue an error or return \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\
173 .global dll_chain \n\
175 pushl %eax # Restore 'return address' \n\
176 jmp *%edx # Jump to next init function \n\
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? */
193 struct dll_info *dll;
198 /* Mechanism for setting up info for passing to dll_chain routines. */
201 struct {long high; long low;};
205 /* The standard DLL initialization routine. */
206 __attribute__ ((used, noinline)) static long long
210 struct func_info *func = (struct func_info *) __builtin_return_address (0);
211 struct dll_info *dll = func->dll;
214 if (InterlockedIncrement (&dll->here))
217 InterlockedDecrement (&dll->here);
218 low_priority_sleep (0);
220 while (InterlockedIncrement (&dll->here));
221 else if (!dll->handle)
223 unsigned fpu_control = 0;
224 __asm__ __volatile__ ("fnstcw %0": "=m" (fpu_control));
225 if ((h = LoadLibrary (dll->name)) != NULL)
227 __asm__ __volatile__ ("fldcw %0": : "m" (fpu_control));
230 else if (!(func->decoration & 1))
231 api_fatal ("could not load %s, %E", dll->name);
233 dll->handle = INVALID_HANDLE_VALUE;
236 InterlockedDecrement (&dll->here);
238 /* Kludge alert. Redirects the return address to dll_chain. */
239 __asm__ __volatile__ (" \n\
240 movl $dll_chain,4(%ebp) \n\
243 /* Set "arguments for dll_chain. */
244 ret.low = (long) dll->init;
245 ret.high = (long) func;
249 /* Initialization function for winsock stuff. */
250 WSADATA NO_COPY wsadata;
251 __attribute__ ((used, noinline, regparm(1))) static long long
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;
258 while (InterlockedIncrement (&here))
260 InterlockedDecrement (&here);
261 low_priority_sleep (0);
266 int (*wsastartup) (int, WSADATA *);
268 /* Don't use autoload to load WSAStartup to eliminate recursion. */
269 wsastartup = (int (*)(int, WSADATA *))
270 GetProcAddress ((HMODULE) (dll->handle), "WSAStartup");
273 int res = wsastartup ((2<<8) | 2, &wsadata);
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);
288 /* Kludge alert. Redirects the return address to dll_chain. */
289 __asm__ __volatile__ (" \n\
290 movl $dll_chain,4(%ebp) \n\
293 InterlockedDecrement (&here);
295 volatile retchain ret;
296 /* Set "arguments for dll_chain. */
297 ret.low = (long) dll_func_load;
298 ret.high = (long) func;
302 LoadDLLprime (ws2_32, _wsock_init)
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)
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)
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)
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)
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)
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)
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)
410 LoadDLLfunc (CoTaskMemFree, 4, ole32)
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)
422 LoadDLLfunc (SHGetDesktopFolder, 4, shell32)
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)
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)
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)
453 LoadDLLfuncEx (UuidCreate, 4, rpcrt4, 1)
454 LoadDLLfuncEx (UuidCreateSequential, 4, rpcrt4, 1)
456 LoadDLLfuncEx2 (DnsQuery_A, 24, dnsapi, 1, 127) // ERROR_PROC_NOT_FOUND
457 LoadDLLfuncEx (DnsRecordListFree, 8, dnsapi, 1)