diff --git a/include/wine/library.h b/include/wine/library.h index a2b4fa8331e..5387f30f16e 100644 --- a/include/wine/library.h +++ b/include/wine/library.h @@ -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 ); diff --git a/library/loader.c b/library/loader.c index 95922d042e6..4d202ac7218 100644 --- a/library/loader.c +++ b/library/loader.c @@ -11,13 +11,17 @@ #include #include #include - +#include +#ifdef HAVE_SYS_MMAN_H +#include +#endif #ifdef HAVE_DL_API #include #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; } } diff --git a/relay32/builtin32.c b/relay32/builtin32.c index c17a402bb86..540ff9f95bc 100644 --- a/relay32/builtin32.c +++ b/relay32/builtin32.c @@ -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)*/ }