1 /* From wine1.2-1.1.42/dlls/ntdll/loader.c */
6 * Copyright 1995, 2003 Alexandre Julliard
7 * Copyright 2002 Dmitry Timoshkov for CodeWeavers
8 * Copyright 2010 g10 Code GmbH
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
36 /* convert PE image VirtualAddress to Real Address */
37 static void *get_rva( HMODULE module, DWORD va )
39 return (void *)((char *)module + va);
43 #define USE_HIMEMCE_MAP
44 #ifdef USE_HIMEMCE_MAP
45 /* Support for DLL loading. */
47 #include "himemce-map.h"
49 static int himemce_map_initialized;
50 static struct himemce_map *himemce_map;
51 int himemce_mod_loaded[HIMEMCE_MAP_MAX_MODULES];
54 himemce_invoke_dll_mains (DWORD reason, LPVOID reserved)
61 for (i = 0; i < himemce_map->nr_modules; i++)
62 if (himemce_mod_loaded[modidx])
64 char *ptr = himemce_map->module[i].base;
65 IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)ptr;
66 IMAGE_NT_HEADERS *nt = (IMAGE_NT_HEADERS *)(ptr + dos->e_lfanew);
67 BOOL WINAPI (*dllmain) (HINSTANCE, DWORD, LPVOID);
70 dllmain = nt->OptionalHeader.AddressOfEntryPoint;
71 res = (*dllmain) (ptr, reason, reserved);
72 if (reason == DLL_PROCESS_ATTACH && !res)
74 ERR ("attaching %s failed (ignored)", himemce_map->module[i].name);
85 if (himemce_map_initialized)
87 himemce_map_initialized = 1;
88 himemce_map = himemce_map_open ();
91 TRACE ("can not open himemce map\n");
94 TRACE ("himemce map found at %p (reserving 0x%x bytes at %p)\n", himemce_map,
95 himemce_map->low_start, himemce_map->low_size);
96 ptr = VirtualAlloc(himemce_map->low_start, himemce_map->low_size,
97 MEM_RESERVE, PAGE_EXECUTE_READWRITE);
100 TRACE ("failed to reserve memory: %i\n", GetLastError ());
101 himemce_map_close (himemce_map);
106 himemce_set_dllmain_cb (himemce_invoke_dll_mains);
110 # define page_mask 0xfff
111 # define page_shift 12
112 # define page_size 0x1000
114 #define ROUND_SIZE(size) \
115 (((SIZE_T)(size) + page_mask) & ~page_mask)
118 section_size (IMAGE_SECTION_HEADER *sec)
120 static const SIZE_T sector_align = 0x1ff;
121 SIZE_T map_size, file_size, end;
123 if (!sec->Misc.VirtualSize)
124 map_size = ROUND_SIZE( sec->SizeOfRawData );
126 map_size = ROUND_SIZE( sec->Misc.VirtualSize );
128 file_size = (sec->SizeOfRawData + (sec->PointerToRawData & sector_align)
129 + sector_align) & ~sector_align;
130 if (file_size > map_size) file_size = map_size;
131 end = ROUND_SIZE( file_size );
132 if (end > map_size) end = map_size;
137 /* Returns the base of the module after loading it, if necessary.
138 NULL if not found, -1 if a fatal error occurs. */
140 himemce_map_load_dll (const char *name)
142 struct himemce_module *mod;
145 IMAGE_DOS_HEADER *dos;
146 IMAGE_NT_HEADERS *nt;
147 IMAGE_SECTION_HEADER *sec;
150 const IMAGE_IMPORT_DESCRIPTOR *imports;
157 mod = himemce_map_find_module (himemce_map, name);
160 modidx = mod - himemce_map->module;
161 if (himemce_mod_loaded[modidx])
164 /* First map the sections low. */
166 dos = (IMAGE_DOS_HEADER *) ptr;
167 nt = (IMAGE_NT_HEADERS *) (ptr + dos->e_lfanew);
168 sec = (IMAGE_SECTION_HEADER *) ((char*) &nt->OptionalHeader
169 + nt->FileHeader.SizeOfOptionalHeader);
170 sec_cnt = nt->FileHeader.NumberOfSections;
171 for (idx = 0; idx < sec_cnt; idx++)
176 if (! sec[idx].PointerToLinenumbers)
178 secsize = section_size (&sec[idx]);
179 secptr = VirtualAlloc ((void *) sec[idx].PointerToLinenumbers,
180 secsize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
183 TRACE ("could not allocate 0x%x bytes of low memory at %p: %i\n",
184 secsize, sec[idx].PointerToLinenumbers, GetLastError ());
187 memcpy (secptr, ptr + sec[idx].VirtualAddress, secsize);
190 /* To break circles, we claim that we loaded before recursing. */
191 himemce_mod_loaded[modidx]++;
192 imports = MyRtlImageDirectoryEntryToData ((HMODULE) ptr, TRUE,
193 IMAGE_DIRECTORY_ENTRY_IMPORT,
198 while (imports[idx].Name && imports[idx].FirstThunk)
200 char *iname = ptr + imports[idx].Name;
204 ibase = himemce_map_load_dll (iname);
205 if (ibase == (void *) -1)
207 /* Nothing to do if ibase !=0: Successful loading of high DLL. */
210 ibase = LoadLibrary (iname);
213 TRACE ("Could not find %s, dependency of %s\n", iname, name);
225 get_rva_low (char *module, size_t rva)
227 IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)module;
228 IMAGE_NT_HEADERS *nt = (IMAGE_NT_HEADERS *)(module + dos->e_lfanew);
229 IMAGE_SECTION_HEADER *sec;
233 sec = (IMAGE_SECTION_HEADER*)((char*)&nt->OptionalHeader
234 + nt->FileHeader.SizeOfalHeader);
235 sec_cnt = nt->FileHeader.NumberOfSections;
237 for (idx = 0; idx < sec_cnt; idx++)
239 if (! sec[idx].PointerToLinenumbers)
241 if (rva >= sec[idx].VirtualAddress
242 && rva < sec[idx].VirtualAddress + section_size (&sec[idx]))
246 return (void *)((char *)module + rva);
248 return (void *)((char *)sec[idx].PointerToLinenumbers
249 + (rva - sec[idx].VirtualAddress));
254 find_ordinal_export (void *module, const IMAGE_EXPORT_DIRECTORY *exports,
255 DWORD exp_size, DWORD ordinal, LPCWSTR load_path)
258 const DWORD *functions = get_rva (module, exports->AddressOfFunctions);
260 if (ordinal >= exports->NumberOfFunctions)
262 TRACE(" ordinal %d out of range!\n", ordinal + exports->Base );
265 if (!functions[ordinal]) return NULL;
268 /* if the address falls into the export dir, it's a forward */
269 if (((const char *)proc >= (const char *)exports) &&
270 ((const char *)proc < (const char *)exports + exp_size))
271 return find_forwarded_export( module, (const char *)proc, load_path );
274 proc = get_rva_low (module, functions[ordinal]);
279 find_named_export (void *module, const IMAGE_EXPORT_DIRECTORY *exports,
280 DWORD exp_size, const char *name, int hint,
283 const WORD *ordinals = get_rva (module, exports->AddressOfNameOrdinals);
284 const DWORD *names = get_rva (module, exports->AddressOfNames);
285 int min = 0, max = exports->NumberOfNames - 1;
287 /* first check the hint */
288 if (hint >= 0 && hint <= max)
290 char *ename = get_rva( module, names[hint] );
291 if (!strcmp( ename, name ))
292 return find_ordinal_export( module, exports, exp_size,
293 ordinals[hint], load_path);
296 /* then do a binary search */
299 int res, pos = (min + max) / 2;
300 char *ename = get_rva( module, names[pos] );
301 if (!(res = strcmp( ename, name )))
302 return find_ordinal_export( module, exports, exp_size,
303 ordinals[pos], load_path);
304 if (res > 0) max = pos - 1;
313 PIMAGE_NT_HEADERS MyRtlImageNtHeader(HMODULE hModule)
315 IMAGE_NT_HEADERS *ret;
316 IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)hModule;
319 if (dos->e_magic == IMAGE_DOS_SIGNATURE)
321 ret = (IMAGE_NT_HEADERS *)((char *)dos + dos->e_lfanew);
322 if (ret->Signature != IMAGE_NT_SIGNATURE) ret = NULL;
328 /* internal representation of 32bit modules. per process. */
329 typedef struct _wine_modref
333 struct _wine_modref **deps;
336 /* FIXME: cmp with himemce-map.h */
337 #define MAX_MODREFS 64
338 WINE_MODREF *modrefs[MAX_MODREFS];
342 static WINE_MODREF *current_modref;
345 /* convert from straight ASCII to Unicode without depending on the current codepage */
346 static void ascii_to_unicode( WCHAR *dst, const char *src, size_t len )
348 while (len--) *dst++ = (unsigned char)*src++;
352 /***********************************************************************
353 * RtlImageDirectoryEntryToData (NTDLL.@)
355 PVOID MyRtlImageDirectoryEntryToData( HMODULE module, BOOL image, WORD dir, ULONG *size )
357 const IMAGE_NT_HEADERS *nt;
360 if ((ULONG_PTR)module & 1) /* mapped as data file */
362 module = (HMODULE)((ULONG_PTR)module & ~1);
365 if (!(nt = MyRtlImageNtHeader( module ))) return NULL;
366 if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
368 const IMAGE_NT_HEADERS64 *nt64 = (const IMAGE_NT_HEADERS64 *)nt;
370 if (dir >= nt64->OptionalHeader.NumberOfRvaAndSizes) return NULL;
371 if (!(addr = nt64->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL;
372 *size = nt64->OptionalHeader.DataDirectory[dir].Size;
373 if (image || addr < nt64->OptionalHeader.SizeOfHeaders) return (char *)module + addr;
375 else if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
377 const IMAGE_NT_HEADERS32 *nt32 = (const IMAGE_NT_HEADERS32 *)nt;
379 if (dir >= nt32->OptionalHeader.NumberOfRvaAndSizes) return NULL;
380 if (!(addr = nt32->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL;
381 *size = nt32->OptionalHeader.DataDirectory[dir].Size;
382 if (image || addr < nt32->OptionalHeader.SizeOfHeaders) return (char *)module + addr;
387 /* not mapped as image, need to find the section containing the virtual address */
388 return RtlImageRvaToVa( nt, module, addr, NULL );
395 #define allocate_stub(x,y) (0xdeadbeef)
397 /*************************************************************************
400 * Import the dll specified by the given import descriptor.
401 * The loader_section must be locked while calling this function.
403 static WINE_MODREF *import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LPCWSTR load_path )
405 NTSTATUS status = STATUS_SUCCESS;
406 // WINE_MODREF *wmImp;
408 #ifdef USE_HIMEMCE_MAP
410 const IMAGE_EXPORT_DIRECTORY *exports;
413 const IMAGE_THUNK_DATA *import_list;
414 IMAGE_THUNK_DATA *thunk_list;
416 const char *name = get_rva( module, descr->Name );
417 DWORD len = strlen(name);
420 SIZE_T protect_size = 0;
427 thunk_list = get_rva( module, (DWORD)descr->FirstThunk );
428 if (descr->OriginalFirstThunk)
429 import_list = get_rva( module, (DWORD)descr->OriginalFirstThunk );
431 import_list = thunk_list;
433 while (len && name[len-1] == ' ') len--; /* remove trailing spaces */
436 if (! _stricmp (name, "coredll.dll"))
440 #ifdef USE_HIMEMCE_MAP
441 imp_base = himemce_map_load_dll (name);
442 if (imp_base == (void *) -1)
443 status = GetLastError ();
448 if (len * sizeof(WCHAR) < sizeof(buffer))
450 ascii_to_unicode( buffer, name, len );
452 // status = load_dll( load_path, buffer, 0, &wmImp );
453 imp_mod = LoadLibrary (buffer);
454 if (imp_mod == INVALID_HANDLE_VALUE)
455 status = GetLastError ();
457 else /* need to allocate a larger buffer */
459 WCHAR *ptr = malloc ((len + 1) * sizeof(WCHAR) );
460 if (!ptr) return NULL;
461 ascii_to_unicode( ptr, name, len );
463 // status = load_dll( load_path, ptr, 0, &wmImp );
464 imp_mod = LoadLibrary (ptr);
465 if (imp_mod == INVALID_HANDLE_VALUE)
466 status = GetLastError ();
469 #ifdef USE_HIMEMCE_MAP
474 if (status == STATUS_DLL_NOT_FOUND)
475 TRACE("Library %s (which is needed by %s) not found\n",
476 name, current_modref->ldr.FullDllName);
478 TRACE("Loading library %s (which is needed by %s) failed (error %x).\n",
479 name, current_modref->ldr.FullDllName, status);
484 /* unprotect the import address table since it can be located in
485 * readonly section */
486 while (import_list[protect_size].u1.Ordinal) protect_size++;
487 protect_base = thunk_list;
488 protect_size *= sizeof(*thunk_list);
489 NtProtectVirtualMemory( NtCurrentProcess(), &protect_base,
490 &protect_size, PAGE_WRITECOPY, &protect_old );
493 #ifdef USE_HIMEMCE_MAP
496 exports = MyRtlImageDirectoryEntryToData( imp_base, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size );
500 /* set all imported function to deadbeef */
501 while (import_list->u1.Ordinal)
503 if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))
505 int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
506 TRACE("No implementation for %s.%d", name, ordinal );
507 thunk_list->u1.Function = (PDWORD)(ULONG_PTR)allocate_stub( name, IntToPtr(ordinal) );
511 IMAGE_IMPORT_BY_NAME *pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );
512 TRACE("No implementation for %s.%s", name, pe_name->Name );
513 thunk_list->u1.Function = (PDWORD)(ULONG_PTR)allocate_stub( name, (const char*)pe_name->Name );
515 TRACE(" imported from %s, allocating stub %p\n",
516 current_modref->ldr.FullDllName,
517 (void *)thunk_list->u1.Function );
526 while (import_list->u1.Ordinal)
528 if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))
530 int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
532 #ifdef USE_HIMEMCE_MAP
534 thunk_list->u1.Function = (PDWORD)(ULONG_PTR)find_ordinal_export( imp_base, exports, exp_size,
535 ordinal - exports->Base, load_path );
542 #define COREDLL_MALLOC 1041
543 #define COREDLL_CALLOC 1346
544 #define COREDLL_FREE 1018
545 #define COREDLL_REALLOC 1054
547 if (ordinal == COREDLL_MALLOC)
548 thunk_list->u1.Function = (PWORD) dlmalloc;
549 else if (ordinal == COREDLL_CALLOC)
550 thunk_list->u1.Function = (PWORD) dlcalloc;
551 else if (ordinal == COREDLL_FREE)
552 thunk_list->u1.Function = (PWORD) dlfree;
553 else if (ordinal == COREDLL_REALLOC)
554 thunk_list->u1.Function = (PWORD) dlrealloc;
556 thunk_list->u1.Function = (PWORD)(ULONG_PTR)GetProcAddress (imp_mod, (void *) (ordinal & 0xffff));
560 thunk_list->u1.Function = (PDWORD)(ULONG_PTR)GetProcAddress (imp_mod, (void *) (ordinal & 0xffff));
562 if (!thunk_list->u1.Function)
564 thunk_list->u1.Function = (PDWORD) allocate_stub( name, IntToPtr(ordinal) );
565 TRACE("No implementation for %s.%d imported from %s, setting to %p\n",
566 name, ordinal, current_modref->ldr.FullDllName,
567 (void *)thunk_list->u1.Function );
569 TRACE("--- Ordinal %s.%d = %p\n", name, ordinal, (void *)thunk_list->u1.Function );
571 else /* import by name */
573 IMAGE_IMPORT_BY_NAME *pe_name;
575 pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );
576 symname = (const char*)pe_name->Name;
578 #ifdef USE_HIMEMCE_MAP
580 thunk_list->u1.Function = (PDWORD)(ULONG_PTR)find_named_export( imp_base, exports, exp_size,
581 (const char*)pe_name->Name,
582 pe_name->Hint, load_path );
588 if (! strcmp (symname, "malloc"))
589 thunk_list->u1.Function = (PWORD) dlmalloc;
590 else if (! strcmp (symname, "calloc"))
591 thunk_list->u1.Function = (PWORD) dlcalloc;
592 else if (! strcmp (symname, "free"))
593 thunk_list->u1.Function = (PWORD) dlfree;
594 else if (! strcmp (symname, "realloc"))
595 thunk_list->u1.Function = (PWORD) dlrealloc;
597 thunk_list->u1.Function = (PDWORD)(ULONG_PTR)GetProcAddressA (imp_mod, symname);
601 thunk_list->u1.Function = (PDWORD)(ULONG_PTR)GetProcAddressA (imp_mod, symname);
602 if (!thunk_list->u1.Function)
604 thunk_list->u1.Function = (PDWORD) allocate_stub (name, symname);
605 TRACE("No implementation for %s.%s imported from %s, setting to %p\n",
606 name, symname, current_modref->ldr.FullDllName,
607 (void *)thunk_list->u1.Function );
609 TRACE("--- %s %s.%d = %p\n",
610 symname, name, pe_name->Hint, (void *)thunk_list->u1.Function);
617 /* restore old protection of the import address table */
618 NtProtectVirtualMemory( NtCurrentProcess(), &protect_base, &protect_size, protect_old, NULL );
626 /****************************************************************
629 * Fixup all imports of a given module.
630 * The loader_section must be locked while calling this function.
632 static NTSTATUS fixup_imports( WINE_MODREF *wm, LPCWSTR load_path )
635 const IMAGE_IMPORT_DESCRIPTOR *imports;
641 if (!(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) return STATUS_SUCCESS; /* already done */
642 wm->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;
644 if (!(imports = MyRtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE,
645 IMAGE_DIRECTORY_ENTRY_IMPORT, &size )))
646 return STATUS_SUCCESS;
649 while (imports[nb_imports].Name && imports[nb_imports].FirstThunk) nb_imports++;
651 if (!nb_imports) return STATUS_SUCCESS; /* no imports */
654 if (!create_module_activation_context( &wm->ldr ))
655 RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );
659 /* Allocate module dependency list */
660 wm->nDeps = nb_imports;
661 wm->deps = RtlAllocateHeap( GetProcessHeap(), 0, nb_imports*sizeof(WINE_MODREF *) );
664 /* load the imported modules. They are automatically
665 * added to the modref list of the process.
667 prev = current_modref;
669 status = STATUS_SUCCESS;
670 for (i = 0; i < nb_imports; i++)
672 // if (!(wm->deps[i] = import_dll( wm->ldr.BaseAddress, &imports[i], load_path )))
673 if (! import_dll( wm->ldr.BaseAddress, &imports[i], load_path ))
674 status = STATUS_DLL_NOT_FOUND;
676 current_modref = prev;
677 // if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
679 #ifdef USE_HIMEMCE_MAP
680 himemce_invoke_dll_mains (DLL_PROCESS_ATTACH, NULL);
687 static BOOL is_dll_native_subsystem( HMODULE module, const IMAGE_NT_HEADERS *nt, LPCWSTR filename )
693 /*************************************************************************
696 * Looks for the referenced HMODULE in the current process
697 * The loader_section must be locked while calling this function.
699 static WINE_MODREF *get_modref( HMODULE hmod )
702 for (i = 0; i < nr_modrefs; i++)
703 if (modrefs[i]->ldr.BaseAddress == hmod)
710 static WINE_MODREF *alloc_module( HMODULE hModule, LPCWSTR filename )
714 const IMAGE_NT_HEADERS *nt = MyRtlImageNtHeader(hModule);
716 PLIST_ENTRY entry, mark;
719 if (!(wm = malloc (sizeof(*wm)))) return NULL;
724 wm->ldr.BaseAddress = hModule;
725 wm->ldr.EntryPoint = NULL;
726 wm->ldr.SizeOfImage = nt->OptionalHeader.SizeOfImage;
727 wm->ldr.Flags = LDR_DONT_RESOLVE_REFS;
728 wm->ldr.LoadCount = 1;
729 wm->ldr.TlsIndex = -1;
730 wm->ldr.SectionHandle = NULL;
731 wm->ldr.CheckSum = 0;
732 wm->ldr.TimeDateStamp = 0;
733 wm->ldr.ActivationContext = 0;
735 wcscpy (wm->ldr.FullDllName, filename);
736 if ((p = wcsrchr( wm->ldr.FullDllName, L'\\' ))) p++;
737 else p = wm->ldr.FullDllName;
738 wcscpy (wm->ldr.BaseDllName, p );
740 if ((nt->FileHeader.Characteristics & IMAGE_FILE_DLL) && !is_dll_native_subsystem( hModule, nt, p ))
742 wm->ldr.Flags |= LDR_IMAGE_IS_DLL;
743 if (nt->OptionalHeader.AddressOfEntryPoint)
744 wm->ldr.EntryPoint = (char *)hModule + nt->OptionalHeader.AddressOfEntryPoint;
748 InsertTailList(&NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList,
749 &wm->ldr.InLoadOrderModuleList);
751 /* insert module in MemoryList, sorted in increasing base addresses */
752 mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
753 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
755 if (CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList)->BaseAddress > wm->ldr.BaseAddress)
758 entry->Blink->Flink = &wm->ldr.InMemoryOrderModuleList;
759 wm->ldr.InMemoryOrderModuleList.Blink = entry->Blink;
760 wm->ldr.InMemoryOrderModuleList.Flink = entry;
761 entry->Blink = &wm->ldr.InMemoryOrderModuleList;
763 /* wait until init is called for inserting into this list */
764 wm->ldr.InInitializationOrderModuleList.Flink = NULL;
765 wm->ldr.InInitializationOrderModuleList.Blink = NULL;
768 modrefs[nr_modrefs++] = wm;
774 static NTSTATUS load_native_dll( LPCWSTR load_path, LPCWSTR name, HANDLE file,
775 DWORD flags, WINE_MODREF** pwm )
784 TRACE("Trying native dll %S\n", name);
787 status = MyNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ,
788 NULL, &size, PAGE_READONLY, SEC_IMAGE, file );
789 if (status != STATUS_SUCCESS) return status;
792 status = MyNtMapViewOfSection( mapping, NtCurrentProcess(),
793 &module, 0, 0, &size, &len, ViewShare, 0, PAGE_READONLY );
794 CloseHandle( mapping );
795 if (status < 0) return status;
797 /* create the MODREF */
799 if (!(wm = alloc_module( module, name ))) return STATUS_NO_MEMORY;
803 if (!(flags & DONT_RESOLVE_DLL_REFERENCES))
806 return (STATUS_NOT_IMPLEMENTED);
808 if ((status = fixup_imports( wm, load_path )) != STATUS_SUCCESS)
811 /* the module has only be inserted in the load & memory order lists */
812 RemoveEntryList(&wm->ldr.InLoadOrderModuleList);
813 RemoveEntryList(&wm->ldr.InMemoryOrderModuleList);
815 /* FIXME: there are several more dangling references
816 * left. Including dlls loaded by this dll before the
817 * failed one. Unrolling is rather difficult with the
818 * current structure and we can leave them lying
819 * around with no problems, so we don't care.
820 * As these might reference our wm, we don't free it.
828 TRACE( "Loaded %S at %p: native\n", wm->ldr.FullDllName, module );
830 wm->ldr.LoadCount = 1;
832 return STATUS_SUCCESS;
836 static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname,
837 WCHAR *filename, ULONG *size, WINE_MODREF **pwm, HANDLE *handle )
839 HMODULE hnd = GetModuleHandle (NULL);
843 assert (*size == MAX_PATH);
845 if (libname[0] == L'/' || libname[0] == L'\\')
847 wcscpy (filename, libname);
851 len = GetModuleFileName (hnd, filename, MAX_PATH);
852 filename[len++] = L'\\';
853 wcscpy (&filename[len], libname);
855 TRACE( "opening %S\n", filename);
859 *handle = CreateFile( filename, GENERIC_READ, FILE_SHARE_READ, NULL,
860 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
861 TRACE ("find_dll_file: 0x%p (0x%x)\n", *handle, GetFileSize (*handle, NULL));
863 return STATUS_SUCCESS;
867 static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, DWORD flags, WINE_MODREF** pwm )
869 WCHAR filename[MAX_PATH];
874 TRACE( "looking for %S in %S\n", libname, load_path ? load_path : L"default path" );
878 find_dll_file( load_path, libname, filename, &size, pwm, &handle );
881 nts = STATUS_DLL_NOT_FOUND;
883 nts = load_native_dll( load_path, filename, handle, flags, pwm );
885 if (nts == STATUS_SUCCESS)
887 /* Initialize DLL just loaded */
888 TRACE("Loaded module %S at %p\n", filename, (*pwm)->ldr.BaseAddress);
890 CloseHandle( handle );
894 TRACE("Failed to load module %S; status=%x\n", libname, nts);
896 CloseHandle( handle );
901 NTSTATUS MyLdrLoadDll(LPCWSTR path_name, DWORD flags,
902 LPCWSTR libname, HMODULE* hModule)
907 /* Support for dll path removed. */
908 nts = load_dll( path_name, libname, flags, &wm );
911 assert (wm->ldr.Flags & LDR_DONT_RESOLVE_REFS);
913 if (nts == STATUS_SUCCESS && !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))
915 nts = process_attach( wm, NULL );
916 if (nts != STATUS_SUCCESS)
918 LdrUnloadDll(wm->ldr.BaseAddress);
923 *hModule = (wm) ? wm->ldr.BaseAddress : NULL;
930 /***********************************************************************
931 * LdrProcessRelocationBlock (NTDLL.@)
933 * Apply relocations to a given page of a mapped PE image.
935 IMAGE_BASE_RELOCATION * MyLdrProcessRelocationBlock( void *page, UINT count,
936 USHORT *relocs, INT_PTR delta )
940 USHORT offset = *relocs & 0xfff;
941 int type = *relocs >> 12;
944 case IMAGE_REL_BASED_ABSOLUTE:
947 case IMAGE_REL_BASED_HIGH:
948 *(short *)((char *)page + offset) += HIWORD(delta);
950 case IMAGE_REL_BASED_LOW:
951 *(short *)((char *)page + offset) += LOWORD(delta);
953 case IMAGE_REL_BASED_HIGHLOW:
954 *(int *)((char *)page + offset) += delta;
957 case IMAGE_REL_BASED_DIR64:
958 *(INT_PTR *)((char *)page + offset) += delta;
962 TRACE("Unknown/unsupported fixup type %x.\n", type);
967 return (IMAGE_BASE_RELOCATION *)relocs; /* return address of next block */
971 void MyLdrInitializeThunk( void *kernel_start, ULONG_PTR unknown2,
972 ULONG_PTR unknown3, ULONG_PTR unknown4 )
974 static const WCHAR globalflagW[] = {'G','l','o','b','a','l','F','l','a','g',0};
977 LPCWSTR load_path = NULL;
978 PEB *peb = current_peb();
979 IMAGE_NT_HEADERS *nt = MyRtlImageNtHeader( peb->ImageBaseAddress );
980 void (*_kernel_start) (void *ptr) = kernel_start;
983 if (main_exe_file) NtClose( main_exe_file ); /* at this point the main module is created */
986 /* allocate the modref for the main exe (if not already done) */
987 wm = get_modref( peb->ImageBaseAddress );
989 if (wm->ldr.Flags & LDR_IMAGE_IS_DLL)
991 TRACE("%S is a dll, not an executable\n", wm->ldr.FullDllName );
995 // peb->ProcessParameters->ImagePathName = wm->ldr.FullDllName;
996 // version_init( wm->ldr.FullDllName );
998 // LdrQueryImageFileExecutionOptions( &peb->ProcessParameters->ImagePathName, globalflagW,
999 // REG_DWORD, &peb->NtGlobalFlag, sizeof(peb->NtGlobalFlag), NULL );
1001 /* the main exe needs to be the first in the load order list */
1002 // RemoveEntryList( &wm->ldr.InLoadOrderModuleList );
1003 // InsertHeadList( &peb->LdrData->InLoadOrderModuleList, &wm->ldr.InLoadOrderModuleList );
1005 // if ((status = virtual_alloc_thread_stack( NtCurrentTeb(), 0, 0 )) != STATUS_SUCCESS) goto error;
1006 // if ((status = server_init_process_done()) != STATUS_SUCCESS) goto error;
1009 // load_path = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer;
1010 if ((status = fixup_imports( wm, load_path )) != STATUS_SUCCESS) goto error;
1011 // if ((status = alloc_process_tls()) != STATUS_SUCCESS) goto error;
1012 // if ((status = alloc_thread_tls()) != STATUS_SUCCESS) goto error;
1013 // heap_set_debug_flags( GetProcessHeap() );
1016 /* FIXME: This may be interesting at some point. */
1017 status = wine_call_on_stack( attach_process_dlls, wm, NtCurrentTeb()->Tib.StackBase );
1018 if (status != STATUS_SUCCESS) goto error;
1021 // virtual_release_address_space( nt->FileHeader.Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE );
1022 // virtual_clear_thread_stack();
1023 // wine_switch_to_stack( start_process, kernel_start, NtCurrentTeb()->Tib.StackBase );
1024 // stack( start_process, kernel_start, NtCurrentTeb()->Tib.StackBase );
1025 _kernel_start (peb);
1028 TRACE( "Main exe initialization for %S failed, status %x\n",
1029 wm->ldr.FullDllName, status);
1030 // peb->ProcessParameters->ImagePathName, status );
1031 // NtTerminateProcess( GetCurrentProcess(), status );