2009-12-01 Jb Evain <jbevain@novell.com>
[mono.git] / mono / metadata / coree.c
blob9e48a3fe07749222d678cbc693ef0a21672a5b0b
1 /*
2 * coree.c: mscoree.dll functions
4 * Author:
5 * Kornel Pal <http://www.kornelpal.hu/>
7 * Copyright (C) 2008 Kornel Pal
8 */
10 #include <config.h>
12 #ifdef HOST_WIN32
14 #if _WIN32_WINNT < 0x0501
15 /* Required for ACTCTX. */
16 #undef _WIN32_WINNT
17 #define _WIN32_WINNT 0x0501
18 #endif /* _WIN32_WINNT < 0x0501 */
20 #include <string.h>
21 #include <glib.h>
22 #include <mono/io-layer/io-layer.h>
23 #include <mono/utils/mono-path.h>
24 #include "cil-coff.h"
25 #include "metadata-internals.h"
26 #include "image.h"
27 #include "assembly.h"
28 #include "domain-internals.h"
29 #include "appdomain.h"
30 #include "object.h"
31 #include "loader.h"
32 #include "threads.h"
33 #include "environment.h"
34 #include "coree.h"
36 HMODULE coree_module_handle = NULL;
38 static gboolean init_from_coree = FALSE;
40 gchar*
41 mono_get_module_file_name (HMODULE module_handle)
43 gunichar2* file_name;
44 gchar* file_name_utf8;
45 DWORD buffer_size;
46 DWORD size;
48 buffer_size = 1024;
49 file_name = g_new (gunichar2, buffer_size);
51 for (;;) {
52 size = GetModuleFileName (module_handle, file_name, buffer_size);
53 if (!size) {
54 g_free (file_name);
55 return NULL;
58 g_assert (size <= buffer_size);
59 if (size != buffer_size)
60 break;
62 buffer_size += 1024;
63 file_name = g_realloc (file_name, buffer_size * sizeof (gunichar2));
66 file_name_utf8 = g_utf16_to_utf8 (file_name, size, NULL, NULL, NULL);
67 g_free (file_name);
69 return file_name_utf8;
72 /* Entry point called by LdrLoadDll of ntdll.dll after _CorValidateImage. */
73 BOOL STDMETHODCALLTYPE _CorDllMain(HINSTANCE hInst, DWORD dwReason, LPVOID lpReserved)
75 MonoAssembly* assembly;
76 MonoImage* image;
77 gchar* file_name;
78 gchar* error;
80 switch (dwReason)
82 case DLL_PROCESS_ATTACH:
83 DisableThreadLibraryCalls (hInst);
85 file_name = mono_get_module_file_name (hInst);
87 if (mono_get_root_domain ()) {
88 image = mono_image_open_from_module_handle (hInst, mono_path_resolve_symlinks (file_name), TRUE, NULL);
89 } else {
90 init_from_coree = TRUE;
91 mono_runtime_load (file_name, NULL);
92 error = (gchar*) mono_check_corlib_version ();
93 if (error) {
94 g_free (error);
95 g_free (file_name);
96 mono_runtime_quit ();
97 return FALSE;
100 image = mono_image_open (file_name, NULL);
101 if (image) {
102 image->has_entry_point = TRUE;
103 mono_close_exe_image ();
104 /* Decrement reference count to zero. (Image will not be closed.) */
105 mono_image_close (image);
109 if (!image) {
110 g_free (file_name);
111 return FALSE;
115 * FIXME: Find a better way to call mono_image_fixup_vtable. Only
116 * loader trampolines should be used and assembly loading should
117 * probably be delayed until the first call to an exported function.
119 if (image->tables [MONO_TABLE_ASSEMBLY].rows && ((MonoCLIImageInfo*) image->image_info)->cli_cli_header.ch_vtable_fixups.rva)
120 assembly = mono_assembly_open (file_name, NULL);
122 g_free (file_name);
123 break;
124 case DLL_PROCESS_DETACH:
125 if (lpReserved != NULL)
126 /* The process is terminating. */
127 return TRUE;
128 file_name = mono_get_module_file_name (hInst);
129 image = mono_image_loaded (file_name);
130 if (image)
131 mono_image_close (image);
133 g_free (file_name);
134 break;
137 return TRUE;
140 /* Called by ntdll.dll reagardless of entry point after _CorValidateImage. */
141 __int32 STDMETHODCALLTYPE _CorExeMain(void)
143 MonoDomain* domain;
144 MonoAssembly* assembly;
145 MonoImage* image;
146 MonoMethod* method;
147 guint32 entry;
148 gchar* file_name;
149 gchar* error;
150 int argc;
151 gunichar2** argvw;
152 gchar** argv;
153 int i;
155 file_name = mono_get_module_file_name (NULL);
156 init_from_coree = TRUE;
157 domain = mono_runtime_load (file_name, NULL);
159 error = (gchar*) mono_check_corlib_version ();
160 if (error) {
161 g_free (error);
162 g_free (file_name);
163 MessageBox (NULL, L"Corlib not in sync with this runtime.", NULL, MB_ICONERROR);
164 mono_runtime_quit ();
165 ExitProcess (1);
168 assembly = mono_assembly_open (file_name, NULL);
169 mono_close_exe_image ();
170 if (!assembly) {
171 g_free (file_name);
172 MessageBox (NULL, L"Cannot open assembly.", NULL, MB_ICONERROR);
173 mono_runtime_quit ();
174 ExitProcess (1);
177 image = assembly->image;
178 entry = mono_image_get_entry_point (image);
179 if (!entry) {
180 g_free (file_name);
181 MessageBox (NULL, L"Assembly doesn't have an entry point.", NULL, MB_ICONERROR);
182 mono_runtime_quit ();
183 ExitProcess (1);
186 method = mono_get_method (image, entry, NULL);
187 if (method == NULL) {
188 g_free (file_name);
189 MessageBox (NULL, L"The entry point method could not be loaded.", NULL, MB_ICONERROR);
190 mono_runtime_quit ();
191 ExitProcess (1);
194 argvw = CommandLineToArgvW (GetCommandLine (), &argc);
195 argv = g_new0 (gchar*, argc);
196 argv [0] = file_name;
197 for (i = 1; i < argc; ++i)
198 argv [i] = g_utf16_to_utf8 (argvw [i], -1, NULL, NULL, NULL);
199 LocalFree (argvw);
201 mono_runtime_run_main (method, argc, argv, NULL);
202 mono_thread_manage ();
204 mono_runtime_quit ();
206 /* return does not terminate the process. */
207 ExitProcess (mono_environment_exitcode_get ());
210 /* Called by msvcrt.dll when shutting down. */
211 void STDMETHODCALLTYPE CorExitProcess(int exitCode)
213 /* FIXME: This is not currently supported by the runtime. */
214 #if 0
215 if (mono_get_root_domain () && !mono_runtime_is_shutting_down ()) {
216 mono_runtime_set_shutting_down ();
217 mono_thread_suspend_all_other_threads ();
218 mono_runtime_quit ();
220 #endif
221 ExitProcess (exitCode);
224 /* Called by ntdll.dll before _CorDllMain and _CorExeMain. */
225 STDAPI _CorValidateImage(PVOID *ImageBase, LPCWSTR FileName)
227 IMAGE_DOS_HEADER* DosHeader;
228 IMAGE_NT_HEADERS32* NtHeaders32;
229 IMAGE_NT_HEADERS64* NtHeaders64;
230 IMAGE_DATA_DIRECTORY* CliHeaderDir;
231 MonoCLIHeader* CliHeader;
232 DWORD SizeOfHeaders;
233 DWORD* Address;
234 DWORD OldProtect;
236 DosHeader = (IMAGE_DOS_HEADER*)*ImageBase;
237 if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE)
238 return STATUS_INVALID_IMAGE_FORMAT;
240 NtHeaders32 = (IMAGE_NT_HEADERS32*)((DWORD_PTR)DosHeader + DosHeader->e_lfanew);
241 if (NtHeaders32->Signature != IMAGE_NT_SIGNATURE)
242 return STATUS_INVALID_IMAGE_FORMAT;
244 #ifdef _WIN64
245 NtHeaders64 = (IMAGE_NT_HEADERS64*)NtHeaders32;
246 if (NtHeaders64->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
248 if (NtHeaders64->OptionalHeader.NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)
249 return STATUS_INVALID_IMAGE_FORMAT;
251 CliHeaderDir = &NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR];
252 if (!CliHeaderDir->VirtualAddress)
253 return STATUS_INVALID_IMAGE_FORMAT;
255 CliHeader = (MonoCLIHeader*)((DWORD_PTR)DosHeader + CliHeaderDir->VirtualAddress);
256 if (CliHeader->ch_flags & CLI_FLAGS_32BITREQUIRED)
257 return STATUS_INVALID_IMAGE_FORMAT;
259 if (CliHeader->ch_flags & CLI_FLAGS_ILONLY)
261 /* Avoid calling _CorDllMain because imports are not resolved for IL only images. */
262 if (NtHeaders64->OptionalHeader.AddressOfEntryPoint != 0)
264 Address = &NtHeaders64->OptionalHeader.AddressOfEntryPoint;
265 if (!VirtualProtect(Address, sizeof(DWORD), PAGE_READWRITE, &OldProtect))
266 return E_UNEXPECTED;
267 *Address = (DWORD)0;
268 if (!VirtualProtect(Address, sizeof(DWORD), OldProtect, &OldProtect))
269 return E_UNEXPECTED;
273 return STATUS_SUCCESS;
276 if (NtHeaders32->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
277 return STATUS_INVALID_IMAGE_FORMAT;
279 if (NtHeaders32->OptionalHeader.NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)
280 return STATUS_INVALID_IMAGE_FORMAT;
282 CliHeaderDir = &NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR];
283 if (!CliHeaderDir->VirtualAddress)
284 return STATUS_INVALID_IMAGE_FORMAT;
286 CliHeader = (MonoCLIHeader*)((DWORD_PTR)DosHeader + CliHeaderDir->VirtualAddress);
287 if (!(CliHeader->ch_flags & CLI_FLAGS_ILONLY) || (CliHeader->ch_flags & CLI_FLAGS_32BITREQUIRED))
288 return STATUS_INVALID_IMAGE_FORMAT;
290 /* Fixup IMAGE_NT_HEADERS32 to IMAGE_NT_HEADERS64. */
291 SizeOfHeaders = NtHeaders32->OptionalHeader.SizeOfHeaders;
292 if (SizeOfHeaders < DosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS64) + (sizeof(IMAGE_SECTION_HEADER) * NtHeaders32->FileHeader.NumberOfSections))
293 return STATUS_INVALID_IMAGE_FORMAT;
295 if (!VirtualProtect(DosHeader, SizeOfHeaders, PAGE_READWRITE, &OldProtect))
296 return E_UNEXPECTED;
298 memmove(NtHeaders64 + 1, IMAGE_FIRST_SECTION(NtHeaders32), sizeof(IMAGE_SECTION_HEADER) * NtHeaders32->FileHeader.NumberOfSections);
300 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES - 1].Size = 0;
301 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES - 1].VirtualAddress = 0;
302 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size;
303 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress;
304 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].Size = 0;
305 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress = 0;
306 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = 0;
307 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = 0;
308 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0;
309 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0;
310 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size = 0;
311 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress = 0;
312 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size = 0;
313 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress = 0;
314 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_GLOBALPTR].Size = 0;
315 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_GLOBALPTR].VirtualAddress = 0;
316 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_ARCHITECTURE].Size = 0;
317 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_ARCHITECTURE].VirtualAddress = 0;
318 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
319 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
320 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
321 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;
322 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
323 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress;
324 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size = 0;
325 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress = 0;
326 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size;
327 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
328 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = 0;
329 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = 0;
330 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = 0;
331 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = 0;
333 NtHeaders64->OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
334 NtHeaders64->OptionalHeader.LoaderFlags = NtHeaders32->OptionalHeader.LoaderFlags;
335 NtHeaders64->OptionalHeader.SizeOfHeapCommit = (ULONGLONG)NtHeaders32->OptionalHeader.SizeOfHeapCommit;
336 NtHeaders64->OptionalHeader.SizeOfHeapReserve = (ULONGLONG)NtHeaders32->OptionalHeader.SizeOfHeapReserve;
337 NtHeaders64->OptionalHeader.SizeOfStackCommit = (ULONGLONG)NtHeaders32->OptionalHeader.SizeOfStackCommit;
338 NtHeaders64->OptionalHeader.SizeOfStackReserve = (ULONGLONG)NtHeaders32->OptionalHeader.SizeOfStackReserve;
339 NtHeaders64->OptionalHeader.DllCharacteristics = NtHeaders32->OptionalHeader.DllCharacteristics;
340 NtHeaders64->OptionalHeader.Subsystem = NtHeaders32->OptionalHeader.Subsystem;
341 NtHeaders64->OptionalHeader.CheckSum = NtHeaders32->OptionalHeader.CheckSum;
342 NtHeaders64->OptionalHeader.SizeOfHeaders = NtHeaders32->OptionalHeader.SizeOfHeaders;
343 NtHeaders64->OptionalHeader.SizeOfImage = NtHeaders32->OptionalHeader.SizeOfImage;
344 NtHeaders64->OptionalHeader.Win32VersionValue = NtHeaders32->OptionalHeader.Win32VersionValue;
345 NtHeaders64->OptionalHeader.MinorSubsystemVersion = NtHeaders32->OptionalHeader.MinorSubsystemVersion;
346 NtHeaders64->OptionalHeader.MajorSubsystemVersion = NtHeaders32->OptionalHeader.MajorSubsystemVersion;
347 NtHeaders64->OptionalHeader.MinorImageVersion = NtHeaders32->OptionalHeader.MinorImageVersion;
348 NtHeaders64->OptionalHeader.MajorImageVersion = NtHeaders32->OptionalHeader.MajorImageVersion;
349 NtHeaders64->OptionalHeader.MinorOperatingSystemVersion = NtHeaders32->OptionalHeader.MinorOperatingSystemVersion;
350 NtHeaders64->OptionalHeader.MajorOperatingSystemVersion = NtHeaders32->OptionalHeader.MajorOperatingSystemVersion;
351 NtHeaders64->OptionalHeader.FileAlignment = NtHeaders32->OptionalHeader.FileAlignment;
352 NtHeaders64->OptionalHeader.SectionAlignment = NtHeaders32->OptionalHeader.SectionAlignment;
353 NtHeaders64->OptionalHeader.ImageBase = (ULONGLONG)NtHeaders32->OptionalHeader.ImageBase;
354 /* BaseOfCode is at the same offset. */
355 NtHeaders64->OptionalHeader.AddressOfEntryPoint = 0;
356 NtHeaders64->OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR64_MAGIC;
357 NtHeaders64->FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER64);
359 if (!VirtualProtect(DosHeader, SizeOfHeaders, OldProtect, &OldProtect))
360 return E_UNEXPECTED;
361 #else
362 if (NtHeaders32->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
363 return STATUS_INVALID_IMAGE_FORMAT;
365 if (NtHeaders32->OptionalHeader.NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)
366 return STATUS_INVALID_IMAGE_FORMAT;
368 CliHeaderDir = &NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR];
369 if (!CliHeaderDir->VirtualAddress)
370 return STATUS_INVALID_IMAGE_FORMAT;
372 Address = &NtHeaders32->OptionalHeader.AddressOfEntryPoint;
373 if (!VirtualProtect(Address, sizeof(DWORD), PAGE_READWRITE, &OldProtect))
374 return E_UNEXPECTED;
375 if (NtHeaders32->FileHeader.Characteristics & IMAGE_FILE_DLL)
376 *Address = (DWORD)((DWORD_PTR)&_CorDllMain - (DWORD_PTR)DosHeader);
377 else
378 *Address = (DWORD)((DWORD_PTR)&_CorExeMain - (DWORD_PTR)DosHeader);
379 if (!VirtualProtect(Address, sizeof(DWORD), OldProtect, &OldProtect))
380 return E_UNEXPECTED;
381 #endif
383 return STATUS_SUCCESS;
386 /* Called by ntdll.dll. */
387 STDAPI_(VOID) _CorImageUnloading(PVOID ImageBase)
389 /* Nothing to do. */
392 STDAPI CorBindToRuntimeEx(LPCWSTR pwszVersion, LPCWSTR pwszBuildFlavor, DWORD startupFlags, REFCLSID rclsid, REFIID riid, LPVOID FAR *ppv)
394 if (ppv == NULL)
395 return E_POINTER;
397 *ppv = NULL;
398 return E_NOTIMPL;
401 STDAPI CorBindToRuntime(LPCWSTR pwszVersion, LPCWSTR pwszBuildFlavor, REFCLSID rclsid, REFIID riid, LPVOID FAR *ppv)
403 return CorBindToRuntimeEx (pwszVersion, pwszBuildFlavor, 0, rclsid, riid, ppv);
406 HMODULE WINAPI MonoLoadImage(LPCWSTR FileName)
408 HANDLE FileHandle;
409 DWORD FileSize;
410 HANDLE MapHandle;
411 IMAGE_DOS_HEADER* DosHeader;
412 IMAGE_NT_HEADERS32* NtHeaders32;
413 IMAGE_NT_HEADERS64* NtHeaders64;
414 HMODULE ModuleHandle;
416 FileHandle = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
417 if (FileHandle == INVALID_HANDLE_VALUE)
418 return NULL;
420 FileSize = GetFileSize(FileHandle, NULL);
421 if (FileSize == INVALID_FILE_SIZE)
422 goto CloseFile;
424 MapHandle = CreateFileMapping(FileHandle, NULL, PAGE_READONLY, 0, 0, NULL);
425 if (MapHandle == NULL)
426 goto CloseFile;
428 DosHeader = (IMAGE_DOS_HEADER*)MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 0);
429 if (DosHeader == NULL)
430 goto CloseMap;
432 if (FileSize < sizeof(IMAGE_DOS_HEADER) || DosHeader->e_magic != IMAGE_DOS_SIGNATURE || FileSize < DosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS32))
433 goto InvalidImageFormat;
435 NtHeaders32 = (IMAGE_NT_HEADERS32*)((DWORD_PTR)DosHeader + DosHeader->e_lfanew);
436 if (NtHeaders32->Signature != IMAGE_NT_SIGNATURE)
437 goto InvalidImageFormat;
439 #ifdef _WIN64
440 NtHeaders64 = (IMAGE_NT_HEADERS64*)NtHeaders32;
441 if (NtHeaders64->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
443 if (FileSize < DosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS64) ||
444 NtHeaders64->OptionalHeader.NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR ||
445 !NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress)
446 goto InvalidImageFormat;
448 goto ValidImage;
450 #endif
452 if (NtHeaders32->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC ||
453 NtHeaders32->OptionalHeader.NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR ||
454 !NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress)
456 InvalidImageFormat:
457 SetLastError(STATUS_INVALID_IMAGE_FORMAT);
458 goto UnmapView;
461 ValidImage:
462 UnmapViewOfFile(DosHeader);
463 CloseHandle(MapHandle);
465 ModuleHandle = LoadLibrary(FileName);
467 CloseHandle(FileHandle);
468 return ModuleHandle;
470 UnmapView:
471 UnmapViewOfFile(DosHeader);
472 CloseMap:
473 CloseHandle(MapHandle);
474 CloseFile:
475 CloseHandle(FileHandle);
476 return NULL;
479 typedef struct _EXPORT_FIXUP
481 LPCSTR Name;
482 union
484 PVOID Pointer;
485 DWORD_PTR DWordPtr;
486 BYTE Bytes[sizeof(PVOID)];
487 #ifdef _M_IA64
488 PLABEL_DESCRIPTOR* PLabel;
489 #endif
490 } ProcAddress;
491 } EXPORT_FIXUP;
493 /* Has to be binary ordered. */
494 static const EXPORT_FIXUP ExportFixups[] = {
495 {"CorBindToRuntime", &CorBindToRuntime},
496 {"CorBindToRuntimeEx", &CorBindToRuntimeEx},
497 {"CorExitProcess", &CorExitProcess},
498 {"_CorDllMain", &_CorDllMain},
499 {"_CorExeMain", &_CorExeMain},
500 {"_CorImageUnloading", &_CorImageUnloading},
501 {"_CorValidateImage", &_CorValidateImage},
502 {NULL, NULL}
505 #define EXPORT_FIXUP_COUNT (sizeof(ExportFixups) / sizeof(EXPORT_FIXUP) - 1)
507 static HMODULE ExportFixupModuleHandle = NULL;
508 static DWORD ExportFixupRvas[EXPORT_FIXUP_COUNT];
510 /* Fixup exported functions of mscoree.dll to our implementations. */
511 STDAPI MonoFixupCorEE(HMODULE ModuleHandle)
513 IMAGE_DOS_HEADER* DosHeader;
514 IMAGE_NT_HEADERS* NtHeaders;
515 IMAGE_DATA_DIRECTORY* ExportDataDir;
516 IMAGE_EXPORT_DIRECTORY* ExportDir;
517 DWORD* Functions;
518 DWORD* Names;
519 WORD* NameOrdinals;
520 EXPORT_FIXUP* ExportFixup;
521 DWORD* ExportFixupRva;
522 DWORD* Address;
523 DWORD OldProtect;
524 DWORD ProcRva;
525 DWORD i;
526 int cmp;
527 #ifdef _WIN64
528 MEMORY_BASIC_INFORMATION MemoryInfo;
529 PVOID Region;
530 PVOID RegionBase;
531 PVOID MaxRegionBase;
532 #ifdef _M_IA64
533 PLABEL_DESCRIPTOR* PLabel;
535 #define ELEMENT_SIZE sizeof(PLABEL_DESCRIPTOR)
536 #define REGION_WRITE_PROTECT PAGE_READWRITE
537 #define REGION_PROTECT PAGE_READ
538 #else
539 BYTE* Trampoline;
541 #define ELEMENT_SIZE 13
542 #define REGION_WRITE_PROTECT PAGE_EXECUTE_READWRITE
543 #define REGION_PROTECT PAGE_EXECUTE_READ
544 #endif
545 #endif
547 if (ExportFixupModuleHandle != NULL)
548 return ModuleHandle == ExportFixupModuleHandle ? S_OK : E_FAIL;
550 DosHeader = (IMAGE_DOS_HEADER*)ModuleHandle;
551 if (DosHeader == NULL)
552 return E_POINTER;
554 if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE)
555 return E_INVALIDARG;
557 NtHeaders = (IMAGE_NT_HEADERS*)((DWORD_PTR)DosHeader + DosHeader->e_lfanew);
558 if (NtHeaders->Signature != IMAGE_NT_SIGNATURE)
559 return E_INVALIDARG;
561 if (NtHeaders->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)
562 return E_INVALIDARG;
564 if (NtHeaders->OptionalHeader.NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_EXPORT)
565 return E_FAIL;
567 ExportDataDir = &NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
568 if (!ExportDataDir->VirtualAddress)
569 return E_FAIL;
571 #ifdef _WIN64
572 /* Allocate memory after base address because RVAs are 32-bit unsigned integers. */
573 RegionBase = DosHeader;
574 MaxRegionBase = (PVOID)((DWORD_PTR)RegionBase + (DWORD_PTR)(0x100000000L - (ELEMENT_SIZE * (EXPORT_FIXUP_COUNT - 1))));
575 for (;;)
577 if (!VirtualQuery(RegionBase, &MemoryInfo, sizeof(MEMORY_BASIC_INFORMATION)))
578 return E_UNEXPECTED;
579 if (MemoryInfo.State == MEM_FREE && MemoryInfo.RegionSize >= ELEMENT_SIZE * EXPORT_FIXUP_COUNT)
581 Region = VirtualAlloc(RegionBase, ELEMENT_SIZE * EXPORT_FIXUP_COUNT, MEM_COMMIT | MEM_RESERVE, REGION_WRITE_PROTECT);
582 if (Region != NULL)
583 break;
585 RegionBase = (PVOID)((DWORD_PTR)MemoryInfo.BaseAddress + (DWORD_PTR)MemoryInfo.RegionSize);
586 if (RegionBase > MaxRegionBase)
587 return E_OUTOFMEMORY;
590 #ifdef _M_IA64
591 PLabel = (PLABEL_DESCRIPTOR*)Region;
592 #else
593 Trampoline = (BYTE*)Region;
594 #endif
595 #endif
597 ExportDir = (IMAGE_EXPORT_DIRECTORY*)((DWORD_PTR)DosHeader + ExportDataDir->VirtualAddress);
598 Functions = (DWORD*)((DWORD_PTR)DosHeader + ExportDir->AddressOfFunctions);
599 Names = (DWORD*)((DWORD_PTR)DosHeader + ExportDir->AddressOfNames);
600 NameOrdinals = (WORD*)((DWORD_PTR)DosHeader + ExportDir->AddressOfNameOrdinals);
601 ExportFixup = (EXPORT_FIXUP*)&ExportFixups;
602 ExportFixupRva = (DWORD*)&ExportFixupRvas;
604 for (i = 0; i < ExportDir->NumberOfNames; i++)
606 cmp = strcmp((LPCSTR)((DWORD_PTR)DosHeader + Names[i]), ExportFixup->Name);
607 if (cmp > 0)
608 return E_FAIL;
610 if (cmp == 0)
612 #ifdef _WIN64
613 #if defined(_M_IA64)
614 ProcRva = (DWORD)((DWORD_PTR)PLabel - (DWORD_PTR)DosHeader);
615 *(PLabel)++ = *ExportFixup->ProcAddress.PLabel;
616 #elif defined(_M_AMD64)
617 ProcRva = (DWORD)((DWORD_PTR)Trampoline - (DWORD_PTR)DosHeader);
618 /* mov r11, ExportFixup->ProcAddress */
619 *(Trampoline)++ = 0x49;
620 *(Trampoline)++ = 0xBB;
621 *(Trampoline)++ = ExportFixup->ProcAddress.Bytes[0];
622 *(Trampoline)++ = ExportFixup->ProcAddress.Bytes[1];
623 *(Trampoline)++ = ExportFixup->ProcAddress.Bytes[2];
624 *(Trampoline)++ = ExportFixup->ProcAddress.Bytes[3];
625 *(Trampoline)++ = ExportFixup->ProcAddress.Bytes[4];
626 *(Trampoline)++ = ExportFixup->ProcAddress.Bytes[5];
627 *(Trampoline)++ = ExportFixup->ProcAddress.Bytes[6];
628 *(Trampoline)++ = ExportFixup->ProcAddress.Bytes[7];
629 /* jmp r11 */
630 *(Trampoline)++ = 0x41;
631 *(Trampoline)++ = 0xFF;
632 *(Trampoline)++ = 0xE3;
633 #else
634 #error Unsupported architecture.
635 #endif
636 #else
637 ProcRva = (DWORD)(ExportFixup->ProcAddress.DWordPtr - (DWORD_PTR)DosHeader);
638 #endif
639 Address = &Functions[NameOrdinals[i]];
640 if (!VirtualProtect(Address, sizeof(DWORD), PAGE_READWRITE, &OldProtect))
641 return E_UNEXPECTED;
642 *ExportFixupRva = *Address;
643 *Address = ProcRva;
644 if (!VirtualProtect(Address, sizeof(DWORD), OldProtect, &OldProtect))
645 return E_UNEXPECTED;
646 ExportFixup++;
647 if (ExportFixup->Name == NULL) {
648 #ifdef _WIN64
649 if (!VirtualProtect(Region, ELEMENT_SIZE * EXPORT_FIXUP_COUNT, REGION_PROTECT, &OldProtect))
650 return E_UNEXPECTED;
651 #endif
653 ExportFixupModuleHandle = ModuleHandle;
654 return S_OK;
656 ExportFixupRva++;
659 return E_FAIL;
662 /* Executable images are only mapped by the OS loader. We need to do fixups for native code support. */
663 STDAPI MonoFixupExe(HMODULE ModuleHandle)
665 IMAGE_DOS_HEADER* DosHeader;
666 IMAGE_NT_HEADERS* NtHeaders;
667 DWORD_PTR* Address;
668 DWORD OldProtect;
669 DWORD_PTR BaseDiff;
671 DosHeader = (IMAGE_DOS_HEADER*)ModuleHandle;
672 if (DosHeader == NULL)
673 return E_POINTER;
675 if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE)
676 return E_INVALIDARG;
678 NtHeaders = (IMAGE_NT_HEADERS*)((DWORD_PTR)DosHeader + DosHeader->e_lfanew);
679 if (NtHeaders->Signature != IMAGE_NT_SIGNATURE)
680 return E_INVALIDARG;
682 if (NtHeaders->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)
683 return E_INVALIDARG;
685 if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL)
686 return S_OK;
688 if (NtHeaders->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)
690 IMAGE_DATA_DIRECTORY* CliHeaderDir;
691 MonoCLIHeader* CliHeader;
693 CliHeaderDir = &NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR];
694 if (CliHeaderDir->VirtualAddress)
696 CliHeader = (MonoCLIHeader*)((DWORD_PTR)DosHeader + CliHeaderDir->VirtualAddress);
697 if (CliHeader->ch_flags & CLI_FLAGS_ILONLY)
698 return S_OK;
702 BaseDiff = (DWORD_PTR)DosHeader - NtHeaders->OptionalHeader.ImageBase;
703 if (BaseDiff != 0)
705 if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
706 return E_FAIL;
708 Address = &NtHeaders->OptionalHeader.ImageBase;
709 if (!VirtualProtect(Address, sizeof(DWORD_PTR), PAGE_READWRITE, &OldProtect))
710 return E_UNEXPECTED;
711 *Address = (DWORD_PTR)DosHeader;
712 if (!VirtualProtect(Address, sizeof(DWORD_PTR), OldProtect, &OldProtect))
713 return E_UNEXPECTED;
715 if (NtHeaders->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_BASERELOC)
717 IMAGE_DATA_DIRECTORY* BaseRelocDir;
718 IMAGE_BASE_RELOCATION* BaseReloc;
719 USHORT* RelocBlock;
720 ULONG BaseRelocSize;
721 ULONG RelocBlockSize;
722 USHORT RelocOffset;
723 DWORD_PTR UNALIGNED *RelocFixup;
725 BaseRelocDir = &NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
726 if (BaseRelocDir->VirtualAddress)
728 BaseReloc = (IMAGE_BASE_RELOCATION*)((DWORD_PTR)DosHeader + BaseRelocDir->VirtualAddress);
729 BaseRelocSize = BaseRelocDir->Size;
731 while (BaseRelocSize)
733 RelocBlockSize = BaseReloc->SizeOfBlock;
735 if (!RelocBlockSize || BaseRelocSize < RelocBlockSize)
736 return E_FAIL;
738 BaseRelocSize -= RelocBlockSize;
739 RelocBlock = (USHORT*)((DWORD_PTR)BaseReloc + sizeof(IMAGE_BASE_RELOCATION));
740 RelocBlockSize -= sizeof(IMAGE_BASE_RELOCATION);
741 RelocBlockSize /= sizeof(USHORT);
743 while (RelocBlockSize-- != 0)
745 RelocOffset = *RelocBlock & (USHORT)0x0fff;
746 RelocFixup = (DWORD_PTR*)((DWORD_PTR)DosHeader + BaseReloc->VirtualAddress + RelocOffset);
748 switch (*RelocBlock >> 12)
750 case IMAGE_REL_BASED_ABSOLUTE:
751 break;
753 #ifdef _WIN64
754 case IMAGE_REL_BASED_DIR64:
755 #else
756 case IMAGE_REL_BASED_HIGHLOW:
757 #endif
758 if (!VirtualProtect(RelocFixup, sizeof(DWORD_PTR), PAGE_EXECUTE_READWRITE, &OldProtect))
759 return E_UNEXPECTED;
760 *RelocFixup += BaseDiff;
761 if (!VirtualProtect(RelocFixup, sizeof(DWORD_PTR), OldProtect, &OldProtect))
762 return E_UNEXPECTED;
763 break;
765 default:
766 return E_FAIL;
769 RelocBlock++;
771 BaseReloc = (IMAGE_BASE_RELOCATION*)RelocBlock;
777 if (NtHeaders->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_IMPORT)
779 IMAGE_DATA_DIRECTORY* ImportDir;
780 IMAGE_IMPORT_DESCRIPTOR* ImportDesc;
781 HMODULE ImportModuleHandle;
782 IMAGE_THUNK_DATA* ImportThunkData;
783 DWORD_PTR ProcAddress;
785 ImportDir = &NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
786 if (ImportDir->VirtualAddress != 0)
788 ImportDesc = (IMAGE_IMPORT_DESCRIPTOR*)((DWORD_PTR)DosHeader + ImportDir->VirtualAddress);
789 while (ImportDesc->Name && ImportDesc->OriginalFirstThunk)
791 ImportModuleHandle = LoadLibraryA((PCSTR)((DWORD_PTR)DosHeader + ImportDesc->Name));
792 if (ImportModuleHandle == NULL)
793 return E_FAIL;
795 ImportThunkData = (IMAGE_THUNK_DATA*)((DWORD_PTR)DosHeader + ImportDesc->OriginalFirstThunk);
796 while (ImportThunkData->u1.Ordinal != 0)
798 if (IMAGE_SNAP_BY_ORDINAL(ImportThunkData->u1.Ordinal))
799 ProcAddress = (DWORD_PTR)GetProcAddress(ImportModuleHandle, (LPCSTR)IMAGE_ORDINAL(ImportThunkData->u1.Ordinal));
800 else
802 IMAGE_IMPORT_BY_NAME* ImportByName = (IMAGE_IMPORT_BY_NAME*)((DWORD_PTR)DosHeader + ImportThunkData->u1.AddressOfData);
803 ProcAddress = (DWORD_PTR)GetProcAddress(ImportModuleHandle, ImportByName->Name);
805 if (ProcAddress == 0)
806 return E_FAIL;
807 Address = (DWORD_PTR*)((DWORD_PTR)ImportThunkData - ImportDesc->OriginalFirstThunk + ImportDesc->FirstThunk);
808 if (!VirtualProtect(Address, sizeof(DWORD_PTR), PAGE_READWRITE, &OldProtect))
809 return E_UNEXPECTED;
810 *Address = ProcAddress;
811 if (!VirtualProtect(Address, sizeof(DWORD_PTR), OldProtect, &OldProtect))
812 return E_UNEXPECTED;
813 ImportThunkData++;
816 ImportDesc++;
821 return S_OK;
824 static void
825 mono_set_act_ctx (const char* file_name)
827 typedef HANDLE (WINAPI* CREATEACTCTXW_PROC) (PCACTCTXW pActCtx);
828 typedef BOOL (WINAPI* ACTIVATEACTCTX_PROC) (HANDLE hActCtx, ULONG_PTR* lpCookie);
830 HMODULE kernel32_handle;
831 CREATEACTCTXW_PROC CreateActCtx_proc;
832 ACTIVATEACTCTX_PROC ActivateActCtx_proc;
833 gchar* full_path;
834 gunichar2* full_path_utf16;
835 gchar* dir_name;
836 gunichar2* dir_name_utf16;
837 gchar* base_name;
838 gunichar2* base_name_utf16;
839 ACTCTX act_ctx;
840 HANDLE handle;
841 ULONG_PTR cookie;
843 kernel32_handle = GetModuleHandle (L"kernel32.dll");
844 if (!kernel32_handle)
845 return;
846 CreateActCtx_proc = (CREATEACTCTXW_PROC) GetProcAddress (kernel32_handle, "CreateActCtxW");
847 if (!CreateActCtx_proc)
848 return;
849 ActivateActCtx_proc = (ACTIVATEACTCTX_PROC) GetProcAddress (kernel32_handle, "ActivateActCtx");
850 if (!ActivateActCtx_proc)
851 return;
853 full_path = mono_path_canonicalize (file_name);
854 full_path_utf16 = g_utf8_to_utf16 (full_path, -1, NULL, NULL, NULL);
855 dir_name = g_path_get_dirname (full_path);
856 dir_name_utf16 = g_utf8_to_utf16 (dir_name, -1, NULL, NULL, NULL);
857 base_name = g_path_get_basename (full_path);
858 base_name_utf16 = g_utf8_to_utf16 (base_name, -1, NULL, NULL, NULL);
859 g_free (base_name);
860 g_free (dir_name);
861 g_free (full_path);
863 memset (&act_ctx, 0, sizeof (ACTCTX));
864 act_ctx.cbSize = sizeof (ACTCTX);
865 act_ctx.dwFlags = ACTCTX_FLAG_SET_PROCESS_DEFAULT | ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID | ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_APPLICATION_NAME_VALID;
866 act_ctx.lpSource = full_path_utf16;
867 act_ctx.lpAssemblyDirectory = dir_name_utf16;
868 act_ctx.lpResourceName = MAKEINTRESOURCE (CREATEPROCESS_MANIFEST_RESOURCE_ID);
869 act_ctx.lpApplicationName = base_name_utf16;
871 handle = CreateActCtx_proc (&act_ctx);
872 if (handle == INVALID_HANDLE_VALUE && GetLastError () == ERROR_SXS_PROCESS_DEFAULT_ALREADY_SET) {
873 act_ctx.dwFlags &= ~ACTCTX_FLAG_SET_PROCESS_DEFAULT;
874 handle = CreateActCtx_proc (&act_ctx);
877 g_free (base_name_utf16);
878 g_free (dir_name_utf16);
879 g_free (full_path_utf16);
881 if (handle != INVALID_HANDLE_VALUE)
882 ActivateActCtx_proc (handle, &cookie);
885 void
886 mono_load_coree (const char* exe_file_name)
888 HMODULE module_handle;
889 gunichar2* file_name;
890 UINT required_size;
891 UINT size;
893 if (coree_module_handle)
894 return;
896 if (!init_from_coree && exe_file_name)
897 mono_set_act_ctx (exe_file_name);
899 /* ntdll.dll loads mscoree.dll from the system32 directory. */
900 required_size = GetSystemDirectory (NULL, 0);
901 file_name = g_new (gunichar2, required_size + 12);
902 size = GetSystemDirectory (file_name, required_size);
903 g_assert (size < required_size);
904 if (file_name [size - 1] != L'\\')
905 file_name [size++] = L'\\';
906 memcpy (&file_name [size], L"mscoree.dll", 12 * sizeof (gunichar2));
908 module_handle = LoadLibrary (file_name);
909 g_free (file_name);
911 if (module_handle && !SUCCEEDED (MonoFixupCorEE (module_handle))) {
912 FreeLibrary (module_handle);
913 module_handle = NULL;
916 coree_module_handle = module_handle;
919 void
920 mono_fixup_exe_image (MonoImage* image)
922 if (!init_from_coree && image && image->is_module_handle)
923 MonoFixupExe ((HMODULE) image->raw_data);
926 #endif /* HOST_WIN32 */