Do builtin modules fixups in library/loader.c before calling the
load_dll callback.
This commit is contained in:
parent
4e951ea25b
commit
db4c45671f
|
@ -11,9 +11,7 @@
|
|||
|
||||
/* dll loading */
|
||||
|
||||
struct _IMAGE_NT_HEADERS;
|
||||
|
||||
typedef void (*load_dll_callback_t)( const struct _IMAGE_NT_HEADERS *, const char * );
|
||||
typedef void (*load_dll_callback_t)( void *, const char * );
|
||||
|
||||
extern void wine_dll_set_callback( load_dll_callback_t load );
|
||||
extern void *wine_dll_load( const char *filename );
|
||||
|
|
161
library/loader.c
161
library/loader.c
|
@ -11,13 +11,17 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#ifdef HAVE_SYS_MMAN_H
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
#ifdef HAVE_DL_API
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#include "windef.h"
|
||||
#include "winnt.h"
|
||||
#include "wine/library.h"
|
||||
#include "wine/port.h"
|
||||
|
||||
#define MAX_DLLS 100
|
||||
|
||||
|
@ -116,6 +120,151 @@ static void *dlopen_dll( const char *name )
|
|||
}
|
||||
|
||||
|
||||
/* adjust an array of pointers to make them into RVAs */
|
||||
static inline void fixup_rva_ptrs( void *array, void *base, int count )
|
||||
{
|
||||
void **ptr = (void **)array;
|
||||
while (count--)
|
||||
{
|
||||
if (*ptr) *ptr = (void *)((char *)*ptr - (char *)base);
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* fixup RVAs in the resource directory */
|
||||
static void fixup_resources( IMAGE_RESOURCE_DIRECTORY *dir, char *root, void *base )
|
||||
{
|
||||
IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
|
||||
int i;
|
||||
|
||||
entry = (IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
|
||||
for (i = 0; i < dir->NumberOfNamedEntries + dir->NumberOfIdEntries; i++, entry++)
|
||||
{
|
||||
void *ptr = root + entry->u2.s.OffsetToDirectory;
|
||||
if (entry->u2.s.DataIsDirectory) fixup_resources( ptr, root, base );
|
||||
else
|
||||
{
|
||||
IMAGE_RESOURCE_DATA_ENTRY *data = ptr;
|
||||
fixup_rva_ptrs( &data->OffsetToData, base, 1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* map a builtin dll in memory and fixup RVAs */
|
||||
static void *map_dll( const IMAGE_NT_HEADERS *nt_descr )
|
||||
{
|
||||
IMAGE_DATA_DIRECTORY *dir;
|
||||
IMAGE_DOS_HEADER *dos;
|
||||
IMAGE_NT_HEADERS *nt;
|
||||
IMAGE_SECTION_HEADER *sec;
|
||||
BYTE *addr, *code_start, *data_start;
|
||||
size_t page_size = getpagesize();
|
||||
int nb_sections = 2; /* code + data */
|
||||
|
||||
size_t size = (sizeof(IMAGE_DOS_HEADER)
|
||||
+ sizeof(IMAGE_NT_HEADERS)
|
||||
+ nb_sections * sizeof(IMAGE_SECTION_HEADER));
|
||||
|
||||
assert( size <= page_size );
|
||||
|
||||
if (nt_descr->OptionalHeader.ImageBase)
|
||||
{
|
||||
addr = wine_anon_mmap( (void *)nt_descr->OptionalHeader.ImageBase,
|
||||
page_size, PROT_READ|PROT_WRITE, MAP_FIXED );
|
||||
if (addr != (BYTE *)nt_descr->OptionalHeader.ImageBase) return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* this will leak memory; but it should never happen */
|
||||
addr = wine_anon_mmap( NULL, page_size, PROT_READ|PROT_WRITE, 0 );
|
||||
if (addr == (BYTE *)-1) return NULL;
|
||||
}
|
||||
|
||||
dos = (IMAGE_DOS_HEADER *)addr;
|
||||
nt = (IMAGE_NT_HEADERS *)(dos + 1);
|
||||
sec = (IMAGE_SECTION_HEADER *)(nt + 1);
|
||||
code_start = addr + page_size;
|
||||
|
||||
/* HACK! */
|
||||
data_start = code_start + page_size;
|
||||
|
||||
/* Build the DOS and NT headers */
|
||||
|
||||
dos->e_magic = IMAGE_DOS_SIGNATURE;
|
||||
dos->e_lfanew = sizeof(*dos);
|
||||
|
||||
*nt = *nt_descr;
|
||||
|
||||
nt->FileHeader.NumberOfSections = nb_sections;
|
||||
nt->OptionalHeader.SizeOfCode = data_start - code_start;
|
||||
nt->OptionalHeader.SizeOfInitializedData = 0;
|
||||
nt->OptionalHeader.SizeOfUninitializedData = 0;
|
||||
nt->OptionalHeader.ImageBase = (DWORD)addr;
|
||||
|
||||
fixup_rva_ptrs( &nt->OptionalHeader.AddressOfEntryPoint, addr, 1 );
|
||||
|
||||
/* Build the code section */
|
||||
|
||||
strcpy( sec->Name, ".text" );
|
||||
sec->SizeOfRawData = data_start - code_start;
|
||||
sec->Misc.VirtualSize = sec->SizeOfRawData;
|
||||
sec->VirtualAddress = code_start - addr;
|
||||
sec->PointerToRawData = code_start - addr;
|
||||
sec->Characteristics = (IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ);
|
||||
sec++;
|
||||
|
||||
/* Build the data section */
|
||||
|
||||
strcpy( sec->Name, ".data" );
|
||||
sec->SizeOfRawData = 0;
|
||||
sec->Misc.VirtualSize = sec->SizeOfRawData;
|
||||
sec->VirtualAddress = data_start - addr;
|
||||
sec->PointerToRawData = data_start - addr;
|
||||
sec->Characteristics = (IMAGE_SCN_CNT_INITIALIZED_DATA |
|
||||
IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ);
|
||||
sec++;
|
||||
|
||||
/* Build the import directory */
|
||||
|
||||
dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY];
|
||||
if (dir->Size)
|
||||
{
|
||||
IMAGE_IMPORT_DESCRIPTOR *imports = (void *)dir->VirtualAddress;
|
||||
fixup_rva_ptrs( &dir->VirtualAddress, addr, 1 );
|
||||
/* we can fixup everything at once since we only have pointers and 0 values */
|
||||
fixup_rva_ptrs( imports, addr, dir->Size / sizeof(void*) );
|
||||
}
|
||||
|
||||
/* Build the resource directory */
|
||||
|
||||
dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_RESOURCE_DIRECTORY];
|
||||
if (dir->Size)
|
||||
{
|
||||
void *ptr = (void *)dir->VirtualAddress;
|
||||
fixup_rva_ptrs( &dir->VirtualAddress, addr, 1 );
|
||||
fixup_resources( ptr, ptr, addr );
|
||||
}
|
||||
|
||||
/* Build the export directory */
|
||||
|
||||
dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_EXPORT_DIRECTORY];
|
||||
if (dir->Size)
|
||||
{
|
||||
IMAGE_EXPORT_DIRECTORY *exports = (void *)dir->VirtualAddress;
|
||||
fixup_rva_ptrs( &dir->VirtualAddress, addr, 1 );
|
||||
fixup_rva_ptrs( (void *)exports->AddressOfFunctions, addr, exports->NumberOfFunctions );
|
||||
fixup_rva_ptrs( (void *)exports->AddressOfNames, addr, exports->NumberOfNames );
|
||||
fixup_rva_ptrs( &exports->Name, addr, 1 );
|
||||
fixup_rva_ptrs( &exports->AddressOfFunctions, addr, 1 );
|
||||
fixup_rva_ptrs( &exports->AddressOfNames, addr, 1 );
|
||||
fixup_rva_ptrs( &exports->AddressOfNameOrdinals, addr, 1 );
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* __wine_dll_register
|
||||
*
|
||||
|
@ -123,7 +272,7 @@ static void *dlopen_dll( const char *name )
|
|||
*/
|
||||
void __wine_dll_register( const IMAGE_NT_HEADERS *header, const char *filename )
|
||||
{
|
||||
if (load_dll_callback) load_dll_callback( header, filename );
|
||||
if (load_dll_callback) load_dll_callback( map_dll(header), filename );
|
||||
else
|
||||
{
|
||||
if (!(header->FileHeader.Characteristics & IMAGE_FILE_DLL))
|
||||
|
@ -154,10 +303,10 @@ void wine_dll_set_callback( load_dll_callback_t load )
|
|||
const IMAGE_NT_HEADERS *nt = builtin_dlls[i].nt;
|
||||
if (!nt) continue;
|
||||
builtin_dlls[i].nt = NULL;
|
||||
load_dll_callback( nt, builtin_dlls[i].filename );
|
||||
load_dll_callback( map_dll(nt), builtin_dlls[i].filename );
|
||||
}
|
||||
nb_dlls = 0;
|
||||
if (main_exe) load_dll_callback( main_exe, "" );
|
||||
if (main_exe) load_dll_callback( map_dll(main_exe), "" );
|
||||
}
|
||||
|
||||
|
||||
|
@ -182,7 +331,7 @@ void *wine_dll_load( const char *filename )
|
|||
{
|
||||
const IMAGE_NT_HEADERS *nt = builtin_dlls[i].nt;
|
||||
builtin_dlls[i].nt = NULL;
|
||||
load_dll_callback( nt, builtin_dlls[i].filename );
|
||||
load_dll_callback( map_dll(nt), builtin_dlls[i].filename );
|
||||
return (void *)1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,15 +47,14 @@ void *BUILTIN32_dlopen( const char *name )
|
|||
|
||||
if (!(handle = wine_dll_load( name )))
|
||||
{
|
||||
char buffer[128];
|
||||
LPSTR pErr, p;
|
||||
pErr = dlerror();
|
||||
p = strchr(pErr, ':');
|
||||
if ((p) &&
|
||||
(!strncmp(p, ": undefined symbol", 18))) /* undef symbol -> ERR() */
|
||||
ERR("failed to load %s: %s\n", buffer, pErr);
|
||||
ERR("failed to load %s: %s\n", name, pErr);
|
||||
else /* WARN() for libraries that are supposed to be native */
|
||||
WARN("failed to load %s: %s\n", buffer, pErr );
|
||||
WARN("failed to load %s: %s\n", name, pErr );
|
||||
}
|
||||
return handle;
|
||||
#else
|
||||
|
@ -76,193 +75,32 @@ int BUILTIN32_dlclose( void *handle )
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* fixup_rva_ptrs
|
||||
*
|
||||
* Adjust an array of pointers to make them into RVAs.
|
||||
*/
|
||||
static inline void fixup_rva_ptrs( void *array, void *base, int count )
|
||||
{
|
||||
void **ptr = (void **)array;
|
||||
while (count--)
|
||||
{
|
||||
if (*ptr) *ptr = (void *)((char *)*ptr - (char *)base);
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* fixup_resources
|
||||
*/
|
||||
static void fixup_resources( IMAGE_RESOURCE_DIRECTORY *dir, char *root, void *base )
|
||||
{
|
||||
IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
|
||||
int i;
|
||||
|
||||
entry = (IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
|
||||
for (i = 0; i < dir->NumberOfNamedEntries + dir->NumberOfIdEntries; i++, entry++)
|
||||
{
|
||||
void *ptr = root + entry->u2.s.OffsetToDirectory;
|
||||
if (entry->u2.s.DataIsDirectory) fixup_resources( ptr, root, base );
|
||||
else
|
||||
{
|
||||
IMAGE_RESOURCE_DATA_ENTRY *data = ptr;
|
||||
fixup_rva_ptrs( &data->OffsetToData, base, 1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* load_image
|
||||
*
|
||||
* Load a built-in Win32 module. Helper function for load_library.
|
||||
*/
|
||||
static HMODULE load_image( const IMAGE_NT_HEADERS *nt_descr, const char *filename )
|
||||
{
|
||||
IMAGE_DATA_DIRECTORY *dir;
|
||||
IMAGE_DOS_HEADER *dos;
|
||||
IMAGE_NT_HEADERS *nt;
|
||||
IMAGE_SECTION_HEADER *sec;
|
||||
INT size, nb_sections;
|
||||
BYTE *addr, *code_start, *data_start;
|
||||
int page_size = VIRTUAL_GetPageSize();
|
||||
|
||||
/* Allocate the module */
|
||||
|
||||
nb_sections = 2; /* code + data */
|
||||
|
||||
size = (sizeof(IMAGE_DOS_HEADER)
|
||||
+ sizeof(IMAGE_NT_HEADERS)
|
||||
+ nb_sections * sizeof(IMAGE_SECTION_HEADER));
|
||||
|
||||
assert( size <= page_size );
|
||||
|
||||
if (nt_descr->OptionalHeader.ImageBase)
|
||||
{
|
||||
void *base = (void *)nt_descr->OptionalHeader.ImageBase;
|
||||
if ((addr = wine_anon_mmap( base, page_size, PROT_READ|PROT_WRITE, MAP_FIXED )) != base)
|
||||
{
|
||||
ERR("failed to map over PE header for %s at %p\n", filename, base );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(addr = VirtualAlloc( NULL, page_size, MEM_COMMIT, PAGE_READWRITE ))) return 0;
|
||||
}
|
||||
|
||||
dos = (IMAGE_DOS_HEADER *)addr;
|
||||
nt = (IMAGE_NT_HEADERS *)(dos + 1);
|
||||
sec = (IMAGE_SECTION_HEADER *)(nt + 1);
|
||||
code_start = addr + page_size;
|
||||
|
||||
/* HACK! */
|
||||
data_start = code_start + page_size;
|
||||
|
||||
/* Build the DOS and NT headers */
|
||||
|
||||
dos->e_magic = IMAGE_DOS_SIGNATURE;
|
||||
dos->e_lfanew = sizeof(*dos);
|
||||
|
||||
*nt = *nt_descr;
|
||||
|
||||
nt->FileHeader.NumberOfSections = nb_sections;
|
||||
nt->OptionalHeader.SizeOfCode = data_start - code_start;
|
||||
nt->OptionalHeader.SizeOfInitializedData = 0;
|
||||
nt->OptionalHeader.SizeOfUninitializedData = 0;
|
||||
nt->OptionalHeader.ImageBase = (DWORD)addr;
|
||||
|
||||
fixup_rva_ptrs( &nt->OptionalHeader.AddressOfEntryPoint, addr, 1 );
|
||||
|
||||
/* Build the code section */
|
||||
|
||||
strcpy( sec->Name, ".text" );
|
||||
sec->SizeOfRawData = data_start - code_start;
|
||||
sec->Misc.VirtualSize = sec->SizeOfRawData;
|
||||
sec->VirtualAddress = code_start - addr;
|
||||
sec->PointerToRawData = code_start - addr;
|
||||
sec->Characteristics = (IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ);
|
||||
sec++;
|
||||
|
||||
/* Build the data section */
|
||||
|
||||
strcpy( sec->Name, ".data" );
|
||||
sec->SizeOfRawData = 0;
|
||||
sec->Misc.VirtualSize = sec->SizeOfRawData;
|
||||
sec->VirtualAddress = data_start - addr;
|
||||
sec->PointerToRawData = data_start - addr;
|
||||
sec->Characteristics = (IMAGE_SCN_CNT_INITIALIZED_DATA |
|
||||
IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ);
|
||||
sec++;
|
||||
|
||||
/* Build the import directory */
|
||||
|
||||
dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY];
|
||||
if (dir->Size)
|
||||
{
|
||||
IMAGE_IMPORT_DESCRIPTOR *imports = (void *)dir->VirtualAddress;
|
||||
fixup_rva_ptrs( &dir->VirtualAddress, addr, 1 );
|
||||
/* we can fixup everything at once since we only have pointers and 0 values */
|
||||
fixup_rva_ptrs( imports, addr, dir->Size / sizeof(void*) );
|
||||
}
|
||||
|
||||
/* Build the resource directory */
|
||||
|
||||
dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_RESOURCE_DIRECTORY];
|
||||
if (dir->Size)
|
||||
{
|
||||
void *ptr = (void *)dir->VirtualAddress;
|
||||
fixup_rva_ptrs( &dir->VirtualAddress, addr, 1 );
|
||||
fixup_resources( ptr, ptr, addr );
|
||||
}
|
||||
|
||||
/* Build the export directory */
|
||||
|
||||
dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_EXPORT_DIRECTORY];
|
||||
if (dir->Size)
|
||||
{
|
||||
IMAGE_EXPORT_DIRECTORY *exports = (void *)dir->VirtualAddress;
|
||||
fixup_rva_ptrs( &dir->VirtualAddress, addr, 1 );
|
||||
fixup_rva_ptrs( (void *)exports->AddressOfFunctions, addr, exports->NumberOfFunctions );
|
||||
fixup_rva_ptrs( (void *)exports->AddressOfNames, addr, exports->NumberOfNames );
|
||||
fixup_rva_ptrs( &exports->Name, addr, 1 );
|
||||
fixup_rva_ptrs( &exports->AddressOfFunctions, addr, 1 );
|
||||
fixup_rva_ptrs( &exports->AddressOfNames, addr, 1 );
|
||||
fixup_rva_ptrs( &exports->AddressOfNameOrdinals, addr, 1 );
|
||||
|
||||
/* Setup relay debugging entry points */
|
||||
if (TRACE_ON(relay)) RELAY_SetupDLL( addr );
|
||||
}
|
||||
|
||||
return (HMODULE)addr;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* load_library
|
||||
*
|
||||
* Load a library in memory; callback function for wine_dll_register
|
||||
*/
|
||||
static void load_library( const IMAGE_NT_HEADERS *nt, const char *filename )
|
||||
static void load_library( void *base, const char *filename )
|
||||
{
|
||||
HMODULE module;
|
||||
HMODULE module = (HMODULE)base;
|
||||
WINE_MODREF *wm;
|
||||
|
||||
if (!(nt->FileHeader.Characteristics & IMAGE_FILE_DLL))
|
||||
if (!base)
|
||||
{
|
||||
ERR("could not map image for %s\n", filename ? filename : "main exe" );
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(PE_HEADER(module)->FileHeader.Characteristics & IMAGE_FILE_DLL))
|
||||
{
|
||||
/* if we already have an executable, ignore this one */
|
||||
if (!main_module) main_module = load_image( nt, "main exe" );
|
||||
if (!main_module) main_module = module;
|
||||
return; /* don't create the modref here, will be done later on */
|
||||
}
|
||||
|
||||
if (GetModuleHandleA( filename ))
|
||||
MESSAGE( "Warning: loading builtin %s, but native version already present. Expect trouble.\n", filename );
|
||||
|
||||
/* Load built-in module */
|
||||
if (!(module = load_image( nt, filename ))) return;
|
||||
|
||||
/* Create 32-bit MODREF */
|
||||
if (!(wm = PE_CreateModule( module, filename, 0, -1, TRUE )))
|
||||
{
|
||||
|
@ -270,7 +108,7 @@ static void load_library( const IMAGE_NT_HEADERS *nt, const char *filename )
|
|||
SetLastError( ERROR_OUTOFMEMORY );
|
||||
return;
|
||||
}
|
||||
TRACE( "loaded %s %p %x %p\n", filename, wm, module, nt );
|
||||
TRACE( "loaded %s %p %x\n", filename, wm, module );
|
||||
wm->refCount++; /* we don't support freeing builtin dlls (FIXME)*/
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue