Commit 0412cc55 authored by Alexandre Julliard's avatar Alexandre Julliard

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.
parent 5980477d
......@@ -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 );
/* module handling */
extern FARPROC MODULE_GetProcAddress( HMODULE hModule, LPCSTR function, int hint, BOOL snoop );
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)
{
......
......@@ -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
* Load one PE format DLL/EXE into memory
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment