Do builtin modules fixups in library/loader.c before calling the

load_dll callback.
This commit is contained in:
Alexandre Julliard 2000-11-08 23:02:48 +00:00
parent 4e951ea25b
commit db4c45671f
3 changed files with 169 additions and 184 deletions

View File

@ -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 );

View File

@ -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;
}
}

View File

@ -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)*/
}