Merge pull request #3092 from alexanderkyte/mobile_static_fix_runtime_tests
[mono-project.git] / mono / metadata / coree.c
blob4436229376e10101b1d16f827601c72f466d2328
1 /*
2 * coree.c: mscoree.dll functions
4 * Author:
5 * Kornel Pal <http://www.kornelpal.hu/>
7 * Copyright (C) 2008 Kornel Pal
8 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
9 */
11 #include <config.h>
13 #ifdef HOST_WIN32
15 #include <string.h>
16 #include <glib.h>
17 #include <mono/io-layer/io-layer.h>
18 #include <mono/utils/mono-path.h>
19 #include "cil-coff.h"
20 #include "metadata-internals.h"
21 #include "image.h"
22 #include "assembly.h"
23 #include "domain-internals.h"
24 #include "appdomain.h"
25 #include "object.h"
26 #include "object-internals.h"
27 #include "loader.h"
28 #include "threads.h"
29 #include "environment.h"
30 #include "coree.h"
32 #include <shellapi.h>
34 HMODULE coree_module_handle = NULL;
36 static gboolean init_from_coree = FALSE;
38 gchar*
39 mono_get_module_file_name (HMODULE module_handle)
41 gunichar2* file_name;
42 gchar* file_name_utf8;
43 DWORD buffer_size;
44 DWORD size;
46 buffer_size = 1024;
47 file_name = g_new (gunichar2, buffer_size);
49 for (;;) {
50 size = GetModuleFileName (module_handle, file_name, buffer_size);
51 if (!size) {
52 g_free (file_name);
53 return NULL;
56 g_assert (size <= buffer_size);
57 if (size != buffer_size)
58 break;
60 buffer_size += 1024;
61 file_name = g_realloc (file_name, buffer_size * sizeof (gunichar2));
64 file_name_utf8 = g_utf16_to_utf8 (file_name, size, NULL, NULL, NULL);
65 g_free (file_name);
67 return file_name_utf8;
70 /* Entry point called by LdrLoadDll of ntdll.dll after _CorValidateImage. */
71 BOOL STDMETHODCALLTYPE _CorDllMain(HINSTANCE hInst, DWORD dwReason, LPVOID lpReserved)
73 MonoAssembly* assembly;
74 MonoImage* image;
75 gchar* file_name;
76 gchar* error;
78 switch (dwReason)
80 case DLL_PROCESS_ATTACH:
81 DisableThreadLibraryCalls (hInst);
83 file_name = mono_get_module_file_name (hInst);
85 if (mono_get_root_domain ()) {
86 image = mono_image_open_from_module_handle (hInst, mono_path_resolve_symlinks (file_name), TRUE, NULL);
87 } else {
88 init_from_coree = TRUE;
89 mono_runtime_load (file_name, NULL);
90 error = (gchar*) mono_check_corlib_version ();
91 if (error) {
92 g_free (error);
93 g_free (file_name);
94 mono_runtime_quit ();
95 return FALSE;
98 image = mono_image_open (file_name, NULL);
99 if (image) {
100 image->has_entry_point = TRUE;
101 mono_close_exe_image ();
102 /* Decrement reference count to zero. (Image will not be closed.) */
103 mono_image_close (image);
107 if (!image) {
108 g_free (file_name);
109 return FALSE;
113 * FIXME: Find a better way to call mono_image_fixup_vtable. Only
114 * loader trampolines should be used and assembly loading should
115 * probably be delayed until the first call to an exported function.
117 if (image->tables [MONO_TABLE_ASSEMBLY].rows && ((MonoCLIImageInfo*) image->image_info)->cli_cli_header.ch_vtable_fixups.rva)
118 assembly = mono_assembly_open (file_name, NULL);
120 g_free (file_name);
121 break;
122 case DLL_PROCESS_DETACH:
123 if (lpReserved != NULL)
124 /* The process is terminating. */
125 return TRUE;
126 file_name = mono_get_module_file_name (hInst);
127 image = mono_image_loaded (file_name);
128 if (image)
129 mono_image_close (image);
131 g_free (file_name);
132 break;
135 return TRUE;
138 /* Called by ntdll.dll reagardless of entry point after _CorValidateImage. */
139 __int32 STDMETHODCALLTYPE _CorExeMain(void)
141 MonoError error;
142 MonoDomain* domain;
143 MonoAssembly* assembly;
144 MonoImage* image;
145 MonoMethod* method;
146 guint32 entry;
147 gchar* file_name;
148 gchar* corlib_version_error;
149 int argc;
150 gunichar2** argvw;
151 gchar** argv;
152 int i;
154 file_name = mono_get_module_file_name (NULL);
155 init_from_coree = TRUE;
156 domain = mono_runtime_load (file_name, NULL);
158 corlib_version_error = (gchar*) mono_check_corlib_version ();
159 if (corlib_version_error) {
160 g_free (corlib_version_error);
161 g_free (file_name);
162 MessageBox (NULL, L"Corlib not in sync with this runtime.", NULL, MB_ICONERROR);
163 mono_runtime_quit ();
164 ExitProcess (1);
167 assembly = mono_assembly_open (file_name, NULL);
168 mono_close_exe_image ();
169 if (!assembly) {
170 g_free (file_name);
171 MessageBox (NULL, L"Cannot open assembly.", NULL, MB_ICONERROR);
172 mono_runtime_quit ();
173 ExitProcess (1);
176 image = assembly->image;
177 entry = mono_image_get_entry_point (image);
178 if (!entry) {
179 g_free (file_name);
180 MessageBox (NULL, L"Assembly doesn't have an entry point.", NULL, MB_ICONERROR);
181 mono_runtime_quit ();
182 ExitProcess (1);
185 method = mono_get_method_checked (image, entry, NULL, NULL, &error);
186 if (method == NULL) {
187 g_free (file_name);
188 mono_error_cleanup (&error); /* FIXME don't swallow the error */
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_checked (method, argc, argv, &error);
202 mono_error_raise_exception (&error); /* OK, triggers unhandled exn handler */
203 mono_thread_manage ();
205 mono_runtime_quit ();
207 /* return does not terminate the process. */
208 ExitProcess (mono_environment_exitcode_get ());
211 /* Called by msvcrt.dll when shutting down. */
212 void STDMETHODCALLTYPE CorExitProcess(int exitCode)
214 /* FIXME: This is not currently supported by the runtime. */
215 #if 0
216 if (mono_get_root_domain () && !mono_runtime_is_shutting_down ()) {
217 mono_runtime_set_shutting_down ();
218 mono_thread_suspend_all_other_threads ();
219 mono_runtime_quit ();
221 #endif
222 ExitProcess (exitCode);
225 /* Called by ntdll.dll before _CorDllMain and _CorExeMain. */
226 STDAPI _CorValidateImage(PVOID *ImageBase, LPCWSTR FileName)
228 IMAGE_DOS_HEADER* DosHeader;
229 IMAGE_NT_HEADERS32* NtHeaders32;
230 IMAGE_DATA_DIRECTORY* CliHeaderDir;
231 #ifdef _WIN64
232 IMAGE_NT_HEADERS64* NtHeaders64;
233 MonoCLIHeader* CliHeader;
234 DWORD SizeOfHeaders;
235 #endif
236 DWORD* Address;
237 DWORD OldProtect;
239 DosHeader = (IMAGE_DOS_HEADER*)*ImageBase;
240 if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE)
241 return STATUS_INVALID_IMAGE_FORMAT;
243 NtHeaders32 = (IMAGE_NT_HEADERS32*)((DWORD_PTR)DosHeader + DosHeader->e_lfanew);
244 if (NtHeaders32->Signature != IMAGE_NT_SIGNATURE)
245 return STATUS_INVALID_IMAGE_FORMAT;
247 #ifdef _WIN64
248 NtHeaders64 = (IMAGE_NT_HEADERS64*)NtHeaders32;
249 if (NtHeaders64->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
251 if (NtHeaders64->OptionalHeader.NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)
252 return STATUS_INVALID_IMAGE_FORMAT;
254 CliHeaderDir = &NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR];
255 if (!CliHeaderDir->VirtualAddress)
256 return STATUS_INVALID_IMAGE_FORMAT;
258 CliHeader = (MonoCLIHeader*)((DWORD_PTR)DosHeader + CliHeaderDir->VirtualAddress);
259 if (CliHeader->ch_flags & CLI_FLAGS_32BITREQUIRED)
260 return STATUS_INVALID_IMAGE_FORMAT;
262 if (CliHeader->ch_flags & CLI_FLAGS_ILONLY)
264 /* Avoid calling _CorDllMain because imports are not resolved for IL only images. */
265 if (NtHeaders64->OptionalHeader.AddressOfEntryPoint != 0)
267 Address = &NtHeaders64->OptionalHeader.AddressOfEntryPoint;
268 if (!VirtualProtect(Address, sizeof(DWORD), PAGE_READWRITE, &OldProtect))
269 return E_UNEXPECTED;
270 *Address = (DWORD)0;
271 if (!VirtualProtect(Address, sizeof(DWORD), OldProtect, &OldProtect))
272 return E_UNEXPECTED;
276 return STATUS_SUCCESS;
279 if (NtHeaders32->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
280 return STATUS_INVALID_IMAGE_FORMAT;
282 if (NtHeaders32->OptionalHeader.NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)
283 return STATUS_INVALID_IMAGE_FORMAT;
285 CliHeaderDir = &NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR];
286 if (!CliHeaderDir->VirtualAddress)
287 return STATUS_INVALID_IMAGE_FORMAT;
289 CliHeader = (MonoCLIHeader*)((DWORD_PTR)DosHeader + CliHeaderDir->VirtualAddress);
290 if (!(CliHeader->ch_flags & CLI_FLAGS_ILONLY) || (CliHeader->ch_flags & CLI_FLAGS_32BITREQUIRED))
291 return STATUS_INVALID_IMAGE_FORMAT;
293 /* Fixup IMAGE_NT_HEADERS32 to IMAGE_NT_HEADERS64. */
294 SizeOfHeaders = NtHeaders32->OptionalHeader.SizeOfHeaders;
295 if (SizeOfHeaders < DosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS64) + (sizeof(IMAGE_SECTION_HEADER) * NtHeaders32->FileHeader.NumberOfSections))
296 return STATUS_INVALID_IMAGE_FORMAT;
298 if (!VirtualProtect(DosHeader, SizeOfHeaders, PAGE_READWRITE, &OldProtect))
299 return E_UNEXPECTED;
301 memmove(NtHeaders64 + 1, IMAGE_FIRST_SECTION(NtHeaders32), sizeof(IMAGE_SECTION_HEADER) * NtHeaders32->FileHeader.NumberOfSections);
303 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES - 1].Size = 0;
304 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES - 1].VirtualAddress = 0;
305 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size;
306 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress;
307 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].Size = 0;
308 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress = 0;
309 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = 0;
310 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = 0;
311 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0;
312 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0;
313 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size = 0;
314 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress = 0;
315 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size = 0;
316 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress = 0;
317 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_GLOBALPTR].Size = 0;
318 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_GLOBALPTR].VirtualAddress = 0;
319 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_ARCHITECTURE].Size = 0;
320 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_ARCHITECTURE].VirtualAddress = 0;
321 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
322 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
323 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
324 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;
325 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
326 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress;
327 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size = 0;
328 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress = 0;
329 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size;
330 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
331 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = 0;
332 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = 0;
333 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = 0;
334 NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = 0;
336 NtHeaders64->OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
337 NtHeaders64->OptionalHeader.LoaderFlags = NtHeaders32->OptionalHeader.LoaderFlags;
338 NtHeaders64->OptionalHeader.SizeOfHeapCommit = (ULONGLONG)NtHeaders32->OptionalHeader.SizeOfHeapCommit;
339 NtHeaders64->OptionalHeader.SizeOfHeapReserve = (ULONGLONG)NtHeaders32->OptionalHeader.SizeOfHeapReserve;
340 NtHeaders64->OptionalHeader.SizeOfStackCommit = (ULONGLONG)NtHeaders32->OptionalHeader.SizeOfStackCommit;
341 NtHeaders64->OptionalHeader.SizeOfStackReserve = (ULONGLONG)NtHeaders32->OptionalHeader.SizeOfStackReserve;
342 NtHeaders64->OptionalHeader.DllCharacteristics = NtHeaders32->OptionalHeader.DllCharacteristics;
343 NtHeaders64->OptionalHeader.Subsystem = NtHeaders32->OptionalHeader.Subsystem;
344 NtHeaders64->OptionalHeader.CheckSum = NtHeaders32->OptionalHeader.CheckSum;
345 NtHeaders64->OptionalHeader.SizeOfHeaders = NtHeaders32->OptionalHeader.SizeOfHeaders;
346 NtHeaders64->OptionalHeader.SizeOfImage = NtHeaders32->OptionalHeader.SizeOfImage;
347 NtHeaders64->OptionalHeader.Win32VersionValue = NtHeaders32->OptionalHeader.Win32VersionValue;
348 NtHeaders64->OptionalHeader.MinorSubsystemVersion = NtHeaders32->OptionalHeader.MinorSubsystemVersion;
349 NtHeaders64->OptionalHeader.MajorSubsystemVersion = NtHeaders32->OptionalHeader.MajorSubsystemVersion;
350 NtHeaders64->OptionalHeader.MinorImageVersion = NtHeaders32->OptionalHeader.MinorImageVersion;
351 NtHeaders64->OptionalHeader.MajorImageVersion = NtHeaders32->OptionalHeader.MajorImageVersion;
352 NtHeaders64->OptionalHeader.MinorOperatingSystemVersion = NtHeaders32->OptionalHeader.MinorOperatingSystemVersion;
353 NtHeaders64->OptionalHeader.MajorOperatingSystemVersion = NtHeaders32->OptionalHeader.MajorOperatingSystemVersion;
354 NtHeaders64->OptionalHeader.FileAlignment = NtHeaders32->OptionalHeader.FileAlignment;
355 NtHeaders64->OptionalHeader.SectionAlignment = NtHeaders32->OptionalHeader.SectionAlignment;
356 NtHeaders64->OptionalHeader.ImageBase = (ULONGLONG)NtHeaders32->OptionalHeader.ImageBase;
357 /* BaseOfCode is at the same offset. */
358 NtHeaders64->OptionalHeader.AddressOfEntryPoint = 0;
359 NtHeaders64->OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR64_MAGIC;
360 NtHeaders64->FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER64);
362 if (!VirtualProtect(DosHeader, SizeOfHeaders, OldProtect, &OldProtect))
363 return E_UNEXPECTED;
364 #else
365 if (NtHeaders32->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
366 return STATUS_INVALID_IMAGE_FORMAT;
368 if (NtHeaders32->OptionalHeader.NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)
369 return STATUS_INVALID_IMAGE_FORMAT;
371 CliHeaderDir = &NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR];
372 if (!CliHeaderDir->VirtualAddress)
373 return STATUS_INVALID_IMAGE_FORMAT;
375 Address = &NtHeaders32->OptionalHeader.AddressOfEntryPoint;
376 if (!VirtualProtect(Address, sizeof(DWORD), PAGE_READWRITE, &OldProtect))
377 return E_UNEXPECTED;
378 if (NtHeaders32->FileHeader.Characteristics & IMAGE_FILE_DLL)
379 *Address = (DWORD)((DWORD_PTR)&_CorDllMain - (DWORD_PTR)DosHeader);
380 else
381 *Address = (DWORD)((DWORD_PTR)&_CorExeMain - (DWORD_PTR)DosHeader);
382 if (!VirtualProtect(Address, sizeof(DWORD), OldProtect, &OldProtect))
383 return E_UNEXPECTED;
384 #endif
386 return STATUS_SUCCESS;
389 /* Called by ntdll.dll. */
390 STDAPI_(VOID) _CorImageUnloading(PVOID ImageBase)
392 /* Nothing to do. */
395 STDAPI CorBindToRuntimeEx(LPCWSTR pwszVersion, LPCWSTR pwszBuildFlavor, DWORD startupFlags, REFCLSID rclsid, REFIID riid, LPVOID FAR *ppv)
397 if (ppv == NULL)
398 return E_POINTER;
400 *ppv = NULL;
401 return E_NOTIMPL;
404 STDAPI CorBindToRuntime(LPCWSTR pwszVersion, LPCWSTR pwszBuildFlavor, REFCLSID rclsid, REFIID riid, LPVOID FAR *ppv)
406 return CorBindToRuntimeEx (pwszVersion, pwszBuildFlavor, 0, rclsid, riid, ppv);
409 HMODULE WINAPI MonoLoadImage(LPCWSTR FileName)
411 HANDLE FileHandle;
412 DWORD FileSize;
413 HANDLE MapHandle;
414 IMAGE_DOS_HEADER* DosHeader;
415 IMAGE_NT_HEADERS32* NtHeaders32;
416 #ifdef _WIN64
417 IMAGE_NT_HEADERS64* NtHeaders64;
418 #endif
419 HMODULE ModuleHandle;
421 FileHandle = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
422 if (FileHandle == INVALID_HANDLE_VALUE)
423 return NULL;
425 FileSize = GetFileSize(FileHandle, NULL);
426 if (FileSize == INVALID_FILE_SIZE)
427 goto CloseFile;
429 MapHandle = CreateFileMapping(FileHandle, NULL, PAGE_READONLY, 0, 0, NULL);
430 if (MapHandle == NULL)
431 goto CloseFile;
433 DosHeader = (IMAGE_DOS_HEADER*)MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 0);
434 if (DosHeader == NULL)
435 goto CloseMap;
437 if (FileSize < sizeof(IMAGE_DOS_HEADER) || DosHeader->e_magic != IMAGE_DOS_SIGNATURE || FileSize < DosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS32))
438 goto InvalidImageFormat;
440 NtHeaders32 = (IMAGE_NT_HEADERS32*)((DWORD_PTR)DosHeader + DosHeader->e_lfanew);
441 if (NtHeaders32->Signature != IMAGE_NT_SIGNATURE)
442 goto InvalidImageFormat;
444 #ifdef _WIN64
445 NtHeaders64 = (IMAGE_NT_HEADERS64*)NtHeaders32;
446 if (NtHeaders64->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
448 if (FileSize < DosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS64) ||
449 NtHeaders64->OptionalHeader.NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR ||
450 !NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress)
451 goto InvalidImageFormat;
453 goto ValidImage;
455 #endif
457 if (NtHeaders32->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC ||
458 NtHeaders32->OptionalHeader.NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR ||
459 !NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress)
461 InvalidImageFormat:
462 SetLastError(STATUS_INVALID_IMAGE_FORMAT);
463 goto UnmapView;
466 #ifdef _WIN64
467 ValidImage:
468 #endif
469 UnmapViewOfFile(DosHeader);
470 CloseHandle(MapHandle);
472 ModuleHandle = LoadLibrary(FileName);
474 CloseHandle(FileHandle);
475 return ModuleHandle;
477 UnmapView:
478 UnmapViewOfFile(DosHeader);
479 CloseMap:
480 CloseHandle(MapHandle);
481 CloseFile:
482 CloseHandle(FileHandle);
483 return NULL;
486 typedef struct _EXPORT_FIXUP
488 LPCSTR Name;
489 union
491 PVOID Pointer;
492 DWORD_PTR DWordPtr;
493 BYTE Bytes[sizeof(PVOID)];
494 #ifdef _M_IA64
495 PLABEL_DESCRIPTOR* PLabel;
496 #endif
497 } ProcAddress;
498 } EXPORT_FIXUP;
500 /* Has to be binary ordered. */
501 static const EXPORT_FIXUP ExportFixups[] = {
502 {"CorBindToRuntime", &CorBindToRuntime},
503 {"CorBindToRuntimeEx", &CorBindToRuntimeEx},
504 {"CorExitProcess", &CorExitProcess},
505 {"_CorDllMain", &_CorDllMain},
506 {"_CorExeMain", &_CorExeMain},
507 {"_CorImageUnloading", &_CorImageUnloading},
508 {"_CorValidateImage", &_CorValidateImage},
509 {NULL, NULL}
512 #define EXPORT_FIXUP_COUNT (sizeof(ExportFixups) / sizeof(EXPORT_FIXUP) - 1)
514 static HMODULE ExportFixupModuleHandle = NULL;
515 static DWORD ExportFixupRvas[EXPORT_FIXUP_COUNT];
517 /* Fixup exported functions of mscoree.dll to our implementations. */
518 STDAPI MonoFixupCorEE(HMODULE ModuleHandle)
520 IMAGE_DOS_HEADER* DosHeader;
521 IMAGE_NT_HEADERS* NtHeaders;
522 IMAGE_DATA_DIRECTORY* ExportDataDir;
523 IMAGE_EXPORT_DIRECTORY* ExportDir;
524 DWORD* Functions;
525 DWORD* Names;
526 WORD* NameOrdinals;
527 EXPORT_FIXUP* ExportFixup;
528 DWORD* ExportFixupRva;
529 DWORD* Address;
530 DWORD OldProtect;
531 DWORD ProcRva;
532 DWORD i;
533 int cmp;
534 #ifdef _WIN64
535 MEMORY_BASIC_INFORMATION MemoryInfo;
536 PVOID Region;
537 PVOID RegionBase;
538 PVOID MaxRegionBase;
539 #ifdef _M_IA64
540 PLABEL_DESCRIPTOR* PLabel;
542 #define ELEMENT_SIZE sizeof(PLABEL_DESCRIPTOR)
543 #define REGION_WRITE_PROTECT PAGE_READWRITE
544 #define REGION_PROTECT PAGE_READ
545 #else
546 BYTE* Trampoline;
548 #define ELEMENT_SIZE 13
549 #define REGION_WRITE_PROTECT PAGE_EXECUTE_READWRITE
550 #define REGION_PROTECT PAGE_EXECUTE_READ
551 #endif
552 #endif
554 if (ExportFixupModuleHandle != NULL)
555 return ModuleHandle == ExportFixupModuleHandle ? S_OK : E_FAIL;
557 DosHeader = (IMAGE_DOS_HEADER*)ModuleHandle;
558 if (DosHeader == NULL)
559 return E_POINTER;
561 if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE)
562 return E_INVALIDARG;
564 NtHeaders = (IMAGE_NT_HEADERS*)((DWORD_PTR)DosHeader + DosHeader->e_lfanew);
565 if (NtHeaders->Signature != IMAGE_NT_SIGNATURE)
566 return E_INVALIDARG;
568 if (NtHeaders->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)
569 return E_INVALIDARG;
571 if (NtHeaders->OptionalHeader.NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_EXPORT)
572 return E_FAIL;
574 ExportDataDir = &NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
575 if (!ExportDataDir->VirtualAddress)
576 return E_FAIL;
578 #ifdef _WIN64
579 /* Allocate memory after base address because RVAs are 32-bit unsigned integers. */
580 RegionBase = DosHeader;
581 MaxRegionBase = (PVOID)((DWORD_PTR)RegionBase + (DWORD_PTR)(0x100000000L - (ELEMENT_SIZE * (EXPORT_FIXUP_COUNT - 1))));
582 for (;;)
584 if (!VirtualQuery(RegionBase, &MemoryInfo, sizeof(MEMORY_BASIC_INFORMATION)))
585 return E_UNEXPECTED;
586 if (MemoryInfo.State == MEM_FREE && MemoryInfo.RegionSize >= ELEMENT_SIZE * EXPORT_FIXUP_COUNT)
588 Region = VirtualAlloc(RegionBase, ELEMENT_SIZE * EXPORT_FIXUP_COUNT, MEM_COMMIT | MEM_RESERVE, REGION_WRITE_PROTECT);
589 if (Region != NULL)
590 break;
592 RegionBase = (PVOID)((DWORD_PTR)MemoryInfo.BaseAddress + (DWORD_PTR)MemoryInfo.RegionSize);
593 if (RegionBase > MaxRegionBase)
594 return E_OUTOFMEMORY;
597 #ifdef _M_IA64
598 PLabel = (PLABEL_DESCRIPTOR*)Region;
599 #else
600 Trampoline = (BYTE*)Region;
601 #endif
602 #endif
604 ExportDir = (IMAGE_EXPORT_DIRECTORY*)((DWORD_PTR)DosHeader + ExportDataDir->VirtualAddress);
605 Functions = (DWORD*)((DWORD_PTR)DosHeader + ExportDir->AddressOfFunctions);
606 Names = (DWORD*)((DWORD_PTR)DosHeader + ExportDir->AddressOfNames);
607 NameOrdinals = (WORD*)((DWORD_PTR)DosHeader + ExportDir->AddressOfNameOrdinals);
608 ExportFixup = (EXPORT_FIXUP*)&ExportFixups;
609 ExportFixupRva = (DWORD*)&ExportFixupRvas;
611 for (i = 0; i < ExportDir->NumberOfNames; i++)
613 cmp = strcmp((LPCSTR)((DWORD_PTR)DosHeader + Names[i]), ExportFixup->Name);
614 if (cmp > 0)
615 return E_FAIL;
617 if (cmp == 0)
619 #ifdef _WIN64
620 #if defined(_M_IA64)
621 ProcRva = (DWORD)((DWORD_PTR)PLabel - (DWORD_PTR)DosHeader);
622 *(PLabel)++ = *ExportFixup->ProcAddress.PLabel;
623 #elif defined(_M_AMD64)
624 ProcRva = (DWORD)((DWORD_PTR)Trampoline - (DWORD_PTR)DosHeader);
625 /* mov r11, ExportFixup->ProcAddress */
626 *(Trampoline)++ = 0x49;
627 *(Trampoline)++ = 0xBB;
628 *(Trampoline)++ = ExportFixup->ProcAddress.Bytes[0];
629 *(Trampoline)++ = ExportFixup->ProcAddress.Bytes[1];
630 *(Trampoline)++ = ExportFixup->ProcAddress.Bytes[2];
631 *(Trampoline)++ = ExportFixup->ProcAddress.Bytes[3];
632 *(Trampoline)++ = ExportFixup->ProcAddress.Bytes[4];
633 *(Trampoline)++ = ExportFixup->ProcAddress.Bytes[5];
634 *(Trampoline)++ = ExportFixup->ProcAddress.Bytes[6];
635 *(Trampoline)++ = ExportFixup->ProcAddress.Bytes[7];
636 /* jmp r11 */
637 *(Trampoline)++ = 0x41;
638 *(Trampoline)++ = 0xFF;
639 *(Trampoline)++ = 0xE3;
640 #else
641 #error Unsupported architecture.
642 #endif
643 #else
644 ProcRva = (DWORD)(ExportFixup->ProcAddress.DWordPtr - (DWORD_PTR)DosHeader);
645 #endif
646 Address = &Functions[NameOrdinals[i]];
647 if (!VirtualProtect(Address, sizeof(DWORD), PAGE_READWRITE, &OldProtect))
648 return E_UNEXPECTED;
649 *ExportFixupRva = *Address;
650 *Address = ProcRva;
651 if (!VirtualProtect(Address, sizeof(DWORD), OldProtect, &OldProtect))
652 return E_UNEXPECTED;
653 ExportFixup++;
654 if (ExportFixup->Name == NULL) {
655 #ifdef _WIN64
656 if (!VirtualProtect(Region, ELEMENT_SIZE * EXPORT_FIXUP_COUNT, REGION_PROTECT, &OldProtect))
657 return E_UNEXPECTED;
658 #endif
660 ExportFixupModuleHandle = ModuleHandle;
661 return S_OK;
663 ExportFixupRva++;
666 return E_FAIL;
669 /* Executable images are only mapped by the OS loader. We need to do fixups for native code support. */
670 STDAPI MonoFixupExe(HMODULE ModuleHandle)
672 IMAGE_DOS_HEADER* DosHeader;
673 IMAGE_NT_HEADERS* NtHeaders;
674 DWORD_PTR* Address;
675 DWORD OldProtect;
676 DWORD_PTR BaseDiff;
678 DosHeader = (IMAGE_DOS_HEADER*)ModuleHandle;
679 if (DosHeader == NULL)
680 return E_POINTER;
682 if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE)
683 return E_INVALIDARG;
685 NtHeaders = (IMAGE_NT_HEADERS*)((DWORD_PTR)DosHeader + DosHeader->e_lfanew);
686 if (NtHeaders->Signature != IMAGE_NT_SIGNATURE)
687 return E_INVALIDARG;
689 if (NtHeaders->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)
690 return E_INVALIDARG;
692 if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL)
693 return S_OK;
695 if (NtHeaders->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)
697 IMAGE_DATA_DIRECTORY* CliHeaderDir;
698 MonoCLIHeader* CliHeader;
700 CliHeaderDir = &NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR];
701 if (CliHeaderDir->VirtualAddress)
703 CliHeader = (MonoCLIHeader*)((DWORD_PTR)DosHeader + CliHeaderDir->VirtualAddress);
704 if (CliHeader->ch_flags & CLI_FLAGS_ILONLY)
705 return S_OK;
709 BaseDiff = (DWORD_PTR)DosHeader - NtHeaders->OptionalHeader.ImageBase;
710 if (BaseDiff != 0)
712 if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
713 return E_FAIL;
715 Address = &NtHeaders->OptionalHeader.ImageBase;
716 if (!VirtualProtect(Address, sizeof(DWORD_PTR), PAGE_READWRITE, &OldProtect))
717 return E_UNEXPECTED;
718 *Address = (DWORD_PTR)DosHeader;
719 if (!VirtualProtect(Address, sizeof(DWORD_PTR), OldProtect, &OldProtect))
720 return E_UNEXPECTED;
722 if (NtHeaders->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_BASERELOC)
724 IMAGE_DATA_DIRECTORY* BaseRelocDir;
725 IMAGE_BASE_RELOCATION* BaseReloc;
726 USHORT* RelocBlock;
727 ULONG BaseRelocSize;
728 ULONG RelocBlockSize;
729 USHORT RelocOffset;
730 DWORD_PTR UNALIGNED *RelocFixup;
732 BaseRelocDir = &NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
733 if (BaseRelocDir->VirtualAddress)
735 BaseReloc = (IMAGE_BASE_RELOCATION*)((DWORD_PTR)DosHeader + BaseRelocDir->VirtualAddress);
736 BaseRelocSize = BaseRelocDir->Size;
738 while (BaseRelocSize)
740 RelocBlockSize = BaseReloc->SizeOfBlock;
742 if (!RelocBlockSize || BaseRelocSize < RelocBlockSize)
743 return E_FAIL;
745 BaseRelocSize -= RelocBlockSize;
746 RelocBlock = (USHORT*)((DWORD_PTR)BaseReloc + sizeof(IMAGE_BASE_RELOCATION));
747 RelocBlockSize -= sizeof(IMAGE_BASE_RELOCATION);
748 RelocBlockSize /= sizeof(USHORT);
750 while (RelocBlockSize-- != 0)
752 RelocOffset = *RelocBlock & (USHORT)0x0fff;
753 RelocFixup = (DWORD_PTR*)((DWORD_PTR)DosHeader + BaseReloc->VirtualAddress + RelocOffset);
755 switch (*RelocBlock >> 12)
757 case IMAGE_REL_BASED_ABSOLUTE:
758 break;
760 #ifdef _WIN64
761 case IMAGE_REL_BASED_DIR64:
762 #else
763 case IMAGE_REL_BASED_HIGHLOW:
764 #endif
765 if (!VirtualProtect(RelocFixup, sizeof(DWORD_PTR), PAGE_EXECUTE_READWRITE, &OldProtect))
766 return E_UNEXPECTED;
767 *RelocFixup += BaseDiff;
768 if (!VirtualProtect(RelocFixup, sizeof(DWORD_PTR), OldProtect, &OldProtect))
769 return E_UNEXPECTED;
770 break;
772 default:
773 return E_FAIL;
776 RelocBlock++;
778 BaseReloc = (IMAGE_BASE_RELOCATION*)RelocBlock;
784 if (NtHeaders->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_IMPORT)
786 IMAGE_DATA_DIRECTORY* ImportDir;
787 IMAGE_IMPORT_DESCRIPTOR* ImportDesc;
788 HMODULE ImportModuleHandle;
789 IMAGE_THUNK_DATA* ImportThunkData;
790 DWORD_PTR ProcAddress;
792 ImportDir = &NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
793 if (ImportDir->VirtualAddress != 0)
795 ImportDesc = (IMAGE_IMPORT_DESCRIPTOR*)((DWORD_PTR)DosHeader + ImportDir->VirtualAddress);
796 while (ImportDesc->Name && ImportDesc->OriginalFirstThunk)
798 ImportModuleHandle = LoadLibraryA((PCSTR)((DWORD_PTR)DosHeader + ImportDesc->Name));
799 if (ImportModuleHandle == NULL)
800 return E_FAIL;
802 ImportThunkData = (IMAGE_THUNK_DATA*)((DWORD_PTR)DosHeader + ImportDesc->OriginalFirstThunk);
803 while (ImportThunkData->u1.Ordinal != 0)
805 if (IMAGE_SNAP_BY_ORDINAL(ImportThunkData->u1.Ordinal))
806 ProcAddress = (DWORD_PTR)GetProcAddress(ImportModuleHandle, (LPCSTR)IMAGE_ORDINAL(ImportThunkData->u1.Ordinal));
807 else
809 IMAGE_IMPORT_BY_NAME* ImportByName = (IMAGE_IMPORT_BY_NAME*)((DWORD_PTR)DosHeader + ImportThunkData->u1.AddressOfData);
810 ProcAddress = (DWORD_PTR)GetProcAddress(ImportModuleHandle, ImportByName->Name);
812 if (ProcAddress == 0)
813 return E_FAIL;
814 Address = (DWORD_PTR*)((DWORD_PTR)ImportThunkData - ImportDesc->OriginalFirstThunk + ImportDesc->FirstThunk);
815 if (!VirtualProtect(Address, sizeof(DWORD_PTR), PAGE_READWRITE, &OldProtect))
816 return E_UNEXPECTED;
817 *Address = ProcAddress;
818 if (!VirtualProtect(Address, sizeof(DWORD_PTR), OldProtect, &OldProtect))
819 return E_UNEXPECTED;
820 ImportThunkData++;
823 ImportDesc++;
828 return S_OK;
831 static void
832 mono_set_act_ctx (const char* file_name)
834 typedef HANDLE (WINAPI* CREATEACTCTXW_PROC) (PCACTCTXW pActCtx);
835 typedef BOOL (WINAPI* ACTIVATEACTCTX_PROC) (HANDLE hActCtx, ULONG_PTR* lpCookie);
837 HMODULE kernel32_handle;
838 CREATEACTCTXW_PROC CreateActCtx_proc;
839 ACTIVATEACTCTX_PROC ActivateActCtx_proc;
840 gchar* full_path;
841 gunichar2* full_path_utf16;
842 gchar* dir_name;
843 gunichar2* dir_name_utf16;
844 gchar* base_name;
845 gunichar2* base_name_utf16;
846 ACTCTX act_ctx;
847 HANDLE handle;
848 ULONG_PTR cookie;
850 kernel32_handle = GetModuleHandle (L"kernel32.dll");
851 if (!kernel32_handle)
852 return;
853 CreateActCtx_proc = (CREATEACTCTXW_PROC) GetProcAddress (kernel32_handle, "CreateActCtxW");
854 if (!CreateActCtx_proc)
855 return;
856 ActivateActCtx_proc = (ACTIVATEACTCTX_PROC) GetProcAddress (kernel32_handle, "ActivateActCtx");
857 if (!ActivateActCtx_proc)
858 return;
860 full_path = mono_path_canonicalize (file_name);
861 full_path_utf16 = g_utf8_to_utf16 (full_path, -1, NULL, NULL, NULL);
862 dir_name = g_path_get_dirname (full_path);
863 dir_name_utf16 = g_utf8_to_utf16 (dir_name, -1, NULL, NULL, NULL);
864 base_name = g_path_get_basename (full_path);
865 base_name_utf16 = g_utf8_to_utf16 (base_name, -1, NULL, NULL, NULL);
866 g_free (base_name);
867 g_free (dir_name);
868 g_free (full_path);
870 memset (&act_ctx, 0, sizeof (ACTCTX));
871 act_ctx.cbSize = sizeof (ACTCTX);
872 act_ctx.dwFlags = ACTCTX_FLAG_SET_PROCESS_DEFAULT | ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID | ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_APPLICATION_NAME_VALID;
873 act_ctx.lpSource = full_path_utf16;
874 act_ctx.lpAssemblyDirectory = dir_name_utf16;
875 act_ctx.lpResourceName = MAKEINTRESOURCE (CREATEPROCESS_MANIFEST_RESOURCE_ID);
876 act_ctx.lpApplicationName = base_name_utf16;
878 handle = CreateActCtx_proc (&act_ctx);
879 if (handle == INVALID_HANDLE_VALUE && GetLastError () == ERROR_SXS_PROCESS_DEFAULT_ALREADY_SET) {
880 act_ctx.dwFlags &= ~ACTCTX_FLAG_SET_PROCESS_DEFAULT;
881 handle = CreateActCtx_proc (&act_ctx);
884 g_free (base_name_utf16);
885 g_free (dir_name_utf16);
886 g_free (full_path_utf16);
888 if (handle != INVALID_HANDLE_VALUE)
889 ActivateActCtx_proc (handle, &cookie);
892 void
893 mono_load_coree (const char* exe_file_name)
895 HMODULE module_handle;
896 gunichar2* file_name;
897 UINT required_size;
898 UINT size;
900 if (coree_module_handle)
901 return;
903 if (!init_from_coree && exe_file_name)
904 mono_set_act_ctx (exe_file_name);
906 /* ntdll.dll loads mscoree.dll from the system32 directory. */
907 required_size = GetSystemDirectory (NULL, 0);
908 file_name = g_new (gunichar2, required_size + 12);
909 size = GetSystemDirectory (file_name, required_size);
910 g_assert (size < required_size);
911 if (file_name [size - 1] != L'\\')
912 file_name [size++] = L'\\';
913 memcpy (&file_name [size], L"mscoree.dll", 12 * sizeof (gunichar2));
915 module_handle = LoadLibrary (file_name);
916 g_free (file_name);
918 if (module_handle && !SUCCEEDED (MonoFixupCorEE (module_handle))) {
919 FreeLibrary (module_handle);
920 module_handle = NULL;
923 coree_module_handle = module_handle;
926 void
927 mono_fixup_exe_image (MonoImage* image)
929 if (!init_from_coree && image && image->is_module_handle)
930 MonoFixupExe ((HMODULE) image->raw_data);
933 #endif /* HOST_WIN32 */