3 * Routine for saving an image to a file.
7 * Paolo Molaro (lupus@ximian.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2011 Rodrigo Kumpera
12 * Copyright 2016 Microsoft
14 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
20 #include "mono/metadata/dynamic-image-internals.h"
21 #include "mono/metadata/dynamic-stream-internals.h"
22 #include "mono/metadata/mono-ptr-array.h"
23 #include "mono/metadata/object-internals.h"
24 #include "mono/metadata/sre-internals.h"
25 #include "mono/metadata/security-manager.h"
26 #include "mono/metadata/tabledefs.h"
27 #include "mono/metadata/tokentype.h"
28 #include "mono/metadata/w32file.h"
29 #include "mono/metadata/w32error.h"
31 #include "mono/utils/checked-build.h"
32 #include "mono/utils/mono-digest.h"
33 #include "mono/utils/mono-error-internals.h"
34 #include "mono/utils/w32api.h"
36 #define TEXT_OFFSET 512
37 #define CLI_H_SIZE 136
38 #define FILE_ALIGN 512
39 #define VIRT_ALIGN 8192
40 #define START_TEXT_RVA 0x00002000
42 static void mono_image_get_generic_param_info (MonoReflectionGenericParam *gparam, guint32 owner, MonoDynamicImage *assembly);
45 alloc_table (MonoDynamicTable *table, guint nrows)
47 mono_dynimage_alloc_table (table, nrows);
51 string_heap_insert (MonoDynamicStream *sh, const char *str)
53 return mono_dynstream_insert_string (sh, str);
57 string_heap_insert_mstring (MonoDynamicStream *sh, MonoString *str, MonoError *error)
59 return mono_dynstream_insert_mstring (sh, str, error);
63 mono_image_add_stream_data (MonoDynamicStream *stream, const char *data, guint32 len)
65 return mono_dynstream_add_data (stream, data, len);
69 mono_image_add_stream_zero (MonoDynamicStream *stream, guint32 len)
71 return mono_dynstream_add_zero (stream, len);
75 stream_data_align (MonoDynamicStream *stream)
77 mono_dynstream_data_align (stream);
81 mono_image_typedef_or_ref (MonoDynamicImage *assembly, MonoType *type)
83 return mono_dynimage_encode_typedef_or_ref_full (assembly, type, TRUE);
87 find_index_in_table (MonoDynamicImage *assembly, int table_idx, int col, guint32 token)
89 MONO_REQ_GC_NEUTRAL_MODE;
92 MonoDynamicTable *table;
95 table = &assembly->tables [table_idx];
97 g_assert (col < table->columns);
99 values = table->values + table->columns;
100 for (i = 1; i <= table->rows; ++i) {
101 if (values [col] == token)
103 values += table->columns;
109 * Copy len * nelem bytes from val to dest, swapping bytes to LE if necessary.
110 * dest may be misaligned.
113 swap_with_size (char *dest, const char* val, int len, int nelem) {
114 MONO_REQ_GC_NEUTRAL_MODE;
115 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
118 for (elem = 0; elem < nelem; ++elem) {
144 g_assert_not_reached ();
150 memcpy (dest, val, len * nelem);
155 add_mono_string_to_blob_cached (MonoDynamicImage *assembly, MonoString *str)
157 MONO_REQ_GC_UNSAFE_MODE;
161 guint32 idx = 0, len;
163 len = str->length * 2;
164 mono_metadata_encode_value (len, b, &b);
165 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
167 char *swapped = g_malloc (2 * mono_string_length (str));
168 const char *p = (const char*)mono_string_chars (str);
170 swap_with_size (swapped, p, 2, mono_string_length (str));
171 idx = mono_dynamic_image_add_to_blob_cached (assembly, blob_size, b-blob_size, swapped, len);
175 idx = mono_dynamic_image_add_to_blob_cached (assembly, blob_size, b-blob_size, (char*)mono_string_chars (str), len);
181 image_create_token_raw (MonoDynamicImage *assembly, MonoObject* obj_raw, gboolean create_methodspec, gboolean register_token, MonoError *error)
183 HANDLE_FUNCTION_ENTER (); /* FIXME callers of image_create_token_raw should use handles */
185 MONO_HANDLE_DCL (MonoObject, obj);
186 guint32 result = mono_image_create_token (assembly, obj, create_methodspec, register_token, error);
187 HANDLE_FUNCTION_RETURN_VAL (result);
192 * idx is the table index of the object
193 * type is one of MONO_CUSTOM_ATTR_*
196 mono_image_add_cattrs (MonoDynamicImage *assembly, guint32 idx, guint32 type, MonoArray *cattrs, MonoError *error)
198 MONO_REQ_GC_UNSAFE_MODE;
200 MonoDynamicTable *table;
201 MonoReflectionCustomAttr *cattr;
203 guint32 count, i, token;
209 /* it is legal to pass a NULL cattrs: we avoid to use the if in a lot of places */
212 count = mono_array_length (cattrs);
213 table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
214 table->rows += count;
215 alloc_table (table, table->rows);
216 values = table->values + table->next_idx * MONO_CUSTOM_ATTR_SIZE;
217 idx <<= MONO_CUSTOM_ATTR_BITS;
219 for (i = 0; i < count; ++i) {
220 cattr = (MonoReflectionCustomAttr*)mono_array_get (cattrs, gpointer, i);
221 values [MONO_CUSTOM_ATTR_PARENT] = idx;
222 token = image_create_token_raw (assembly, (MonoObject*)cattr->ctor, FALSE, FALSE, error); /* FIXME use handles */
223 if (!mono_error_ok (error)) goto fail;
224 type = mono_metadata_token_index (token);
225 type <<= MONO_CUSTOM_ATTR_TYPE_BITS;
226 switch (mono_metadata_token_table (token)) {
227 case MONO_TABLE_METHOD:
228 type |= MONO_CUSTOM_ATTR_TYPE_METHODDEF;
230 * fixup_cattrs () needs to fix this up. We can't use image->tokens, since it contains the old token for the
231 * method, not the one returned by mono_image_create_token ().
233 mono_g_hash_table_insert (assembly->remapped_tokens, GUINT_TO_POINTER (token), cattr->ctor);
235 case MONO_TABLE_MEMBERREF:
236 type |= MONO_CUSTOM_ATTR_TYPE_MEMBERREF;
239 g_warning ("got wrong token in custom attr");
242 values [MONO_CUSTOM_ATTR_TYPE] = type;
244 mono_metadata_encode_value (mono_array_length (cattr->data), p, &p);
245 values [MONO_CUSTOM_ATTR_VALUE] = mono_dynamic_image_add_to_blob_cached (assembly, blob_size, p - blob_size,
246 mono_array_addr (cattr->data, char, 0), mono_array_length (cattr->data));
247 values += MONO_CUSTOM_ATTR_SIZE;
258 mono_image_add_decl_security (MonoDynamicImage *assembly, guint32 parent_token, MonoArray *permissions)
260 MONO_REQ_GC_UNSAFE_MODE;
262 MonoDynamicTable *table;
264 guint32 count, i, idx;
265 MonoReflectionPermissionSet *perm;
270 count = mono_array_length (permissions);
271 table = &assembly->tables [MONO_TABLE_DECLSECURITY];
272 table->rows += count;
273 alloc_table (table, table->rows);
275 for (i = 0; i < mono_array_length (permissions); ++i) {
276 perm = (MonoReflectionPermissionSet*)mono_array_addr (permissions, MonoReflectionPermissionSet, i);
278 values = table->values + table->next_idx * MONO_DECL_SECURITY_SIZE;
280 idx = mono_metadata_token_index (parent_token);
281 idx <<= MONO_HAS_DECL_SECURITY_BITS;
282 switch (mono_metadata_token_table (parent_token)) {
283 case MONO_TABLE_TYPEDEF:
284 idx |= MONO_HAS_DECL_SECURITY_TYPEDEF;
286 case MONO_TABLE_METHOD:
287 idx |= MONO_HAS_DECL_SECURITY_METHODDEF;
289 case MONO_TABLE_ASSEMBLY:
290 idx |= MONO_HAS_DECL_SECURITY_ASSEMBLY;
293 g_assert_not_reached ();
296 values [MONO_DECL_SECURITY_ACTION] = perm->action;
297 values [MONO_DECL_SECURITY_PARENT] = idx;
298 values [MONO_DECL_SECURITY_PERMISSIONSET] = add_mono_string_to_blob_cached (assembly, perm->pset);
305 * method_encode_code:
307 * @assembly the assembly
308 * @mb the managed MethodBuilder
309 * @error set on error
311 * Note that the return value is not sensible if @error is set.
314 method_encode_code (MonoDynamicImage *assembly, ReflectionMethodBuilder *mb, MonoError *error)
316 MONO_REQ_GC_UNSAFE_MODE;
322 gint32 num_locals = 0;
323 gint32 num_exception = 0;
326 char fat_header [12];
329 guint32 local_sig = 0;
330 guint32 header_size = 12;
335 if ((mb->attrs & (METHOD_ATTRIBUTE_PINVOKE_IMPL | METHOD_ATTRIBUTE_ABSTRACT)) ||
336 (mb->iattrs & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)))
340 g_print ("Encode method %s\n", mono_string_to_utf8 (mb->name));*/
342 code = mb->ilgen->code;
343 code_size = mb->ilgen->code_len;
344 max_stack = mb->ilgen->max_stack;
345 num_locals = mb->ilgen->locals ? mono_array_length (mb->ilgen->locals) : 0;
346 if (mb->ilgen->ex_handlers)
347 num_exception = mono_reflection_method_count_clauses (mb->ilgen);
351 MonoError inner_error;
352 char *name = mono_string_to_utf8_checked (mb->name, &inner_error);
353 if (!is_ok (&inner_error)) {
354 name = g_strdup ("");
355 mono_error_cleanup (&inner_error);
357 char *str = g_strdup_printf ("Method %s does not have any IL associated", name);
358 mono_error_set_argument (error, NULL, "a method does not have any IL associated");
364 code_size = mono_array_length (code);
365 max_stack = 8; /* we probably need to run a verifier on the code... */
368 stream_data_align (&assembly->code);
370 /* check for exceptions, maxstack, locals */
371 maybe_small = (max_stack <= 8) && (!num_locals) && (!num_exception);
373 if (code_size < 64 && !(code_size & 1)) {
374 flags = (code_size << 2) | 0x2;
375 } else if (code_size < 32 && (code_size & 1)) {
376 flags = (code_size << 2) | 0x6; /* LAMESPEC: see metadata.c */
380 idx = mono_image_add_stream_data (&assembly->code, &flags, 1);
381 /* add to the fixup todo list */
382 if (mb->ilgen && mb->ilgen->num_token_fixups)
383 mono_g_hash_table_insert (assembly->token_fixups, mb->ilgen, GUINT_TO_POINTER (idx + 1));
384 mono_image_add_stream_data (&assembly->code, mono_array_addr (code, char, 0), code_size);
385 return assembly->text_rva + idx;
389 local_sig = MONO_TOKEN_SIGNATURE | mono_dynimage_encode_locals (assembly, mb->ilgen, error);
390 return_val_if_nok (error, 0);
393 * FIXME: need to set also the header size in fat_flags.
394 * (and more sects and init locals flags)
398 fat_flags |= METHOD_HEADER_MORE_SECTS;
400 fat_flags |= METHOD_HEADER_INIT_LOCALS;
401 fat_header [0] = fat_flags;
402 fat_header [1] = (header_size / 4 ) << 4;
403 short_value = GUINT16_TO_LE (max_stack);
404 memcpy (fat_header + 2, &short_value, 2);
405 int_value = GUINT32_TO_LE (code_size);
406 memcpy (fat_header + 4, &int_value, 4);
407 int_value = GUINT32_TO_LE (local_sig);
408 memcpy (fat_header + 8, &int_value, 4);
409 idx = mono_image_add_stream_data (&assembly->code, fat_header, 12);
410 /* add to the fixup todo list */
411 if (mb->ilgen && mb->ilgen->num_token_fixups)
412 mono_g_hash_table_insert (assembly->token_fixups, mb->ilgen, GUINT_TO_POINTER (idx + 12));
414 mono_image_add_stream_data (&assembly->code, mono_array_addr (code, char, 0), code_size);
416 unsigned char sheader [4];
417 MonoILExceptionInfo * ex_info;
418 MonoILExceptionBlock * ex_block;
421 stream_data_align (&assembly->code);
422 /* always use fat format for now */
423 sheader [0] = METHOD_HEADER_SECTION_FAT_FORMAT | METHOD_HEADER_SECTION_EHTABLE;
424 num_exception *= 6 * sizeof (guint32);
425 num_exception += 4; /* include the size of the header */
426 sheader [1] = num_exception & 0xff;
427 sheader [2] = (num_exception >> 8) & 0xff;
428 sheader [3] = (num_exception >> 16) & 0xff;
429 mono_image_add_stream_data (&assembly->code, (char*)sheader, 4);
430 /* fat header, so we are already aligned */
432 for (i = mono_array_length (mb->ilgen->ex_handlers) - 1; i >= 0; --i) {
433 ex_info = (MonoILExceptionInfo *)mono_array_addr (mb->ilgen->ex_handlers, MonoILExceptionInfo, i);
434 if (ex_info->handlers) {
435 int finally_start = ex_info->start + ex_info->len;
436 for (j = 0; j < mono_array_length (ex_info->handlers); ++j) {
438 ex_block = (MonoILExceptionBlock*)mono_array_addr (ex_info->handlers, MonoILExceptionBlock, j);
440 val = GUINT32_TO_LE (ex_block->type);
441 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
443 val = GUINT32_TO_LE (ex_info->start);
444 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
445 /* need fault, too, probably */
446 if (ex_block->type == MONO_EXCEPTION_CLAUSE_FINALLY)
447 val = GUINT32_TO_LE (finally_start - ex_info->start);
449 val = GUINT32_TO_LE (ex_info->len);
450 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
452 val = GUINT32_TO_LE (ex_block->start);
453 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
455 val = GUINT32_TO_LE (ex_block->len);
456 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
457 finally_start = ex_block->start + ex_block->len;
458 if (ex_block->extype) {
459 MonoType *extype = mono_reflection_type_get_handle ((MonoReflectionType*)ex_block->extype, error);
460 return_val_if_nok (error, 0);
462 val = mono_metadata_token_from_dor (mono_image_typedef_or_ref (assembly, extype));
464 if (ex_block->type == MONO_EXCEPTION_CLAUSE_FILTER)
465 val = ex_block->filter_offset;
469 val = GUINT32_TO_LE (val);
470 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
471 /*g_print ("out clause %d: from %d len=%d, handler at %d, %d, finally_start=%d, ex_info->start=%d, ex_info->len=%d, ex_block->type=%d, j=%d, i=%d\n",
472 clause.flags, clause.try_offset, clause.try_len, clause.handler_offset, clause.handler_len, finally_start, ex_info->start, ex_info->len, ex_block->type, j, i);*/
475 g_error ("No clauses for ex info block %d", i);
479 return assembly->text_rva + idx;
483 * Fill in the MethodDef and ParamDef tables for a method.
484 * This is used for both normal methods and constructors.
487 mono_image_basic_method (ReflectionMethodBuilder *mb, MonoDynamicImage *assembly, MonoError *error)
489 MONO_REQ_GC_UNSAFE_MODE;
491 MonoDynamicTable *table;
497 /* room in this table is already allocated */
498 table = &assembly->tables [MONO_TABLE_METHOD];
499 *mb->table_idx = table->next_idx ++;
500 g_hash_table_insert (assembly->method_to_table_idx, mb->mhandle, GUINT_TO_POINTER ((*mb->table_idx)));
501 values = table->values + *mb->table_idx * MONO_METHOD_SIZE;
502 values [MONO_METHOD_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->name, error);
503 return_val_if_nok (error, FALSE);
504 values [MONO_METHOD_FLAGS] = mb->attrs;
505 values [MONO_METHOD_IMPLFLAGS] = mb->iattrs;
506 values [MONO_METHOD_SIGNATURE] = mono_dynimage_encode_method_builder_signature (assembly, mb, error);
507 return_val_if_nok (error, FALSE);
508 values [MONO_METHOD_RVA] = method_encode_code (assembly, mb, error);
509 return_val_if_nok (error, FALSE);
511 table = &assembly->tables [MONO_TABLE_PARAM];
512 values [MONO_METHOD_PARAMLIST] = table->next_idx;
514 mono_image_add_decl_security (assembly,
515 mono_metadata_make_token (MONO_TABLE_METHOD, *mb->table_idx), mb->permissions);
518 MonoDynamicTable *mtable;
521 mtable = &assembly->tables [MONO_TABLE_FIELDMARSHAL];
522 mvalues = mtable->values + mtable->next_idx * MONO_FIELD_MARSHAL_SIZE;
525 for (i = 0; i < mono_array_length (mb->pinfo); ++i) {
526 if (mono_array_get (mb->pinfo, gpointer, i))
529 table->rows += count;
530 alloc_table (table, table->rows);
531 values = table->values + table->next_idx * MONO_PARAM_SIZE;
532 for (i = 0; i < mono_array_length (mb->pinfo); ++i) {
533 MonoReflectionParamBuilder *pb;
534 if ((pb = mono_array_get (mb->pinfo, MonoReflectionParamBuilder*, i))) {
535 values [MONO_PARAM_FLAGS] = pb->attrs;
536 values [MONO_PARAM_SEQUENCE] = i;
537 if (pb->name != NULL) {
538 values [MONO_PARAM_NAME] = string_heap_insert_mstring (&assembly->sheap, pb->name, error);
539 return_val_if_nok (error, FALSE);
541 values [MONO_PARAM_NAME] = 0;
543 values += MONO_PARAM_SIZE;
544 if (pb->marshal_info) {
546 alloc_table (mtable, mtable->rows);
547 mvalues = mtable->values + mtable->rows * MONO_FIELD_MARSHAL_SIZE;
548 mvalues [MONO_FIELD_MARSHAL_PARENT] = (table->next_idx << MONO_HAS_FIELD_MARSHAL_BITS) | MONO_HAS_FIELD_MARSHAL_PARAMDEF;
549 mvalues [MONO_FIELD_MARSHAL_NATIVE_TYPE] = mono_dynimage_save_encode_marshal_blob (assembly, pb->marshal_info, error);
550 return_val_if_nok (error, FALSE);
552 pb->table_idx = table->next_idx++;
553 if (pb->attrs & PARAM_ATTRIBUTE_HAS_DEFAULT) {
554 guint32 field_type = 0;
555 mtable = &assembly->tables [MONO_TABLE_CONSTANT];
557 alloc_table (mtable, mtable->rows);
558 mvalues = mtable->values + mtable->rows * MONO_CONSTANT_SIZE;
559 mvalues [MONO_CONSTANT_PARENT] = MONO_HASCONSTANT_PARAM | (pb->table_idx << MONO_HASCONSTANT_BITS);
560 mvalues [MONO_CONSTANT_VALUE] = mono_dynimage_encode_constant (assembly, pb->def_value, &field_type);
561 mvalues [MONO_CONSTANT_TYPE] = field_type;
562 mvalues [MONO_CONSTANT_PADDING] = 0;
572 mono_image_add_methodimpl (MonoDynamicImage *assembly, MonoReflectionMethodBuilder *mb, MonoError *error)
574 MONO_REQ_GC_UNSAFE_MODE;
576 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mb->type;
577 MonoDynamicTable *table;
580 MonoReflectionMethod *m;
585 if (!mb->override_methods)
588 for (i = 0; i < mono_array_length (mb->override_methods); ++i) {
589 m = mono_array_get (mb->override_methods, MonoReflectionMethod*, i);
591 table = &assembly->tables [MONO_TABLE_METHODIMPL];
593 alloc_table (table, table->rows);
594 values = table->values + table->rows * MONO_METHODIMPL_SIZE;
595 values [MONO_METHODIMPL_CLASS] = tb->table_idx;
596 values [MONO_METHODIMPL_BODY] = MONO_METHODDEFORREF_METHODDEF | (mb->table_idx << MONO_METHODDEFORREF_BITS);
598 tok = image_create_token_raw (assembly, (MonoObject*)m, FALSE, FALSE, error); /* FIXME use handles */
599 return_val_if_nok (error, FALSE);
601 switch (mono_metadata_token_table (tok)) {
602 case MONO_TABLE_MEMBERREF:
603 tok = (mono_metadata_token_index (tok) << MONO_METHODDEFORREF_BITS ) | MONO_METHODDEFORREF_METHODREF;
605 case MONO_TABLE_METHOD:
606 tok = (mono_metadata_token_index (tok) << MONO_METHODDEFORREF_BITS ) | MONO_METHODDEFORREF_METHODDEF;
609 g_assert_not_reached ();
611 values [MONO_METHODIMPL_DECLARATION] = tok;
617 #ifndef DISABLE_REFLECTION_EMIT
619 mono_image_get_method_info (MonoReflectionMethodBuilder *mb, MonoDynamicImage *assembly, MonoError *error)
621 MONO_REQ_GC_UNSAFE_MODE;
623 MonoDynamicTable *table;
625 ReflectionMethodBuilder rmb;
630 if (!mono_reflection_methodbuilder_from_method_builder (&rmb, mb, error) ||
631 !mono_image_basic_method (&rmb, assembly, error))
634 mb->table_idx = *rmb.table_idx;
636 if (mb->dll) { /* It's a P/Invoke method */
638 /* map CharSet values to on-disk values */
639 int ncharset = (mb->charset ? (mb->charset - 1) * 2 : 0);
640 int extra_flags = mb->extra_flags;
641 table = &assembly->tables [MONO_TABLE_IMPLMAP];
643 alloc_table (table, table->rows);
644 values = table->values + table->rows * MONO_IMPLMAP_SIZE;
646 values [MONO_IMPLMAP_FLAGS] = (mb->native_cc << 8) | ncharset | extra_flags;
647 values [MONO_IMPLMAP_MEMBER] = (mb->table_idx << 1) | 1; /* memberforwarded: method */
649 values [MONO_IMPLMAP_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->dllentry, error);
650 return_val_if_nok (error, FALSE);
652 values [MONO_IMPLMAP_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->name, error);
653 return_val_if_nok (error, FALSE);
655 moduleref = string_heap_insert_mstring (&assembly->sheap, mb->dll, error);
656 return_val_if_nok (error, FALSE);
657 if (!(values [MONO_IMPLMAP_SCOPE] = find_index_in_table (assembly, MONO_TABLE_MODULEREF, MONO_MODULEREF_NAME, moduleref))) {
658 table = &assembly->tables [MONO_TABLE_MODULEREF];
660 alloc_table (table, table->rows);
661 table->values [table->rows * MONO_MODULEREF_SIZE + MONO_MODULEREF_NAME] = moduleref;
662 values [MONO_IMPLMAP_SCOPE] = table->rows;
666 if (mb->generic_params) {
667 table = &assembly->tables [MONO_TABLE_GENERICPARAM];
668 table->rows += mono_array_length (mb->generic_params);
669 alloc_table (table, table->rows);
670 for (i = 0; i < mono_array_length (mb->generic_params); ++i) {
671 guint32 owner = MONO_TYPEORMETHOD_METHOD | (mb->table_idx << MONO_TYPEORMETHOD_BITS);
673 mono_image_get_generic_param_info (
674 (MonoReflectionGenericParam *)mono_array_get (mb->generic_params, gpointer, i), owner, assembly);
682 mono_image_get_ctor_info (MonoDomain *domain, MonoReflectionCtorBuilder *mb, MonoDynamicImage *assembly, MonoError *error)
684 MONO_REQ_GC_UNSAFE_MODE;
686 ReflectionMethodBuilder rmb;
688 if (!mono_reflection_methodbuilder_from_ctor_builder (&rmb, mb, error))
691 if (!mono_image_basic_method (&rmb, assembly, error))
694 mb->table_idx = *rmb.table_idx;
701 mono_image_get_field_info (MonoReflectionFieldBuilder *fb, MonoDynamicImage *assembly, MonoError *error)
703 MONO_REQ_GC_UNSAFE_MODE;
707 MonoDynamicTable *table;
710 /* maybe this fixup should be done in the C# code */
711 if (fb->attrs & FIELD_ATTRIBUTE_LITERAL)
712 fb->attrs |= FIELD_ATTRIBUTE_HAS_DEFAULT;
713 table = &assembly->tables [MONO_TABLE_FIELD];
714 fb->table_idx = table->next_idx ++;
715 g_hash_table_insert (assembly->field_to_table_idx, fb->handle, GUINT_TO_POINTER (fb->table_idx));
716 values = table->values + fb->table_idx * MONO_FIELD_SIZE;
717 values [MONO_FIELD_NAME] = string_heap_insert_mstring (&assembly->sheap, fb->name, error);
718 return_if_nok (error);
719 values [MONO_FIELD_FLAGS] = fb->attrs;
720 values [MONO_FIELD_SIGNATURE] = mono_dynimage_encode_field_signature (assembly, fb, error);
721 return_if_nok (error);
723 if (fb->offset != -1) {
724 table = &assembly->tables [MONO_TABLE_FIELDLAYOUT];
726 alloc_table (table, table->rows);
727 values = table->values + table->rows * MONO_FIELD_LAYOUT_SIZE;
728 values [MONO_FIELD_LAYOUT_FIELD] = fb->table_idx;
729 values [MONO_FIELD_LAYOUT_OFFSET] = fb->offset;
731 if (fb->attrs & FIELD_ATTRIBUTE_LITERAL) {
732 MonoTypeEnum field_type = (MonoTypeEnum)0;
733 table = &assembly->tables [MONO_TABLE_CONSTANT];
735 alloc_table (table, table->rows);
736 values = table->values + table->rows * MONO_CONSTANT_SIZE;
737 values [MONO_CONSTANT_PARENT] = MONO_HASCONSTANT_FIEDDEF | (fb->table_idx << MONO_HASCONSTANT_BITS);
738 values [MONO_CONSTANT_VALUE] = mono_dynimage_encode_constant (assembly, fb->def_value, &field_type);
739 values [MONO_CONSTANT_TYPE] = field_type;
740 values [MONO_CONSTANT_PADDING] = 0;
742 if (fb->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA) {
744 table = &assembly->tables [MONO_TABLE_FIELDRVA];
746 alloc_table (table, table->rows);
747 values = table->values + table->rows * MONO_FIELD_RVA_SIZE;
748 values [MONO_FIELD_RVA_FIELD] = fb->table_idx;
750 * We store it in the code section because it's simpler for now.
753 if (mono_array_length (fb->rva_data) >= 10)
754 stream_data_align (&assembly->code);
755 rva_idx = mono_image_add_stream_data (&assembly->code, mono_array_addr (fb->rva_data, char, 0), mono_array_length (fb->rva_data));
757 rva_idx = mono_image_add_stream_zero (&assembly->code, mono_class_value_size (fb->handle->parent, NULL));
758 values [MONO_FIELD_RVA_RVA] = rva_idx + assembly->text_rva;
760 if (fb->marshal_info) {
761 table = &assembly->tables [MONO_TABLE_FIELDMARSHAL];
763 alloc_table (table, table->rows);
764 values = table->values + table->rows * MONO_FIELD_MARSHAL_SIZE;
765 values [MONO_FIELD_MARSHAL_PARENT] = (fb->table_idx << MONO_HAS_FIELD_MARSHAL_BITS) | MONO_HAS_FIELD_MARSHAL_FIELDSREF;
766 values [MONO_FIELD_MARSHAL_NATIVE_TYPE] = mono_dynimage_save_encode_marshal_blob (assembly, fb->marshal_info, error);
767 return_if_nok (error);
772 mono_image_get_property_info (MonoReflectionPropertyBuilder *pb, MonoDynamicImage *assembly, MonoError *error)
774 MONO_REQ_GC_UNSAFE_MODE;
778 MonoDynamicTable *table;
780 guint num_methods = 0;
784 * we need to set things in the following tables:
785 * PROPERTYMAP (info already filled in _get_type_info ())
786 * PROPERTY (rows already preallocated in _get_type_info ())
787 * METHOD (method info already done with the generic method code)
791 table = &assembly->tables [MONO_TABLE_PROPERTY];
792 pb->table_idx = table->next_idx ++;
793 values = table->values + pb->table_idx * MONO_PROPERTY_SIZE;
794 values [MONO_PROPERTY_NAME] = string_heap_insert_mstring (&assembly->sheap, pb->name, error);
795 return_if_nok (error);
796 values [MONO_PROPERTY_FLAGS] = pb->attrs;
797 values [MONO_PROPERTY_TYPE] = mono_dynimage_save_encode_property_signature (assembly, pb, error);
798 return_if_nok (error);
801 /* FIXME: we still don't handle 'other' methods */
802 if (pb->get_method) num_methods ++;
803 if (pb->set_method) num_methods ++;
805 table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
806 table->rows += num_methods;
807 alloc_table (table, table->rows);
809 if (pb->get_method) {
810 semaidx = table->next_idx ++;
811 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
812 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_GETTER;
813 values [MONO_METHOD_SEMA_METHOD] = pb->get_method->table_idx;
814 values [MONO_METHOD_SEMA_ASSOCIATION] = (pb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_PROPERTY;
816 if (pb->set_method) {
817 semaidx = table->next_idx ++;
818 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
819 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_SETTER;
820 values [MONO_METHOD_SEMA_METHOD] = pb->set_method->table_idx;
821 values [MONO_METHOD_SEMA_ASSOCIATION] = (pb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_PROPERTY;
823 if (pb->attrs & PROPERTY_ATTRIBUTE_HAS_DEFAULT) {
824 MonoTypeEnum field_type = (MonoTypeEnum)0;
825 table = &assembly->tables [MONO_TABLE_CONSTANT];
827 alloc_table (table, table->rows);
828 values = table->values + table->rows * MONO_CONSTANT_SIZE;
829 values [MONO_CONSTANT_PARENT] = MONO_HASCONSTANT_PROPERTY | (pb->table_idx << MONO_HASCONSTANT_BITS);
830 values [MONO_CONSTANT_VALUE] = mono_dynimage_encode_constant (assembly, pb->def_value, &field_type);
831 values [MONO_CONSTANT_TYPE] = field_type;
832 values [MONO_CONSTANT_PADDING] = 0;
837 mono_image_get_event_info (MonoReflectionEventBuilder *eb, MonoDynamicImage *assembly, MonoError *error)
839 MONO_REQ_GC_UNSAFE_MODE;
841 MonoDynamicTable *table;
843 guint num_methods = 0;
847 * we need to set things in the following tables:
848 * EVENTMAP (info already filled in _get_type_info ())
849 * EVENT (rows already preallocated in _get_type_info ())
850 * METHOD (method info already done with the generic method code)
853 table = &assembly->tables [MONO_TABLE_EVENT];
854 eb->table_idx = table->next_idx ++;
855 values = table->values + eb->table_idx * MONO_EVENT_SIZE;
856 values [MONO_EVENT_NAME] = string_heap_insert_mstring (&assembly->sheap, eb->name, error);
857 return_if_nok (error);
858 values [MONO_EVENT_FLAGS] = eb->attrs;
859 MonoType *ebtype = mono_reflection_type_get_handle (eb->type, error);
860 return_if_nok (error);
861 values [MONO_EVENT_TYPE] = mono_image_typedef_or_ref (assembly, ebtype);
864 * FIXME: we still don't handle 'other' methods
866 if (eb->add_method) num_methods ++;
867 if (eb->remove_method) num_methods ++;
868 if (eb->raise_method) num_methods ++;
870 table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
871 table->rows += num_methods;
872 alloc_table (table, table->rows);
874 if (eb->add_method) {
875 semaidx = table->next_idx ++;
876 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
877 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_ADD_ON;
878 values [MONO_METHOD_SEMA_METHOD] = eb->add_method->table_idx;
879 values [MONO_METHOD_SEMA_ASSOCIATION] = (eb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_EVENT;
881 if (eb->remove_method) {
882 semaidx = table->next_idx ++;
883 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
884 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_REMOVE_ON;
885 values [MONO_METHOD_SEMA_METHOD] = eb->remove_method->table_idx;
886 values [MONO_METHOD_SEMA_ASSOCIATION] = (eb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_EVENT;
888 if (eb->raise_method) {
889 semaidx = table->next_idx ++;
890 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
891 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_FIRE;
892 values [MONO_METHOD_SEMA_METHOD] = eb->raise_method->table_idx;
893 values [MONO_METHOD_SEMA_ASSOCIATION] = (eb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_EVENT;
898 encode_constraints (MonoReflectionGenericParam *gparam, guint32 owner, MonoDynamicImage *assembly, MonoError *error)
900 MONO_REQ_GC_UNSAFE_MODE;
904 MonoDynamicTable *table;
905 guint32 num_constraints, i;
909 table = &assembly->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
910 num_constraints = gparam->iface_constraints ?
911 mono_array_length (gparam->iface_constraints) : 0;
912 table->rows += num_constraints;
913 if (gparam->base_type)
915 alloc_table (table, table->rows);
917 if (gparam->base_type) {
918 table_idx = table->next_idx ++;
919 values = table->values + table_idx * MONO_GENPARCONSTRAINT_SIZE;
921 MonoType *gpbasetype = mono_reflection_type_get_handle (gparam->base_type, error);
922 return_if_nok (error);
923 values [MONO_GENPARCONSTRAINT_GENERICPAR] = owner;
924 values [MONO_GENPARCONSTRAINT_CONSTRAINT] = mono_image_typedef_or_ref (assembly, gpbasetype);
927 for (i = 0; i < num_constraints; i++) {
928 MonoReflectionType *constraint = (MonoReflectionType *)mono_array_get (
929 gparam->iface_constraints, gpointer, i);
931 table_idx = table->next_idx ++;
932 values = table->values + table_idx * MONO_GENPARCONSTRAINT_SIZE;
934 MonoType *constraint_type = mono_reflection_type_get_handle (constraint, error);
935 return_if_nok (error);
937 values [MONO_GENPARCONSTRAINT_GENERICPAR] = owner;
938 values [MONO_GENPARCONSTRAINT_CONSTRAINT] = mono_image_typedef_or_ref (assembly, constraint_type);
943 mono_image_get_generic_param_info (MonoReflectionGenericParam *gparam, guint32 owner, MonoDynamicImage *assembly)
945 MONO_REQ_GC_UNSAFE_MODE;
947 GenericParamTableEntry *entry;
950 * The GenericParam table must be sorted according to the `owner' field.
951 * We need to do this sorting prior to writing the GenericParamConstraint
952 * table, since we have to use the final GenericParam table indices there
953 * and they must also be sorted.
956 entry = g_new0 (GenericParamTableEntry, 1);
957 entry->owner = owner;
958 /* FIXME: track where gen_params should be freed and remove the GC root as well */
959 MONO_GC_REGISTER_ROOT_IF_MOVING (entry->gparam, MONO_ROOT_SOURCE_REFLECTION, "reflection generic parameter");
960 entry->gparam = gparam;
962 g_ptr_array_add (assembly->gen_params, entry);
966 write_generic_param_entry (MonoDynamicImage *assembly, GenericParamTableEntry *entry, MonoError *error)
968 MONO_REQ_GC_UNSAFE_MODE;
970 MonoDynamicTable *table;
971 MonoGenericParam *param;
977 table = &assembly->tables [MONO_TABLE_GENERICPARAM];
978 table_idx = table->next_idx ++;
979 values = table->values + table_idx * MONO_GENERICPARAM_SIZE;
981 MonoType *gparam_type = mono_reflection_type_get_handle ((MonoReflectionType*)entry->gparam, error);
982 return_val_if_nok (error, FALSE);
984 param = gparam_type->data.generic_param;
986 values [MONO_GENERICPARAM_OWNER] = entry->owner;
987 values [MONO_GENERICPARAM_FLAGS] = entry->gparam->attrs;
988 values [MONO_GENERICPARAM_NUMBER] = mono_generic_param_num (param);
989 values [MONO_GENERICPARAM_NAME] = string_heap_insert (&assembly->sheap, mono_generic_param_info (param)->name);
991 if (!mono_image_add_cattrs (assembly, table_idx, MONO_CUSTOM_ATTR_GENERICPAR, entry->gparam->cattrs, error))
994 encode_constraints (entry->gparam, table_idx, assembly, error);
995 return_val_if_nok (error, FALSE);
1001 collect_types (MonoPtrArray *types, MonoReflectionTypeBuilder *type)
1005 mono_ptr_array_append (*types, type);
1007 if (!type->subtypes)
1010 for (i = 0; i < mono_array_length (type->subtypes); ++i) {
1011 MonoReflectionTypeBuilder *subtype = mono_array_get (type->subtypes, MonoReflectionTypeBuilder*, i);
1012 collect_types (types, subtype);
1017 compare_types_by_table_idx (MonoReflectionTypeBuilder **type1, MonoReflectionTypeBuilder **type2)
1019 if ((*type1)->table_idx < (*type2)->table_idx)
1022 if ((*type1)->table_idx > (*type2)->table_idx)
1029 params_add_cattrs (MonoDynamicImage *assembly, MonoArray *pinfo, MonoError *error) {
1035 for (i = 0; i < mono_array_length (pinfo); ++i) {
1036 MonoReflectionParamBuilder *pb;
1037 pb = mono_array_get (pinfo, MonoReflectionParamBuilder *, i);
1040 if (!mono_image_add_cattrs (assembly, pb->table_idx, MONO_CUSTOM_ATTR_PARAMDEF, pb->cattrs, error))
1048 type_add_cattrs (MonoDynamicImage *assembly, MonoReflectionTypeBuilder *tb, MonoError *error) {
1053 if (!mono_image_add_cattrs (assembly, tb->table_idx, MONO_CUSTOM_ATTR_TYPEDEF, tb->cattrs, error))
1056 for (i = 0; i < tb->num_fields; ++i) {
1057 MonoReflectionFieldBuilder* fb;
1058 fb = mono_array_get (tb->fields, MonoReflectionFieldBuilder*, i);
1059 if (!mono_image_add_cattrs (assembly, fb->table_idx, MONO_CUSTOM_ATTR_FIELDDEF, fb->cattrs, error))
1064 for (i = 0; i < mono_array_length (tb->events); ++i) {
1065 MonoReflectionEventBuilder* eb;
1066 eb = mono_array_get (tb->events, MonoReflectionEventBuilder*, i);
1067 if (!mono_image_add_cattrs (assembly, eb->table_idx, MONO_CUSTOM_ATTR_EVENT, eb->cattrs, error))
1071 if (tb->properties) {
1072 for (i = 0; i < mono_array_length (tb->properties); ++i) {
1073 MonoReflectionPropertyBuilder* pb;
1074 pb = mono_array_get (tb->properties, MonoReflectionPropertyBuilder*, i);
1075 if (!mono_image_add_cattrs (assembly, pb->table_idx, MONO_CUSTOM_ATTR_PROPERTY, pb->cattrs, error))
1080 for (i = 0; i < mono_array_length (tb->ctors); ++i) {
1081 MonoReflectionCtorBuilder* cb;
1082 cb = mono_array_get (tb->ctors, MonoReflectionCtorBuilder*, i);
1083 if (!mono_image_add_cattrs (assembly, cb->table_idx, MONO_CUSTOM_ATTR_METHODDEF, cb->cattrs, error) ||
1084 !params_add_cattrs (assembly, cb->pinfo, error))
1090 for (i = 0; i < tb->num_methods; ++i) {
1091 MonoReflectionMethodBuilder* mb;
1092 mb = mono_array_get (tb->methods, MonoReflectionMethodBuilder*, i);
1093 if (!mono_image_add_cattrs (assembly, mb->table_idx, MONO_CUSTOM_ATTR_METHODDEF, mb->cattrs, error) ||
1094 !params_add_cattrs (assembly, mb->pinfo, error))
1100 for (i = 0; i < mono_array_length (tb->subtypes); ++i) {
1101 if (!type_add_cattrs (assembly, mono_array_get (tb->subtypes, MonoReflectionTypeBuilder*, i), error))
1110 module_add_cattrs (MonoDynamicImage *assembly, MonoReflectionModuleBuilder *moduleb, MonoError *error)
1116 if (!mono_image_add_cattrs (assembly, moduleb->table_idx, MONO_CUSTOM_ATTR_MODULE, moduleb->cattrs, error))
1119 if (moduleb->global_methods) {
1120 for (i = 0; i < mono_array_length (moduleb->global_methods); ++i) {
1121 MonoReflectionMethodBuilder* mb = mono_array_get (moduleb->global_methods, MonoReflectionMethodBuilder*, i);
1122 if (!mono_image_add_cattrs (assembly, mb->table_idx, MONO_CUSTOM_ATTR_METHODDEF, mb->cattrs, error) ||
1123 !params_add_cattrs (assembly, mb->pinfo, error))
1128 if (moduleb->global_fields) {
1129 for (i = 0; i < mono_array_length (moduleb->global_fields); ++i) {
1130 MonoReflectionFieldBuilder *fb = mono_array_get (moduleb->global_fields, MonoReflectionFieldBuilder*, i);
1131 if (!mono_image_add_cattrs (assembly, fb->table_idx, MONO_CUSTOM_ATTR_FIELDDEF, fb->cattrs, error))
1136 if (moduleb->types) {
1137 for (i = 0; i < moduleb->num_types; ++i) {
1138 if (!type_add_cattrs (assembly, mono_array_get (moduleb->types, MonoReflectionTypeBuilder*, i), error))
1147 mono_image_fill_file_table (MonoDomain *domain, MonoReflectionModule *module, MonoDynamicImage *assembly, MonoError *error)
1149 MonoDynamicTable *table;
1153 char *b = blob_size;
1158 table = &assembly->tables [MONO_TABLE_FILE];
1160 alloc_table (table, table->rows);
1161 values = table->values + table->next_idx * MONO_FILE_SIZE;
1162 values [MONO_FILE_FLAGS] = FILE_CONTAINS_METADATA;
1163 values [MONO_FILE_NAME] = string_heap_insert (&assembly->sheap, module->image->module_name);
1164 if (image_is_dynamic (module->image)) {
1165 /* This depends on the fact that the main module is emitted last */
1166 dir = mono_string_to_utf8_checked (((MonoReflectionModuleBuilder*)module)->assemblyb->dir, error);
1167 return_val_if_nok (error, FALSE);
1168 path = g_strdup_printf ("%s%c%s", dir, G_DIR_SEPARATOR, module->image->module_name);
1171 path = g_strdup (module->image->name);
1173 mono_sha1_get_digest_from_file (path, hash);
1176 mono_metadata_encode_value (20, b, &b);
1177 values [MONO_FILE_HASH_VALUE] = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
1178 mono_image_add_stream_data (&assembly->blob, (char*)hash, 20);
1184 mono_image_fill_module_table (MonoDomain *domain, MonoReflectionModuleBuilder *mb, MonoDynamicImage *assembly, MonoError *error)
1186 MonoDynamicTable *table;
1191 table = &assembly->tables [MONO_TABLE_MODULE];
1192 mb->table_idx = table->next_idx ++;
1193 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->module.name, error);
1194 return_if_nok (error);
1195 i = mono_image_add_stream_data (&assembly->guid, mono_array_addr (mb->guid, char, 0), 16);
1198 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_GENERATION] = 0;
1199 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_MVID] = i;
1200 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_ENC] = 0;
1201 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_ENCBASE] = 0;
1205 mono_image_fill_export_table_from_class (MonoDomain *domain, MonoClass *klass,
1206 guint32 module_index, guint32 parent_index, MonoDynamicImage *assembly)
1208 MonoDynamicTable *table;
1212 visib = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_VISIBILITY_MASK;
1213 if (! ((visib & TYPE_ATTRIBUTE_PUBLIC) || (visib & TYPE_ATTRIBUTE_NESTED_PUBLIC)))
1216 table = &assembly->tables [MONO_TABLE_EXPORTEDTYPE];
1218 alloc_table (table, table->rows);
1219 values = table->values + table->next_idx * MONO_EXP_TYPE_SIZE;
1221 values [MONO_EXP_TYPE_FLAGS] = mono_class_get_flags (klass);
1222 values [MONO_EXP_TYPE_TYPEDEF] = klass->type_token;
1223 if (klass->nested_in)
1224 values [MONO_EXP_TYPE_IMPLEMENTATION] = (parent_index << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_EXP_TYPE;
1226 values [MONO_EXP_TYPE_IMPLEMENTATION] = (module_index << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_FILE;
1227 values [MONO_EXP_TYPE_NAME] = string_heap_insert (&assembly->sheap, klass->name);
1228 values [MONO_EXP_TYPE_NAMESPACE] = string_heap_insert (&assembly->sheap, klass->name_space);
1230 res = table->next_idx;
1234 /* Emit nested types */
1235 GList *nested_classes = mono_class_get_nested_classes_property (klass);
1237 for (tmp = nested_classes; tmp; tmp = tmp->next)
1238 mono_image_fill_export_table_from_class (domain, (MonoClass *)tmp->data, module_index, table->next_idx - 1, assembly);
1244 mono_image_fill_export_table (MonoDomain *domain, MonoReflectionTypeBuilder *tb,
1245 guint32 module_index, guint32 parent_index, MonoDynamicImage *assembly,
1253 MonoType *t = mono_reflection_type_get_handle ((MonoReflectionType*)tb, error);
1254 return_if_nok (error);
1256 klass = mono_class_from_mono_type (t);
1258 klass->type_token = mono_metadata_make_token (MONO_TABLE_TYPEDEF, tb->table_idx);
1260 idx = mono_image_fill_export_table_from_class (domain, klass, module_index,
1261 parent_index, assembly);
1265 * We need to do this ourselves since klass->nested_classes is not set up.
1268 for (i = 0; i < mono_array_length (tb->subtypes); ++i) {
1269 mono_image_fill_export_table (domain, mono_array_get (tb->subtypes, MonoReflectionTypeBuilder*, i), module_index, idx, assembly, error);
1270 return_if_nok (error);
1276 mono_image_fill_export_table_from_module (MonoDomain *domain, MonoReflectionModule *module,
1277 guint32 module_index, MonoDynamicImage *assembly)
1279 MonoImage *image = module->image;
1283 t = &image->tables [MONO_TABLE_TYPEDEF];
1285 for (i = 0; i < t->rows; ++i) {
1287 MonoClass *klass = mono_class_get_checked (image, mono_metadata_make_token (MONO_TABLE_TYPEDEF, i + 1), &error);
1288 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
1290 if (mono_class_is_public (klass))
1291 mono_image_fill_export_table_from_class (domain, klass, module_index, 0, assembly);
1296 add_exported_type (MonoReflectionAssemblyBuilder *assemblyb, MonoDynamicImage *assembly, MonoClass *klass, guint32 parent_index)
1298 MonoDynamicTable *table;
1300 guint32 scope, scope_idx, impl, current_idx;
1301 gboolean forwarder = TRUE;
1302 gpointer iter = NULL;
1305 if (klass->nested_in) {
1306 impl = (parent_index << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_EXP_TYPE;
1309 scope = mono_reflection_resolution_scope_from_image (assembly, klass->image);
1310 g_assert ((scope & MONO_RESOLUTION_SCOPE_MASK) == MONO_RESOLUTION_SCOPE_ASSEMBLYREF);
1311 scope_idx = scope >> MONO_RESOLUTION_SCOPE_BITS;
1312 impl = (scope_idx << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_ASSEMBLYREF;
1315 table = &assembly->tables [MONO_TABLE_EXPORTEDTYPE];
1318 alloc_table (table, table->rows);
1319 current_idx = table->next_idx;
1320 values = table->values + current_idx * MONO_EXP_TYPE_SIZE;
1322 values [MONO_EXP_TYPE_FLAGS] = forwarder ? TYPE_ATTRIBUTE_FORWARDER : 0;
1323 values [MONO_EXP_TYPE_TYPEDEF] = 0;
1324 values [MONO_EXP_TYPE_IMPLEMENTATION] = impl;
1325 values [MONO_EXP_TYPE_NAME] = string_heap_insert (&assembly->sheap, klass->name);
1326 values [MONO_EXP_TYPE_NAMESPACE] = string_heap_insert (&assembly->sheap, klass->name_space);
1330 while ((nested = mono_class_get_nested_types (klass, &iter)))
1331 add_exported_type (assemblyb, assembly, nested, current_idx);
1335 mono_image_fill_export_table_from_type_forwarders (MonoReflectionAssemblyBuilder *assemblyb, MonoDynamicImage *assembly)
1341 if (!assemblyb->type_forwarders)
1344 for (i = 0; i < mono_array_length (assemblyb->type_forwarders); ++i) {
1345 MonoReflectionType *t = mono_array_get (assemblyb->type_forwarders, MonoReflectionType *, i);
1350 type = mono_reflection_type_get_handle (t, &error);
1351 mono_error_assert_ok (&error);
1354 klass = mono_class_from_mono_type (type);
1356 add_exported_type (assemblyb, assembly, klass, 0);
1360 #define align_pointer(base,p)\
1362 guint32 __diff = (unsigned char*)(p)-(unsigned char*)(base);\
1364 (p) += 4 - (__diff & 3);\
1368 compare_constants (const void *a, const void *b)
1370 const guint32 *a_values = (const guint32 *)a;
1371 const guint32 *b_values = (const guint32 *)b;
1372 return a_values [MONO_CONSTANT_PARENT] - b_values [MONO_CONSTANT_PARENT];
1376 compare_semantics (const void *a, const void *b)
1378 const guint32 *a_values = (const guint32 *)a;
1379 const guint32 *b_values = (const guint32 *)b;
1380 int assoc = a_values [MONO_METHOD_SEMA_ASSOCIATION] - b_values [MONO_METHOD_SEMA_ASSOCIATION];
1383 return a_values [MONO_METHOD_SEMA_SEMANTICS] - b_values [MONO_METHOD_SEMA_SEMANTICS];
1387 compare_custom_attrs (const void *a, const void *b)
1389 const guint32 *a_values = (const guint32 *)a;
1390 const guint32 *b_values = (const guint32 *)b;
1392 return a_values [MONO_CUSTOM_ATTR_PARENT] - b_values [MONO_CUSTOM_ATTR_PARENT];
1396 compare_field_marshal (const void *a, const void *b)
1398 const guint32 *a_values = (const guint32 *)a;
1399 const guint32 *b_values = (const guint32 *)b;
1401 return a_values [MONO_FIELD_MARSHAL_PARENT] - b_values [MONO_FIELD_MARSHAL_PARENT];
1405 compare_nested (const void *a, const void *b)
1407 const guint32 *a_values = (const guint32 *)a;
1408 const guint32 *b_values = (const guint32 *)b;
1410 return a_values [MONO_NESTED_CLASS_NESTED] - b_values [MONO_NESTED_CLASS_NESTED];
1414 compare_genericparam (const void *a, const void *b)
1417 const GenericParamTableEntry **a_entry = (const GenericParamTableEntry **) a;
1418 const GenericParamTableEntry **b_entry = (const GenericParamTableEntry **) b;
1420 if ((*b_entry)->owner == (*a_entry)->owner) {
1421 MonoType *a_type = mono_reflection_type_get_handle ((MonoReflectionType*)(*a_entry)->gparam, &error);
1422 mono_error_assert_ok (&error);
1423 MonoType *b_type = mono_reflection_type_get_handle ((MonoReflectionType*)(*b_entry)->gparam, &error);
1424 mono_error_assert_ok (&error);
1426 mono_type_get_generic_param_num (a_type) -
1427 mono_type_get_generic_param_num (b_type);
1429 return (*a_entry)->owner - (*b_entry)->owner;
1433 compare_declsecurity_attrs (const void *a, const void *b)
1435 const guint32 *a_values = (const guint32 *)a;
1436 const guint32 *b_values = (const guint32 *)b;
1438 return a_values [MONO_DECL_SECURITY_PARENT] - b_values [MONO_DECL_SECURITY_PARENT];
1442 compare_interface_impl (const void *a, const void *b)
1444 const guint32 *a_values = (const guint32 *)a;
1445 const guint32 *b_values = (const guint32 *)b;
1447 int klass = a_values [MONO_INTERFACEIMPL_CLASS] - b_values [MONO_INTERFACEIMPL_CLASS];
1451 return a_values [MONO_INTERFACEIMPL_INTERFACE] - b_values [MONO_INTERFACEIMPL_INTERFACE];
1456 MonoDynamicStream *stream;
1460 * build_compressed_metadata() fills in the blob of data that represents the
1461 * raw metadata as it will be saved in the PE file. The five streams are output
1462 * and the metadata tables are comnpressed from the guint32 array representation,
1463 * to the compressed on-disk format.
1466 build_compressed_metadata (MonoDynamicImage *assembly, MonoError *error)
1468 MonoDynamicTable *table;
1470 guint64 valid_mask = 0;
1471 guint64 sorted_mask;
1472 guint32 heapt_size = 0;
1473 guint32 meta_size = 256; /* allow for header and other stuff */
1474 guint32 table_offset;
1475 guint32 ntables = 0;
1481 struct StreamDesc stream_desc [5];
1485 qsort (assembly->gen_params->pdata, assembly->gen_params->len, sizeof (gpointer), compare_genericparam);
1486 for (i = 0; i < assembly->gen_params->len; i++) {
1487 GenericParamTableEntry *entry = (GenericParamTableEntry *)g_ptr_array_index (assembly->gen_params, i);
1488 if (!write_generic_param_entry (assembly, entry, error))
1492 stream_desc [0].name = "#~";
1493 stream_desc [0].stream = &assembly->tstream;
1494 stream_desc [1].name = "#Strings";
1495 stream_desc [1].stream = &assembly->sheap;
1496 stream_desc [2].name = "#US";
1497 stream_desc [2].stream = &assembly->us;
1498 stream_desc [3].name = "#Blob";
1499 stream_desc [3].stream = &assembly->blob;
1500 stream_desc [4].name = "#GUID";
1501 stream_desc [4].stream = &assembly->guid;
1503 /* tables that are sorted */
1504 sorted_mask = ((guint64)1 << MONO_TABLE_CONSTANT) | ((guint64)1 << MONO_TABLE_FIELDMARSHAL)
1505 | ((guint64)1 << MONO_TABLE_METHODSEMANTICS) | ((guint64)1 << MONO_TABLE_CLASSLAYOUT)
1506 | ((guint64)1 << MONO_TABLE_FIELDLAYOUT) | ((guint64)1 << MONO_TABLE_FIELDRVA)
1507 | ((guint64)1 << MONO_TABLE_IMPLMAP) | ((guint64)1 << MONO_TABLE_NESTEDCLASS)
1508 | ((guint64)1 << MONO_TABLE_METHODIMPL) | ((guint64)1 << MONO_TABLE_CUSTOMATTRIBUTE)
1509 | ((guint64)1 << MONO_TABLE_DECLSECURITY) | ((guint64)1 << MONO_TABLE_GENERICPARAM)
1510 | ((guint64)1 << MONO_TABLE_INTERFACEIMPL);
1512 /* Compute table sizes */
1513 /* the MonoImage has already been created in mono_reflection_dynimage_basic_init() */
1514 meta = &assembly->image;
1516 /* sizes should be multiple of 4 */
1517 mono_dynstream_data_align (&assembly->blob);
1518 mono_dynstream_data_align (&assembly->guid);
1519 mono_dynstream_data_align (&assembly->sheap);
1520 mono_dynstream_data_align (&assembly->us);
1522 /* Setup the info used by compute_sizes () */
1523 meta->idx_blob_wide = assembly->blob.index >= 65536 ? 1 : 0;
1524 meta->idx_guid_wide = assembly->guid.index >= 65536 ? 1 : 0;
1525 meta->idx_string_wide = assembly->sheap.index >= 65536 ? 1 : 0;
1527 meta_size += assembly->blob.index;
1528 meta_size += assembly->guid.index;
1529 meta_size += assembly->sheap.index;
1530 meta_size += assembly->us.index;
1532 for (i=0; i < MONO_TABLE_NUM; ++i)
1533 meta->tables [i].rows = assembly->tables [i].rows;
1535 for (i = 0; i < MONO_TABLE_NUM; i++){
1536 if (meta->tables [i].rows == 0)
1538 valid_mask |= (guint64)1 << i;
1540 meta->tables [i].row_size = mono_metadata_compute_size (
1541 meta, i, &meta->tables [i].size_bitfield);
1542 heapt_size += meta->tables [i].row_size * meta->tables [i].rows;
1544 heapt_size += 24; /* #~ header size */
1545 heapt_size += ntables * 4;
1546 /* make multiple of 4 */
1549 meta_size += heapt_size;
1550 meta->raw_metadata = (char *)g_malloc0 (meta_size);
1551 p = (unsigned char*)meta->raw_metadata;
1552 /* the metadata signature */
1553 *p++ = 'B'; *p++ = 'S'; *p++ = 'J'; *p++ = 'B';
1554 /* version numbers and 4 bytes reserved */
1555 int16val = (guint16*)p;
1556 *int16val++ = GUINT16_TO_LE (meta->md_version_major);
1557 *int16val = GUINT16_TO_LE (meta->md_version_minor);
1559 /* version string */
1560 int32val = (guint32*)p;
1561 *int32val = GUINT32_TO_LE ((strlen (meta->version) + 3) & (~3)); /* needs to be multiple of 4 */
1563 memcpy (p, meta->version, strlen (meta->version));
1564 p += GUINT32_FROM_LE (*int32val);
1565 align_pointer (meta->raw_metadata, p);
1566 int16val = (guint16*)p;
1567 *int16val++ = GUINT16_TO_LE (0); /* flags must be 0 */
1568 *int16val = GUINT16_TO_LE (5); /* number of streams */
1572 * write the stream info.
1574 table_offset = (p - (unsigned char*)meta->raw_metadata) + 5 * 8 + 40; /* room needed for stream headers */
1575 table_offset += 3; table_offset &= ~3;
1577 assembly->tstream.index = heapt_size;
1578 for (i = 0; i < 5; ++i) {
1579 int32val = (guint32*)p;
1580 stream_desc [i].stream->offset = table_offset;
1581 *int32val++ = GUINT32_TO_LE (table_offset);
1582 *int32val = GUINT32_TO_LE (stream_desc [i].stream->index);
1583 table_offset += GUINT32_FROM_LE (*int32val);
1584 table_offset += 3; table_offset &= ~3;
1586 strcpy ((char*)p, stream_desc [i].name);
1587 p += strlen (stream_desc [i].name) + 1;
1588 align_pointer (meta->raw_metadata, p);
1591 * now copy the data, the table stream header and contents goes first.
1593 g_assert ((p - (unsigned char*)meta->raw_metadata) < assembly->tstream.offset);
1594 p = (guchar*)meta->raw_metadata + assembly->tstream.offset;
1595 int32val = (guint32*)p;
1596 *int32val = GUINT32_TO_LE (0); /* reserved */
1599 *p++ = 2; /* version */
1602 if (meta->idx_string_wide)
1604 if (meta->idx_guid_wide)
1606 if (meta->idx_blob_wide)
1609 *p++ = 1; /* reserved */
1610 int64val = (guint64*)p;
1611 *int64val++ = GUINT64_TO_LE (valid_mask);
1612 *int64val++ = GUINT64_TO_LE (valid_mask & sorted_mask); /* bitvector of sorted tables */
1614 int32val = (guint32*)p;
1615 for (i = 0; i < MONO_TABLE_NUM; i++){
1616 if (meta->tables [i].rows == 0)
1618 *int32val++ = GUINT32_TO_LE (meta->tables [i].rows);
1620 p = (unsigned char*)int32val;
1622 /* sort the tables that still need sorting */
1623 table = &assembly->tables [MONO_TABLE_CONSTANT];
1625 qsort (table->values + MONO_CONSTANT_SIZE, table->rows, sizeof (guint32) * MONO_CONSTANT_SIZE, compare_constants);
1626 table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
1628 qsort (table->values + MONO_METHOD_SEMA_SIZE, table->rows, sizeof (guint32) * MONO_METHOD_SEMA_SIZE, compare_semantics);
1629 table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1631 qsort (table->values + MONO_CUSTOM_ATTR_SIZE, table->rows, sizeof (guint32) * MONO_CUSTOM_ATTR_SIZE, compare_custom_attrs);
1632 table = &assembly->tables [MONO_TABLE_FIELDMARSHAL];
1634 qsort (table->values + MONO_FIELD_MARSHAL_SIZE, table->rows, sizeof (guint32) * MONO_FIELD_MARSHAL_SIZE, compare_field_marshal);
1635 table = &assembly->tables [MONO_TABLE_NESTEDCLASS];
1637 qsort (table->values + MONO_NESTED_CLASS_SIZE, table->rows, sizeof (guint32) * MONO_NESTED_CLASS_SIZE, compare_nested);
1638 /* Section 21.11 DeclSecurity in Partition II doesn't specify this to be sorted by MS implementation requires it */
1639 table = &assembly->tables [MONO_TABLE_DECLSECURITY];
1641 qsort (table->values + MONO_DECL_SECURITY_SIZE, table->rows, sizeof (guint32) * MONO_DECL_SECURITY_SIZE, compare_declsecurity_attrs);
1642 table = &assembly->tables [MONO_TABLE_INTERFACEIMPL];
1644 qsort (table->values + MONO_INTERFACEIMPL_SIZE, table->rows, sizeof (guint32) * MONO_INTERFACEIMPL_SIZE, compare_interface_impl);
1646 /* compress the tables */
1647 for (i = 0; i < MONO_TABLE_NUM; i++){
1650 guint32 bitfield = meta->tables [i].size_bitfield;
1651 if (!meta->tables [i].rows)
1653 if (assembly->tables [i].columns != mono_metadata_table_count (bitfield))
1654 g_error ("col count mismatch in %d: %d %d", i, assembly->tables [i].columns, mono_metadata_table_count (bitfield));
1655 meta->tables [i].base = (char*)p;
1656 for (row = 1; row <= meta->tables [i].rows; ++row) {
1657 values = assembly->tables [i].values + row * assembly->tables [i].columns;
1658 for (col = 0; col < assembly->tables [i].columns; ++col) {
1659 switch (mono_metadata_table_size (bitfield, col)) {
1661 *p++ = values [col];
1664 *p++ = values [col] & 0xff;
1665 *p++ = (values [col] >> 8) & 0xff;
1668 *p++ = values [col] & 0xff;
1669 *p++ = (values [col] >> 8) & 0xff;
1670 *p++ = (values [col] >> 16) & 0xff;
1671 *p++ = (values [col] >> 24) & 0xff;
1674 g_assert_not_reached ();
1678 g_assert ((p - (const unsigned char*)meta->tables [i].base) == (meta->tables [i].rows * meta->tables [i].row_size));
1681 g_assert (assembly->guid.offset + assembly->guid.index < meta_size);
1682 memcpy (meta->raw_metadata + assembly->sheap.offset, assembly->sheap.data, assembly->sheap.index);
1683 memcpy (meta->raw_metadata + assembly->us.offset, assembly->us.data, assembly->us.index);
1684 memcpy (meta->raw_metadata + assembly->blob.offset, assembly->blob.data, assembly->blob.index);
1685 memcpy (meta->raw_metadata + assembly->guid.offset, assembly->guid.data, assembly->guid.index);
1687 assembly->meta_size = assembly->guid.offset + assembly->guid.index;
1693 * Some tables in metadata need to be sorted according to some criteria, but
1694 * when methods and fields are first created with reflection, they may be assigned a token
1695 * that doesn't correspond to the final token they will get assigned after the sorting.
1696 * ILGenerator.cs keeps a fixup table that maps the position of tokens in the IL code stream
1697 * with the reflection objects that represent them. Once all the tables are set up, the
1698 * reflection objects will contains the correct table index. fixup_method() will fixup the
1699 * tokens for the method with ILGenerator @ilgen.
1702 fixup_method (MonoReflectionILGen *ilgen, gpointer value, MonoDynamicImage *assembly)
1704 guint32 code_idx = GPOINTER_TO_UINT (value);
1705 MonoReflectionILTokenInfo *iltoken;
1706 MonoReflectionTypeBuilder *tb;
1707 MonoReflectionArrayMethod *am;
1709 unsigned char *target;
1711 for (i = 0; i < ilgen->num_token_fixups; ++i) {
1712 iltoken = (MonoReflectionILTokenInfo *)mono_array_addr_with_size (ilgen->token_fixups, sizeof (MonoReflectionILTokenInfo), i);
1713 target = (guchar*)assembly->code.data + code_idx + iltoken->code_pos;
1714 switch (target [3]) {
1715 case MONO_TABLE_FIELD:
1716 if (!strcmp (iltoken->member->vtable->klass->name, "FieldBuilder")) {
1717 g_assert_not_reached ();
1718 } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoField")) {
1719 MonoClassField *f = ((MonoReflectionField*)iltoken->member)->field;
1720 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->field_to_table_idx, f));
1722 g_assert_not_reached ();
1725 case MONO_TABLE_METHOD:
1726 if (!strcmp (iltoken->member->vtable->klass->name, "MethodBuilder")) {
1727 g_assert_not_reached ();
1728 } else if (!strcmp (iltoken->member->vtable->klass->name, "ConstructorBuilder")) {
1729 g_assert_not_reached ();
1730 } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoMethod") ||
1731 !strcmp (iltoken->member->vtable->klass->name, "MonoCMethod")) {
1732 MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
1733 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, m));
1735 g_assert_not_reached ();
1738 case MONO_TABLE_TYPEDEF:
1739 if (!strcmp (iltoken->member->vtable->klass->name, "TypeBuilder")) {
1740 g_assert_not_reached ();
1741 } else if (!strcmp (iltoken->member->vtable->klass->name, "RuntimeType")) {
1742 MonoClass *k = mono_class_from_mono_type (((MonoReflectionType*)iltoken->member)->type);
1743 MonoObject *obj = mono_class_get_ref_info_raw (k); /* FIXME use handles */
1745 g_assert (!strcmp (mono_object_class (obj)->name, "TypeBuilder"));
1746 tb = (MonoReflectionTypeBuilder*)obj;
1747 idx = tb->table_idx;
1749 g_assert_not_reached ();
1752 case MONO_TABLE_MEMBERREF:
1753 if (!strcmp (iltoken->member->vtable->klass->name, "MonoArrayMethod")) {
1754 am = (MonoReflectionArrayMethod*)iltoken->member;
1755 idx = am->table_idx;
1756 } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoMethod") ||
1757 !strcmp (iltoken->member->vtable->klass->name, "MonoCMethod")) {
1758 MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
1759 g_assert (mono_class_is_ginst (m->klass) || mono_class_is_gtd (m->klass));
1761 } else if (!strcmp (iltoken->member->vtable->klass->name, "FieldBuilder")) {
1762 g_assert_not_reached ();
1764 } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoField")) {
1766 } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodBuilder") ||
1767 !strcmp (iltoken->member->vtable->klass->name, "ConstructorBuilder")) {
1768 g_assert_not_reached ();
1770 } else if (!strcmp (iltoken->member->vtable->klass->name, "FieldOnTypeBuilderInst")) {
1771 g_assert_not_reached ();
1773 } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodOnTypeBuilderInst")) {
1774 g_assert_not_reached ();
1776 } else if (!strcmp (iltoken->member->vtable->klass->name, "ConstructorOnTypeBuilderInst")) {
1777 g_assert_not_reached ();
1780 g_assert_not_reached ();
1783 case MONO_TABLE_METHODSPEC:
1784 if (!strcmp (iltoken->member->vtable->klass->name, "MonoMethod")) {
1785 MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
1786 g_assert (mono_method_signature (m)->generic_param_count);
1788 } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodBuilder")) {
1789 g_assert_not_reached ();
1791 } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodOnTypeBuilderInst")) {
1792 g_assert_not_reached ();
1795 g_assert_not_reached ();
1798 case MONO_TABLE_TYPESPEC:
1799 if (!strcmp (iltoken->member->vtable->klass->name, "RuntimeType")) {
1802 g_assert_not_reached ();
1806 g_error ("got unexpected table 0x%02x in fixup", target [3]);
1808 target [0] = idx & 0xff;
1809 target [1] = (idx >> 8) & 0xff;
1810 target [2] = (idx >> 16) & 0xff;
1817 * The CUSTOM_ATTRIBUTE table might contain METHODDEF tokens whose final
1818 * value is not known when the table is emitted.
1821 fixup_cattrs (MonoDynamicImage *assembly)
1823 MonoDynamicTable *table;
1825 guint32 type, i, idx, token;
1828 table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1830 for (i = 0; i < table->rows; ++i) {
1831 values = table->values + ((i + 1) * MONO_CUSTOM_ATTR_SIZE);
1833 type = values [MONO_CUSTOM_ATTR_TYPE];
1834 if ((type & MONO_CUSTOM_ATTR_TYPE_MASK) == MONO_CUSTOM_ATTR_TYPE_METHODDEF) {
1835 idx = type >> MONO_CUSTOM_ATTR_TYPE_BITS;
1836 token = mono_metadata_make_token (MONO_TABLE_METHOD, idx);
1837 ctor = (MonoObject *)mono_g_hash_table_lookup (assembly->remapped_tokens, GUINT_TO_POINTER (token));
1840 if (!strcmp (ctor->vtable->klass->name, "MonoCMethod")) {
1841 MonoMethod *m = ((MonoReflectionMethod*)ctor)->method;
1842 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, m));
1843 values [MONO_CUSTOM_ATTR_TYPE] = (idx << MONO_CUSTOM_ATTR_TYPE_BITS) | MONO_CUSTOM_ATTR_TYPE_METHODDEF;
1844 } else if (!strcmp (ctor->vtable->klass->name, "ConstructorBuilder")) {
1845 MonoMethod *m = ((MonoReflectionCtorBuilder*)ctor)->mhandle;
1846 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, m));
1847 values [MONO_CUSTOM_ATTR_TYPE] = (idx << MONO_CUSTOM_ATTR_TYPE_BITS) | MONO_CUSTOM_ATTR_TYPE_METHODDEF;
1854 assembly_add_resource_manifest (MonoReflectionModuleBuilder *mb, MonoDynamicImage *assembly, MonoReflectionResource *rsrc, guint32 implementation, MonoError *error)
1856 MonoDynamicTable *table;
1861 table = &assembly->tables [MONO_TABLE_MANIFESTRESOURCE];
1863 alloc_table (table, table->rows);
1864 values = table->values + table->next_idx * MONO_MANIFEST_SIZE;
1865 values [MONO_MANIFEST_OFFSET] = rsrc->offset;
1866 values [MONO_MANIFEST_FLAGS] = rsrc->attrs;
1867 values [MONO_MANIFEST_NAME] = string_heap_insert_mstring (&assembly->sheap, rsrc->name, error);
1868 return_val_if_nok (error, FALSE);
1869 values [MONO_MANIFEST_IMPLEMENTATION] = implementation;
1875 assembly_add_resource (MonoReflectionModuleBuilder *mb, MonoDynamicImage *assembly, MonoReflectionResource *rsrc, MonoError *error)
1877 MonoDynamicTable *table;
1881 char *b = blob_size;
1883 guint32 idx, offset;
1887 if (rsrc->filename) {
1888 name = mono_string_to_utf8_checked (rsrc->filename, error);
1889 return_val_if_nok (error, FALSE);
1890 sname = g_path_get_basename (name);
1892 table = &assembly->tables [MONO_TABLE_FILE];
1894 alloc_table (table, table->rows);
1895 values = table->values + table->next_idx * MONO_FILE_SIZE;
1896 values [MONO_FILE_FLAGS] = FILE_CONTAINS_NO_METADATA;
1897 values [MONO_FILE_NAME] = string_heap_insert (&assembly->sheap, sname);
1900 mono_sha1_get_digest_from_file (name, hash);
1901 mono_metadata_encode_value (20, b, &b);
1902 values [MONO_FILE_HASH_VALUE] = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
1903 mono_image_add_stream_data (&assembly->blob, (char*)hash, 20);
1905 idx = table->next_idx++;
1907 idx = MONO_IMPLEMENTATION_FILE | (idx << MONO_IMPLEMENTATION_BITS);
1913 data = mono_array_addr (rsrc->data, char, 0);
1914 len = mono_array_length (rsrc->data);
1920 sizebuf [0] = offset; sizebuf [1] = offset >> 8;
1921 sizebuf [2] = offset >> 16; sizebuf [3] = offset >> 24;
1922 rsrc->offset = mono_image_add_stream_data (&assembly->resources, sizebuf, 4);
1923 mono_image_add_stream_data (&assembly->resources, data, len);
1927 * The entry should be emitted into the MANIFESTRESOURCE table of
1928 * the main module, but that needs to reference the FILE table
1929 * which isn't emitted yet.
1936 return assembly_add_resource_manifest (mb, assembly, rsrc, idx, error);
1940 set_version_from_string (MonoString *version, guint32 *values, MonoError *error)
1942 gchar *ver, *p, *str;
1947 values [MONO_ASSEMBLY_MAJOR_VERSION] = 0;
1948 values [MONO_ASSEMBLY_MINOR_VERSION] = 0;
1949 values [MONO_ASSEMBLY_REV_NUMBER] = 0;
1950 values [MONO_ASSEMBLY_BUILD_NUMBER] = 0;
1953 ver = str = mono_string_to_utf8_checked (version, error);
1954 return_val_if_nok (error, FALSE);
1955 for (i = 0; i < 4; ++i) {
1956 values [MONO_ASSEMBLY_MAJOR_VERSION + i] = strtol (ver, &p, 10);
1962 /* handle Revision and Build */
1973 load_public_key (MonoArray *pkey, MonoDynamicImage *assembly) {
1977 char *b = blob_size;
1982 len = mono_array_length (pkey);
1983 mono_metadata_encode_value (len, b, &b);
1984 token = mono_image_add_stream_data (&assembly->blob, blob_size, b - blob_size);
1985 mono_image_add_stream_data (&assembly->blob, mono_array_addr (pkey, char, 0), len);
1987 assembly->public_key = (guint8 *)g_malloc (len);
1988 memcpy (assembly->public_key, mono_array_addr (pkey, char, 0), len);
1989 assembly->public_key_len = len;
1991 /* Special case: check for ECMA key (16 bytes) */
1992 if ((len == MONO_ECMA_KEY_LENGTH) && mono_is_ecma_key (mono_array_addr (pkey, char, 0), len)) {
1993 /* In this case we must reserve 128 bytes (1024 bits) for the signature */
1994 assembly->strong_name_size = MONO_DEFAULT_PUBLIC_KEY_LENGTH;
1995 } else if (len >= MONO_PUBLIC_KEY_HEADER_LENGTH + MONO_MINIMUM_PUBLIC_KEY_LENGTH) {
1996 /* minimum key size (in 2.0) is 384 bits */
1997 assembly->strong_name_size = len - MONO_PUBLIC_KEY_HEADER_LENGTH;
1999 /* FIXME - verifier */
2000 g_warning ("Invalid public key length: %d bits (total: %d)", (int)MONO_PUBLIC_KEY_BIT_SIZE (len), (int)len);
2001 assembly->strong_name_size = MONO_DEFAULT_PUBLIC_KEY_LENGTH; /* to be safe */
2003 assembly->strong_name = (char *)g_malloc0 (assembly->strong_name_size);
2009 mono_image_emit_manifest (MonoReflectionModuleBuilder *moduleb, MonoError *error)
2011 MonoDynamicTable *table;
2012 MonoDynamicImage *assembly;
2013 MonoReflectionAssemblyBuilder *assemblyb;
2017 guint32 module_index;
2021 assemblyb = moduleb->assemblyb;
2022 assembly = moduleb->dynamic_image;
2023 domain = mono_object_domain (assemblyb);
2025 /* Emit ASSEMBLY table */
2026 table = &assembly->tables [MONO_TABLE_ASSEMBLY];
2027 alloc_table (table, 1);
2028 values = table->values + MONO_ASSEMBLY_SIZE;
2029 values [MONO_ASSEMBLY_HASH_ALG] = assemblyb->algid? assemblyb->algid: ASSEMBLY_HASH_SHA1;
2030 values [MONO_ASSEMBLY_NAME] = string_heap_insert_mstring (&assembly->sheap, assemblyb->name, error);
2031 return_val_if_nok (error, FALSE);
2032 if (assemblyb->culture) {
2033 values [MONO_ASSEMBLY_CULTURE] = string_heap_insert_mstring (&assembly->sheap, assemblyb->culture, error);
2034 return_val_if_nok (error, FALSE);
2036 values [MONO_ASSEMBLY_CULTURE] = string_heap_insert (&assembly->sheap, "");
2038 values [MONO_ASSEMBLY_PUBLIC_KEY] = load_public_key (assemblyb->public_key, assembly);
2039 values [MONO_ASSEMBLY_FLAGS] = assemblyb->flags;
2040 if (!set_version_from_string (assemblyb->version, values, error))
2043 /* Emit FILE + EXPORTED_TYPE table */
2045 for (i = 0; i < mono_array_length (assemblyb->modules); ++i) {
2047 MonoReflectionModuleBuilder *file_module =
2048 mono_array_get (assemblyb->modules, MonoReflectionModuleBuilder*, i);
2049 if (file_module != moduleb) {
2050 if (!mono_image_fill_file_table (domain, (MonoReflectionModule*)file_module, assembly, error))
2053 if (file_module->types) {
2054 for (j = 0; j < file_module->num_types; ++j) {
2055 MonoReflectionTypeBuilder *tb = mono_array_get (file_module->types, MonoReflectionTypeBuilder*, j);
2056 mono_image_fill_export_table (domain, tb, module_index, 0, assembly, error);
2057 return_val_if_nok (error, FALSE);
2062 if (assemblyb->loaded_modules) {
2063 for (i = 0; i < mono_array_length (assemblyb->loaded_modules); ++i) {
2064 MonoReflectionModule *file_module =
2065 mono_array_get (assemblyb->loaded_modules, MonoReflectionModule*, i);
2066 if (!mono_image_fill_file_table (domain, file_module, assembly, error))
2069 mono_image_fill_export_table_from_module (domain, file_module, module_index, assembly);
2072 if (assemblyb->type_forwarders)
2073 mono_image_fill_export_table_from_type_forwarders (assemblyb, assembly);
2075 /* Emit MANIFESTRESOURCE table */
2077 for (i = 0; i < mono_array_length (assemblyb->modules); ++i) {
2079 MonoReflectionModuleBuilder *file_module =
2080 mono_array_get (assemblyb->modules, MonoReflectionModuleBuilder*, i);
2081 /* The table for the main module is emitted later */
2082 if (file_module != moduleb) {
2084 if (file_module->resources) {
2085 int len = mono_array_length (file_module->resources);
2086 for (j = 0; j < len; ++j) {
2087 MonoReflectionResource* res = (MonoReflectionResource*)mono_array_addr (file_module->resources, MonoReflectionResource, j);
2088 if (!assembly_add_resource_manifest (file_module, assembly, res, MONO_IMPLEMENTATION_FILE | (module_index << MONO_IMPLEMENTATION_BITS), error))
2097 #ifndef DISABLE_REFLECTION_EMIT_SAVE
2100 * Insert into the metadata tables all the info about the TypeBuilder tb.
2101 * Data in the tables is inserted in a predefined order, since some tables need to be sorted.
2104 mono_image_get_type_info (MonoDomain *domain, MonoReflectionTypeBuilder *tb, MonoDynamicImage *assembly, MonoError *error)
2106 MonoDynamicTable *table;
2108 int i, is_object = 0, is_system = 0;
2113 table = &assembly->tables [MONO_TABLE_TYPEDEF];
2114 values = table->values + tb->table_idx * MONO_TYPEDEF_SIZE;
2115 values [MONO_TYPEDEF_FLAGS] = tb->attrs;
2116 n = mono_string_to_utf8_checked (tb->name, error);
2117 return_val_if_nok (error, FALSE);
2118 if (strcmp (n, "Object") == 0)
2120 values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, n);
2122 n = mono_string_to_utf8_checked (tb->nspace, error);
2123 return_val_if_nok (error, FALSE);
2124 if (strcmp (n, "System") == 0)
2126 values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, n);
2128 if (tb->parent && !(is_system && is_object) &&
2129 !(tb->attrs & TYPE_ATTRIBUTE_INTERFACE)) { /* interfaces don't have a parent */
2130 MonoType *parent_type = mono_reflection_type_get_handle ((MonoReflectionType*)tb->parent, error);
2131 return_val_if_nok (error, FALSE);
2132 values [MONO_TYPEDEF_EXTENDS] = mono_image_typedef_or_ref (assembly, parent_type);
2134 values [MONO_TYPEDEF_EXTENDS] = 0;
2136 values [MONO_TYPEDEF_FIELD_LIST] = assembly->tables [MONO_TABLE_FIELD].next_idx;
2137 values [MONO_TYPEDEF_METHOD_LIST] = assembly->tables [MONO_TABLE_METHOD].next_idx;
2140 * if we have explicitlayout or sequentiallayouts, output data in the
2141 * ClassLayout table.
2143 if (((tb->attrs & TYPE_ATTRIBUTE_LAYOUT_MASK) != TYPE_ATTRIBUTE_AUTO_LAYOUT) &&
2144 ((tb->class_size > 0) || (tb->packing_size > 0))) {
2145 table = &assembly->tables [MONO_TABLE_CLASSLAYOUT];
2147 alloc_table (table, table->rows);
2148 values = table->values + table->rows * MONO_CLASS_LAYOUT_SIZE;
2149 values [MONO_CLASS_LAYOUT_PARENT] = tb->table_idx;
2150 values [MONO_CLASS_LAYOUT_CLASS_SIZE] = tb->class_size;
2151 values [MONO_CLASS_LAYOUT_PACKING_SIZE] = tb->packing_size;
2154 /* handle interfaces */
2155 if (tb->interfaces) {
2156 table = &assembly->tables [MONO_TABLE_INTERFACEIMPL];
2158 table->rows += mono_array_length (tb->interfaces);
2159 alloc_table (table, table->rows);
2160 values = table->values + (i + 1) * MONO_INTERFACEIMPL_SIZE;
2161 for (i = 0; i < mono_array_length (tb->interfaces); ++i) {
2162 MonoReflectionType* iface = (MonoReflectionType*) mono_array_get (tb->interfaces, gpointer, i);
2163 MonoType *iface_type = mono_reflection_type_get_handle (iface, error);
2164 return_val_if_nok (error, FALSE);
2165 values [MONO_INTERFACEIMPL_CLASS] = tb->table_idx;
2166 values [MONO_INTERFACEIMPL_INTERFACE] = mono_image_typedef_or_ref (assembly, iface_type);
2167 values += MONO_INTERFACEIMPL_SIZE;
2173 table = &assembly->tables [MONO_TABLE_FIELD];
2174 table->rows += tb->num_fields;
2175 alloc_table (table, table->rows);
2176 for (i = 0; i < tb->num_fields; ++i) {
2177 mono_image_get_field_info (
2178 mono_array_get (tb->fields, MonoReflectionFieldBuilder*, i), assembly, error);
2179 return_val_if_nok (error, FALSE);
2183 /* handle constructors */
2185 table = &assembly->tables [MONO_TABLE_METHOD];
2186 table->rows += mono_array_length (tb->ctors);
2187 alloc_table (table, table->rows);
2188 for (i = 0; i < mono_array_length (tb->ctors); ++i) {
2189 if (!mono_image_get_ctor_info (domain,
2190 mono_array_get (tb->ctors, MonoReflectionCtorBuilder*, i),
2196 /* handle methods */
2198 table = &assembly->tables [MONO_TABLE_METHOD];
2199 table->rows += tb->num_methods;
2200 alloc_table (table, table->rows);
2201 for (i = 0; i < tb->num_methods; ++i) {
2202 if (!mono_image_get_method_info (
2203 mono_array_get (tb->methods, MonoReflectionMethodBuilder*, i), assembly, error))
2208 /* Do the same with properties etc.. */
2209 if (tb->events && mono_array_length (tb->events)) {
2210 table = &assembly->tables [MONO_TABLE_EVENT];
2211 table->rows += mono_array_length (tb->events);
2212 alloc_table (table, table->rows);
2213 table = &assembly->tables [MONO_TABLE_EVENTMAP];
2215 alloc_table (table, table->rows);
2216 values = table->values + table->rows * MONO_EVENT_MAP_SIZE;
2217 values [MONO_EVENT_MAP_PARENT] = tb->table_idx;
2218 values [MONO_EVENT_MAP_EVENTLIST] = assembly->tables [MONO_TABLE_EVENT].next_idx;
2219 for (i = 0; i < mono_array_length (tb->events); ++i) {
2220 mono_image_get_event_info (
2221 mono_array_get (tb->events, MonoReflectionEventBuilder*, i), assembly, error);
2222 return_val_if_nok (error, FALSE);
2225 if (tb->properties && mono_array_length (tb->properties)) {
2226 table = &assembly->tables [MONO_TABLE_PROPERTY];
2227 table->rows += mono_array_length (tb->properties);
2228 alloc_table (table, table->rows);
2229 table = &assembly->tables [MONO_TABLE_PROPERTYMAP];
2231 alloc_table (table, table->rows);
2232 values = table->values + table->rows * MONO_PROPERTY_MAP_SIZE;
2233 values [MONO_PROPERTY_MAP_PARENT] = tb->table_idx;
2234 values [MONO_PROPERTY_MAP_PROPERTY_LIST] = assembly->tables [MONO_TABLE_PROPERTY].next_idx;
2235 for (i = 0; i < mono_array_length (tb->properties); ++i) {
2236 mono_image_get_property_info (
2237 mono_array_get (tb->properties, MonoReflectionPropertyBuilder*, i), assembly, error);
2238 return_val_if_nok (error, FALSE);
2242 /* handle generic parameters */
2243 if (tb->generic_params) {
2244 table = &assembly->tables [MONO_TABLE_GENERICPARAM];
2245 table->rows += mono_array_length (tb->generic_params);
2246 alloc_table (table, table->rows);
2247 for (i = 0; i < mono_array_length (tb->generic_params); ++i) {
2248 guint32 owner = MONO_TYPEORMETHOD_TYPE | (tb->table_idx << MONO_TYPEORMETHOD_BITS);
2250 mono_image_get_generic_param_info (
2251 mono_array_get (tb->generic_params, MonoReflectionGenericParam*, i), owner, assembly);
2255 mono_image_add_decl_security (assembly,
2256 mono_metadata_make_token (MONO_TABLE_TYPEDEF, tb->table_idx), tb->permissions);
2259 MonoDynamicTable *ntable;
2261 ntable = &assembly->tables [MONO_TABLE_NESTEDCLASS];
2262 ntable->rows += mono_array_length (tb->subtypes);
2263 alloc_table (ntable, ntable->rows);
2264 values = ntable->values + ntable->next_idx * MONO_NESTED_CLASS_SIZE;
2266 for (i = 0; i < mono_array_length (tb->subtypes); ++i) {
2267 MonoReflectionTypeBuilder *subtype = mono_array_get (tb->subtypes, MonoReflectionTypeBuilder*, i);
2269 values [MONO_NESTED_CLASS_NESTED] = subtype->table_idx;
2270 values [MONO_NESTED_CLASS_ENCLOSING] = tb->table_idx;
2271 /*g_print ("nesting %s (%d) in %s (%d) (rows %d/%d)\n",
2272 mono_string_to_utf8 (subtype->name), subtype->table_idx,
2273 mono_string_to_utf8 (tb->name), tb->table_idx,
2274 ntable->next_idx, ntable->rows);*/
2275 values += MONO_NESTED_CLASS_SIZE;
2285 * mono_image_build_metadata() will fill the info in all the needed metadata tables
2286 * for the modulebuilder @moduleb.
2287 * At the end of the process, method and field tokens are fixed up and the
2288 * on-disk compressed metadata representation is created.
2289 * Return TRUE on success, or FALSE on failure and sets @error
2292 mono_image_build_metadata (MonoReflectionModuleBuilder *moduleb, MonoError *error)
2294 MonoDynamicTable *table;
2295 MonoDynamicImage *assembly;
2296 MonoReflectionAssemblyBuilder *assemblyb;
2304 assemblyb = moduleb->assemblyb;
2305 assembly = moduleb->dynamic_image;
2306 domain = mono_object_domain (assemblyb);
2308 if (assembly->text_rva)
2311 assembly->text_rva = START_TEXT_RVA;
2313 if (moduleb->is_main) {
2314 mono_image_emit_manifest (moduleb, error);
2315 return_val_if_nok (error, FALSE);
2318 table = &assembly->tables [MONO_TABLE_TYPEDEF];
2319 table->rows = 1; /* .<Module> */
2321 alloc_table (table, table->rows);
2323 * Set the first entry.
2325 values = table->values + table->columns;
2326 values [MONO_TYPEDEF_FLAGS] = 0;
2327 values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, "<Module>") ;
2328 values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, "") ;
2329 values [MONO_TYPEDEF_EXTENDS] = 0;
2330 values [MONO_TYPEDEF_FIELD_LIST] = 1;
2331 values [MONO_TYPEDEF_METHOD_LIST] = 1;
2334 * handle global methods
2335 * FIXME: test what to do when global methods are defined in multiple modules.
2337 if (moduleb->global_methods) {
2338 table = &assembly->tables [MONO_TABLE_METHOD];
2339 table->rows += mono_array_length (moduleb->global_methods);
2340 alloc_table (table, table->rows);
2341 for (i = 0; i < mono_array_length (moduleb->global_methods); ++i) {
2342 if (!mono_image_get_method_info (
2343 mono_array_get (moduleb->global_methods, MonoReflectionMethodBuilder*, i), assembly, error))
2347 if (moduleb->global_fields) {
2348 table = &assembly->tables [MONO_TABLE_FIELD];
2349 table->rows += mono_array_length (moduleb->global_fields);
2350 alloc_table (table, table->rows);
2351 for (i = 0; i < mono_array_length (moduleb->global_fields); ++i) {
2352 mono_image_get_field_info (
2353 mono_array_get (moduleb->global_fields, MonoReflectionFieldBuilder*, i), assembly,
2360 table = &assembly->tables [MONO_TABLE_MODULE];
2361 alloc_table (table, 1);
2362 mono_image_fill_module_table (domain, moduleb, assembly, error);
2366 /* Collect all types into a list sorted by their table_idx */
2367 mono_ptr_array_init (types, moduleb->num_types, MONO_ROOT_SOURCE_REFLECTION, "dynamic module types list");
2370 for (i = 0; i < moduleb->num_types; ++i) {
2371 MonoReflectionTypeBuilder *type = mono_array_get (moduleb->types, MonoReflectionTypeBuilder*, i);
2372 collect_types (&types, type);
2375 mono_ptr_array_sort (types, (int (*)(const void *, const void *))compare_types_by_table_idx);
2376 table = &assembly->tables [MONO_TABLE_TYPEDEF];
2377 table->rows += mono_ptr_array_size (types);
2378 alloc_table (table, table->rows);
2381 * Emit type names + namespaces at one place inside the string heap,
2382 * so load_class_names () needs to touch fewer pages.
2384 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2385 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2386 string_heap_insert_mstring (&assembly->sheap, tb->nspace, error);
2390 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2391 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2392 string_heap_insert_mstring (&assembly->sheap, tb->name, error);
2397 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2398 MonoReflectionTypeBuilder *type = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2399 if (!mono_image_get_type_info (domain, type, assembly, error))
2404 * table->rows is already set above and in mono_image_fill_module_table.
2406 /* add all the custom attributes at the end, once all the indexes are stable */
2407 if (!mono_image_add_cattrs (assembly, 1, MONO_CUSTOM_ATTR_ASSEMBLY, assemblyb->cattrs, error))
2410 /* CAS assembly permissions */
2411 if (assemblyb->permissions_minimum)
2412 mono_image_add_decl_security (assembly, mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1), assemblyb->permissions_minimum);
2413 if (assemblyb->permissions_optional)
2414 mono_image_add_decl_security (assembly, mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1), assemblyb->permissions_optional);
2415 if (assemblyb->permissions_refused)
2416 mono_image_add_decl_security (assembly, mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1), assemblyb->permissions_refused);
2418 if (!module_add_cattrs (assembly, moduleb, error))
2422 mono_g_hash_table_foreach (assembly->token_fixups, (GHFunc)fixup_method, assembly);
2424 /* Create the MethodImpl table. We do this after emitting all methods so we already know
2425 * the final tokens and don't need another fixup pass. */
2427 if (moduleb->global_methods) {
2428 for (i = 0; i < mono_array_length (moduleb->global_methods); ++i) {
2429 MonoReflectionMethodBuilder *mb = mono_array_get (
2430 moduleb->global_methods, MonoReflectionMethodBuilder*, i);
2431 if (!mono_image_add_methodimpl (assembly, mb, error))
2436 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2437 MonoReflectionTypeBuilder *type = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2438 if (type->methods) {
2439 for (j = 0; j < type->num_methods; ++j) {
2440 MonoReflectionMethodBuilder *mb = mono_array_get (
2441 type->methods, MonoReflectionMethodBuilder*, j);
2443 if (!mono_image_add_methodimpl (assembly, mb, error))
2449 fixup_cattrs (assembly);
2452 mono_ptr_array_destroy (types);
2455 return mono_error_ok (error);
2458 #else /* DISABLE_REFLECTION_EMIT_SAVE */
2461 mono_image_build_metadata (MonoReflectionModuleBuilder *moduleb, MonoError *error)
2463 g_error ("This mono runtime was configured with --enable-minimal=reflection_emit_save, so saving of dynamic assemblies is not supported.");
2466 #endif /* DISABLE_REFLECTION_EMIT_SAVE */
2468 #ifndef DISABLE_REFLECTION_EMIT_SAVE
2471 calc_section_size (MonoDynamicImage *assembly)
2475 /* alignment constraints */
2476 mono_image_add_stream_zero (&assembly->code, 4 - (assembly->code.index % 4));
2477 g_assert ((assembly->code.index % 4) == 0);
2478 assembly->meta_size += 3;
2479 assembly->meta_size &= ~3;
2480 mono_image_add_stream_zero (&assembly->resources, 4 - (assembly->resources.index % 4));
2481 g_assert ((assembly->resources.index % 4) == 0);
2483 assembly->sections [MONO_SECTION_TEXT].size = assembly->meta_size + assembly->code.index + assembly->resources.index + assembly->strong_name_size;
2484 assembly->sections [MONO_SECTION_TEXT].attrs = SECT_FLAGS_HAS_CODE | SECT_FLAGS_MEM_EXECUTE | SECT_FLAGS_MEM_READ;
2487 if (assembly->win32_res) {
2488 guint32 res_size = (assembly->win32_res_size + 3) & ~3;
2490 assembly->sections [MONO_SECTION_RSRC].size = res_size;
2491 assembly->sections [MONO_SECTION_RSRC].attrs = SECT_FLAGS_HAS_INITIALIZED_DATA | SECT_FLAGS_MEM_READ;
2495 assembly->sections [MONO_SECTION_RELOC].size = 12;
2496 assembly->sections [MONO_SECTION_RELOC].attrs = SECT_FLAGS_MEM_READ | SECT_FLAGS_MEM_DISCARDABLE | SECT_FLAGS_HAS_INITIALIZED_DATA;
2506 MonoReflectionWin32Resource *win32_res; /* Only for leaf nodes */
2510 resource_tree_compare_by_id (gconstpointer a, gconstpointer b)
2512 ResTreeNode *t1 = (ResTreeNode*)a;
2513 ResTreeNode *t2 = (ResTreeNode*)b;
2515 return t1->id - t2->id;
2519 * resource_tree_create:
2521 * Organize the resources into a resource tree.
2523 static ResTreeNode *
2524 resource_tree_create (MonoArray *win32_resources)
2526 ResTreeNode *tree, *res_node, *type_node, *lang_node;
2530 tree = g_new0 (ResTreeNode, 1);
2532 for (i = 0; i < mono_array_length (win32_resources); ++i) {
2533 MonoReflectionWin32Resource *win32_res =
2534 (MonoReflectionWin32Resource*)mono_array_addr (win32_resources, MonoReflectionWin32Resource, i);
2538 /* FIXME: BUG: this stores managed references in unmanaged memory */
2539 lang_node = g_new0 (ResTreeNode, 1);
2540 lang_node->id = win32_res->lang_id;
2541 lang_node->win32_res = win32_res;
2543 /* Create type node if neccesary */
2545 for (l = tree->children; l; l = l->next)
2546 if (((ResTreeNode*)(l->data))->id == win32_res->res_type) {
2547 type_node = (ResTreeNode*)l->data;
2552 type_node = g_new0 (ResTreeNode, 1);
2553 type_node->id = win32_res->res_type;
2556 * The resource types have to be sorted otherwise
2557 * Windows Explorer can't display the version information.
2559 tree->children = g_slist_insert_sorted (tree->children,
2560 type_node, resource_tree_compare_by_id);
2563 /* Create res node if neccesary */
2565 for (l = type_node->children; l; l = l->next)
2566 if (((ResTreeNode*)(l->data))->id == win32_res->res_id) {
2567 res_node = (ResTreeNode*)l->data;
2572 res_node = g_new0 (ResTreeNode, 1);
2573 res_node->id = win32_res->res_id;
2574 type_node->children = g_slist_append (type_node->children, res_node);
2577 res_node->children = g_slist_append (res_node->children, lang_node);
2584 * resource_tree_encode:
2586 * Encode the resource tree into the format used in the PE file.
2589 resource_tree_encode (ResTreeNode *node, char *begin, char *p, char **endbuf)
2592 MonoPEResourceDir dir;
2593 MonoPEResourceDirEntry dir_entry;
2594 MonoPEResourceDataEntry data_entry;
2596 guint32 res_id_entries;
2599 * For the format of the resource directory, see the article
2600 * "An In-Depth Look into the Win32 Portable Executable File Format" by
2604 memset (&dir, 0, sizeof (dir));
2605 memset (&dir_entry, 0, sizeof (dir_entry));
2606 memset (&data_entry, 0, sizeof (data_entry));
2608 g_assert (sizeof (dir) == 16);
2609 g_assert (sizeof (dir_entry) == 8);
2610 g_assert (sizeof (data_entry) == 16);
2612 node->offset = p - begin;
2614 /* IMAGE_RESOURCE_DIRECTORY */
2615 res_id_entries = g_slist_length (node->children);
2616 dir.res_id_entries = GUINT16_TO_LE (res_id_entries);
2618 memcpy (p, &dir, sizeof (dir));
2621 /* Reserve space for entries */
2623 p += sizeof (dir_entry) * res_id_entries;
2625 /* Write children */
2626 for (l = node->children; l; l = l->next) {
2627 ResTreeNode *child = (ResTreeNode*)l->data;
2629 if (child->win32_res) {
2632 child->offset = p - begin;
2634 /* IMAGE_RESOURCE_DATA_ENTRY */
2635 data_entry.rde_data_offset = GUINT32_TO_LE (p - begin + sizeof (data_entry));
2636 size = mono_array_length (child->win32_res->res_data);
2637 data_entry.rde_size = GUINT32_TO_LE (size);
2639 memcpy (p, &data_entry, sizeof (data_entry));
2640 p += sizeof (data_entry);
2642 memcpy (p, mono_array_addr (child->win32_res->res_data, char, 0), size);
2645 resource_tree_encode (child, begin, p, &p);
2649 /* IMAGE_RESOURCE_ENTRY */
2650 for (l = node->children; l; l = l->next) {
2651 ResTreeNode *child = (ResTreeNode*)l->data;
2653 MONO_PE_RES_DIR_ENTRY_SET_NAME (dir_entry, FALSE, child->id);
2654 MONO_PE_RES_DIR_ENTRY_SET_DIR (dir_entry, !child->win32_res, child->offset);
2656 memcpy (entries, &dir_entry, sizeof (dir_entry));
2657 entries += sizeof (dir_entry);
2664 resource_tree_free (ResTreeNode * node)
2667 for (list = node->children; list; list = list->next)
2668 resource_tree_free ((ResTreeNode*)list->data);
2669 g_slist_free(node->children);
2674 assembly_add_win32_resources (MonoDynamicImage *assembly, MonoReflectionAssemblyBuilder *assemblyb)
2679 MonoReflectionWin32Resource *win32_res;
2682 if (!assemblyb->win32_resources)
2686 * Resources are stored in a three level tree inside the PE file.
2687 * - level one contains a node for each type of resource
2688 * - level two contains a node for each resource
2689 * - level three contains a node for each instance of a resource for a
2690 * specific language.
2693 tree = resource_tree_create (assemblyb->win32_resources);
2695 /* Estimate the size of the encoded tree */
2697 for (i = 0; i < mono_array_length (assemblyb->win32_resources); ++i) {
2698 win32_res = (MonoReflectionWin32Resource*)mono_array_addr (assemblyb->win32_resources, MonoReflectionWin32Resource, i);
2699 size += mono_array_length (win32_res->res_data);
2701 /* Directory structure */
2702 size += mono_array_length (assemblyb->win32_resources) * 256;
2703 p = buf = (char *)g_malloc (size);
2705 resource_tree_encode (tree, p, p, &p);
2707 g_assert (p - buf <= size);
2709 assembly->win32_res = (char *)g_malloc (p - buf);
2710 assembly->win32_res_size = p - buf;
2711 memcpy (assembly->win32_res, buf, p - buf);
2714 resource_tree_free (tree);
2718 fixup_resource_directory (char *res_section, char *p, guint32 rva)
2720 MonoPEResourceDir *dir = (MonoPEResourceDir*)p;
2723 p += sizeof (MonoPEResourceDir);
2724 for (i = 0; i < GUINT16_FROM_LE (dir->res_named_entries) + GUINT16_FROM_LE (dir->res_id_entries); ++i) {
2725 MonoPEResourceDirEntry *dir_entry = (MonoPEResourceDirEntry*)p;
2726 char *child = res_section + MONO_PE_RES_DIR_ENTRY_DIR_OFFSET (*dir_entry);
2727 if (MONO_PE_RES_DIR_ENTRY_IS_DIR (*dir_entry)) {
2728 fixup_resource_directory (res_section, child, rva);
2730 MonoPEResourceDataEntry *data_entry = (MonoPEResourceDataEntry*)child;
2731 data_entry->rde_data_offset = GUINT32_TO_LE (GUINT32_FROM_LE (data_entry->rde_data_offset) + rva);
2734 p += sizeof (MonoPEResourceDirEntry);
2739 checked_write_file (HANDLE f, gconstpointer buffer, guint32 numbytes)
2742 if (!mono_w32file_write (f, buffer, numbytes, &dummy))
2743 g_error ("mono_w32file_write returned %d\n", mono_w32error_get_last ());
2747 * mono_image_create_pefile:
2748 * @mb: a module builder object
2750 * This function creates the PE-COFF header, the image sections, the CLI header * etc. all the data is written in
2751 * assembly->pefile where it can be easily retrieved later in chunks.
2754 mono_image_create_pefile (MonoReflectionModuleBuilder *mb, HANDLE file, MonoError *error)
2756 MonoMSDOSHeader *msdos;
2757 MonoDotNetHeader *header;
2758 MonoSectionTable *section;
2759 MonoCLIHeader *cli_header;
2760 guint32 size, image_size, virtual_base, text_offset;
2761 guint32 header_start, section_start, file_offset, virtual_offset;
2762 MonoDynamicImage *assembly;
2763 MonoReflectionAssemblyBuilder *assemblyb;
2764 MonoDynamicStream pefile_stream = {0};
2765 MonoDynamicStream *pefile = &pefile_stream;
2767 guint32 *rva, value;
2769 static const unsigned char msheader[] = {
2770 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
2771 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2772 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2773 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
2774 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68,
2775 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f,
2776 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,
2777 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
2782 assemblyb = mb->assemblyb;
2784 mono_reflection_dynimage_basic_init (assemblyb);
2785 assembly = mb->dynamic_image;
2787 assembly->pe_kind = assemblyb->pe_kind;
2788 assembly->machine = assemblyb->machine;
2789 ((MonoDynamicImage*)assemblyb->dynamic_assembly->assembly.image)->pe_kind = assemblyb->pe_kind;
2790 ((MonoDynamicImage*)assemblyb->dynamic_assembly->assembly.image)->machine = assemblyb->machine;
2792 if (!mono_image_build_metadata (mb, error))
2796 if (mb->is_main && assemblyb->resources) {
2797 int len = mono_array_length (assemblyb->resources);
2798 for (i = 0; i < len; ++i) {
2799 if (!assembly_add_resource (mb, assembly, (MonoReflectionResource*)mono_array_addr (assemblyb->resources, MonoReflectionResource, i), error))
2804 if (mb->resources) {
2805 int len = mono_array_length (mb->resources);
2806 for (i = 0; i < len; ++i) {
2807 if (!assembly_add_resource (mb, assembly, (MonoReflectionResource*)mono_array_addr (mb->resources, MonoReflectionResource, i), error))
2812 if (!build_compressed_metadata (assembly, error))
2816 assembly_add_win32_resources (assembly, assemblyb);
2818 nsections = calc_section_size (assembly);
2820 /* The DOS header and stub */
2821 g_assert (sizeof (MonoMSDOSHeader) == sizeof (msheader));
2822 mono_image_add_stream_data (pefile, (char*)msheader, sizeof (msheader));
2824 /* the dotnet header */
2825 header_start = mono_image_add_stream_zero (pefile, sizeof (MonoDotNetHeader));
2827 /* the section tables */
2828 section_start = mono_image_add_stream_zero (pefile, sizeof (MonoSectionTable) * nsections);
2830 file_offset = section_start + sizeof (MonoSectionTable) * nsections;
2831 virtual_offset = VIRT_ALIGN;
2834 for (i = 0; i < MONO_SECTION_MAX; ++i) {
2835 if (!assembly->sections [i].size)
2838 file_offset += FILE_ALIGN - 1;
2839 file_offset &= ~(FILE_ALIGN - 1);
2840 virtual_offset += VIRT_ALIGN - 1;
2841 virtual_offset &= ~(VIRT_ALIGN - 1);
2843 assembly->sections [i].offset = file_offset;
2844 assembly->sections [i].rva = virtual_offset;
2846 file_offset += assembly->sections [i].size;
2847 virtual_offset += assembly->sections [i].size;
2848 image_size += (assembly->sections [i].size + VIRT_ALIGN - 1) & ~(VIRT_ALIGN - 1);
2851 file_offset += FILE_ALIGN - 1;
2852 file_offset &= ~(FILE_ALIGN - 1);
2854 image_size += section_start + sizeof (MonoSectionTable) * nsections;
2856 /* back-patch info */
2857 msdos = (MonoMSDOSHeader*)pefile->data;
2858 msdos->pe_offset = GUINT32_FROM_LE (sizeof (MonoMSDOSHeader));
2860 header = (MonoDotNetHeader*)(pefile->data + header_start);
2861 header->pesig [0] = 'P';
2862 header->pesig [1] = 'E';
2864 header->coff.coff_machine = GUINT16_FROM_LE (assemblyb->machine);
2865 header->coff.coff_sections = GUINT16_FROM_LE (nsections);
2866 header->coff.coff_time = GUINT32_FROM_LE (time (NULL));
2867 header->coff.coff_opt_header_size = GUINT16_FROM_LE (sizeof (MonoDotNetHeader) - sizeof (MonoCOFFHeader) - 4);
2868 if (assemblyb->pekind == 1) {
2870 header->coff.coff_attributes = GUINT16_FROM_LE (0x210e);
2873 header->coff.coff_attributes = GUINT16_FROM_LE (0x010e);
2876 virtual_base = 0x400000; /* FIXME: 0x10000000 if a DLL */
2878 header->pe.pe_magic = GUINT16_FROM_LE (0x10B);
2879 header->pe.pe_major = 6;
2880 header->pe.pe_minor = 0;
2881 size = assembly->sections [MONO_SECTION_TEXT].size;
2882 size += FILE_ALIGN - 1;
2883 size &= ~(FILE_ALIGN - 1);
2884 header->pe.pe_code_size = GUINT32_FROM_LE(size);
2885 size = assembly->sections [MONO_SECTION_RSRC].size;
2886 size += FILE_ALIGN - 1;
2887 size &= ~(FILE_ALIGN - 1);
2888 header->pe.pe_data_size = GUINT32_FROM_LE(size);
2889 g_assert (START_TEXT_RVA == assembly->sections [MONO_SECTION_TEXT].rva);
2890 header->pe.pe_rva_code_base = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_TEXT].rva);
2891 header->pe.pe_rva_data_base = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].rva);
2892 /* pe_rva_entry_point always at the beginning of the text section */
2893 header->pe.pe_rva_entry_point = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_TEXT].rva);
2895 header->nt.pe_image_base = GUINT32_FROM_LE (virtual_base);
2896 header->nt.pe_section_align = GUINT32_FROM_LE (VIRT_ALIGN);
2897 header->nt.pe_file_alignment = GUINT32_FROM_LE (FILE_ALIGN);
2898 header->nt.pe_os_major = GUINT16_FROM_LE (4);
2899 header->nt.pe_os_minor = GUINT16_FROM_LE (0);
2900 header->nt.pe_subsys_major = GUINT16_FROM_LE (4);
2901 size = section_start;
2902 size += FILE_ALIGN - 1;
2903 size &= ~(FILE_ALIGN - 1);
2904 header->nt.pe_header_size = GUINT32_FROM_LE (size);
2906 size += VIRT_ALIGN - 1;
2907 size &= ~(VIRT_ALIGN - 1);
2908 header->nt.pe_image_size = GUINT32_FROM_LE (size);
2911 // Translate the PEFileKind value to the value expected by the Windows loader
2917 // PEFileKinds.Dll == 1
2918 // PEFileKinds.ConsoleApplication == 2
2919 // PEFileKinds.WindowApplication == 3
2922 // IMAGE_SUBSYSTEM_WINDOWS_GUI 2 // Image runs in the Windows GUI subsystem.
2923 // IMAGE_SUBSYSTEM_WINDOWS_CUI 3 // Image runs in the Windows character subsystem.
2925 if (assemblyb->pekind == 3)
2930 header->nt.pe_subsys_required = GUINT16_FROM_LE (kind);
2932 header->nt.pe_stack_reserve = GUINT32_FROM_LE (0x00100000);
2933 header->nt.pe_stack_commit = GUINT32_FROM_LE (0x00001000);
2934 header->nt.pe_heap_reserve = GUINT32_FROM_LE (0x00100000);
2935 header->nt.pe_heap_commit = GUINT32_FROM_LE (0x00001000);
2936 header->nt.pe_loader_flags = GUINT32_FROM_LE (0);
2937 header->nt.pe_data_dir_count = GUINT32_FROM_LE (16);
2939 /* fill data directory entries */
2941 header->datadir.pe_resource_table.size = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].size);
2942 header->datadir.pe_resource_table.rva = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].rva);
2944 header->datadir.pe_reloc_table.size = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RELOC].size);
2945 header->datadir.pe_reloc_table.rva = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RELOC].rva);
2947 header->datadir.pe_cli_header.size = GUINT32_FROM_LE (72);
2948 header->datadir.pe_cli_header.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->cli_header_offset);
2949 header->datadir.pe_iat.size = GUINT32_FROM_LE (8);
2950 header->datadir.pe_iat.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->iat_offset);
2951 /* patch entrypoint name */
2952 if (assemblyb->pekind == 1)
2953 memcpy (assembly->code.data + assembly->imp_names_offset + 2, "_CorDllMain", 12);
2955 memcpy (assembly->code.data + assembly->imp_names_offset + 2, "_CorExeMain", 12);
2956 /* patch imported function RVA name */
2957 rva = (guint32*)(assembly->code.data + assembly->iat_offset);
2958 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->imp_names_offset);
2960 /* the import table */
2961 header->datadir.pe_import_table.size = GUINT32_FROM_LE (79); /* FIXME: magic number? */
2962 header->datadir.pe_import_table.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->idt_offset);
2963 /* patch imported dll RVA name and other entries in the dir */
2964 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, name_rva));
2965 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->imp_names_offset + 14); /* 14 is hint+strlen+1 of func name */
2966 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, import_address_table_rva));
2967 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->iat_offset);
2968 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, import_lookup_table));
2969 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->ilt_offset);
2971 p = (guchar*)(assembly->code.data + assembly->ilt_offset);
2972 value = (assembly->text_rva + assembly->imp_names_offset);
2973 *p++ = (value) & 0xff;
2974 *p++ = (value >> 8) & (0xff);
2975 *p++ = (value >> 16) & (0xff);
2976 *p++ = (value >> 24) & (0xff);
2978 /* the CLI header info */
2979 cli_header = (MonoCLIHeader*)(assembly->code.data + assembly->cli_header_offset);
2980 cli_header->ch_size = GUINT32_FROM_LE (72);
2981 cli_header->ch_runtime_major = GUINT16_FROM_LE (2);
2982 cli_header->ch_runtime_minor = GUINT16_FROM_LE (5);
2983 cli_header->ch_flags = GUINT32_FROM_LE (assemblyb->pe_kind);
2984 if (assemblyb->entry_point) {
2985 guint32 table_idx = 0;
2986 if (!strcmp (assemblyb->entry_point->object.vtable->klass->name, "MethodBuilder")) {
2987 MonoReflectionMethodBuilder *methodb = (MonoReflectionMethodBuilder*)assemblyb->entry_point;
2988 table_idx = methodb->table_idx;
2990 table_idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, assemblyb->entry_point->method));
2992 cli_header->ch_entry_point = GUINT32_FROM_LE (table_idx | MONO_TOKEN_METHOD_DEF);
2994 cli_header->ch_entry_point = GUINT32_FROM_LE (0);
2996 /* The embedded managed resources */
2997 text_offset = assembly->text_rva + assembly->code.index;
2998 cli_header->ch_resources.rva = GUINT32_FROM_LE (text_offset);
2999 cli_header->ch_resources.size = GUINT32_FROM_LE (assembly->resources.index);
3000 text_offset += assembly->resources.index;
3001 cli_header->ch_metadata.rva = GUINT32_FROM_LE (text_offset);
3002 cli_header->ch_metadata.size = GUINT32_FROM_LE (assembly->meta_size);
3003 text_offset += assembly->meta_size;
3004 if (assembly->strong_name_size) {
3005 cli_header->ch_strong_name.rva = GUINT32_FROM_LE (text_offset);
3006 cli_header->ch_strong_name.size = GUINT32_FROM_LE (assembly->strong_name_size);
3007 text_offset += assembly->strong_name_size;
3010 /* write the section tables and section content */
3011 section = (MonoSectionTable*)(pefile->data + section_start);
3012 for (i = 0; i < MONO_SECTION_MAX; ++i) {
3013 static const char section_names [][7] = {
3014 ".text", ".rsrc", ".reloc"
3016 if (!assembly->sections [i].size)
3018 strcpy (section->st_name, section_names [i]);
3019 /*g_print ("output section %s (%d), size: %d\n", section->st_name, i, assembly->sections [i].size);*/
3020 section->st_virtual_address = GUINT32_FROM_LE (assembly->sections [i].rva);
3021 section->st_virtual_size = GUINT32_FROM_LE (assembly->sections [i].size);
3022 section->st_raw_data_size = GUINT32_FROM_LE (GUINT32_TO_LE (section->st_virtual_size) + (FILE_ALIGN - 1));
3023 section->st_raw_data_size &= GUINT32_FROM_LE (~(FILE_ALIGN - 1));
3024 section->st_raw_data_ptr = GUINT32_FROM_LE (assembly->sections [i].offset);
3025 section->st_flags = GUINT32_FROM_LE (assembly->sections [i].attrs);
3029 checked_write_file (file, pefile->data, pefile->index);
3031 mono_dynamic_stream_reset (pefile);
3033 for (i = 0; i < MONO_SECTION_MAX; ++i) {
3034 if (!assembly->sections [i].size)
3037 if (mono_w32file_seek (file, assembly->sections [i].offset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
3038 g_error ("mono_w32file_seek returned %d\n", mono_w32error_get_last ());
3041 case MONO_SECTION_TEXT:
3042 /* patch entry point */
3043 p = (guchar*)(assembly->code.data + 2);
3044 value = (virtual_base + assembly->text_rva + assembly->iat_offset);
3045 *p++ = (value) & 0xff;
3046 *p++ = (value >> 8) & 0xff;
3047 *p++ = (value >> 16) & 0xff;
3048 *p++ = (value >> 24) & 0xff;
3050 checked_write_file (file, assembly->code.data, assembly->code.index);
3051 checked_write_file (file, assembly->resources.data, assembly->resources.index);
3052 checked_write_file (file, assembly->image.raw_metadata, assembly->meta_size);
3053 checked_write_file (file, assembly->strong_name, assembly->strong_name_size);
3056 g_free (assembly->image.raw_metadata);
3058 case MONO_SECTION_RELOC: {
3062 guint16 type_and_offset;
3066 g_assert (sizeof (reloc) == 12);
3068 reloc.page_rva = GUINT32_FROM_LE (assembly->text_rva);
3069 reloc.block_size = GUINT32_FROM_LE (12);
3072 * the entrypoint is always at the start of the text section
3073 * 3 is IMAGE_REL_BASED_HIGHLOW
3074 * 2 is patch_size_rva - text_rva
3076 reloc.type_and_offset = GUINT16_FROM_LE ((3 << 12) + (2));
3079 checked_write_file (file, &reloc, sizeof (reloc));
3083 case MONO_SECTION_RSRC:
3084 if (assembly->win32_res) {
3086 /* Fixup the offsets in the IMAGE_RESOURCE_DATA_ENTRY structures */
3087 fixup_resource_directory (assembly->win32_res, assembly->win32_res, assembly->sections [i].rva);
3088 checked_write_file (file, assembly->win32_res, assembly->win32_res_size);
3092 g_assert_not_reached ();
3096 /* check that the file is properly padded */
3097 if (mono_w32file_seek (file, file_offset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
3098 g_error ("mono_w32file_seek returned %d\n", mono_w32error_get_last ());
3099 if (! mono_w32file_truncate (file))
3100 g_error ("mono_w32file_truncate returned %d\n", mono_w32error_get_last ());
3102 mono_dynamic_stream_reset (&assembly->code);
3103 mono_dynamic_stream_reset (&assembly->us);
3104 mono_dynamic_stream_reset (&assembly->blob);
3105 mono_dynamic_stream_reset (&assembly->guid);
3106 mono_dynamic_stream_reset (&assembly->sheap);
3108 g_hash_table_foreach (assembly->blob_cache, (GHFunc)g_free, NULL);
3109 g_hash_table_destroy (assembly->blob_cache);
3110 assembly->blob_cache = NULL;
3115 #else /* DISABLE_REFLECTION_EMIT_SAVE */
3118 mono_image_create_pefile (MonoReflectionModuleBuilder *mb, HANDLE file, MonoError *error)
3120 g_assert_not_reached ();
3123 #endif /* DISABLE_REFLECTION_EMIT_SAVE */