Rewrote most of the import fixup code to avoid doing redundant work

for every entry point. Moved it all to dlls/ntdll/loader.c.
Various optimizations in the other loader routines.
This commit is contained in:
Alexandre Julliard 2003-04-05 05:16:11 +00:00
parent 5980477dcc
commit 0412cc55d2
3 changed files with 329 additions and 333 deletions

View File

@ -1,7 +1,7 @@
/* /*
* Loader functions * Loader functions
* *
* Copyright 1995 Alexandre Julliard * Copyright 1995, 2003 Alexandre Julliard
* Copyright 2002 Dmitry Timoshkov for Codeweavers * Copyright 2002 Dmitry Timoshkov for Codeweavers
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
@ -29,12 +29,14 @@
#include "file.h" #include "file.h"
#include "wine/exception.h" #include "wine/exception.h"
#include "excpt.h" #include "excpt.h"
#include "snoop.h"
#include "wine/debug.h" #include "wine/debug.h"
#include "wine/server.h" #include "wine/server.h"
#include "ntdll_misc.h" #include "ntdll_misc.h"
WINE_DEFAULT_DEBUG_CHANNEL(module); WINE_DEFAULT_DEBUG_CHANNEL(module);
WINE_DECLARE_DEBUG_CHANNEL(relay); WINE_DECLARE_DEBUG_CHANNEL(relay);
WINE_DECLARE_DEBUG_CHANNEL(snoop);
WINE_DECLARE_DEBUG_CHANNEL(loaddll); WINE_DECLARE_DEBUG_CHANNEL(loaddll);
typedef DWORD (CALLBACK *DLLENTRYPROC)(HMODULE,DWORD,LPVOID); typedef DWORD (CALLBACK *DLLENTRYPROC)(HMODULE,DWORD,LPVOID);
@ -54,34 +56,291 @@ static WINE_EXCEPTION_FILTER(page_fault)
} }
static CRITICAL_SECTION loader_section = CRITICAL_SECTION_INIT( "loader_section" ); static CRITICAL_SECTION loader_section = CRITICAL_SECTION_INIT( "loader_section" );
static WINE_MODREF *cached_modref;
static NTSTATUS load_dll( LPCSTR libname, DWORD flags, WINE_MODREF** pwm );
static FARPROC find_named_export( HMODULE module, IMAGE_EXPORT_DIRECTORY *exports,
DWORD exp_size, const char *name, int hint );
/* convert PE image VirtualAddress to Real Address */
inline static void *get_rva( HMODULE module, DWORD va )
{
return (void *)((char *)module + va);
}
/************************************************************************* /*************************************************************************
* MODULE32_LookupHMODULE * get_modref
* looks for the referenced HMODULE in the current process *
* NOTE: Assumes that the process critical section is held! * Looks for the referenced HMODULE in the current process
* The loader_section must be locked while calling this function.
*/ */
static WINE_MODREF *MODULE32_LookupHMODULE( HMODULE hmod ) static WINE_MODREF *get_modref( HMODULE hmod )
{ {
WINE_MODREF *wm; WINE_MODREF *wm;
if (!hmod) if (cached_modref && cached_modref->ldr.BaseAddress == hmod) return cached_modref;
return exe_modref;
if (!HIWORD(hmod)) {
ERR("tried to lookup %p in win32 module handler!\n",hmod);
return NULL;
}
for ( wm = MODULE_modref_list; wm; wm=wm->next ) for ( wm = MODULE_modref_list; wm; wm=wm->next )
if (wm->ldr.BaseAddress == hmod) {
return wm; if (wm->ldr.BaseAddress == hmod)
return NULL; {
cached_modref = wm;
break;
}
}
return wm;
} }
/*************************************************************************
* find_forwarded_export
*
* Find the final function pointer for a forwarded function.
* The loader_section must be locked while calling this function.
*/
static FARPROC find_forwarded_export( HMODULE module, const char *forward )
{
IMAGE_EXPORT_DIRECTORY *exports;
DWORD exp_size;
WINE_MODREF *wm;
char mod_name[256];
char *end = strchr(forward, '.');
FARPROC proc = NULL;
if (!end) return NULL;
if (end - forward >= sizeof(mod_name)) return NULL;
memcpy( mod_name, forward, end - forward );
mod_name[end-forward] = 0;
if (!(wm = MODULE_FindModule( mod_name )))
{
WINE_MODREF *user = get_modref( module );
ERR("module not found for forward '%s' used by '%s'\n", forward, user->filename );
return NULL;
}
if ((exports = RtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE,
IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
proc = find_named_export( wm->ldr.BaseAddress, exports, exp_size, end + 1, -1 );
if (!proc)
{
WINE_MODREF *user = get_modref( module );
ERR("function not found for forward '%s' used by '%s'."
" If you are using builtin '%s', try using the native one instead.\n",
forward, user->filename, user->modname );
}
return proc;
}
/*************************************************************************
* find_ordinal_export
*
* Find an exported function by ordinal.
* The exports base must have been subtracted from the ordinal already.
* The loader_section must be locked while calling this function.
*/
static FARPROC find_ordinal_export( HMODULE module, IMAGE_EXPORT_DIRECTORY *exports,
DWORD exp_size, int ordinal )
{
FARPROC proc;
WORD *ordinals = get_rva( module, exports->AddressOfNameOrdinals );
DWORD *functions = get_rva( module, exports->AddressOfFunctions );
if (ordinal >= exports->NumberOfFunctions)
{
TRACE(" ordinal %ld out of range!\n", ordinal + exports->Base );
return NULL;
}
if (!functions[ordinal]) return NULL;
proc = get_rva( module, functions[ordinal] );
/* if the address falls into the export dir, it's a forward */
if (((char *)proc >= (char *)exports) && ((char *)proc < (char *)exports + exp_size))
return find_forwarded_export( module, (char *)proc );
if (TRACE_ON(snoop))
{
/* try to find a name for it */
int i;
char *ename = "@";
DWORD *name = get_rva( module, exports->AddressOfNames );
if (name) for (i = 0; i < exports->NumberOfNames; i++)
{
if (ordinals[i] == ordinal)
{
ename = get_rva( module, name[i] );
break;
}
}
proc = SNOOP_GetProcAddress( module, ename, ordinal, proc );
}
return proc;
}
/*************************************************************************
* find_named_export
*
* Find an exported function by name.
* The loader_section must be locked while calling this function.
*/
static FARPROC find_named_export( HMODULE module, IMAGE_EXPORT_DIRECTORY *exports,
DWORD exp_size, const char *name, int hint )
{
WORD *ordinals = get_rva( module, exports->AddressOfNameOrdinals );
DWORD *names = get_rva( module, exports->AddressOfNames );
int min = 0, max = exports->NumberOfNames - 1;
/* first check the hint */
if (hint >= 0 && hint <= max)
{
char *ename = get_rva( module, names[hint] );
if (!strcmp( ename, name ))
return find_ordinal_export( module, exports, exp_size, ordinals[hint] );
}
/* then do a binary search */
while (min <= max)
{
int res, pos = (min + max) / 2;
char *ename = get_rva( module, names[pos] );
if (!(res = strcmp( ename, name )))
return find_ordinal_export( module, exports, exp_size, ordinals[pos] );
if (res > 0) max = pos - 1;
else min = pos + 1;
}
return NULL;
}
/*************************************************************************
* import_dll
*
* Import the dll specified by the given import descriptor.
* The loader_section must be locked while calling this function.
*/
static WINE_MODREF *import_dll( HMODULE module, IMAGE_IMPORT_DESCRIPTOR *descr )
{
NTSTATUS status;
WINE_MODREF *wmImp;
HMODULE imp_mod;
IMAGE_EXPORT_DIRECTORY *exports;
DWORD exp_size;
IMAGE_THUNK_DATA *import_list, *thunk_list;
char *name = get_rva( module, descr->Name );
status = load_dll( name, 0, &wmImp );
if (status)
{
WINE_MODREF *user = get_modref( module );
if (status == STATUS_NO_SUCH_FILE)
ERR("Module (file) %s (which is needed by %s) not found\n", name, user->filename);
else
ERR("Loading module (file) %s (which is needed by %s) failed (error %ld).\n",
name, user->filename, status);
return NULL;
}
imp_mod = wmImp->ldr.BaseAddress;
if (!(exports = RtlImageDirectoryEntryToData( imp_mod, TRUE,
IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
return NULL;
thunk_list = get_rva( module, (DWORD)descr->FirstThunk );
if (descr->u.OriginalFirstThunk)
import_list = get_rva( module, (DWORD)descr->u.OriginalFirstThunk );
else
import_list = thunk_list;
while (import_list->u1.Ordinal)
{
if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))
{
int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
TRACE("--- Ordinal %s,%d\n", name, ordinal);
thunk_list->u1.Function = (PDWORD)find_ordinal_export( imp_mod, exports, exp_size,
ordinal - exports->Base );
if (!thunk_list->u1.Function)
{
WINE_MODREF *user = get_modref( module );
ERR("No implementation for %s.%d imported from %s, setting to 0xdeadbeef\n",
name, ordinal, user->filename );
thunk_list->u1.Function = (PDWORD)0xdeadbeef;
}
}
else /* import by name */
{
IMAGE_IMPORT_BY_NAME *pe_name;
pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );
TRACE("--- %s %s.%d\n", pe_name->Name, name, pe_name->Hint);
thunk_list->u1.Function = (PDWORD)find_named_export( imp_mod, exports, exp_size,
pe_name->Name, pe_name->Hint );
if (!thunk_list->u1.Function)
{
WINE_MODREF *user = get_modref( module );
ERR("No implementation for %s.%s imported from %s, setting to 0xdeadbeef\n",
name, pe_name->Name, user->filename );
thunk_list->u1.Function = (PDWORD)0xdeadbeef;
}
}
import_list++;
thunk_list++;
}
return wmImp;
}
/****************************************************************
* PE_fixup_imports
*
* Fixup all imports of a given module.
* The loader_section must be locked while calling this function.
*/
DWORD PE_fixup_imports( WINE_MODREF *wm )
{
int i, nb_imports;
IMAGE_IMPORT_DESCRIPTOR *imports;
DWORD size;
if (!(imports = RtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE,
IMAGE_DIRECTORY_ENTRY_IMPORT, &size )))
return 0;
nb_imports = size / sizeof(*imports);
for (i = 0; i < nb_imports; i++)
{
if (!imports[i].Name)
{
nb_imports = i;
break;
}
}
if (!nb_imports) return 0; /* no imports */
/* Allocate module dependency list */
wm->nDeps = nb_imports;
wm->deps = RtlAllocateHeap( ntdll_get_process_heap(), 0, nb_imports*sizeof(WINE_MODREF *) );
/* load the imported modules. They are automatically
* added to the modref list of the process.
*/
for (i = 0; i < nb_imports; i++)
{
if (!(wm->deps[i] = import_dll( wm->ldr.BaseAddress, &imports[i] ))) return 1;
}
return 0;
}
/************************************************************************* /*************************************************************************
* MODULE_AllocModRef * MODULE_AllocModRef
* *
* Allocate a WINE_MODREF structure and add it to the process list * Allocate a WINE_MODREF structure and add it to the process list
* NOTE: Assumes that the process critical section is held! * The loader_section must be locked while calling this function.
*/ */
WINE_MODREF *MODULE_AllocModRef( HMODULE hModule, LPCSTR filename ) WINE_MODREF *MODULE_AllocModRef( HMODULE hModule, LPCSTR filename )
{ {
@ -345,7 +604,7 @@ NTSTATUS WINAPI LdrDisableThreadCalloutsForDll(HMODULE hModule)
RtlEnterCriticalSection( &loader_section ); RtlEnterCriticalSection( &loader_section );
wm = MODULE32_LookupHMODULE( hModule ); wm = get_modref( hModule );
if ( !wm ) if ( !wm )
ret = STATUS_DLL_NOT_FOUND; ret = STATUS_DLL_NOT_FOUND;
else else
@ -398,18 +657,22 @@ WINE_MODREF *MODULE_FindModule(LPCSTR path)
if (!(p = strrchr( dllname, '.')) || strchr( p, '/' ) || strchr( p, '\\')) if (!(p = strrchr( dllname, '.')) || strchr( p, '/' ) || strchr( p, '\\'))
strcat( dllname, ".DLL" ); strcat( dllname, ".DLL" );
for ( wm = MODULE_modref_list; wm; wm = wm->next ) if ((wm = cached_modref) != NULL)
{ {
if ( !FILE_strcasecmp( dllname, wm->modname ) ) if ( !FILE_strcasecmp( dllname, wm->modname ) ) return wm;
break; if ( !FILE_strcasecmp( dllname, wm->filename ) ) return wm;
if ( !FILE_strcasecmp( dllname, wm->filename ) ) if ( !FILE_strcasecmp( dllname, wm->short_modname ) ) return wm;
break; if ( !FILE_strcasecmp( dllname, wm->short_filename ) ) return wm;
if ( !FILE_strcasecmp( dllname, wm->short_modname ) )
break;
if ( !FILE_strcasecmp( dllname, wm->short_filename ) )
break;
} }
for ( wm = MODULE_modref_list; wm; wm = wm->next )
{
if ( !FILE_strcasecmp( dllname, wm->modname ) ) break;
if ( !FILE_strcasecmp( dllname, wm->filename ) ) break;
if ( !FILE_strcasecmp( dllname, wm->short_modname ) ) break;
if ( !FILE_strcasecmp( dllname, wm->short_filename ) ) break;
}
cached_modref = wm;
return wm; return wm;
} }
@ -455,22 +718,15 @@ NTSTATUS WINAPI LdrUnlockLoaderLock( ULONG flags, ULONG magic )
NTSTATUS WINAPI LdrGetDllHandle(ULONG x, ULONG y, PUNICODE_STRING name, HMODULE *base) NTSTATUS WINAPI LdrGetDllHandle(ULONG x, ULONG y, PUNICODE_STRING name, HMODULE *base)
{ {
WINE_MODREF *wm; WINE_MODREF *wm;
STRING str;
if (x != 0 || y != 0) if (x != 0 || y != 0)
FIXME("Unknown behavior, please report\n"); FIXME("Unknown behavior, please report\n");
/* FIXME: we should store module name information as unicode */ /* FIXME: we should store module name information as unicode */
if (name) RtlUnicodeStringToAnsiString( &str, name, TRUE );
{ wm = MODULE_FindModule( str.Buffer );
STRING str; RtlFreeAnsiString( &str );
RtlUnicodeStringToAnsiString( &str, name, TRUE );
wm = MODULE_FindModule( str.Buffer );
RtlFreeAnsiString( &str );
}
else
wm = exe_modref;
if (!wm) if (!wm)
{ {
@ -480,41 +736,42 @@ NTSTATUS WINAPI LdrGetDllHandle(ULONG x, ULONG y, PUNICODE_STRING name, HMODULE
*base = wm->ldr.BaseAddress; *base = wm->ldr.BaseAddress;
TRACE("%lx %lx %s -> %p\n", TRACE("%lx %lx %s -> %p\n", x, y, debugstr_us(name), *base);
x, y, name ? debugstr_wn(name->Buffer, name->Length/sizeof(WCHAR)) : "(null)", *base);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
/***********************************************************************
* MODULE_GetProcAddress (internal)
*/
FARPROC MODULE_GetProcAddress(
HMODULE hModule, /* [in] current module handle */
LPCSTR function, /* [in] function to be looked up */
int hint,
BOOL snoop )
{
WINE_MODREF *wm;
FARPROC retproc = 0;
RtlEnterCriticalSection( &loader_section );
if ((wm = MODULE32_LookupHMODULE( hModule )))
{
retproc = PE_FindExportedFunction( wm, function, hint, snoop );
}
RtlLeaveCriticalSection( &loader_section );
return retproc;
}
/****************************************************************** /******************************************************************
* LdrGetProcedureAddress (NTDLL.@) * LdrGetProcedureAddress (NTDLL.@)
*/ */
NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE base, PANSI_STRING name, ULONG ord, PVOID *address) NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE module, PANSI_STRING name, ULONG ord, PVOID *address)
{ {
*address = MODULE_GetProcAddress( base, name ? name->Buffer : (LPSTR)ord, -1, TRUE ); IMAGE_EXPORT_DIRECTORY *exports;
return (*address) ? STATUS_SUCCESS : STATUS_PROCEDURE_NOT_FOUND; DWORD exp_size;
NTSTATUS ret = STATUS_PROCEDURE_NOT_FOUND;
RtlEnterCriticalSection( &loader_section );
if ((exports = RtlImageDirectoryEntryToData( module, TRUE,
IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
{
void *proc = name ? find_named_export( module, exports, exp_size, name->Buffer, -1 )
: find_ordinal_export( module, exports, exp_size, ord - exports->Base );
if (proc)
{
*address = proc;
ret = STATUS_SUCCESS;
}
}
else
{
/* check if the module itself is invalid to return the proper error */
if (!get_modref( module )) ret = STATUS_DLL_NOT_FOUND;
}
RtlLeaveCriticalSection( &loader_section );
return ret;
} }
@ -550,7 +807,7 @@ static LPCSTR allocate_lib_dir(LPCSTR libname)
} }
/*********************************************************************** /***********************************************************************
* MODULE_LoadLibraryExA (internal) * load_dll (internal)
* *
* Load a PE style module according to the load order. * Load a PE style module according to the load order.
* *
@ -565,7 +822,7 @@ static LPCSTR allocate_lib_dir(LPCSTR libname)
* init function into load_library). * init function into load_library).
* allocated_libdir is TRUE in the stack frame that allocated libdir * allocated_libdir is TRUE in the stack frame that allocated libdir
*/ */
NTSTATUS MODULE_LoadLibraryExA( LPCSTR libname, DWORD flags, WINE_MODREF** pwm) static NTSTATUS load_dll( LPCSTR libname, DWORD flags, WINE_MODREF** pwm )
{ {
int i; int i;
enum loadorder_type loadorder[LOADORDER_NTYPES]; enum loadorder_type loadorder[LOADORDER_NTYPES];
@ -730,7 +987,7 @@ NTSTATUS WINAPI LdrLoadDll(LPCWSTR path_name, DWORD flags, PUNICODE_STRING libna
RtlEnterCriticalSection( &loader_section ); RtlEnterCriticalSection( &loader_section );
switch (nts = MODULE_LoadLibraryExA( str.Buffer, flags, &wm )) switch (nts = load_dll( str.Buffer, flags, &wm ))
{ {
case STATUS_SUCCESS: case STATUS_SUCCESS:
if ( !MODULE_DllProcessAttach( wm, NULL ) ) if ( !MODULE_DllProcessAttach( wm, NULL ) )
@ -849,10 +1106,10 @@ NTSTATUS WINAPI LdrShutdownThread(void)
/*********************************************************************** /***********************************************************************
* MODULE_FlushModrefs * MODULE_FlushModrefs
* *
* NOTE: Assumes that the process critical section is held!
*
* Remove all unused modrefs and call the internal unloading routines * Remove all unused modrefs and call the internal unloading routines
* for the library type. * for the library type.
*
* The loader_section must be locked while calling this function.
*/ */
static void MODULE_FlushModrefs(void) static void MODULE_FlushModrefs(void)
{ {
@ -888,6 +1145,7 @@ static void MODULE_FlushModrefs(void)
if (wm->dlhandle) wine_dll_unload( wm->dlhandle ); if (wm->dlhandle) wine_dll_unload( wm->dlhandle );
else NtUnmapViewOfSection( GetCurrentProcess(), wm->ldr.BaseAddress ); else NtUnmapViewOfSection( GetCurrentProcess(), wm->ldr.BaseAddress );
FreeLibrary16( wm->hDummyMod ); FreeLibrary16( wm->hDummyMod );
if (cached_modref == wm) cached_modref = NULL;
RtlFreeHeap( ntdll_get_process_heap(), 0, wm->deps ); RtlFreeHeap( ntdll_get_process_heap(), 0, wm->deps );
RtlFreeHeap( ntdll_get_process_heap(), 0, wm ); RtlFreeHeap( ntdll_get_process_heap(), 0, wm );
} }
@ -896,7 +1154,7 @@ static void MODULE_FlushModrefs(void)
/*********************************************************************** /***********************************************************************
* MODULE_DecRefCount * MODULE_DecRefCount
* *
* NOTE: Assumes that the process critical section is held! * The loader_section must be locked while calling this function.
*/ */
static void MODULE_DecRefCount( WINE_MODREF *wm ) static void MODULE_DecRefCount( WINE_MODREF *wm )
{ {
@ -944,7 +1202,7 @@ NTSTATUS WINAPI LdrUnloadDll( HMODULE hModule )
WINE_MODREF *wm; WINE_MODREF *wm;
free_lib_count++; free_lib_count++;
if ((wm = MODULE32_LookupHMODULE( hModule )) != NULL) if ((wm = get_modref( hModule )) != NULL)
{ {
TRACE("(%s) - START\n", wm->modname); TRACE("(%s) - START\n", wm->modname);

View File

@ -32,10 +32,7 @@ extern void dump_ObjectAttributes (const OBJECT_ATTRIBUTES *ObjectAttributes);
extern void NTDLL_get_server_timeout( abs_time_t *when, const LARGE_INTEGER *timeout ); extern void NTDLL_get_server_timeout( abs_time_t *when, const LARGE_INTEGER *timeout );
/* module handling */ /* module handling */
extern FARPROC MODULE_GetProcAddress( HMODULE hModule, LPCSTR function, int hint, BOOL snoop );
extern WINE_MODREF *MODULE_AllocModRef( HMODULE hModule, LPCSTR filename ); extern WINE_MODREF *MODULE_AllocModRef( HMODULE hModule, LPCSTR filename );
extern NTSTATUS MODULE_LoadLibraryExA( LPCSTR libname, DWORD flags, WINE_MODREF** );
extern FARPROC PE_FindExportedFunction( WINE_MODREF *wm, LPCSTR funcName, int hint, BOOL snoop );
static inline HANDLE ntdll_get_process_heap(void) static inline HANDLE ntdll_get_process_heap(void)
{ {

View File

@ -101,265 +101,6 @@ void dump_exports( HMODULE hModule )
} }
} }
/* Look up the specified function or ordinal in the export list:
* If it is a string:
* - look up the name in the name list.
* - look up the ordinal with that index.
* - use the ordinal as offset into the functionlist
* If it is an ordinal:
* - use ordinal-pe_export->Base as offset into the function list
*/
FARPROC PE_FindExportedFunction(
WINE_MODREF *wm, /* [in] WINE modreference */
LPCSTR funcName, /* [in] function name */
int hint,
BOOL snoop )
{
WORD * ordinals;
DWORD * function;
int i, ordinal;
DWORD rva_start, addr;
char * forward;
DWORD *name;
char *ename = NULL;
FARPROC proc;
IMAGE_EXPORT_DIRECTORY *exports;
DWORD exp_size;
if (!(exports = RtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE,
IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
return NULL;
if (HIWORD(funcName)) TRACE("(%s)\n",funcName);
else TRACE("(%d)\n",LOWORD(funcName));
ordinals= get_rva(wm->ldr.BaseAddress, exports->AddressOfNameOrdinals);
function= get_rva(wm->ldr.BaseAddress, exports->AddressOfFunctions);
name = get_rva(wm->ldr.BaseAddress, exports->AddressOfNames);
forward = NULL;
rva_start = (char *)exports - (char *)wm->ldr.BaseAddress;
if (HIWORD(funcName))
{
int min = 0, max = exports->NumberOfNames - 1;
/* first check the hint */
if (hint >= 0 && hint <= max)
{
ename = get_rva(wm->ldr.BaseAddress, name[hint]);
if (!strcmp( ename, funcName ))
{
ordinal = ordinals[hint];
goto found;
}
}
/* then do a binary search */
while (min <= max)
{
int res, pos = (min + max) / 2;
ename = get_rva(wm->ldr.BaseAddress, name[pos]);
if (!(res = strcmp( ename, funcName )))
{
ordinal = ordinals[pos];
goto found;
}
if (res > 0) max = pos - 1;
else min = pos + 1;
}
return NULL;
}
else /* find by ordinal */
{
ordinal = LOWORD(funcName) - exports->Base;
if (snoop && name) /* need to find a name for it */
{
for (i = 0; i < exports->NumberOfNames; i++)
if (ordinals[i] == ordinal)
{
ename = get_rva(wm->ldr.BaseAddress, name[i]);
break;
}
}
}
found:
if (ordinal >= exports->NumberOfFunctions)
{
TRACE(" ordinal %ld out of range!\n", ordinal + exports->Base );
return NULL;
}
addr = function[ordinal];
if (!addr) return NULL;
proc = get_rva(wm->ldr.BaseAddress, addr);
if (((char *)proc < (char *)exports) || ((char *)proc >= (char *)exports + exp_size))
{
if (snoop)
{
if (!ename) ename = "@";
proc = SNOOP_GetProcAddress(wm->ldr.BaseAddress,ename,ordinal,proc);
}
return proc;
}
else /* forward entry point */
{
WINE_MODREF *wm_fw;
char *forward = (char *)proc;
char module[256];
char *end = strchr(forward, '.');
if (!end) return NULL;
if (end - forward >= sizeof(module)) return NULL;
memcpy( module, forward, end - forward );
module[end-forward] = 0;
if (!(wm_fw = MODULE_FindModule( module )))
{
ERR("module not found for forward '%s' used by '%s'\n", forward, wm->modname );
return NULL;
}
if (!(proc = MODULE_GetProcAddress( wm_fw->ldr.BaseAddress, end + 1, -1, snoop )))
ERR("function not found for forward '%s' used by '%s'. If you are using builtin '%s', try using the native one instead.\n", forward, wm->modname, wm->modname );
return proc;
}
}
/****************************************************************
* PE_fixup_imports
*/
DWORD PE_fixup_imports( WINE_MODREF *wm )
{
int i,characteristics_detection=1;
IMAGE_IMPORT_DESCRIPTOR *imports, *pe_imp;
DWORD size;
imports = RtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size );
/* first, count the number of imported non-internal modules */
pe_imp = imports;
if (!pe_imp) return 0;
/* OK, now dump the import list */
TRACE("Dumping imports list\n");
/* We assume that we have at least one import with !0 characteristics and
* detect broken imports with all characteristics 0 (notably Borland) and
* switch the detection off for them.
*/
for (i = 0; pe_imp->Name ; pe_imp++) {
if (!i && !pe_imp->u.Characteristics)
characteristics_detection = 0;
if (characteristics_detection && !pe_imp->u.Characteristics)
break;
i++;
}
if (!i) return 0; /* no imports */
/* Allocate module dependency list */
wm->nDeps = i;
wm->deps = RtlAllocateHeap( ntdll_get_process_heap(), 0, i*sizeof(WINE_MODREF *) );
/* load the imported modules. They are automatically
* added to the modref list of the process.
*/
for (i = 0, pe_imp = imports; pe_imp->Name ; pe_imp++) {
WINE_MODREF *wmImp;
IMAGE_IMPORT_BY_NAME *pe_name;
PIMAGE_THUNK_DATA import_list,thunk_list;
char *name = get_rva(wm->ldr.BaseAddress, pe_imp->Name);
NTSTATUS nts;
if (characteristics_detection && !pe_imp->u.Characteristics)
break;
nts = MODULE_LoadLibraryExA( name, 0, &wmImp );
switch (nts)
{
case STATUS_SUCCESS:
break;
case STATUS_NO_SUCH_FILE:
ERR_(module)("Module (file) %s (which is needed by %s) not found\n", name, wm->filename);
return 1;
default:
ERR_(module)("Loading module (file) %s (which is needed by %s) failed (error %ld).\n",
name, wm->filename, GetLastError());
return 1;
}
wm->deps[i++] = wmImp;
/* FIXME: forwarder entries ... */
if (pe_imp->u.OriginalFirstThunk != 0) { /* original MS style */
TRACE("Microsoft style imports used\n");
import_list = get_rva(wm->ldr.BaseAddress, (DWORD)pe_imp->u.OriginalFirstThunk);
thunk_list = get_rva(wm->ldr.BaseAddress, (DWORD)pe_imp->FirstThunk);
while (import_list->u1.Ordinal) {
if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal)) {
int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
TRACE("--- Ordinal %s,%d\n", name, ordinal);
thunk_list->u1.Function=(PDWORD)MODULE_GetProcAddress(
wmImp->ldr.BaseAddress, (LPCSTR)ordinal, -1, TRUE
);
if (!thunk_list->u1.Function) {
ERR("No implementation for %s.%d imported from %s, setting to 0xdeadbeef\n",
name, ordinal, wm->filename );
thunk_list->u1.Function = (PDWORD)0xdeadbeef;
}
} else { /* import by name */
pe_name = get_rva(wm->ldr.BaseAddress, (DWORD)import_list->u1.AddressOfData);
TRACE("--- %s %s.%d\n", pe_name->Name, name, pe_name->Hint);
thunk_list->u1.Function=(PDWORD)MODULE_GetProcAddress(
wmImp->ldr.BaseAddress, pe_name->Name, pe_name->Hint, TRUE
);
if (!thunk_list->u1.Function) {
ERR("No implementation for %s.%d(%s) imported from %s, setting to 0xdeadbeef\n",
name,pe_name->Hint,pe_name->Name,wm->filename);
thunk_list->u1.Function = (PDWORD)0xdeadbeef;
}
}
import_list++;
thunk_list++;
}
} else { /* Borland style */
TRACE("Borland style imports used\n");
thunk_list = get_rva(wm->ldr.BaseAddress, (DWORD)pe_imp->FirstThunk);
while (thunk_list->u1.Ordinal) {
if (IMAGE_SNAP_BY_ORDINAL(thunk_list->u1.Ordinal)) {
/* not sure about this branch, but it seems to work */
int ordinal = IMAGE_ORDINAL(thunk_list->u1.Ordinal);
TRACE("--- Ordinal %s.%d\n",name,ordinal);
thunk_list->u1.Function=(PDWORD)MODULE_GetProcAddress(
wmImp->ldr.BaseAddress, (LPCSTR) ordinal, -1, TRUE
);
if (!thunk_list->u1.Function) {
ERR("No implementation for %s.%d imported from %s, setting to 0xdeadbeef\n",
name,ordinal, wm->filename);
thunk_list->u1.Function = (PDWORD)0xdeadbeef;
}
} else {
pe_name=get_rva(wm->ldr.BaseAddress, (DWORD)thunk_list->u1.AddressOfData);
TRACE("--- %s %s.%d\n",
pe_name->Name,name,pe_name->Hint);
thunk_list->u1.Function=(PDWORD)MODULE_GetProcAddress(
wmImp->ldr.BaseAddress, pe_name->Name, pe_name->Hint, TRUE
);
if (!thunk_list->u1.Function) {
ERR("No implementation for %s.%d(%s) imported from %s, setting to 0xdeadbeef\n",
name, pe_name->Hint, pe_name->Name, wm->filename);
thunk_list->u1.Function = (PDWORD)0xdeadbeef;
}
}
thunk_list++;
}
}
}
return 0;
}
/********************************************************************** /**********************************************************************
* PE_LoadImage * PE_LoadImage
* Load one PE format DLL/EXE into memory * Load one PE format DLL/EXE into memory