📄 autoload.cc
字号:
/* autoload.cc: all dynamic load stuff. Copyright 2000, 2001, 2002 Red Hat, Inc.This file is part of Cygwin.This software is a copyrighted work licensed under the terms of theCygwin license. Please consult the file "CYGWIN_LICENSE" fordetails. */#include "winsup.h"#define USE_SYS_TYPES_FD_SET#include <winsock2.h>/* Macro for defining "auto-load" functions. * Note that this is self-modifying code *gasp*. * The first invocation of a routine will trigger the loading of * the DLL. This will then be followed by the discovery of * the procedure's entry point, which is placed into the location * pointed to by the stack pointer. This code then changes * the "call" operand which invoked it to a "jmp" which will * transfer directly to the DLL function on the next invocation. * * Subsequent calls to routines whose transfer address has not been * determined will skip the "load the dll" step, starting at the * "discovery of the entry point" step. * * So, immediately following the the call to one of the above routines * we have: * DLL info (4 bytes) Pointer to a block of information concerning * the DLL (see below). * DLL args (4 bytes) The number of arguments pushed on the stack by * the call. If this is an odd value then this * is a flag that non-existence of this function * is not a fatal error * func name (n bytes) asciz string containing the name of the function * to be loaded. * * The DLL info block consists of the following * load_state (4 bytes) Pointer to a word containing the routine used * to eventually invoke the function. Initially * points to an init function which loads the * DLL, gets the process's load address, * changes the contents here to point to the * function address, and changes the call *(%eax) * to a jmp func. If the initialization has been * done, only the load part is done. * DLL handle (4 bytes) The handle to use when loading the DLL. * DLL locker (4 bytes) Word to use to avoid multi-thread access during * initialization. * extra init (4 bytes) Extra initialization function. * DLL name (n bytes) asciz string containing the name of the DLL. *//* LoadDLLprime is used to prime the DLL info information, providing an additional initialization routine to call prior to calling the first function. */#define LoadDLLprime(dllname, init_also) __asm__ (" \n\ .section ." #dllname "_info,\"w\" \n\ .linkonce \n\ .long std_dll_init \n\ .long 0 \n\ .long -1 \n\ .long " #init_also " \n\ .asciz \"" #dllname "\" \n\ .text \n\");/* Create a "decorated" name */#define mangle(name, n) #name "@" #n/* Standard DLL load macro. Invokes a fatal warning if the function isn't found. */#define LoadDLLfunc(name, n, dllname) LoadDLLfuncEx (name, n, dllname, 0)#define LoadDLLfuncEx(name, n, dllname, notimp) LoadDLLfuncEx2(name, n, dllname, notimp, 0)/* Main DLL setup stuff. */#define LoadDLLfuncEx2(name, n, dllname, notimp, err) \ LoadDLLprime (dllname, dll_func_load) \ __asm__ (" \n\ .section ." #dllname "_text,\"wx\" \n\ .global _" mangle (name, n) " \n\ .global _win32_" mangle (name, n) " \n\ .align 8 \n\_" mangle (name, n) ": \n\_win32_" mangle (name, n) ": \n\ .byte 0xe9 \n\ .long -4 + 1f - . \n\1:movl (2f),%eax \n\ call *(%eax) \n\2:.long ." #dllname "_info \n\ .long (" #n "+" #notimp ") | " #err "<<16 \n\ .asciz \"" #name "\" \n\ .text \n\");/* DLL loader helper functions used during initialization. *//* The function which finds the address, given the name and overwrites the call so that future invocations go straight to the function in the DLL. */extern "C" void dll_func_load () __asm__ ("dll_func_load");/* Called by the primary initialization function "init_std_dll" to setup the stack and eliminate future calls to init_std_dll for other functions from this DLL. */extern "C" void dll_chain () __asm__ ("dll_chain");/* called by the secondary initialization function to call dll_func_load. */extern "C" void dll_chain1 () __asm__ ("dll_chain1");extern "C" {/* FIXME: This is not thread-safe? */__asm__ (" \n\msg1: \n\ .ascii \"couldn't dynamically determine load address for '%s' (handle %p), %E\\0\"\n\ \n\ .align 32 \n\noload: \n\ popl %edx # Get the address of the information block\n\ movl 4(%edx),%eax # Should we 'ignore' the lack \n\ test $1,%eax # of this function? \n\ jz 1f # Nope. \n\ decl %eax # Yes. This is the # of bytes + 1 \n\ popl %edx # Caller's caller \n\ addl %eax,%esp # Pop off bytes \n\ andl $0xffff0000,%eax# upper word \n\ subl %eax,%esp # adjust for possible return value \n\ pushl %eax # Save for later \n\ movl $127,%eax # ERROR_PROC_NOT_FOUND \n\ pushl %eax # First argument \n\ call _SetLastError@4 # Set it \n\ popl %eax # Get back argument \n\ shrl $16,%eax # return value in high order word \n\ jmp *%edx # Return \n\1: \n\ movl (%edx),%eax # Handle value \n\ pushl 4(%eax) \n\ leal 8(%edx),%eax # Location of name of function \n\ push %eax \n\ push $msg1 # The message \n\ call ___api_fatal # Print message. Never returns \n\ \n\ .globl dll_func_load \n\dll_func_load: \n\ movl (%esp),%eax # 'Return address' contains load info \n\ addl $8,%eax # Address of name of function to load \n\ pushl %eax # Second argument \n\ movl -8(%eax),%eax # Where handle lives \n\ movl 4(%eax),%eax # Address of Handle to DLL \n\ pushl %eax # Handle to DLL \n\ call _GetProcAddress@8# Load it \n\ test %eax,%eax # Success? \n\ jne gotit # Yes \n\ jmp noload # Issue an error or return \n\gotit: \n\ popl %edx # Pointer to 'return address' \n\ subl %edx,%eax # Make it relative \n\ addl $7,%eax # Tweak \n\ subl $12,%edx # Point to jmp \n\ movl %eax,1(%edx) # Move relative address after jump \n\ jmp *%edx # Jump to actual function \n\ \n\ .global dll_chain \n\dll_chain: \n\ pushl %eax # Restore 'return address' \n\ movl (%eax),%eax # Get address of DLL info block \n\ movl $dll_func_load,(%eax) # Just load func now \n\ jmp *%edx # Jump to next init function \n\ \n\dll_chain1: \n\ pushl %eax # Restore 'return address' \n\ jmp *%edx # Jump to next init function \n\");/* C representations of the two info blocks described above. FIXME: These structures confuse gdb for some reason. GDB can print the whole structure but has problems with the name field? */struct dll_info{ DWORD load_state; HANDLE handle; LONG here; void (*init) (); char name[];};struct func_info{ struct dll_info *dll; LONG decoration; char name[];};/* Mechanism for setting up info for passing to dll_chain routines. */union retchain{ struct {long high; long low;}; long long ll;};/* The standard DLL initialization routine. */static long long std_dll_init () __asm__ ("std_dll_init") __attribute__ ((unused));static long longstd_dll_init (){ HANDLE h; struct func_info *func = (struct func_info *) __builtin_return_address (0); struct dll_info *dll = func->dll; retchain ret; if (InterlockedIncrement (&dll->here)) do { InterlockedDecrement (&dll->here); low_priority_sleep (0); } while (InterlockedIncrement (&dll->here)); else if (!dll->handle) { if ((h = LoadLibrary (dll->name)) != NULL) dll->handle = h; else if (!(func->decoration & 1)) api_fatal ("could not load %s, %E", dll->name); else dll->handle = INVALID_HANDLE_VALUE; } InterlockedDecrement (&dll->here); /* Kludge alert. Redirects the return address to dll_chain. */ __asm__ __volatile__ (" \n\ movl $dll_chain,4(%ebp) \n\ "); /* Set "arguments for dll_chain. */ ret.low = (long) dll->init; ret.high = (long) func; return ret.ll;}/* Initialization function for winsock stuff. */static long long wsock_init () __asm__ ("wsock_init") __attribute__ ((unused, regparm(1)));bool NO_COPY wsock_started = 0;static long longwsock_init (){ static LONG NO_COPY here = -1L; struct func_info *func = (struct func_info *) __builtin_return_address (0); struct dll_info *dll = func->dll; __asm__ (" \n\ .section .ws2_32_info \n\ .equ _ws2_32_handle,.ws2_32_info + 4 \n\ .global _ws2_32_handle \n\ .section .wsock32_info \n\ .equ _wsock32_handle,.wsock32_info + 4 \n\ .global _wsock32_handle \n\ .text \n\
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -