kernel32: Move LoadLibrary functions to kernelbase.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2019-10-03 19:41:40 +02:00
parent a5d45e9ae5
commit c5dc41e980
4 changed files with 307 additions and 276 deletions

View File

@ -528,7 +528,7 @@
@ stdcall -import FreeEnvironmentStringsA(ptr)
@ stdcall -import FreeEnvironmentStringsW(ptr)
@ stub -i386 FreeLSCallback
@ stdcall FreeLibrary(long)
@ stdcall -import FreeLibrary(long)
@ stdcall FreeLibraryAndExitThread(long long)
@ stdcall FreeLibraryWhenCallbackReturns(ptr ptr) ntdll.TpCallbackUnloadDllOnCompletion
@ stdcall -import FreeResource(long)
@ -1042,10 +1042,10 @@
@ stdcall LeaveCriticalSection(ptr) ntdll.RtlLeaveCriticalSection
@ stdcall LeaveCriticalSectionWhenCallbackReturns(ptr ptr) ntdll.TpCallbackLeaveCriticalSectionOnCompletion
# @ stub LoadAppInitDlls
@ stdcall LoadLibraryA(str)
@ stdcall LoadLibraryExA( str long long)
@ stdcall LoadLibraryExW(wstr long long)
@ stdcall LoadLibraryW(wstr)
@ stdcall -import LoadLibraryA(str)
@ stdcall -import LoadLibraryExA( str long long)
@ stdcall -import LoadLibraryExW(wstr long long)
@ stdcall -import LoadLibraryW(wstr)
@ stdcall LoadModule(str ptr)
@ stdcall -import LoadResource(long long)
# @ stub LoadStringBaseExW

View File

@ -47,16 +47,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(module);
#define NE_FFLAGS_LIBMODULE 0x8000
/* to keep track of LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE file handles */
struct exclusive_datafile
{
struct list entry;
HMODULE module;
HANDLE file;
};
static struct list exclusive_datafile_list = LIST_INIT( exclusive_datafile_list );
/****************************************************************************
* GetDllDirectoryA (KERNEL32.@)
@ -283,261 +273,6 @@ BOOL WINAPI GetBinaryTypeA( LPCSTR lpApplicationName, LPDWORD lpBinaryType )
return GetBinaryTypeW(NtCurrentTeb()->StaticUnicodeString.Buffer, lpBinaryType);
}
/******************************************************************
* load_library_as_datafile
*/
static BOOL load_library_as_datafile( LPCWSTR load_path, DWORD flags, LPCWSTR name, HMODULE *hmod )
{
static const WCHAR dotDLL[] = {'.','d','l','l',0};
WCHAR filenameW[MAX_PATH];
HANDLE hFile = INVALID_HANDLE_VALUE;
HANDLE mapping;
HMODULE module = 0;
DWORD protect = PAGE_READONLY;
DWORD sharing = FILE_SHARE_READ | FILE_SHARE_DELETE;
*hmod = 0;
if (flags & LOAD_LIBRARY_AS_IMAGE_RESOURCE) protect |= SEC_IMAGE;
if (SearchPathW( load_path, name, dotDLL, ARRAY_SIZE( filenameW ), filenameW, NULL ))
{
hFile = CreateFileW( filenameW, GENERIC_READ, sharing, NULL, OPEN_EXISTING, 0, 0 );
}
if (hFile == INVALID_HANDLE_VALUE) return FALSE;
mapping = CreateFileMappingW( hFile, NULL, protect, 0, 0, NULL );
if (!mapping) goto failed;
module = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
CloseHandle( mapping );
if (!module) goto failed;
if (!(flags & LOAD_LIBRARY_AS_IMAGE_RESOURCE))
{
/* make sure it's a valid PE file */
if (!RtlImageNtHeader( module )) goto failed;
*hmod = (HMODULE)((char *)module + 1); /* set bit 0 for data file module */
if (flags & LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE)
{
struct exclusive_datafile *file = HeapAlloc( GetProcessHeap(), 0, sizeof(*file) );
if (!file) goto failed;
file->module = *hmod;
file->file = hFile;
list_add_head( &exclusive_datafile_list, &file->entry );
TRACE( "delaying close %p for module %p\n", file->file, file->module );
return TRUE;
}
}
else *hmod = (HMODULE)((char *)module + 2); /* set bit 1 for image resource module */
CloseHandle( hFile );
return TRUE;
failed:
if (module) UnmapViewOfFile( module );
CloseHandle( hFile );
return FALSE;
}
/******************************************************************
* load_library
*
* Helper for LoadLibraryExA/W.
*/
static HMODULE load_library( const UNICODE_STRING *libname, DWORD flags )
{
NTSTATUS nts;
HMODULE hModule;
WCHAR *load_path, *dummy;
const DWORD unsupported_flags = (LOAD_IGNORE_CODE_AUTHZ_LEVEL |
LOAD_LIBRARY_REQUIRE_SIGNED_TARGET);
if( flags & unsupported_flags)
FIXME("unsupported flag(s) used (flags: 0x%08x)\n", flags);
if (!set_ntstatus( LdrGetDllPath( libname->Buffer, flags, &load_path, &dummy ))) return 0;
if (flags & (LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE | LOAD_LIBRARY_AS_IMAGE_RESOURCE))
{
ULONG_PTR magic;
LdrLockLoaderLock( 0, NULL, &magic );
if (!LdrGetDllHandle( load_path, flags, libname, &hModule ))
{
LdrAddRefDll( 0, hModule );
LdrUnlockLoaderLock( 0, magic );
goto done;
}
if (load_library_as_datafile( load_path, flags, libname->Buffer, &hModule ))
{
LdrUnlockLoaderLock( 0, magic );
goto done;
}
LdrUnlockLoaderLock( 0, magic );
flags |= DONT_RESOLVE_DLL_REFERENCES; /* Just in case */
/* Fallback to normal behaviour */
}
nts = LdrLoadDll( load_path, flags, libname, &hModule );
if (nts != STATUS_SUCCESS)
{
hModule = 0;
if (nts == STATUS_DLL_NOT_FOUND && (GetVersion() & 0x80000000))
SetLastError( ERROR_DLL_NOT_FOUND );
else
SetLastError( RtlNtStatusToDosError( nts ) );
}
done:
RtlReleasePath( load_path );
return hModule;
}
/******************************************************************
* LoadLibraryExA (KERNEL32.@)
*
* Load a dll file into the process address space.
*
* PARAMS
* libname [I] Name of the file to load
* hfile [I] Reserved, must be 0.
* flags [I] Flags for loading the dll
*
* RETURNS
* Success: A handle to the loaded dll.
* Failure: A NULL handle. Use GetLastError() to determine the cause.
*
* NOTES
* The HFILE parameter is not used and marked reserved in the SDK. I can
* only guess that it should force a file to be mapped, but I rather
* ignore the parameter because it would be extremely difficult to
* integrate this with different types of module representations.
*/
HMODULE WINAPI DECLSPEC_HOTPATCH LoadLibraryExA(LPCSTR libname, HANDLE hfile, DWORD flags)
{
WCHAR *libnameW;
if (!(libnameW = FILE_name_AtoW( libname, FALSE ))) return 0;
return LoadLibraryExW( libnameW, hfile, flags );
}
/***********************************************************************
* LoadLibraryExW (KERNEL32.@)
*
* Unicode version of LoadLibraryExA.
*/
HMODULE WINAPI DECLSPEC_HOTPATCH LoadLibraryExW(LPCWSTR libnameW, HANDLE hfile, DWORD flags)
{
UNICODE_STRING wstr;
HMODULE res;
if (!libnameW)
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
RtlInitUnicodeString( &wstr, libnameW );
if (wstr.Buffer[wstr.Length/sizeof(WCHAR) - 1] != ' ')
return load_library( &wstr, flags );
/* Library name has trailing spaces */
RtlCreateUnicodeString( &wstr, libnameW );
while (wstr.Length > sizeof(WCHAR) &&
wstr.Buffer[wstr.Length/sizeof(WCHAR) - 1] == ' ')
{
wstr.Length -= sizeof(WCHAR);
}
wstr.Buffer[wstr.Length/sizeof(WCHAR)] = '\0';
res = load_library( &wstr, flags );
RtlFreeUnicodeString( &wstr );
return res;
}
/***********************************************************************
* LoadLibraryA (KERNEL32.@)
*
* Load a dll file into the process address space.
*
* PARAMS
* libname [I] Name of the file to load
*
* RETURNS
* Success: A handle to the loaded dll.
* Failure: A NULL handle. Use GetLastError() to determine the cause.
*
* NOTES
* See LoadLibraryExA().
*/
HMODULE WINAPI DECLSPEC_HOTPATCH LoadLibraryA(LPCSTR libname)
{
return LoadLibraryExA(libname, 0, 0);
}
/***********************************************************************
* LoadLibraryW (KERNEL32.@)
*
* Unicode version of LoadLibraryA.
*/
HMODULE WINAPI DECLSPEC_HOTPATCH LoadLibraryW(LPCWSTR libnameW)
{
return LoadLibraryExW(libnameW, 0, 0);
}
/***********************************************************************
* FreeLibrary (KERNEL32.@)
*
* Free a dll loaded into the process address space.
*
* PARAMS
* hLibModule [I] Handle to the dll returned by LoadLibraryA().
*
* RETURNS
* Success: TRUE. The dll is removed if it is not still in use.
* Failure: FALSE. Use GetLastError() to determine the cause.
*/
BOOL WINAPI DECLSPEC_HOTPATCH FreeLibrary(HINSTANCE hLibModule)
{
if (!hLibModule)
{
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
if ((ULONG_PTR)hLibModule & 3) /* this is a datafile module */
{
void *ptr = (void *)((ULONG_PTR)hLibModule & ~3);
if (!RtlImageNtHeader( ptr ))
{
SetLastError( ERROR_BAD_EXE_FORMAT );
return FALSE;
}
if ((ULONG_PTR)hLibModule & 1)
{
struct exclusive_datafile *file;
ULONG_PTR magic;
LdrLockLoaderLock( 0, NULL, &magic );
LIST_FOR_EACH_ENTRY( file, &exclusive_datafile_list, struct exclusive_datafile, entry )
{
if (file->module != hLibModule) continue;
TRACE( "closing %p for module %p\n", file->file, file->module );
CloseHandle( file->file );
list_remove( &file->entry );
HeapFree( GetProcessHeap(), 0, file );
break;
}
LdrUnlockLoaderLock( 0, magic );
}
return UnmapViewOfFile( ptr );
}
return set_ntstatus( LdrUnloadDll( hLibModule ));
}
/***********************************************************************
* GetProcAddress (KERNEL32.@)
*

View File

@ -394,7 +394,7 @@
@ stdcall FreeEnvironmentStringsW(ptr)
# @ stub FreeGPOListInternalA
# @ stub FreeGPOListInternalW
@ stdcall FreeLibrary(long) kernel32.FreeLibrary
@ stdcall FreeLibrary(long)
@ stdcall FreeLibraryAndExitThread(long long)
@ stdcall FreeLibraryWhenCallbackReturns(ptr ptr) ntdll.TpCallbackUnloadDllOnCompletion
@ stdcall FreeResource(long)
@ -618,7 +618,7 @@
# @ stub GetPreviousFgPolicyRefreshInfoInternal
@ stdcall GetPriorityClass(long)
@ stdcall GetPrivateObjectSecurity(ptr long ptr long ptr)
@ stdcall GetProcAddress(long str) kernel32.GetProcAddress
@ stdcall GetProcAddress(long str)
# @ stub GetProcAddressForCaller
# @ stub GetProcessDefaultCpuSets
# @ stub GetProcessGroupAffinity
@ -922,10 +922,10 @@
@ stdcall LeaveCriticalSectionWhenCallbackReturns(ptr ptr) ntdll.TpCallbackLeaveCriticalSectionOnCompletion
# @ stub LoadAppInitDlls
# @ stub LoadEnclaveData
@ stdcall LoadLibraryA(str) kernel32.LoadLibraryA
@ stdcall LoadLibraryExA( str long long) kernel32.LoadLibraryExA
@ stdcall LoadLibraryExW(wstr long long) kernel32.LoadLibraryExW
@ stdcall LoadLibraryW(wstr) kernel32.LoadLibraryW
@ stdcall LoadLibraryA(str)
@ stdcall LoadLibraryExA( str long long)
@ stdcall LoadLibraryExW(wstr long long)
@ stdcall LoadLibraryW(wstr)
# @ stub LoadPackagedLibrary
@ stdcall LoadResource(long long)
@ stdcall LoadStringA(long long ptr long)

View File

@ -31,17 +31,161 @@
#include "winnls.h"
#include "winternl.h"
#include "kernelbase.h"
#include "wine/list.h"
#include "wine/asm.h"
#include "wine/debug.h"
#include "wine/exception.h"
WINE_DEFAULT_DEBUG_CHANNEL(module);
/* to keep track of LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE file handles */
struct exclusive_datafile
{
struct list entry;
HMODULE module;
HANDLE file;
};
static struct list exclusive_datafile_list = LIST_INIT( exclusive_datafile_list );
/***********************************************************************
* Modules
***********************************************************************/
/******************************************************************
* get_proc_address
*/
FARPROC WINAPI get_proc_address( HMODULE module, LPCSTR function )
{
FARPROC proc;
ANSI_STRING str;
if (!module) module = NtCurrentTeb()->Peb->ImageBaseAddress;
if ((ULONG_PTR)function >> 16)
{
RtlInitAnsiString( &str, function );
if (!set_ntstatus( LdrGetProcedureAddress( module, &str, 0, (void**)&proc ))) return NULL;
}
else if (!set_ntstatus( LdrGetProcedureAddress( module, NULL, LOWORD(function), (void**)&proc )))
return NULL;
return proc;
}
/******************************************************************
* load_library_as_datafile
*/
static BOOL load_library_as_datafile( LPCWSTR load_path, DWORD flags, LPCWSTR name, HMODULE *mod_ret )
{
static const WCHAR dotDLL[] = {'.','d','l','l',0};
WCHAR filenameW[MAX_PATH];
HANDLE mapping, file = INVALID_HANDLE_VALUE;
HMODULE module = 0;
DWORD protect = PAGE_READONLY;
*mod_ret = 0;
if (flags & LOAD_LIBRARY_AS_IMAGE_RESOURCE) protect |= SEC_IMAGE;
if (SearchPathW( load_path, name, dotDLL, ARRAY_SIZE( filenameW ), filenameW, NULL ))
{
file = CreateFileW( filenameW, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE,
NULL, OPEN_EXISTING, 0, 0 );
}
if (file == INVALID_HANDLE_VALUE) return FALSE;
mapping = CreateFileMappingW( file, NULL, protect, 0, 0, NULL );
if (!mapping) goto failed;
module = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
CloseHandle( mapping );
if (!module) goto failed;
if (!(flags & LOAD_LIBRARY_AS_IMAGE_RESOURCE))
{
/* make sure it's a valid PE file */
if (!RtlImageNtHeader( module )) goto failed;
*mod_ret = (HMODULE)((char *)module + 1); /* set bit 0 for data file module */
if (flags & LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE)
{
struct exclusive_datafile *file = HeapAlloc( GetProcessHeap(), 0, sizeof(*file) );
if (!file) goto failed;
file->module = *mod_ret;
file->file = file;
list_add_head( &exclusive_datafile_list, &file->entry );
TRACE( "delaying close %p for module %p\n", file->file, file->module );
return TRUE;
}
}
else *mod_ret = (HMODULE)((char *)module + 2); /* set bit 1 for image resource module */
CloseHandle( file );
return TRUE;
failed:
if (module) UnmapViewOfFile( module );
CloseHandle( file );
return FALSE;
}
/******************************************************************
* load_library
*/
static HMODULE load_library( const UNICODE_STRING *libname, DWORD flags )
{
const DWORD unsupported_flags = LOAD_IGNORE_CODE_AUTHZ_LEVEL | LOAD_LIBRARY_REQUIRE_SIGNED_TARGET;
NTSTATUS status;
HMODULE module;
WCHAR *load_path, *dummy;
if (flags & unsupported_flags) FIXME( "unsupported flag(s) used %#08x\n", flags );
if (!set_ntstatus( LdrGetDllPath( libname->Buffer, flags, &load_path, &dummy ))) return 0;
if (flags & (LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE |
LOAD_LIBRARY_AS_IMAGE_RESOURCE))
{
ULONG_PTR magic;
LdrLockLoaderLock( 0, NULL, &magic );
if (!LdrGetDllHandle( load_path, flags, libname, &module ))
{
LdrAddRefDll( 0, module );
LdrUnlockLoaderLock( 0, magic );
goto done;
}
if (load_library_as_datafile( load_path, flags, libname->Buffer, &module ))
{
LdrUnlockLoaderLock( 0, magic );
goto done;
}
LdrUnlockLoaderLock( 0, magic );
flags |= DONT_RESOLVE_DLL_REFERENCES; /* Just in case */
/* Fallback to normal behaviour */
}
status = LdrLoadDll( load_path, flags, libname, &module );
if (status != STATUS_SUCCESS)
{
module = 0;
if (status == STATUS_DLL_NOT_FOUND && (GetVersion() & 0x80000000))
SetLastError( ERROR_DLL_NOT_FOUND );
else
SetLastError( RtlNtStatusToDosError( status ) );
}
done:
RtlReleasePath( load_path );
return module;
}
/****************************************************************************
* AddDllDirectory (kernelbase.@)
*/
@ -83,6 +227,49 @@ BOOL WINAPI DECLSPEC_HOTPATCH DisableThreadLibraryCalls( HMODULE module )
}
/***********************************************************************
* FreeLibrary (kernelbase.@)
*/
BOOL WINAPI DECLSPEC_HOTPATCH FreeLibrary( HINSTANCE module )
{
if (!module)
{
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
if ((ULONG_PTR)module & 3) /* this is a datafile module */
{
void *ptr = (void *)((ULONG_PTR)module & ~3);
if (!RtlImageNtHeader( ptr ))
{
SetLastError( ERROR_BAD_EXE_FORMAT );
return FALSE;
}
if ((ULONG_PTR)module & 1)
{
struct exclusive_datafile *file;
ULONG_PTR magic;
LdrLockLoaderLock( 0, NULL, &magic );
LIST_FOR_EACH_ENTRY( file, &exclusive_datafile_list, struct exclusive_datafile, entry )
{
if (file->module != module) continue;
TRACE( "closing %p for module %p\n", file->file, file->module );
CloseHandle( file->file );
list_remove( &file->entry );
HeapFree( GetProcessHeap(), 0, file );
break;
}
LdrUnlockLoaderLock( 0, magic );
}
return UnmapViewOfFile( ptr );
}
return set_ntstatus( LdrUnloadDll( module ));
}
/***********************************************************************
* GetModuleFileNameA (kernelbase.@)
*/
@ -239,6 +426,115 @@ BOOL WINAPI DECLSPEC_HOTPATCH GetModuleHandleExW( DWORD flags, LPCWSTR name, HMO
}
/***********************************************************************
* GetProcAddress (kernelbase.@)
*/
#ifdef __x86_64__
/*
* Work around a Delphi bug on x86_64. When delay loading a symbol,
* Delphi saves rcx, rdx, r8 and r9 to the stack. It then calls
* GetProcAddress(), pops the saved registers and calls the function.
* This works fine if all of the parameters are ints. However, since
* it does not save xmm0 - 3, it relies on GetProcAddress() preserving
* these registers if the function takes floating point parameters.
* This wrapper saves xmm0 - 3 to the stack.
*/
__ASM_GLOBAL_FUNC( GetProcAddress,
".byte 0x48\n\t" /* hotpatch prolog */
"pushq %rbp\n\t"
__ASM_SEH(".seh_pushreg %rbp\n\t")
__ASM_CFI(".cfi_adjust_cfa_offset 8\n\t")
__ASM_CFI(".cfi_rel_offset %rbp,0\n\t")
"movq %rsp,%rbp\n\t"
__ASM_SEH(".seh_setframe %rbp,0\n\t")
__ASM_CFI(".cfi_def_cfa_register %rbp\n\t")
"subq $0x60,%rsp\n\t"
__ASM_SEH(".seh_stackalloc 0x60\n\t")
__ASM_SEH(".seh_endprologue\n\t")
"movaps %xmm0,-0x10(%rbp)\n\t"
"movaps %xmm1,-0x20(%rbp)\n\t"
"movaps %xmm2,-0x30(%rbp)\n\t"
"movaps %xmm3,-0x40(%rbp)\n\t"
"call " __ASM_NAME("get_proc_address") "\n\t"
"movaps -0x40(%rbp), %xmm3\n\t"
"movaps -0x30(%rbp), %xmm2\n\t"
"movaps -0x20(%rbp), %xmm1\n\t"
"movaps -0x10(%rbp), %xmm0\n\t"
"leaq 0(%rbp),%rsp\n\t"
__ASM_CFI(".cfi_def_cfa_register %rsp\n\t")
"popq %rbp\n\t"
__ASM_CFI(".cfi_adjust_cfa_offset -8\n\t")
__ASM_CFI(".cfi_same_value %rbp\n\t")
"ret" )
#else /* __x86_64__ */
FARPROC WINAPI DECLSPEC_HOTPATCH GetProcAddress( HMODULE module, LPCSTR function )
{
return get_proc_address( module, function );
}
#endif /* __x86_64__ */
/***********************************************************************
* LoadLibraryA (kernelbase.@)
*/
HMODULE WINAPI DECLSPEC_HOTPATCH LoadLibraryA( LPCSTR name )
{
return LoadLibraryExA( name, 0, 0 );
}
/***********************************************************************
* LoadLibraryW (kernelbase.@)
*/
HMODULE WINAPI DECLSPEC_HOTPATCH LoadLibraryW( LPCWSTR name )
{
return LoadLibraryExW( name, 0, 0 );
}
/******************************************************************
* LoadLibraryExA (kernelbase.@)
*/
HMODULE WINAPI DECLSPEC_HOTPATCH LoadLibraryExA( LPCSTR name, HANDLE file, DWORD flags )
{
WCHAR *nameW;
if (!(nameW = file_name_AtoW( name, FALSE ))) return 0;
return LoadLibraryExW( nameW, file, flags );
}
/***********************************************************************
* LoadLibraryExW (kernelbase.@)
*/
HMODULE WINAPI DECLSPEC_HOTPATCH LoadLibraryExW( LPCWSTR name, HANDLE file, DWORD flags )
{
UNICODE_STRING str;
HMODULE module;
if (!name)
{
SetLastError( ERROR_INVALID_PARAMETER );
return 0;
}
RtlInitUnicodeString( &str, name );
if (str.Buffer[str.Length/sizeof(WCHAR) - 1] != ' ') return load_library( &str, flags );
/* library name has trailing spaces */
RtlCreateUnicodeString( &str, name );
while (str.Length > sizeof(WCHAR) && str.Buffer[str.Length/sizeof(WCHAR) - 1] == ' ')
str.Length -= sizeof(WCHAR);
str.Buffer[str.Length/sizeof(WCHAR)] = 0;
module = load_library( &str, flags );
RtlFreeUnicodeString( &str );
return module;
}
/****************************************************************************
* RemoveDllDirectory (kernelbase.@)
*/