2 * sre-save.c: Routine for saving an image to a file.
6 * Paolo Molaro (lupus@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
10 * Copyright 2011 Rodrigo Kumpera
11 * Copyright 2016 Microsoft
13 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
19 #include "mono/metadata/dynamic-image-internals.h"
20 #include "mono/metadata/dynamic-stream-internals.h"
21 #include "mono/metadata/mono-ptr-array.h"
22 #include "mono/metadata/object-internals.h"
23 #include "mono/metadata/sre-internals.h"
24 #include "mono/metadata/security-manager.h"
25 #include "mono/metadata/tabledefs.h"
26 #include "mono/metadata/tokentype.h"
28 #include "mono/utils/checked-build.h"
29 #include "mono/utils/mono-digest.h"
30 #include "mono/utils/mono-error-internals.h"
32 #include "mono/io-layer/io-layer.h"
34 #define TEXT_OFFSET 512
35 #define CLI_H_SIZE 136
36 #define FILE_ALIGN 512
37 #define VIRT_ALIGN 8192
38 #define START_TEXT_RVA 0x00002000
40 static void mono_image_get_generic_param_info (MonoReflectionGenericParam *gparam, guint32 owner, MonoDynamicImage *assembly);
43 alloc_table (MonoDynamicTable *table, guint nrows)
45 mono_dynimage_alloc_table (table, nrows);
49 string_heap_insert (MonoDynamicStream *sh, const char *str)
51 return mono_dynstream_insert_string (sh, str);
55 string_heap_insert_mstring (MonoDynamicStream *sh, MonoString *str, MonoError *error)
57 return mono_dynstream_insert_mstring (sh, str, error);
61 mono_image_add_stream_data (MonoDynamicStream *stream, const char *data, guint32 len)
63 return mono_dynstream_add_data (stream, data, len);
67 mono_image_add_stream_zero (MonoDynamicStream *stream, guint32 len)
69 return mono_dynstream_add_zero (stream, len);
73 stream_data_align (MonoDynamicStream *stream)
75 mono_dynstream_data_align (stream);
79 mono_image_typedef_or_ref (MonoDynamicImage *assembly, MonoType *type)
81 return mono_dynimage_encode_typedef_or_ref_full (assembly, type, TRUE);
85 find_index_in_table (MonoDynamicImage *assembly, int table_idx, int col, guint32 token)
87 MONO_REQ_GC_NEUTRAL_MODE;
90 MonoDynamicTable *table;
93 table = &assembly->tables [table_idx];
95 g_assert (col < table->columns);
97 values = table->values + table->columns;
98 for (i = 1; i <= table->rows; ++i) {
99 if (values [col] == token)
101 values += table->columns;
107 * Copy len * nelem bytes from val to dest, swapping bytes to LE if necessary.
108 * dest may be misaligned.
111 swap_with_size (char *dest, const char* val, int len, int nelem) {
112 MONO_REQ_GC_NEUTRAL_MODE;
113 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
116 for (elem = 0; elem < nelem; ++elem) {
142 g_assert_not_reached ();
148 memcpy (dest, val, len * nelem);
153 add_mono_string_to_blob_cached (MonoDynamicImage *assembly, MonoString *str)
155 MONO_REQ_GC_UNSAFE_MODE;
159 guint32 idx = 0, len;
161 len = str->length * 2;
162 mono_metadata_encode_value (len, b, &b);
163 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
165 char *swapped = g_malloc (2 * mono_string_length (str));
166 const char *p = (const char*)mono_string_chars (str);
168 swap_with_size (swapped, p, 2, mono_string_length (str));
169 idx = mono_dynamic_image_add_to_blob_cached (assembly, blob_size, b-blob_size, swapped, len);
173 idx = mono_dynamic_image_add_to_blob_cached (assembly, blob_size, b-blob_size, (char*)mono_string_chars (str), len);
179 image_create_token_raw (MonoDynamicImage *assembly, MonoObject* obj_raw, gboolean create_methodspec, gboolean register_token, MonoError *error)
181 HANDLE_FUNCTION_ENTER (); /* FIXME callers of image_create_token_raw should use handles */
182 mono_error_init (error);
183 MONO_HANDLE_DCL (MonoObject, obj);
184 guint32 result = mono_image_create_token (assembly, obj, create_methodspec, register_token, error);
185 HANDLE_FUNCTION_RETURN_VAL (result);
190 * idx is the table index of the object
191 * type is one of MONO_CUSTOM_ATTR_*
194 mono_image_add_cattrs (MonoDynamicImage *assembly, guint32 idx, guint32 type, MonoArray *cattrs, MonoError *error)
196 MONO_REQ_GC_UNSAFE_MODE;
198 MonoDynamicTable *table;
199 MonoReflectionCustomAttr *cattr;
201 guint32 count, i, token;
205 mono_error_init (error);
207 /* it is legal to pass a NULL cattrs: we avoid to use the if in a lot of places */
210 count = mono_array_length (cattrs);
211 table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
212 table->rows += count;
213 alloc_table (table, table->rows);
214 values = table->values + table->next_idx * MONO_CUSTOM_ATTR_SIZE;
215 idx <<= MONO_CUSTOM_ATTR_BITS;
217 for (i = 0; i < count; ++i) {
218 cattr = (MonoReflectionCustomAttr*)mono_array_get (cattrs, gpointer, i);
219 values [MONO_CUSTOM_ATTR_PARENT] = idx;
220 token = image_create_token_raw (assembly, (MonoObject*)cattr->ctor, FALSE, FALSE, error); /* FIXME use handles */
221 if (!mono_error_ok (error)) goto fail;
222 type = mono_metadata_token_index (token);
223 type <<= MONO_CUSTOM_ATTR_TYPE_BITS;
224 switch (mono_metadata_token_table (token)) {
225 case MONO_TABLE_METHOD:
226 type |= MONO_CUSTOM_ATTR_TYPE_METHODDEF;
228 * fixup_cattrs () needs to fix this up. We can't use image->tokens, since it contains the old token for the
229 * method, not the one returned by mono_image_create_token ().
231 mono_g_hash_table_insert (assembly->remapped_tokens, GUINT_TO_POINTER (token), cattr->ctor);
233 case MONO_TABLE_MEMBERREF:
234 type |= MONO_CUSTOM_ATTR_TYPE_MEMBERREF;
237 g_warning ("got wrong token in custom attr");
240 values [MONO_CUSTOM_ATTR_TYPE] = type;
242 mono_metadata_encode_value (mono_array_length (cattr->data), p, &p);
243 values [MONO_CUSTOM_ATTR_VALUE] = mono_dynamic_image_add_to_blob_cached (assembly, blob_size, p - blob_size,
244 mono_array_addr (cattr->data, char, 0), mono_array_length (cattr->data));
245 values += MONO_CUSTOM_ATTR_SIZE;
256 mono_image_add_decl_security (MonoDynamicImage *assembly, guint32 parent_token, MonoArray *permissions)
258 MONO_REQ_GC_UNSAFE_MODE;
260 MonoDynamicTable *table;
262 guint32 count, i, idx;
263 MonoReflectionPermissionSet *perm;
268 count = mono_array_length (permissions);
269 table = &assembly->tables [MONO_TABLE_DECLSECURITY];
270 table->rows += count;
271 alloc_table (table, table->rows);
273 for (i = 0; i < mono_array_length (permissions); ++i) {
274 perm = (MonoReflectionPermissionSet*)mono_array_addr (permissions, MonoReflectionPermissionSet, i);
276 values = table->values + table->next_idx * MONO_DECL_SECURITY_SIZE;
278 idx = mono_metadata_token_index (parent_token);
279 idx <<= MONO_HAS_DECL_SECURITY_BITS;
280 switch (mono_metadata_token_table (parent_token)) {
281 case MONO_TABLE_TYPEDEF:
282 idx |= MONO_HAS_DECL_SECURITY_TYPEDEF;
284 case MONO_TABLE_METHOD:
285 idx |= MONO_HAS_DECL_SECURITY_METHODDEF;
287 case MONO_TABLE_ASSEMBLY:
288 idx |= MONO_HAS_DECL_SECURITY_ASSEMBLY;
291 g_assert_not_reached ();
294 values [MONO_DECL_SECURITY_ACTION] = perm->action;
295 values [MONO_DECL_SECURITY_PARENT] = idx;
296 values [MONO_DECL_SECURITY_PERMISSIONSET] = add_mono_string_to_blob_cached (assembly, perm->pset);
303 * method_encode_code:
305 * @assembly the assembly
306 * @mb the managed MethodBuilder
307 * @error set on error
309 * Note that the return value is not sensible if @error is set.
312 method_encode_code (MonoDynamicImage *assembly, ReflectionMethodBuilder *mb, MonoError *error)
314 MONO_REQ_GC_UNSAFE_MODE;
320 gint32 num_locals = 0;
321 gint32 num_exception = 0;
324 char fat_header [12];
327 guint32 local_sig = 0;
328 guint32 header_size = 12;
331 mono_error_init (error);
333 if ((mb->attrs & (METHOD_ATTRIBUTE_PINVOKE_IMPL | METHOD_ATTRIBUTE_ABSTRACT)) ||
334 (mb->iattrs & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)))
338 g_print ("Encode method %s\n", mono_string_to_utf8 (mb->name));*/
340 code = mb->ilgen->code;
341 code_size = mb->ilgen->code_len;
342 max_stack = mb->ilgen->max_stack;
343 num_locals = mb->ilgen->locals ? mono_array_length (mb->ilgen->locals) : 0;
344 if (mb->ilgen->ex_handlers)
345 num_exception = mono_reflection_method_count_clauses (mb->ilgen);
349 MonoError inner_error;
350 char *name = mono_string_to_utf8_checked (mb->name, &inner_error);
351 if (!is_ok (&inner_error)) {
352 name = g_strdup ("");
353 mono_error_cleanup (&inner_error);
355 char *str = g_strdup_printf ("Method %s does not have any IL associated", name);
356 mono_error_set_argument (error, NULL, "a method does not have any IL associated");
362 code_size = mono_array_length (code);
363 max_stack = 8; /* we probably need to run a verifier on the code... */
366 stream_data_align (&assembly->code);
368 /* check for exceptions, maxstack, locals */
369 maybe_small = (max_stack <= 8) && (!num_locals) && (!num_exception);
371 if (code_size < 64 && !(code_size & 1)) {
372 flags = (code_size << 2) | 0x2;
373 } else if (code_size < 32 && (code_size & 1)) {
374 flags = (code_size << 2) | 0x6; /* LAMESPEC: see metadata.c */
378 idx = mono_image_add_stream_data (&assembly->code, &flags, 1);
379 /* add to the fixup todo list */
380 if (mb->ilgen && mb->ilgen->num_token_fixups)
381 mono_g_hash_table_insert (assembly->token_fixups, mb->ilgen, GUINT_TO_POINTER (idx + 1));
382 mono_image_add_stream_data (&assembly->code, mono_array_addr (code, char, 0), code_size);
383 return assembly->text_rva + idx;
387 local_sig = MONO_TOKEN_SIGNATURE | mono_dynimage_encode_locals (assembly, mb->ilgen, error);
388 return_val_if_nok (error, 0);
391 * FIXME: need to set also the header size in fat_flags.
392 * (and more sects and init locals flags)
396 fat_flags |= METHOD_HEADER_MORE_SECTS;
398 fat_flags |= METHOD_HEADER_INIT_LOCALS;
399 fat_header [0] = fat_flags;
400 fat_header [1] = (header_size / 4 ) << 4;
401 short_value = GUINT16_TO_LE (max_stack);
402 memcpy (fat_header + 2, &short_value, 2);
403 int_value = GUINT32_TO_LE (code_size);
404 memcpy (fat_header + 4, &int_value, 4);
405 int_value = GUINT32_TO_LE (local_sig);
406 memcpy (fat_header + 8, &int_value, 4);
407 idx = mono_image_add_stream_data (&assembly->code, fat_header, 12);
408 /* add to the fixup todo list */
409 if (mb->ilgen && mb->ilgen->num_token_fixups)
410 mono_g_hash_table_insert (assembly->token_fixups, mb->ilgen, GUINT_TO_POINTER (idx + 12));
412 mono_image_add_stream_data (&assembly->code, mono_array_addr (code, char, 0), code_size);
414 unsigned char sheader [4];
415 MonoILExceptionInfo * ex_info;
416 MonoILExceptionBlock * ex_block;
419 stream_data_align (&assembly->code);
420 /* always use fat format for now */
421 sheader [0] = METHOD_HEADER_SECTION_FAT_FORMAT | METHOD_HEADER_SECTION_EHTABLE;
422 num_exception *= 6 * sizeof (guint32);
423 num_exception += 4; /* include the size of the header */
424 sheader [1] = num_exception & 0xff;
425 sheader [2] = (num_exception >> 8) & 0xff;
426 sheader [3] = (num_exception >> 16) & 0xff;
427 mono_image_add_stream_data (&assembly->code, (char*)sheader, 4);
428 /* fat header, so we are already aligned */
430 for (i = mono_array_length (mb->ilgen->ex_handlers) - 1; i >= 0; --i) {
431 ex_info = (MonoILExceptionInfo *)mono_array_addr (mb->ilgen->ex_handlers, MonoILExceptionInfo, i);
432 if (ex_info->handlers) {
433 int finally_start = ex_info->start + ex_info->len;
434 for (j = 0; j < mono_array_length (ex_info->handlers); ++j) {
436 ex_block = (MonoILExceptionBlock*)mono_array_addr (ex_info->handlers, MonoILExceptionBlock, j);
438 val = GUINT32_TO_LE (ex_block->type);
439 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
441 val = GUINT32_TO_LE (ex_info->start);
442 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
443 /* need fault, too, probably */
444 if (ex_block->type == MONO_EXCEPTION_CLAUSE_FINALLY)
445 val = GUINT32_TO_LE (finally_start - ex_info->start);
447 val = GUINT32_TO_LE (ex_info->len);
448 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
450 val = GUINT32_TO_LE (ex_block->start);
451 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
453 val = GUINT32_TO_LE (ex_block->len);
454 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
455 finally_start = ex_block->start + ex_block->len;
456 if (ex_block->extype) {
457 MonoType *extype = mono_reflection_type_get_handle ((MonoReflectionType*)ex_block->extype, error);
458 return_val_if_nok (error, 0);
460 val = mono_metadata_token_from_dor (mono_image_typedef_or_ref (assembly, extype));
462 if (ex_block->type == MONO_EXCEPTION_CLAUSE_FILTER)
463 val = ex_block->filter_offset;
467 val = GUINT32_TO_LE (val);
468 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
469 /*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",
470 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);*/
473 g_error ("No clauses for ex info block %d", i);
477 return assembly->text_rva + idx;
481 * Fill in the MethodDef and ParamDef tables for a method.
482 * This is used for both normal methods and constructors.
485 mono_image_basic_method (ReflectionMethodBuilder *mb, MonoDynamicImage *assembly, MonoError *error)
487 MONO_REQ_GC_UNSAFE_MODE;
489 MonoDynamicTable *table;
493 mono_error_init (error);
495 /* room in this table is already allocated */
496 table = &assembly->tables [MONO_TABLE_METHOD];
497 *mb->table_idx = table->next_idx ++;
498 g_hash_table_insert (assembly->method_to_table_idx, mb->mhandle, GUINT_TO_POINTER ((*mb->table_idx)));
499 values = table->values + *mb->table_idx * MONO_METHOD_SIZE;
500 values [MONO_METHOD_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->name, error);
501 return_val_if_nok (error, FALSE);
502 values [MONO_METHOD_FLAGS] = mb->attrs;
503 values [MONO_METHOD_IMPLFLAGS] = mb->iattrs;
504 values [MONO_METHOD_SIGNATURE] = mono_dynimage_encode_method_builder_signature (assembly, mb, error);
505 return_val_if_nok (error, FALSE);
506 values [MONO_METHOD_RVA] = method_encode_code (assembly, mb, error);
507 return_val_if_nok (error, FALSE);
509 table = &assembly->tables [MONO_TABLE_PARAM];
510 values [MONO_METHOD_PARAMLIST] = table->next_idx;
512 mono_image_add_decl_security (assembly,
513 mono_metadata_make_token (MONO_TABLE_METHOD, *mb->table_idx), mb->permissions);
516 MonoDynamicTable *mtable;
519 mtable = &assembly->tables [MONO_TABLE_FIELDMARSHAL];
520 mvalues = mtable->values + mtable->next_idx * MONO_FIELD_MARSHAL_SIZE;
523 for (i = 0; i < mono_array_length (mb->pinfo); ++i) {
524 if (mono_array_get (mb->pinfo, gpointer, i))
527 table->rows += count;
528 alloc_table (table, table->rows);
529 values = table->values + table->next_idx * MONO_PARAM_SIZE;
530 for (i = 0; i < mono_array_length (mb->pinfo); ++i) {
531 MonoReflectionParamBuilder *pb;
532 if ((pb = mono_array_get (mb->pinfo, MonoReflectionParamBuilder*, i))) {
533 values [MONO_PARAM_FLAGS] = pb->attrs;
534 values [MONO_PARAM_SEQUENCE] = i;
535 if (pb->name != NULL) {
536 values [MONO_PARAM_NAME] = string_heap_insert_mstring (&assembly->sheap, pb->name, error);
537 return_val_if_nok (error, FALSE);
539 values [MONO_PARAM_NAME] = 0;
541 values += MONO_PARAM_SIZE;
542 if (pb->marshal_info) {
544 alloc_table (mtable, mtable->rows);
545 mvalues = mtable->values + mtable->rows * MONO_FIELD_MARSHAL_SIZE;
546 mvalues [MONO_FIELD_MARSHAL_PARENT] = (table->next_idx << MONO_HAS_FIELD_MARSHAL_BITS) | MONO_HAS_FIELD_MARSHAL_PARAMDEF;
547 mvalues [MONO_FIELD_MARSHAL_NATIVE_TYPE] = mono_dynimage_save_encode_marshal_blob (assembly, pb->marshal_info, error);
548 return_val_if_nok (error, FALSE);
550 pb->table_idx = table->next_idx++;
551 if (pb->attrs & PARAM_ATTRIBUTE_HAS_DEFAULT) {
552 guint32 field_type = 0;
553 mtable = &assembly->tables [MONO_TABLE_CONSTANT];
555 alloc_table (mtable, mtable->rows);
556 mvalues = mtable->values + mtable->rows * MONO_CONSTANT_SIZE;
557 mvalues [MONO_CONSTANT_PARENT] = MONO_HASCONSTANT_PARAM | (pb->table_idx << MONO_HASCONSTANT_BITS);
558 mvalues [MONO_CONSTANT_VALUE] = mono_dynimage_encode_constant (assembly, pb->def_value, &field_type);
559 mvalues [MONO_CONSTANT_TYPE] = field_type;
560 mvalues [MONO_CONSTANT_PADDING] = 0;
570 mono_image_add_methodimpl (MonoDynamicImage *assembly, MonoReflectionMethodBuilder *mb, MonoError *error)
572 MONO_REQ_GC_UNSAFE_MODE;
574 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mb->type;
575 MonoDynamicTable *table;
578 MonoReflectionMethod *m;
581 mono_error_init (error);
583 if (!mb->override_methods)
586 for (i = 0; i < mono_array_length (mb->override_methods); ++i) {
587 m = mono_array_get (mb->override_methods, MonoReflectionMethod*, i);
589 table = &assembly->tables [MONO_TABLE_METHODIMPL];
591 alloc_table (table, table->rows);
592 values = table->values + table->rows * MONO_METHODIMPL_SIZE;
593 values [MONO_METHODIMPL_CLASS] = tb->table_idx;
594 values [MONO_METHODIMPL_BODY] = MONO_METHODDEFORREF_METHODDEF | (mb->table_idx << MONO_METHODDEFORREF_BITS);
596 tok = image_create_token_raw (assembly, (MonoObject*)m, FALSE, FALSE, error); /* FIXME use handles */
597 return_val_if_nok (error, FALSE);
599 switch (mono_metadata_token_table (tok)) {
600 case MONO_TABLE_MEMBERREF:
601 tok = (mono_metadata_token_index (tok) << MONO_METHODDEFORREF_BITS ) | MONO_METHODDEFORREF_METHODREF;
603 case MONO_TABLE_METHOD:
604 tok = (mono_metadata_token_index (tok) << MONO_METHODDEFORREF_BITS ) | MONO_METHODDEFORREF_METHODDEF;
607 g_assert_not_reached ();
609 values [MONO_METHODIMPL_DECLARATION] = tok;
615 #ifndef DISABLE_REFLECTION_EMIT
617 mono_image_get_method_info (MonoReflectionMethodBuilder *mb, MonoDynamicImage *assembly, MonoError *error)
619 MONO_REQ_GC_UNSAFE_MODE;
621 MonoDynamicTable *table;
623 ReflectionMethodBuilder rmb;
626 mono_error_init (error);
628 if (!mono_reflection_methodbuilder_from_method_builder (&rmb, mb, error) ||
629 !mono_image_basic_method (&rmb, assembly, error))
632 mb->table_idx = *rmb.table_idx;
634 if (mb->dll) { /* It's a P/Invoke method */
636 /* map CharSet values to on-disk values */
637 int ncharset = (mb->charset ? (mb->charset - 1) * 2 : 0);
638 int extra_flags = mb->extra_flags;
639 table = &assembly->tables [MONO_TABLE_IMPLMAP];
641 alloc_table (table, table->rows);
642 values = table->values + table->rows * MONO_IMPLMAP_SIZE;
644 values [MONO_IMPLMAP_FLAGS] = (mb->native_cc << 8) | ncharset | extra_flags;
645 values [MONO_IMPLMAP_MEMBER] = (mb->table_idx << 1) | 1; /* memberforwarded: method */
647 values [MONO_IMPLMAP_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->dllentry, error);
648 return_val_if_nok (error, FALSE);
650 values [MONO_IMPLMAP_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->name, error);
651 return_val_if_nok (error, FALSE);
653 moduleref = string_heap_insert_mstring (&assembly->sheap, mb->dll, error);
654 return_val_if_nok (error, FALSE);
655 if (!(values [MONO_IMPLMAP_SCOPE] = find_index_in_table (assembly, MONO_TABLE_MODULEREF, MONO_MODULEREF_NAME, moduleref))) {
656 table = &assembly->tables [MONO_TABLE_MODULEREF];
658 alloc_table (table, table->rows);
659 table->values [table->rows * MONO_MODULEREF_SIZE + MONO_MODULEREF_NAME] = moduleref;
660 values [MONO_IMPLMAP_SCOPE] = table->rows;
664 if (mb->generic_params) {
665 table = &assembly->tables [MONO_TABLE_GENERICPARAM];
666 table->rows += mono_array_length (mb->generic_params);
667 alloc_table (table, table->rows);
668 for (i = 0; i < mono_array_length (mb->generic_params); ++i) {
669 guint32 owner = MONO_TYPEORMETHOD_METHOD | (mb->table_idx << MONO_TYPEORMETHOD_BITS);
671 mono_image_get_generic_param_info (
672 (MonoReflectionGenericParam *)mono_array_get (mb->generic_params, gpointer, i), owner, assembly);
680 mono_image_get_ctor_info (MonoDomain *domain, MonoReflectionCtorBuilder *mb, MonoDynamicImage *assembly, MonoError *error)
682 MONO_REQ_GC_UNSAFE_MODE;
684 ReflectionMethodBuilder rmb;
686 if (!mono_reflection_methodbuilder_from_ctor_builder (&rmb, mb, error))
689 if (!mono_image_basic_method (&rmb, assembly, error))
692 mb->table_idx = *rmb.table_idx;
699 mono_image_get_field_info (MonoReflectionFieldBuilder *fb, MonoDynamicImage *assembly, MonoError *error)
701 MONO_REQ_GC_UNSAFE_MODE;
703 mono_error_init (error);
705 MonoDynamicTable *table;
708 /* maybe this fixup should be done in the C# code */
709 if (fb->attrs & FIELD_ATTRIBUTE_LITERAL)
710 fb->attrs |= FIELD_ATTRIBUTE_HAS_DEFAULT;
711 table = &assembly->tables [MONO_TABLE_FIELD];
712 fb->table_idx = table->next_idx ++;
713 g_hash_table_insert (assembly->field_to_table_idx, fb->handle, GUINT_TO_POINTER (fb->table_idx));
714 values = table->values + fb->table_idx * MONO_FIELD_SIZE;
715 values [MONO_FIELD_NAME] = string_heap_insert_mstring (&assembly->sheap, fb->name, error);
716 return_if_nok (error);
717 values [MONO_FIELD_FLAGS] = fb->attrs;
718 values [MONO_FIELD_SIGNATURE] = mono_dynimage_encode_field_signature (assembly, fb, error);
719 return_if_nok (error);
721 if (fb->offset != -1) {
722 table = &assembly->tables [MONO_TABLE_FIELDLAYOUT];
724 alloc_table (table, table->rows);
725 values = table->values + table->rows * MONO_FIELD_LAYOUT_SIZE;
726 values [MONO_FIELD_LAYOUT_FIELD] = fb->table_idx;
727 values [MONO_FIELD_LAYOUT_OFFSET] = fb->offset;
729 if (fb->attrs & FIELD_ATTRIBUTE_LITERAL) {
730 MonoTypeEnum field_type = (MonoTypeEnum)0;
731 table = &assembly->tables [MONO_TABLE_CONSTANT];
733 alloc_table (table, table->rows);
734 values = table->values + table->rows * MONO_CONSTANT_SIZE;
735 values [MONO_CONSTANT_PARENT] = MONO_HASCONSTANT_FIEDDEF | (fb->table_idx << MONO_HASCONSTANT_BITS);
736 values [MONO_CONSTANT_VALUE] = mono_dynimage_encode_constant (assembly, fb->def_value, &field_type);
737 values [MONO_CONSTANT_TYPE] = field_type;
738 values [MONO_CONSTANT_PADDING] = 0;
740 if (fb->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA) {
742 table = &assembly->tables [MONO_TABLE_FIELDRVA];
744 alloc_table (table, table->rows);
745 values = table->values + table->rows * MONO_FIELD_RVA_SIZE;
746 values [MONO_FIELD_RVA_FIELD] = fb->table_idx;
748 * We store it in the code section because it's simpler for now.
751 if (mono_array_length (fb->rva_data) >= 10)
752 stream_data_align (&assembly->code);
753 rva_idx = mono_image_add_stream_data (&assembly->code, mono_array_addr (fb->rva_data, char, 0), mono_array_length (fb->rva_data));
755 rva_idx = mono_image_add_stream_zero (&assembly->code, mono_class_value_size (fb->handle->parent, NULL));
756 values [MONO_FIELD_RVA_RVA] = rva_idx + assembly->text_rva;
758 if (fb->marshal_info) {
759 table = &assembly->tables [MONO_TABLE_FIELDMARSHAL];
761 alloc_table (table, table->rows);
762 values = table->values + table->rows * MONO_FIELD_MARSHAL_SIZE;
763 values [MONO_FIELD_MARSHAL_PARENT] = (fb->table_idx << MONO_HAS_FIELD_MARSHAL_BITS) | MONO_HAS_FIELD_MARSHAL_FIELDSREF;
764 values [MONO_FIELD_MARSHAL_NATIVE_TYPE] = mono_dynimage_save_encode_marshal_blob (assembly, fb->marshal_info, error);
765 return_if_nok (error);
770 mono_image_get_property_info (MonoReflectionPropertyBuilder *pb, MonoDynamicImage *assembly, MonoError *error)
772 MONO_REQ_GC_UNSAFE_MODE;
774 mono_error_init (error);
776 MonoDynamicTable *table;
778 guint num_methods = 0;
782 * we need to set things in the following tables:
783 * PROPERTYMAP (info already filled in _get_type_info ())
784 * PROPERTY (rows already preallocated in _get_type_info ())
785 * METHOD (method info already done with the generic method code)
789 table = &assembly->tables [MONO_TABLE_PROPERTY];
790 pb->table_idx = table->next_idx ++;
791 values = table->values + pb->table_idx * MONO_PROPERTY_SIZE;
792 values [MONO_PROPERTY_NAME] = string_heap_insert_mstring (&assembly->sheap, pb->name, error);
793 return_if_nok (error);
794 values [MONO_PROPERTY_FLAGS] = pb->attrs;
795 values [MONO_PROPERTY_TYPE] = mono_dynimage_save_encode_property_signature (assembly, pb, error);
796 return_if_nok (error);
799 /* FIXME: we still don't handle 'other' methods */
800 if (pb->get_method) num_methods ++;
801 if (pb->set_method) num_methods ++;
803 table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
804 table->rows += num_methods;
805 alloc_table (table, table->rows);
807 if (pb->get_method) {
808 semaidx = table->next_idx ++;
809 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
810 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_GETTER;
811 values [MONO_METHOD_SEMA_METHOD] = pb->get_method->table_idx;
812 values [MONO_METHOD_SEMA_ASSOCIATION] = (pb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_PROPERTY;
814 if (pb->set_method) {
815 semaidx = table->next_idx ++;
816 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
817 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_SETTER;
818 values [MONO_METHOD_SEMA_METHOD] = pb->set_method->table_idx;
819 values [MONO_METHOD_SEMA_ASSOCIATION] = (pb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_PROPERTY;
821 if (pb->attrs & PROPERTY_ATTRIBUTE_HAS_DEFAULT) {
822 MonoTypeEnum field_type = (MonoTypeEnum)0;
823 table = &assembly->tables [MONO_TABLE_CONSTANT];
825 alloc_table (table, table->rows);
826 values = table->values + table->rows * MONO_CONSTANT_SIZE;
827 values [MONO_CONSTANT_PARENT] = MONO_HASCONSTANT_PROPERTY | (pb->table_idx << MONO_HASCONSTANT_BITS);
828 values [MONO_CONSTANT_VALUE] = mono_dynimage_encode_constant (assembly, pb->def_value, &field_type);
829 values [MONO_CONSTANT_TYPE] = field_type;
830 values [MONO_CONSTANT_PADDING] = 0;
835 mono_image_get_event_info (MonoReflectionEventBuilder *eb, MonoDynamicImage *assembly, MonoError *error)
837 MONO_REQ_GC_UNSAFE_MODE;
839 MonoDynamicTable *table;
841 guint num_methods = 0;
845 * we need to set things in the following tables:
846 * EVENTMAP (info already filled in _get_type_info ())
847 * EVENT (rows already preallocated in _get_type_info ())
848 * METHOD (method info already done with the generic method code)
851 table = &assembly->tables [MONO_TABLE_EVENT];
852 eb->table_idx = table->next_idx ++;
853 values = table->values + eb->table_idx * MONO_EVENT_SIZE;
854 values [MONO_EVENT_NAME] = string_heap_insert_mstring (&assembly->sheap, eb->name, error);
855 return_if_nok (error);
856 values [MONO_EVENT_FLAGS] = eb->attrs;
857 MonoType *ebtype = mono_reflection_type_get_handle (eb->type, error);
858 return_if_nok (error);
859 values [MONO_EVENT_TYPE] = mono_image_typedef_or_ref (assembly, ebtype);
862 * FIXME: we still don't handle 'other' methods
864 if (eb->add_method) num_methods ++;
865 if (eb->remove_method) num_methods ++;
866 if (eb->raise_method) num_methods ++;
868 table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
869 table->rows += num_methods;
870 alloc_table (table, table->rows);
872 if (eb->add_method) {
873 semaidx = table->next_idx ++;
874 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
875 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_ADD_ON;
876 values [MONO_METHOD_SEMA_METHOD] = eb->add_method->table_idx;
877 values [MONO_METHOD_SEMA_ASSOCIATION] = (eb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_EVENT;
879 if (eb->remove_method) {
880 semaidx = table->next_idx ++;
881 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
882 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_REMOVE_ON;
883 values [MONO_METHOD_SEMA_METHOD] = eb->remove_method->table_idx;
884 values [MONO_METHOD_SEMA_ASSOCIATION] = (eb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_EVENT;
886 if (eb->raise_method) {
887 semaidx = table->next_idx ++;
888 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
889 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_FIRE;
890 values [MONO_METHOD_SEMA_METHOD] = eb->raise_method->table_idx;
891 values [MONO_METHOD_SEMA_ASSOCIATION] = (eb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_EVENT;
896 encode_constraints (MonoReflectionGenericParam *gparam, guint32 owner, MonoDynamicImage *assembly, MonoError *error)
898 MONO_REQ_GC_UNSAFE_MODE;
900 mono_error_init (error);
902 MonoDynamicTable *table;
903 guint32 num_constraints, i;
907 table = &assembly->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
908 num_constraints = gparam->iface_constraints ?
909 mono_array_length (gparam->iface_constraints) : 0;
910 table->rows += num_constraints;
911 if (gparam->base_type)
913 alloc_table (table, table->rows);
915 if (gparam->base_type) {
916 table_idx = table->next_idx ++;
917 values = table->values + table_idx * MONO_GENPARCONSTRAINT_SIZE;
919 MonoType *gpbasetype = mono_reflection_type_get_handle (gparam->base_type, error);
920 return_if_nok (error);
921 values [MONO_GENPARCONSTRAINT_GENERICPAR] = owner;
922 values [MONO_GENPARCONSTRAINT_CONSTRAINT] = mono_image_typedef_or_ref (assembly, gpbasetype);
925 for (i = 0; i < num_constraints; i++) {
926 MonoReflectionType *constraint = (MonoReflectionType *)mono_array_get (
927 gparam->iface_constraints, gpointer, i);
929 table_idx = table->next_idx ++;
930 values = table->values + table_idx * MONO_GENPARCONSTRAINT_SIZE;
932 MonoType *constraint_type = mono_reflection_type_get_handle (constraint, error);
933 return_if_nok (error);
935 values [MONO_GENPARCONSTRAINT_GENERICPAR] = owner;
936 values [MONO_GENPARCONSTRAINT_CONSTRAINT] = mono_image_typedef_or_ref (assembly, constraint_type);
941 mono_image_get_generic_param_info (MonoReflectionGenericParam *gparam, guint32 owner, MonoDynamicImage *assembly)
943 MONO_REQ_GC_UNSAFE_MODE;
945 GenericParamTableEntry *entry;
948 * The GenericParam table must be sorted according to the `owner' field.
949 * We need to do this sorting prior to writing the GenericParamConstraint
950 * table, since we have to use the final GenericParam table indices there
951 * and they must also be sorted.
954 entry = g_new0 (GenericParamTableEntry, 1);
955 entry->owner = owner;
956 /* FIXME: track where gen_params should be freed and remove the GC root as well */
957 MONO_GC_REGISTER_ROOT_IF_MOVING (entry->gparam, MONO_ROOT_SOURCE_REFLECTION, "reflection generic parameter");
958 entry->gparam = gparam;
960 g_ptr_array_add (assembly->gen_params, entry);
964 write_generic_param_entry (MonoDynamicImage *assembly, GenericParamTableEntry *entry, MonoError *error)
966 MONO_REQ_GC_UNSAFE_MODE;
968 MonoDynamicTable *table;
969 MonoGenericParam *param;
973 mono_error_init (error);
975 table = &assembly->tables [MONO_TABLE_GENERICPARAM];
976 table_idx = table->next_idx ++;
977 values = table->values + table_idx * MONO_GENERICPARAM_SIZE;
979 MonoType *gparam_type = mono_reflection_type_get_handle ((MonoReflectionType*)entry->gparam, error);
980 return_val_if_nok (error, FALSE);
982 param = gparam_type->data.generic_param;
984 values [MONO_GENERICPARAM_OWNER] = entry->owner;
985 values [MONO_GENERICPARAM_FLAGS] = entry->gparam->attrs;
986 values [MONO_GENERICPARAM_NUMBER] = mono_generic_param_num (param);
987 values [MONO_GENERICPARAM_NAME] = string_heap_insert (&assembly->sheap, mono_generic_param_info (param)->name);
989 if (!mono_image_add_cattrs (assembly, table_idx, MONO_CUSTOM_ATTR_GENERICPAR, entry->gparam->cattrs, error))
992 encode_constraints (entry->gparam, table_idx, assembly, error);
993 return_val_if_nok (error, FALSE);
999 collect_types (MonoPtrArray *types, MonoReflectionTypeBuilder *type)
1003 mono_ptr_array_append (*types, type);
1005 if (!type->subtypes)
1008 for (i = 0; i < mono_array_length (type->subtypes); ++i) {
1009 MonoReflectionTypeBuilder *subtype = mono_array_get (type->subtypes, MonoReflectionTypeBuilder*, i);
1010 collect_types (types, subtype);
1015 compare_types_by_table_idx (MonoReflectionTypeBuilder **type1, MonoReflectionTypeBuilder **type2)
1017 if ((*type1)->table_idx < (*type2)->table_idx)
1020 if ((*type1)->table_idx > (*type2)->table_idx)
1027 params_add_cattrs (MonoDynamicImage *assembly, MonoArray *pinfo, MonoError *error) {
1030 mono_error_init (error);
1033 for (i = 0; i < mono_array_length (pinfo); ++i) {
1034 MonoReflectionParamBuilder *pb;
1035 pb = mono_array_get (pinfo, MonoReflectionParamBuilder *, i);
1038 if (!mono_image_add_cattrs (assembly, pb->table_idx, MONO_CUSTOM_ATTR_PARAMDEF, pb->cattrs, error))
1046 type_add_cattrs (MonoDynamicImage *assembly, MonoReflectionTypeBuilder *tb, MonoError *error) {
1049 mono_error_init (error);
1051 if (!mono_image_add_cattrs (assembly, tb->table_idx, MONO_CUSTOM_ATTR_TYPEDEF, tb->cattrs, error))
1054 for (i = 0; i < tb->num_fields; ++i) {
1055 MonoReflectionFieldBuilder* fb;
1056 fb = mono_array_get (tb->fields, MonoReflectionFieldBuilder*, i);
1057 if (!mono_image_add_cattrs (assembly, fb->table_idx, MONO_CUSTOM_ATTR_FIELDDEF, fb->cattrs, error))
1062 for (i = 0; i < mono_array_length (tb->events); ++i) {
1063 MonoReflectionEventBuilder* eb;
1064 eb = mono_array_get (tb->events, MonoReflectionEventBuilder*, i);
1065 if (!mono_image_add_cattrs (assembly, eb->table_idx, MONO_CUSTOM_ATTR_EVENT, eb->cattrs, error))
1069 if (tb->properties) {
1070 for (i = 0; i < mono_array_length (tb->properties); ++i) {
1071 MonoReflectionPropertyBuilder* pb;
1072 pb = mono_array_get (tb->properties, MonoReflectionPropertyBuilder*, i);
1073 if (!mono_image_add_cattrs (assembly, pb->table_idx, MONO_CUSTOM_ATTR_PROPERTY, pb->cattrs, error))
1078 for (i = 0; i < mono_array_length (tb->ctors); ++i) {
1079 MonoReflectionCtorBuilder* cb;
1080 cb = mono_array_get (tb->ctors, MonoReflectionCtorBuilder*, i);
1081 if (!mono_image_add_cattrs (assembly, cb->table_idx, MONO_CUSTOM_ATTR_METHODDEF, cb->cattrs, error) ||
1082 !params_add_cattrs (assembly, cb->pinfo, error))
1088 for (i = 0; i < tb->num_methods; ++i) {
1089 MonoReflectionMethodBuilder* mb;
1090 mb = mono_array_get (tb->methods, MonoReflectionMethodBuilder*, i);
1091 if (!mono_image_add_cattrs (assembly, mb->table_idx, MONO_CUSTOM_ATTR_METHODDEF, mb->cattrs, error) ||
1092 !params_add_cattrs (assembly, mb->pinfo, error))
1098 for (i = 0; i < mono_array_length (tb->subtypes); ++i) {
1099 if (!type_add_cattrs (assembly, mono_array_get (tb->subtypes, MonoReflectionTypeBuilder*, i), error))
1108 module_add_cattrs (MonoDynamicImage *assembly, MonoReflectionModuleBuilder *moduleb, MonoError *error)
1112 mono_error_init (error);
1114 if (!mono_image_add_cattrs (assembly, moduleb->table_idx, MONO_CUSTOM_ATTR_MODULE, moduleb->cattrs, error))
1117 if (moduleb->global_methods) {
1118 for (i = 0; i < mono_array_length (moduleb->global_methods); ++i) {
1119 MonoReflectionMethodBuilder* mb = mono_array_get (moduleb->global_methods, MonoReflectionMethodBuilder*, i);
1120 if (!mono_image_add_cattrs (assembly, mb->table_idx, MONO_CUSTOM_ATTR_METHODDEF, mb->cattrs, error) ||
1121 !params_add_cattrs (assembly, mb->pinfo, error))
1126 if (moduleb->global_fields) {
1127 for (i = 0; i < mono_array_length (moduleb->global_fields); ++i) {
1128 MonoReflectionFieldBuilder *fb = mono_array_get (moduleb->global_fields, MonoReflectionFieldBuilder*, i);
1129 if (!mono_image_add_cattrs (assembly, fb->table_idx, MONO_CUSTOM_ATTR_FIELDDEF, fb->cattrs, error))
1134 if (moduleb->types) {
1135 for (i = 0; i < moduleb->num_types; ++i) {
1136 if (!type_add_cattrs (assembly, mono_array_get (moduleb->types, MonoReflectionTypeBuilder*, i), error))
1145 mono_image_fill_file_table (MonoDomain *domain, MonoReflectionModule *module, MonoDynamicImage *assembly, MonoError *error)
1147 MonoDynamicTable *table;
1151 char *b = blob_size;
1154 mono_error_init (error);
1156 table = &assembly->tables [MONO_TABLE_FILE];
1158 alloc_table (table, table->rows);
1159 values = table->values + table->next_idx * MONO_FILE_SIZE;
1160 values [MONO_FILE_FLAGS] = FILE_CONTAINS_METADATA;
1161 values [MONO_FILE_NAME] = string_heap_insert (&assembly->sheap, module->image->module_name);
1162 if (image_is_dynamic (module->image)) {
1163 /* This depends on the fact that the main module is emitted last */
1164 dir = mono_string_to_utf8_checked (((MonoReflectionModuleBuilder*)module)->assemblyb->dir, error);
1165 return_val_if_nok (error, FALSE);
1166 path = g_strdup_printf ("%s%c%s", dir, G_DIR_SEPARATOR, module->image->module_name);
1169 path = g_strdup (module->image->name);
1171 mono_sha1_get_digest_from_file (path, hash);
1174 mono_metadata_encode_value (20, b, &b);
1175 values [MONO_FILE_HASH_VALUE] = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
1176 mono_image_add_stream_data (&assembly->blob, (char*)hash, 20);
1182 mono_image_fill_module_table (MonoDomain *domain, MonoReflectionModuleBuilder *mb, MonoDynamicImage *assembly, MonoError *error)
1184 MonoDynamicTable *table;
1187 mono_error_init (error);
1189 table = &assembly->tables [MONO_TABLE_MODULE];
1190 mb->table_idx = table->next_idx ++;
1191 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->module.name, error);
1192 return_if_nok (error);
1193 i = mono_image_add_stream_data (&assembly->guid, mono_array_addr (mb->guid, char, 0), 16);
1196 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_GENERATION] = 0;
1197 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_MVID] = i;
1198 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_ENC] = 0;
1199 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_ENCBASE] = 0;
1203 mono_image_fill_export_table_from_class (MonoDomain *domain, MonoClass *klass,
1204 guint32 module_index, guint32 parent_index, MonoDynamicImage *assembly)
1206 MonoDynamicTable *table;
1210 visib = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_VISIBILITY_MASK;
1211 if (! ((visib & TYPE_ATTRIBUTE_PUBLIC) || (visib & TYPE_ATTRIBUTE_NESTED_PUBLIC)))
1214 table = &assembly->tables [MONO_TABLE_EXPORTEDTYPE];
1216 alloc_table (table, table->rows);
1217 values = table->values + table->next_idx * MONO_EXP_TYPE_SIZE;
1219 values [MONO_EXP_TYPE_FLAGS] = mono_class_get_flags (klass);
1220 values [MONO_EXP_TYPE_TYPEDEF] = klass->type_token;
1221 if (klass->nested_in)
1222 values [MONO_EXP_TYPE_IMPLEMENTATION] = (parent_index << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_EXP_TYPE;
1224 values [MONO_EXP_TYPE_IMPLEMENTATION] = (module_index << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_FILE;
1225 values [MONO_EXP_TYPE_NAME] = string_heap_insert (&assembly->sheap, klass->name);
1226 values [MONO_EXP_TYPE_NAMESPACE] = string_heap_insert (&assembly->sheap, klass->name_space);
1228 res = table->next_idx;
1232 /* Emit nested types */
1233 GList *nested_classes = mono_class_get_nested_classes_property (klass);
1235 for (tmp = nested_classes; tmp; tmp = tmp->next)
1236 mono_image_fill_export_table_from_class (domain, (MonoClass *)tmp->data, module_index, table->next_idx - 1, assembly);
1242 mono_image_fill_export_table (MonoDomain *domain, MonoReflectionTypeBuilder *tb,
1243 guint32 module_index, guint32 parent_index, MonoDynamicImage *assembly,
1249 mono_error_init (error);
1251 MonoType *t = mono_reflection_type_get_handle ((MonoReflectionType*)tb, error);
1252 return_if_nok (error);
1254 klass = mono_class_from_mono_type (t);
1256 klass->type_token = mono_metadata_make_token (MONO_TABLE_TYPEDEF, tb->table_idx);
1258 idx = mono_image_fill_export_table_from_class (domain, klass, module_index,
1259 parent_index, assembly);
1263 * We need to do this ourselves since klass->nested_classes is not set up.
1266 for (i = 0; i < mono_array_length (tb->subtypes); ++i) {
1267 mono_image_fill_export_table (domain, mono_array_get (tb->subtypes, MonoReflectionTypeBuilder*, i), module_index, idx, assembly, error);
1268 return_if_nok (error);
1274 mono_image_fill_export_table_from_module (MonoDomain *domain, MonoReflectionModule *module,
1275 guint32 module_index, MonoDynamicImage *assembly)
1277 MonoImage *image = module->image;
1281 t = &image->tables [MONO_TABLE_TYPEDEF];
1283 for (i = 0; i < t->rows; ++i) {
1285 MonoClass *klass = mono_class_get_checked (image, mono_metadata_make_token (MONO_TABLE_TYPEDEF, i + 1), &error);
1286 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
1288 if (mono_class_is_public (klass))
1289 mono_image_fill_export_table_from_class (domain, klass, module_index, 0, assembly);
1294 add_exported_type (MonoReflectionAssemblyBuilder *assemblyb, MonoDynamicImage *assembly, MonoClass *klass, guint32 parent_index)
1296 MonoDynamicTable *table;
1298 guint32 scope, scope_idx, impl, current_idx;
1299 gboolean forwarder = TRUE;
1300 gpointer iter = NULL;
1303 if (klass->nested_in) {
1304 impl = (parent_index << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_EXP_TYPE;
1307 scope = mono_reflection_resolution_scope_from_image (assembly, klass->image);
1308 g_assert ((scope & MONO_RESOLUTION_SCOPE_MASK) == MONO_RESOLUTION_SCOPE_ASSEMBLYREF);
1309 scope_idx = scope >> MONO_RESOLUTION_SCOPE_BITS;
1310 impl = (scope_idx << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_ASSEMBLYREF;
1313 table = &assembly->tables [MONO_TABLE_EXPORTEDTYPE];
1316 alloc_table (table, table->rows);
1317 current_idx = table->next_idx;
1318 values = table->values + current_idx * MONO_EXP_TYPE_SIZE;
1320 values [MONO_EXP_TYPE_FLAGS] = forwarder ? TYPE_ATTRIBUTE_FORWARDER : 0;
1321 values [MONO_EXP_TYPE_TYPEDEF] = 0;
1322 values [MONO_EXP_TYPE_IMPLEMENTATION] = impl;
1323 values [MONO_EXP_TYPE_NAME] = string_heap_insert (&assembly->sheap, klass->name);
1324 values [MONO_EXP_TYPE_NAMESPACE] = string_heap_insert (&assembly->sheap, klass->name_space);
1328 while ((nested = mono_class_get_nested_types (klass, &iter)))
1329 add_exported_type (assemblyb, assembly, nested, current_idx);
1333 mono_image_fill_export_table_from_type_forwarders (MonoReflectionAssemblyBuilder *assemblyb, MonoDynamicImage *assembly)
1339 if (!assemblyb->type_forwarders)
1342 for (i = 0; i < mono_array_length (assemblyb->type_forwarders); ++i) {
1343 MonoReflectionType *t = mono_array_get (assemblyb->type_forwarders, MonoReflectionType *, i);
1348 type = mono_reflection_type_get_handle (t, &error);
1349 mono_error_assert_ok (&error);
1352 klass = mono_class_from_mono_type (type);
1354 add_exported_type (assemblyb, assembly, klass, 0);
1358 #define align_pointer(base,p)\
1360 guint32 __diff = (unsigned char*)(p)-(unsigned char*)(base);\
1362 (p) += 4 - (__diff & 3);\
1366 compare_constants (const void *a, const void *b)
1368 const guint32 *a_values = (const guint32 *)a;
1369 const guint32 *b_values = (const guint32 *)b;
1370 return a_values [MONO_CONSTANT_PARENT] - b_values [MONO_CONSTANT_PARENT];
1374 compare_semantics (const void *a, const void *b)
1376 const guint32 *a_values = (const guint32 *)a;
1377 const guint32 *b_values = (const guint32 *)b;
1378 int assoc = a_values [MONO_METHOD_SEMA_ASSOCIATION] - b_values [MONO_METHOD_SEMA_ASSOCIATION];
1381 return a_values [MONO_METHOD_SEMA_SEMANTICS] - b_values [MONO_METHOD_SEMA_SEMANTICS];
1385 compare_custom_attrs (const void *a, const void *b)
1387 const guint32 *a_values = (const guint32 *)a;
1388 const guint32 *b_values = (const guint32 *)b;
1390 return a_values [MONO_CUSTOM_ATTR_PARENT] - b_values [MONO_CUSTOM_ATTR_PARENT];
1394 compare_field_marshal (const void *a, const void *b)
1396 const guint32 *a_values = (const guint32 *)a;
1397 const guint32 *b_values = (const guint32 *)b;
1399 return a_values [MONO_FIELD_MARSHAL_PARENT] - b_values [MONO_FIELD_MARSHAL_PARENT];
1403 compare_nested (const void *a, const void *b)
1405 const guint32 *a_values = (const guint32 *)a;
1406 const guint32 *b_values = (const guint32 *)b;
1408 return a_values [MONO_NESTED_CLASS_NESTED] - b_values [MONO_NESTED_CLASS_NESTED];
1412 compare_genericparam (const void *a, const void *b)
1415 const GenericParamTableEntry **a_entry = (const GenericParamTableEntry **) a;
1416 const GenericParamTableEntry **b_entry = (const GenericParamTableEntry **) b;
1418 if ((*b_entry)->owner == (*a_entry)->owner) {
1419 MonoType *a_type = mono_reflection_type_get_handle ((MonoReflectionType*)(*a_entry)->gparam, &error);
1420 mono_error_assert_ok (&error);
1421 MonoType *b_type = mono_reflection_type_get_handle ((MonoReflectionType*)(*b_entry)->gparam, &error);
1422 mono_error_assert_ok (&error);
1424 mono_type_get_generic_param_num (a_type) -
1425 mono_type_get_generic_param_num (b_type);
1427 return (*a_entry)->owner - (*b_entry)->owner;
1431 compare_declsecurity_attrs (const void *a, const void *b)
1433 const guint32 *a_values = (const guint32 *)a;
1434 const guint32 *b_values = (const guint32 *)b;
1436 return a_values [MONO_DECL_SECURITY_PARENT] - b_values [MONO_DECL_SECURITY_PARENT];
1440 compare_interface_impl (const void *a, const void *b)
1442 const guint32 *a_values = (const guint32 *)a;
1443 const guint32 *b_values = (const guint32 *)b;
1445 int klass = a_values [MONO_INTERFACEIMPL_CLASS] - b_values [MONO_INTERFACEIMPL_CLASS];
1449 return a_values [MONO_INTERFACEIMPL_INTERFACE] - b_values [MONO_INTERFACEIMPL_INTERFACE];
1454 MonoDynamicStream *stream;
1458 * build_compressed_metadata() fills in the blob of data that represents the
1459 * raw metadata as it will be saved in the PE file. The five streams are output
1460 * and the metadata tables are comnpressed from the guint32 array representation,
1461 * to the compressed on-disk format.
1464 build_compressed_metadata (MonoDynamicImage *assembly, MonoError *error)
1466 MonoDynamicTable *table;
1468 guint64 valid_mask = 0;
1469 guint64 sorted_mask;
1470 guint32 heapt_size = 0;
1471 guint32 meta_size = 256; /* allow for header and other stuff */
1472 guint32 table_offset;
1473 guint32 ntables = 0;
1479 struct StreamDesc stream_desc [5];
1481 mono_error_init (error);
1483 qsort (assembly->gen_params->pdata, assembly->gen_params->len, sizeof (gpointer), compare_genericparam);
1484 for (i = 0; i < assembly->gen_params->len; i++) {
1485 GenericParamTableEntry *entry = (GenericParamTableEntry *)g_ptr_array_index (assembly->gen_params, i);
1486 if (!write_generic_param_entry (assembly, entry, error))
1490 stream_desc [0].name = "#~";
1491 stream_desc [0].stream = &assembly->tstream;
1492 stream_desc [1].name = "#Strings";
1493 stream_desc [1].stream = &assembly->sheap;
1494 stream_desc [2].name = "#US";
1495 stream_desc [2].stream = &assembly->us;
1496 stream_desc [3].name = "#Blob";
1497 stream_desc [3].stream = &assembly->blob;
1498 stream_desc [4].name = "#GUID";
1499 stream_desc [4].stream = &assembly->guid;
1501 /* tables that are sorted */
1502 sorted_mask = ((guint64)1 << MONO_TABLE_CONSTANT) | ((guint64)1 << MONO_TABLE_FIELDMARSHAL)
1503 | ((guint64)1 << MONO_TABLE_METHODSEMANTICS) | ((guint64)1 << MONO_TABLE_CLASSLAYOUT)
1504 | ((guint64)1 << MONO_TABLE_FIELDLAYOUT) | ((guint64)1 << MONO_TABLE_FIELDRVA)
1505 | ((guint64)1 << MONO_TABLE_IMPLMAP) | ((guint64)1 << MONO_TABLE_NESTEDCLASS)
1506 | ((guint64)1 << MONO_TABLE_METHODIMPL) | ((guint64)1 << MONO_TABLE_CUSTOMATTRIBUTE)
1507 | ((guint64)1 << MONO_TABLE_DECLSECURITY) | ((guint64)1 << MONO_TABLE_GENERICPARAM)
1508 | ((guint64)1 << MONO_TABLE_INTERFACEIMPL);
1510 /* Compute table sizes */
1511 /* the MonoImage has already been created in mono_reflection_dynimage_basic_init() */
1512 meta = &assembly->image;
1514 /* sizes should be multiple of 4 */
1515 mono_dynstream_data_align (&assembly->blob);
1516 mono_dynstream_data_align (&assembly->guid);
1517 mono_dynstream_data_align (&assembly->sheap);
1518 mono_dynstream_data_align (&assembly->us);
1520 /* Setup the info used by compute_sizes () */
1521 meta->idx_blob_wide = assembly->blob.index >= 65536 ? 1 : 0;
1522 meta->idx_guid_wide = assembly->guid.index >= 65536 ? 1 : 0;
1523 meta->idx_string_wide = assembly->sheap.index >= 65536 ? 1 : 0;
1525 meta_size += assembly->blob.index;
1526 meta_size += assembly->guid.index;
1527 meta_size += assembly->sheap.index;
1528 meta_size += assembly->us.index;
1530 for (i=0; i < MONO_TABLE_NUM; ++i)
1531 meta->tables [i].rows = assembly->tables [i].rows;
1533 for (i = 0; i < MONO_TABLE_NUM; i++){
1534 if (meta->tables [i].rows == 0)
1536 valid_mask |= (guint64)1 << i;
1538 meta->tables [i].row_size = mono_metadata_compute_size (
1539 meta, i, &meta->tables [i].size_bitfield);
1540 heapt_size += meta->tables [i].row_size * meta->tables [i].rows;
1542 heapt_size += 24; /* #~ header size */
1543 heapt_size += ntables * 4;
1544 /* make multiple of 4 */
1547 meta_size += heapt_size;
1548 meta->raw_metadata = (char *)g_malloc0 (meta_size);
1549 p = (unsigned char*)meta->raw_metadata;
1550 /* the metadata signature */
1551 *p++ = 'B'; *p++ = 'S'; *p++ = 'J'; *p++ = 'B';
1552 /* version numbers and 4 bytes reserved */
1553 int16val = (guint16*)p;
1554 *int16val++ = GUINT16_TO_LE (meta->md_version_major);
1555 *int16val = GUINT16_TO_LE (meta->md_version_minor);
1557 /* version string */
1558 int32val = (guint32*)p;
1559 *int32val = GUINT32_TO_LE ((strlen (meta->version) + 3) & (~3)); /* needs to be multiple of 4 */
1561 memcpy (p, meta->version, strlen (meta->version));
1562 p += GUINT32_FROM_LE (*int32val);
1563 align_pointer (meta->raw_metadata, p);
1564 int16val = (guint16*)p;
1565 *int16val++ = GUINT16_TO_LE (0); /* flags must be 0 */
1566 *int16val = GUINT16_TO_LE (5); /* number of streams */
1570 * write the stream info.
1572 table_offset = (p - (unsigned char*)meta->raw_metadata) + 5 * 8 + 40; /* room needed for stream headers */
1573 table_offset += 3; table_offset &= ~3;
1575 assembly->tstream.index = heapt_size;
1576 for (i = 0; i < 5; ++i) {
1577 int32val = (guint32*)p;
1578 stream_desc [i].stream->offset = table_offset;
1579 *int32val++ = GUINT32_TO_LE (table_offset);
1580 *int32val = GUINT32_TO_LE (stream_desc [i].stream->index);
1581 table_offset += GUINT32_FROM_LE (*int32val);
1582 table_offset += 3; table_offset &= ~3;
1584 strcpy ((char*)p, stream_desc [i].name);
1585 p += strlen (stream_desc [i].name) + 1;
1586 align_pointer (meta->raw_metadata, p);
1589 * now copy the data, the table stream header and contents goes first.
1591 g_assert ((p - (unsigned char*)meta->raw_metadata) < assembly->tstream.offset);
1592 p = (guchar*)meta->raw_metadata + assembly->tstream.offset;
1593 int32val = (guint32*)p;
1594 *int32val = GUINT32_TO_LE (0); /* reserved */
1597 *p++ = 2; /* version */
1600 if (meta->idx_string_wide)
1602 if (meta->idx_guid_wide)
1604 if (meta->idx_blob_wide)
1607 *p++ = 1; /* reserved */
1608 int64val = (guint64*)p;
1609 *int64val++ = GUINT64_TO_LE (valid_mask);
1610 *int64val++ = GUINT64_TO_LE (valid_mask & sorted_mask); /* bitvector of sorted tables */
1612 int32val = (guint32*)p;
1613 for (i = 0; i < MONO_TABLE_NUM; i++){
1614 if (meta->tables [i].rows == 0)
1616 *int32val++ = GUINT32_TO_LE (meta->tables [i].rows);
1618 p = (unsigned char*)int32val;
1620 /* sort the tables that still need sorting */
1621 table = &assembly->tables [MONO_TABLE_CONSTANT];
1623 qsort (table->values + MONO_CONSTANT_SIZE, table->rows, sizeof (guint32) * MONO_CONSTANT_SIZE, compare_constants);
1624 table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
1626 qsort (table->values + MONO_METHOD_SEMA_SIZE, table->rows, sizeof (guint32) * MONO_METHOD_SEMA_SIZE, compare_semantics);
1627 table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1629 qsort (table->values + MONO_CUSTOM_ATTR_SIZE, table->rows, sizeof (guint32) * MONO_CUSTOM_ATTR_SIZE, compare_custom_attrs);
1630 table = &assembly->tables [MONO_TABLE_FIELDMARSHAL];
1632 qsort (table->values + MONO_FIELD_MARSHAL_SIZE, table->rows, sizeof (guint32) * MONO_FIELD_MARSHAL_SIZE, compare_field_marshal);
1633 table = &assembly->tables [MONO_TABLE_NESTEDCLASS];
1635 qsort (table->values + MONO_NESTED_CLASS_SIZE, table->rows, sizeof (guint32) * MONO_NESTED_CLASS_SIZE, compare_nested);
1636 /* Section 21.11 DeclSecurity in Partition II doesn't specify this to be sorted by MS implementation requires it */
1637 table = &assembly->tables [MONO_TABLE_DECLSECURITY];
1639 qsort (table->values + MONO_DECL_SECURITY_SIZE, table->rows, sizeof (guint32) * MONO_DECL_SECURITY_SIZE, compare_declsecurity_attrs);
1640 table = &assembly->tables [MONO_TABLE_INTERFACEIMPL];
1642 qsort (table->values + MONO_INTERFACEIMPL_SIZE, table->rows, sizeof (guint32) * MONO_INTERFACEIMPL_SIZE, compare_interface_impl);
1644 /* compress the tables */
1645 for (i = 0; i < MONO_TABLE_NUM; i++){
1648 guint32 bitfield = meta->tables [i].size_bitfield;
1649 if (!meta->tables [i].rows)
1651 if (assembly->tables [i].columns != mono_metadata_table_count (bitfield))
1652 g_error ("col count mismatch in %d: %d %d", i, assembly->tables [i].columns, mono_metadata_table_count (bitfield));
1653 meta->tables [i].base = (char*)p;
1654 for (row = 1; row <= meta->tables [i].rows; ++row) {
1655 values = assembly->tables [i].values + row * assembly->tables [i].columns;
1656 for (col = 0; col < assembly->tables [i].columns; ++col) {
1657 switch (mono_metadata_table_size (bitfield, col)) {
1659 *p++ = values [col];
1662 *p++ = values [col] & 0xff;
1663 *p++ = (values [col] >> 8) & 0xff;
1666 *p++ = values [col] & 0xff;
1667 *p++ = (values [col] >> 8) & 0xff;
1668 *p++ = (values [col] >> 16) & 0xff;
1669 *p++ = (values [col] >> 24) & 0xff;
1672 g_assert_not_reached ();
1676 g_assert ((p - (const unsigned char*)meta->tables [i].base) == (meta->tables [i].rows * meta->tables [i].row_size));
1679 g_assert (assembly->guid.offset + assembly->guid.index < meta_size);
1680 memcpy (meta->raw_metadata + assembly->sheap.offset, assembly->sheap.data, assembly->sheap.index);
1681 memcpy (meta->raw_metadata + assembly->us.offset, assembly->us.data, assembly->us.index);
1682 memcpy (meta->raw_metadata + assembly->blob.offset, assembly->blob.data, assembly->blob.index);
1683 memcpy (meta->raw_metadata + assembly->guid.offset, assembly->guid.data, assembly->guid.index);
1685 assembly->meta_size = assembly->guid.offset + assembly->guid.index;
1691 * Some tables in metadata need to be sorted according to some criteria, but
1692 * when methods and fields are first created with reflection, they may be assigned a token
1693 * that doesn't correspond to the final token they will get assigned after the sorting.
1694 * ILGenerator.cs keeps a fixup table that maps the position of tokens in the IL code stream
1695 * with the reflection objects that represent them. Once all the tables are set up, the
1696 * reflection objects will contains the correct table index. fixup_method() will fixup the
1697 * tokens for the method with ILGenerator @ilgen.
1700 fixup_method (MonoReflectionILGen *ilgen, gpointer value, MonoDynamicImage *assembly)
1702 guint32 code_idx = GPOINTER_TO_UINT (value);
1703 MonoReflectionILTokenInfo *iltoken;
1704 MonoReflectionTypeBuilder *tb;
1705 MonoReflectionArrayMethod *am;
1707 unsigned char *target;
1709 for (i = 0; i < ilgen->num_token_fixups; ++i) {
1710 iltoken = (MonoReflectionILTokenInfo *)mono_array_addr_with_size (ilgen->token_fixups, sizeof (MonoReflectionILTokenInfo), i);
1711 target = (guchar*)assembly->code.data + code_idx + iltoken->code_pos;
1712 switch (target [3]) {
1713 case MONO_TABLE_FIELD:
1714 if (!strcmp (iltoken->member->vtable->klass->name, "FieldBuilder")) {
1715 g_assert_not_reached ();
1716 } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoField")) {
1717 MonoClassField *f = ((MonoReflectionField*)iltoken->member)->field;
1718 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->field_to_table_idx, f));
1720 g_assert_not_reached ();
1723 case MONO_TABLE_METHOD:
1724 if (!strcmp (iltoken->member->vtable->klass->name, "MethodBuilder")) {
1725 g_assert_not_reached ();
1726 } else if (!strcmp (iltoken->member->vtable->klass->name, "ConstructorBuilder")) {
1727 g_assert_not_reached ();
1728 } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoMethod") ||
1729 !strcmp (iltoken->member->vtable->klass->name, "MonoCMethod")) {
1730 MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
1731 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, m));
1733 g_assert_not_reached ();
1736 case MONO_TABLE_TYPEDEF:
1737 if (!strcmp (iltoken->member->vtable->klass->name, "TypeBuilder")) {
1738 g_assert_not_reached ();
1739 } else if (!strcmp (iltoken->member->vtable->klass->name, "RuntimeType")) {
1740 MonoClass *k = mono_class_from_mono_type (((MonoReflectionType*)iltoken->member)->type);
1741 MonoObject *obj = mono_class_get_ref_info_raw (k); /* FIXME use handles */
1743 g_assert (!strcmp (mono_object_class (obj)->name, "TypeBuilder"));
1744 tb = (MonoReflectionTypeBuilder*)obj;
1745 idx = tb->table_idx;
1747 g_assert_not_reached ();
1750 case MONO_TABLE_MEMBERREF:
1751 if (!strcmp (iltoken->member->vtable->klass->name, "MonoArrayMethod")) {
1752 am = (MonoReflectionArrayMethod*)iltoken->member;
1753 idx = am->table_idx;
1754 } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoMethod") ||
1755 !strcmp (iltoken->member->vtable->klass->name, "MonoCMethod")) {
1756 MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
1757 g_assert (mono_class_is_ginst (m->klass) || mono_class_is_gtd (m->klass));
1759 } else if (!strcmp (iltoken->member->vtable->klass->name, "FieldBuilder")) {
1760 g_assert_not_reached ();
1762 } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoField")) {
1764 } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodBuilder") ||
1765 !strcmp (iltoken->member->vtable->klass->name, "ConstructorBuilder")) {
1766 g_assert_not_reached ();
1768 } else if (!strcmp (iltoken->member->vtable->klass->name, "FieldOnTypeBuilderInst")) {
1769 g_assert_not_reached ();
1771 } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodOnTypeBuilderInst")) {
1772 g_assert_not_reached ();
1774 } else if (!strcmp (iltoken->member->vtable->klass->name, "ConstructorOnTypeBuilderInst")) {
1775 g_assert_not_reached ();
1778 g_assert_not_reached ();
1781 case MONO_TABLE_METHODSPEC:
1782 if (!strcmp (iltoken->member->vtable->klass->name, "MonoMethod")) {
1783 MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
1784 g_assert (mono_method_signature (m)->generic_param_count);
1786 } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodBuilder")) {
1787 g_assert_not_reached ();
1789 } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodOnTypeBuilderInst")) {
1790 g_assert_not_reached ();
1793 g_assert_not_reached ();
1796 case MONO_TABLE_TYPESPEC:
1797 if (!strcmp (iltoken->member->vtable->klass->name, "RuntimeType")) {
1800 g_assert_not_reached ();
1804 g_error ("got unexpected table 0x%02x in fixup", target [3]);
1806 target [0] = idx & 0xff;
1807 target [1] = (idx >> 8) & 0xff;
1808 target [2] = (idx >> 16) & 0xff;
1815 * The CUSTOM_ATTRIBUTE table might contain METHODDEF tokens whose final
1816 * value is not known when the table is emitted.
1819 fixup_cattrs (MonoDynamicImage *assembly)
1821 MonoDynamicTable *table;
1823 guint32 type, i, idx, token;
1826 table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1828 for (i = 0; i < table->rows; ++i) {
1829 values = table->values + ((i + 1) * MONO_CUSTOM_ATTR_SIZE);
1831 type = values [MONO_CUSTOM_ATTR_TYPE];
1832 if ((type & MONO_CUSTOM_ATTR_TYPE_MASK) == MONO_CUSTOM_ATTR_TYPE_METHODDEF) {
1833 idx = type >> MONO_CUSTOM_ATTR_TYPE_BITS;
1834 token = mono_metadata_make_token (MONO_TABLE_METHOD, idx);
1835 ctor = (MonoObject *)mono_g_hash_table_lookup (assembly->remapped_tokens, GUINT_TO_POINTER (token));
1838 if (!strcmp (ctor->vtable->klass->name, "MonoCMethod")) {
1839 MonoMethod *m = ((MonoReflectionMethod*)ctor)->method;
1840 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, m));
1841 values [MONO_CUSTOM_ATTR_TYPE] = (idx << MONO_CUSTOM_ATTR_TYPE_BITS) | MONO_CUSTOM_ATTR_TYPE_METHODDEF;
1842 } else if (!strcmp (ctor->vtable->klass->name, "ConstructorBuilder")) {
1843 MonoMethod *m = ((MonoReflectionCtorBuilder*)ctor)->mhandle;
1844 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, m));
1845 values [MONO_CUSTOM_ATTR_TYPE] = (idx << MONO_CUSTOM_ATTR_TYPE_BITS) | MONO_CUSTOM_ATTR_TYPE_METHODDEF;
1852 assembly_add_resource_manifest (MonoReflectionModuleBuilder *mb, MonoDynamicImage *assembly, MonoReflectionResource *rsrc, guint32 implementation, MonoError *error)
1854 MonoDynamicTable *table;
1857 mono_error_init (error);
1859 table = &assembly->tables [MONO_TABLE_MANIFESTRESOURCE];
1861 alloc_table (table, table->rows);
1862 values = table->values + table->next_idx * MONO_MANIFEST_SIZE;
1863 values [MONO_MANIFEST_OFFSET] = rsrc->offset;
1864 values [MONO_MANIFEST_FLAGS] = rsrc->attrs;
1865 values [MONO_MANIFEST_NAME] = string_heap_insert_mstring (&assembly->sheap, rsrc->name, error);
1866 return_val_if_nok (error, FALSE);
1867 values [MONO_MANIFEST_IMPLEMENTATION] = implementation;
1873 assembly_add_resource (MonoReflectionModuleBuilder *mb, MonoDynamicImage *assembly, MonoReflectionResource *rsrc, MonoError *error)
1875 MonoDynamicTable *table;
1879 char *b = blob_size;
1881 guint32 idx, offset;
1883 mono_error_init (error);
1885 if (rsrc->filename) {
1886 name = mono_string_to_utf8_checked (rsrc->filename, error);
1887 return_val_if_nok (error, FALSE);
1888 sname = g_path_get_basename (name);
1890 table = &assembly->tables [MONO_TABLE_FILE];
1892 alloc_table (table, table->rows);
1893 values = table->values + table->next_idx * MONO_FILE_SIZE;
1894 values [MONO_FILE_FLAGS] = FILE_CONTAINS_NO_METADATA;
1895 values [MONO_FILE_NAME] = string_heap_insert (&assembly->sheap, sname);
1898 mono_sha1_get_digest_from_file (name, hash);
1899 mono_metadata_encode_value (20, b, &b);
1900 values [MONO_FILE_HASH_VALUE] = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
1901 mono_image_add_stream_data (&assembly->blob, (char*)hash, 20);
1903 idx = table->next_idx++;
1905 idx = MONO_IMPLEMENTATION_FILE | (idx << MONO_IMPLEMENTATION_BITS);
1911 data = mono_array_addr (rsrc->data, char, 0);
1912 len = mono_array_length (rsrc->data);
1918 sizebuf [0] = offset; sizebuf [1] = offset >> 8;
1919 sizebuf [2] = offset >> 16; sizebuf [3] = offset >> 24;
1920 rsrc->offset = mono_image_add_stream_data (&assembly->resources, sizebuf, 4);
1921 mono_image_add_stream_data (&assembly->resources, data, len);
1925 * The entry should be emitted into the MANIFESTRESOURCE table of
1926 * the main module, but that needs to reference the FILE table
1927 * which isn't emitted yet.
1934 return assembly_add_resource_manifest (mb, assembly, rsrc, idx, error);
1938 set_version_from_string (MonoString *version, guint32 *values, MonoError *error)
1940 gchar *ver, *p, *str;
1943 mono_error_init (error);
1945 values [MONO_ASSEMBLY_MAJOR_VERSION] = 0;
1946 values [MONO_ASSEMBLY_MINOR_VERSION] = 0;
1947 values [MONO_ASSEMBLY_REV_NUMBER] = 0;
1948 values [MONO_ASSEMBLY_BUILD_NUMBER] = 0;
1951 ver = str = mono_string_to_utf8_checked (version, error);
1952 return_val_if_nok (error, FALSE);
1953 for (i = 0; i < 4; ++i) {
1954 values [MONO_ASSEMBLY_MAJOR_VERSION + i] = strtol (ver, &p, 10);
1960 /* handle Revision and Build */
1971 load_public_key (MonoArray *pkey, MonoDynamicImage *assembly) {
1975 char *b = blob_size;
1980 len = mono_array_length (pkey);
1981 mono_metadata_encode_value (len, b, &b);
1982 token = mono_image_add_stream_data (&assembly->blob, blob_size, b - blob_size);
1983 mono_image_add_stream_data (&assembly->blob, mono_array_addr (pkey, char, 0), len);
1985 assembly->public_key = (guint8 *)g_malloc (len);
1986 memcpy (assembly->public_key, mono_array_addr (pkey, char, 0), len);
1987 assembly->public_key_len = len;
1989 /* Special case: check for ECMA key (16 bytes) */
1990 if ((len == MONO_ECMA_KEY_LENGTH) && mono_is_ecma_key (mono_array_addr (pkey, char, 0), len)) {
1991 /* In this case we must reserve 128 bytes (1024 bits) for the signature */
1992 assembly->strong_name_size = MONO_DEFAULT_PUBLIC_KEY_LENGTH;
1993 } else if (len >= MONO_PUBLIC_KEY_HEADER_LENGTH + MONO_MINIMUM_PUBLIC_KEY_LENGTH) {
1994 /* minimum key size (in 2.0) is 384 bits */
1995 assembly->strong_name_size = len - MONO_PUBLIC_KEY_HEADER_LENGTH;
1997 /* FIXME - verifier */
1998 g_warning ("Invalid public key length: %d bits (total: %d)", (int)MONO_PUBLIC_KEY_BIT_SIZE (len), (int)len);
1999 assembly->strong_name_size = MONO_DEFAULT_PUBLIC_KEY_LENGTH; /* to be safe */
2001 assembly->strong_name = (char *)g_malloc0 (assembly->strong_name_size);
2007 mono_image_emit_manifest (MonoReflectionModuleBuilder *moduleb, MonoError *error)
2009 MonoDynamicTable *table;
2010 MonoDynamicImage *assembly;
2011 MonoReflectionAssemblyBuilder *assemblyb;
2015 guint32 module_index;
2017 mono_error_init (error);
2019 assemblyb = moduleb->assemblyb;
2020 assembly = moduleb->dynamic_image;
2021 domain = mono_object_domain (assemblyb);
2023 /* Emit ASSEMBLY table */
2024 table = &assembly->tables [MONO_TABLE_ASSEMBLY];
2025 alloc_table (table, 1);
2026 values = table->values + MONO_ASSEMBLY_SIZE;
2027 values [MONO_ASSEMBLY_HASH_ALG] = assemblyb->algid? assemblyb->algid: ASSEMBLY_HASH_SHA1;
2028 values [MONO_ASSEMBLY_NAME] = string_heap_insert_mstring (&assembly->sheap, assemblyb->name, error);
2029 return_val_if_nok (error, FALSE);
2030 if (assemblyb->culture) {
2031 values [MONO_ASSEMBLY_CULTURE] = string_heap_insert_mstring (&assembly->sheap, assemblyb->culture, error);
2032 return_val_if_nok (error, FALSE);
2034 values [MONO_ASSEMBLY_CULTURE] = string_heap_insert (&assembly->sheap, "");
2036 values [MONO_ASSEMBLY_PUBLIC_KEY] = load_public_key (assemblyb->public_key, assembly);
2037 values [MONO_ASSEMBLY_FLAGS] = assemblyb->flags;
2038 if (!set_version_from_string (assemblyb->version, values, error))
2041 /* Emit FILE + EXPORTED_TYPE table */
2043 for (i = 0; i < mono_array_length (assemblyb->modules); ++i) {
2045 MonoReflectionModuleBuilder *file_module =
2046 mono_array_get (assemblyb->modules, MonoReflectionModuleBuilder*, i);
2047 if (file_module != moduleb) {
2048 if (!mono_image_fill_file_table (domain, (MonoReflectionModule*)file_module, assembly, error))
2051 if (file_module->types) {
2052 for (j = 0; j < file_module->num_types; ++j) {
2053 MonoReflectionTypeBuilder *tb = mono_array_get (file_module->types, MonoReflectionTypeBuilder*, j);
2054 mono_image_fill_export_table (domain, tb, module_index, 0, assembly, error);
2055 return_val_if_nok (error, FALSE);
2060 if (assemblyb->loaded_modules) {
2061 for (i = 0; i < mono_array_length (assemblyb->loaded_modules); ++i) {
2062 MonoReflectionModule *file_module =
2063 mono_array_get (assemblyb->loaded_modules, MonoReflectionModule*, i);
2064 if (!mono_image_fill_file_table (domain, file_module, assembly, error))
2067 mono_image_fill_export_table_from_module (domain, file_module, module_index, assembly);
2070 if (assemblyb->type_forwarders)
2071 mono_image_fill_export_table_from_type_forwarders (assemblyb, assembly);
2073 /* Emit MANIFESTRESOURCE table */
2075 for (i = 0; i < mono_array_length (assemblyb->modules); ++i) {
2077 MonoReflectionModuleBuilder *file_module =
2078 mono_array_get (assemblyb->modules, MonoReflectionModuleBuilder*, i);
2079 /* The table for the main module is emitted later */
2080 if (file_module != moduleb) {
2082 if (file_module->resources) {
2083 int len = mono_array_length (file_module->resources);
2084 for (j = 0; j < len; ++j) {
2085 MonoReflectionResource* res = (MonoReflectionResource*)mono_array_addr (file_module->resources, MonoReflectionResource, j);
2086 if (!assembly_add_resource_manifest (file_module, assembly, res, MONO_IMPLEMENTATION_FILE | (module_index << MONO_IMPLEMENTATION_BITS), error))
2095 #ifndef DISABLE_REFLECTION_EMIT_SAVE
2098 * Insert into the metadata tables all the info about the TypeBuilder tb.
2099 * Data in the tables is inserted in a predefined order, since some tables need to be sorted.
2102 mono_image_get_type_info (MonoDomain *domain, MonoReflectionTypeBuilder *tb, MonoDynamicImage *assembly, MonoError *error)
2104 MonoDynamicTable *table;
2106 int i, is_object = 0, is_system = 0;
2109 mono_error_init (error);
2111 table = &assembly->tables [MONO_TABLE_TYPEDEF];
2112 values = table->values + tb->table_idx * MONO_TYPEDEF_SIZE;
2113 values [MONO_TYPEDEF_FLAGS] = tb->attrs;
2114 n = mono_string_to_utf8_checked (tb->name, error);
2115 return_val_if_nok (error, FALSE);
2116 if (strcmp (n, "Object") == 0)
2118 values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, n);
2120 n = mono_string_to_utf8_checked (tb->nspace, error);
2121 return_val_if_nok (error, FALSE);
2122 if (strcmp (n, "System") == 0)
2124 values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, n);
2126 if (tb->parent && !(is_system && is_object) &&
2127 !(tb->attrs & TYPE_ATTRIBUTE_INTERFACE)) { /* interfaces don't have a parent */
2128 MonoType *parent_type = mono_reflection_type_get_handle ((MonoReflectionType*)tb->parent, error);
2129 return_val_if_nok (error, FALSE);
2130 values [MONO_TYPEDEF_EXTENDS] = mono_image_typedef_or_ref (assembly, parent_type);
2132 values [MONO_TYPEDEF_EXTENDS] = 0;
2134 values [MONO_TYPEDEF_FIELD_LIST] = assembly->tables [MONO_TABLE_FIELD].next_idx;
2135 values [MONO_TYPEDEF_METHOD_LIST] = assembly->tables [MONO_TABLE_METHOD].next_idx;
2138 * if we have explicitlayout or sequentiallayouts, output data in the
2139 * ClassLayout table.
2141 if (((tb->attrs & TYPE_ATTRIBUTE_LAYOUT_MASK) != TYPE_ATTRIBUTE_AUTO_LAYOUT) &&
2142 ((tb->class_size > 0) || (tb->packing_size > 0))) {
2143 table = &assembly->tables [MONO_TABLE_CLASSLAYOUT];
2145 alloc_table (table, table->rows);
2146 values = table->values + table->rows * MONO_CLASS_LAYOUT_SIZE;
2147 values [MONO_CLASS_LAYOUT_PARENT] = tb->table_idx;
2148 values [MONO_CLASS_LAYOUT_CLASS_SIZE] = tb->class_size;
2149 values [MONO_CLASS_LAYOUT_PACKING_SIZE] = tb->packing_size;
2152 /* handle interfaces */
2153 if (tb->interfaces) {
2154 table = &assembly->tables [MONO_TABLE_INTERFACEIMPL];
2156 table->rows += mono_array_length (tb->interfaces);
2157 alloc_table (table, table->rows);
2158 values = table->values + (i + 1) * MONO_INTERFACEIMPL_SIZE;
2159 for (i = 0; i < mono_array_length (tb->interfaces); ++i) {
2160 MonoReflectionType* iface = (MonoReflectionType*) mono_array_get (tb->interfaces, gpointer, i);
2161 MonoType *iface_type = mono_reflection_type_get_handle (iface, error);
2162 return_val_if_nok (error, FALSE);
2163 values [MONO_INTERFACEIMPL_CLASS] = tb->table_idx;
2164 values [MONO_INTERFACEIMPL_INTERFACE] = mono_image_typedef_or_ref (assembly, iface_type);
2165 values += MONO_INTERFACEIMPL_SIZE;
2171 table = &assembly->tables [MONO_TABLE_FIELD];
2172 table->rows += tb->num_fields;
2173 alloc_table (table, table->rows);
2174 for (i = 0; i < tb->num_fields; ++i) {
2175 mono_image_get_field_info (
2176 mono_array_get (tb->fields, MonoReflectionFieldBuilder*, i), assembly, error);
2177 return_val_if_nok (error, FALSE);
2181 /* handle constructors */
2183 table = &assembly->tables [MONO_TABLE_METHOD];
2184 table->rows += mono_array_length (tb->ctors);
2185 alloc_table (table, table->rows);
2186 for (i = 0; i < mono_array_length (tb->ctors); ++i) {
2187 if (!mono_image_get_ctor_info (domain,
2188 mono_array_get (tb->ctors, MonoReflectionCtorBuilder*, i),
2194 /* handle methods */
2196 table = &assembly->tables [MONO_TABLE_METHOD];
2197 table->rows += tb->num_methods;
2198 alloc_table (table, table->rows);
2199 for (i = 0; i < tb->num_methods; ++i) {
2200 if (!mono_image_get_method_info (
2201 mono_array_get (tb->methods, MonoReflectionMethodBuilder*, i), assembly, error))
2206 /* Do the same with properties etc.. */
2207 if (tb->events && mono_array_length (tb->events)) {
2208 table = &assembly->tables [MONO_TABLE_EVENT];
2209 table->rows += mono_array_length (tb->events);
2210 alloc_table (table, table->rows);
2211 table = &assembly->tables [MONO_TABLE_EVENTMAP];
2213 alloc_table (table, table->rows);
2214 values = table->values + table->rows * MONO_EVENT_MAP_SIZE;
2215 values [MONO_EVENT_MAP_PARENT] = tb->table_idx;
2216 values [MONO_EVENT_MAP_EVENTLIST] = assembly->tables [MONO_TABLE_EVENT].next_idx;
2217 for (i = 0; i < mono_array_length (tb->events); ++i) {
2218 mono_image_get_event_info (
2219 mono_array_get (tb->events, MonoReflectionEventBuilder*, i), assembly, error);
2220 return_val_if_nok (error, FALSE);
2223 if (tb->properties && mono_array_length (tb->properties)) {
2224 table = &assembly->tables [MONO_TABLE_PROPERTY];
2225 table->rows += mono_array_length (tb->properties);
2226 alloc_table (table, table->rows);
2227 table = &assembly->tables [MONO_TABLE_PROPERTYMAP];
2229 alloc_table (table, table->rows);
2230 values = table->values + table->rows * MONO_PROPERTY_MAP_SIZE;
2231 values [MONO_PROPERTY_MAP_PARENT] = tb->table_idx;
2232 values [MONO_PROPERTY_MAP_PROPERTY_LIST] = assembly->tables [MONO_TABLE_PROPERTY].next_idx;
2233 for (i = 0; i < mono_array_length (tb->properties); ++i) {
2234 mono_image_get_property_info (
2235 mono_array_get (tb->properties, MonoReflectionPropertyBuilder*, i), assembly, error);
2236 return_val_if_nok (error, FALSE);
2240 /* handle generic parameters */
2241 if (tb->generic_params) {
2242 table = &assembly->tables [MONO_TABLE_GENERICPARAM];
2243 table->rows += mono_array_length (tb->generic_params);
2244 alloc_table (table, table->rows);
2245 for (i = 0; i < mono_array_length (tb->generic_params); ++i) {
2246 guint32 owner = MONO_TYPEORMETHOD_TYPE | (tb->table_idx << MONO_TYPEORMETHOD_BITS);
2248 mono_image_get_generic_param_info (
2249 mono_array_get (tb->generic_params, MonoReflectionGenericParam*, i), owner, assembly);
2253 mono_image_add_decl_security (assembly,
2254 mono_metadata_make_token (MONO_TABLE_TYPEDEF, tb->table_idx), tb->permissions);
2257 MonoDynamicTable *ntable;
2259 ntable = &assembly->tables [MONO_TABLE_NESTEDCLASS];
2260 ntable->rows += mono_array_length (tb->subtypes);
2261 alloc_table (ntable, ntable->rows);
2262 values = ntable->values + ntable->next_idx * MONO_NESTED_CLASS_SIZE;
2264 for (i = 0; i < mono_array_length (tb->subtypes); ++i) {
2265 MonoReflectionTypeBuilder *subtype = mono_array_get (tb->subtypes, MonoReflectionTypeBuilder*, i);
2267 values [MONO_NESTED_CLASS_NESTED] = subtype->table_idx;
2268 values [MONO_NESTED_CLASS_ENCLOSING] = tb->table_idx;
2269 /*g_print ("nesting %s (%d) in %s (%d) (rows %d/%d)\n",
2270 mono_string_to_utf8 (subtype->name), subtype->table_idx,
2271 mono_string_to_utf8 (tb->name), tb->table_idx,
2272 ntable->next_idx, ntable->rows);*/
2273 values += MONO_NESTED_CLASS_SIZE;
2283 * mono_image_build_metadata() will fill the info in all the needed metadata tables
2284 * for the modulebuilder @moduleb.
2285 * At the end of the process, method and field tokens are fixed up and the
2286 * on-disk compressed metadata representation is created.
2287 * Return TRUE on success, or FALSE on failure and sets @error
2290 mono_image_build_metadata (MonoReflectionModuleBuilder *moduleb, MonoError *error)
2292 MonoDynamicTable *table;
2293 MonoDynamicImage *assembly;
2294 MonoReflectionAssemblyBuilder *assemblyb;
2300 mono_error_init (error);
2302 assemblyb = moduleb->assemblyb;
2303 assembly = moduleb->dynamic_image;
2304 domain = mono_object_domain (assemblyb);
2306 if (assembly->text_rva)
2309 assembly->text_rva = START_TEXT_RVA;
2311 if (moduleb->is_main) {
2312 mono_image_emit_manifest (moduleb, error);
2313 return_val_if_nok (error, FALSE);
2316 table = &assembly->tables [MONO_TABLE_TYPEDEF];
2317 table->rows = 1; /* .<Module> */
2319 alloc_table (table, table->rows);
2321 * Set the first entry.
2323 values = table->values + table->columns;
2324 values [MONO_TYPEDEF_FLAGS] = 0;
2325 values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, "<Module>") ;
2326 values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, "") ;
2327 values [MONO_TYPEDEF_EXTENDS] = 0;
2328 values [MONO_TYPEDEF_FIELD_LIST] = 1;
2329 values [MONO_TYPEDEF_METHOD_LIST] = 1;
2332 * handle global methods
2333 * FIXME: test what to do when global methods are defined in multiple modules.
2335 if (moduleb->global_methods) {
2336 table = &assembly->tables [MONO_TABLE_METHOD];
2337 table->rows += mono_array_length (moduleb->global_methods);
2338 alloc_table (table, table->rows);
2339 for (i = 0; i < mono_array_length (moduleb->global_methods); ++i) {
2340 if (!mono_image_get_method_info (
2341 mono_array_get (moduleb->global_methods, MonoReflectionMethodBuilder*, i), assembly, error))
2345 if (moduleb->global_fields) {
2346 table = &assembly->tables [MONO_TABLE_FIELD];
2347 table->rows += mono_array_length (moduleb->global_fields);
2348 alloc_table (table, table->rows);
2349 for (i = 0; i < mono_array_length (moduleb->global_fields); ++i) {
2350 mono_image_get_field_info (
2351 mono_array_get (moduleb->global_fields, MonoReflectionFieldBuilder*, i), assembly,
2358 table = &assembly->tables [MONO_TABLE_MODULE];
2359 alloc_table (table, 1);
2360 mono_image_fill_module_table (domain, moduleb, assembly, error);
2364 /* Collect all types into a list sorted by their table_idx */
2365 mono_ptr_array_init (types, moduleb->num_types, MONO_ROOT_SOURCE_REFLECTION, "dynamic module types list");
2368 for (i = 0; i < moduleb->num_types; ++i) {
2369 MonoReflectionTypeBuilder *type = mono_array_get (moduleb->types, MonoReflectionTypeBuilder*, i);
2370 collect_types (&types, type);
2373 mono_ptr_array_sort (types, (int (*)(const void *, const void *))compare_types_by_table_idx);
2374 table = &assembly->tables [MONO_TABLE_TYPEDEF];
2375 table->rows += mono_ptr_array_size (types);
2376 alloc_table (table, table->rows);
2379 * Emit type names + namespaces at one place inside the string heap,
2380 * so load_class_names () needs to touch fewer pages.
2382 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2383 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2384 string_heap_insert_mstring (&assembly->sheap, tb->nspace, error);
2388 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2389 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2390 string_heap_insert_mstring (&assembly->sheap, tb->name, error);
2395 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2396 MonoReflectionTypeBuilder *type = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2397 if (!mono_image_get_type_info (domain, type, assembly, error))
2402 * table->rows is already set above and in mono_image_fill_module_table.
2404 /* add all the custom attributes at the end, once all the indexes are stable */
2405 if (!mono_image_add_cattrs (assembly, 1, MONO_CUSTOM_ATTR_ASSEMBLY, assemblyb->cattrs, error))
2408 /* CAS assembly permissions */
2409 if (assemblyb->permissions_minimum)
2410 mono_image_add_decl_security (assembly, mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1), assemblyb->permissions_minimum);
2411 if (assemblyb->permissions_optional)
2412 mono_image_add_decl_security (assembly, mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1), assemblyb->permissions_optional);
2413 if (assemblyb->permissions_refused)
2414 mono_image_add_decl_security (assembly, mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1), assemblyb->permissions_refused);
2416 if (!module_add_cattrs (assembly, moduleb, error))
2420 mono_g_hash_table_foreach (assembly->token_fixups, (GHFunc)fixup_method, assembly);
2422 /* Create the MethodImpl table. We do this after emitting all methods so we already know
2423 * the final tokens and don't need another fixup pass. */
2425 if (moduleb->global_methods) {
2426 for (i = 0; i < mono_array_length (moduleb->global_methods); ++i) {
2427 MonoReflectionMethodBuilder *mb = mono_array_get (
2428 moduleb->global_methods, MonoReflectionMethodBuilder*, i);
2429 if (!mono_image_add_methodimpl (assembly, mb, error))
2434 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2435 MonoReflectionTypeBuilder *type = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2436 if (type->methods) {
2437 for (j = 0; j < type->num_methods; ++j) {
2438 MonoReflectionMethodBuilder *mb = mono_array_get (
2439 type->methods, MonoReflectionMethodBuilder*, j);
2441 if (!mono_image_add_methodimpl (assembly, mb, error))
2447 fixup_cattrs (assembly);
2450 mono_ptr_array_destroy (types);
2453 return mono_error_ok (error);
2456 #else /* DISABLE_REFLECTION_EMIT_SAVE */
2459 mono_image_build_metadata (MonoReflectionModuleBuilder *moduleb, MonoError *error)
2461 g_error ("This mono runtime was configured with --enable-minimal=reflection_emit_save, so saving of dynamic assemblies is not supported.");
2464 #endif /* DISABLE_REFLECTION_EMIT_SAVE */
2466 #ifndef DISABLE_REFLECTION_EMIT_SAVE
2469 calc_section_size (MonoDynamicImage *assembly)
2473 /* alignment constraints */
2474 mono_image_add_stream_zero (&assembly->code, 4 - (assembly->code.index % 4));
2475 g_assert ((assembly->code.index % 4) == 0);
2476 assembly->meta_size += 3;
2477 assembly->meta_size &= ~3;
2478 mono_image_add_stream_zero (&assembly->resources, 4 - (assembly->resources.index % 4));
2479 g_assert ((assembly->resources.index % 4) == 0);
2481 assembly->sections [MONO_SECTION_TEXT].size = assembly->meta_size + assembly->code.index + assembly->resources.index + assembly->strong_name_size;
2482 assembly->sections [MONO_SECTION_TEXT].attrs = SECT_FLAGS_HAS_CODE | SECT_FLAGS_MEM_EXECUTE | SECT_FLAGS_MEM_READ;
2485 if (assembly->win32_res) {
2486 guint32 res_size = (assembly->win32_res_size + 3) & ~3;
2488 assembly->sections [MONO_SECTION_RSRC].size = res_size;
2489 assembly->sections [MONO_SECTION_RSRC].attrs = SECT_FLAGS_HAS_INITIALIZED_DATA | SECT_FLAGS_MEM_READ;
2493 assembly->sections [MONO_SECTION_RELOC].size = 12;
2494 assembly->sections [MONO_SECTION_RELOC].attrs = SECT_FLAGS_MEM_READ | SECT_FLAGS_MEM_DISCARDABLE | SECT_FLAGS_HAS_INITIALIZED_DATA;
2504 MonoReflectionWin32Resource *win32_res; /* Only for leaf nodes */
2508 resource_tree_compare_by_id (gconstpointer a, gconstpointer b)
2510 ResTreeNode *t1 = (ResTreeNode*)a;
2511 ResTreeNode *t2 = (ResTreeNode*)b;
2513 return t1->id - t2->id;
2517 * resource_tree_create:
2519 * Organize the resources into a resource tree.
2521 static ResTreeNode *
2522 resource_tree_create (MonoArray *win32_resources)
2524 ResTreeNode *tree, *res_node, *type_node, *lang_node;
2528 tree = g_new0 (ResTreeNode, 1);
2530 for (i = 0; i < mono_array_length (win32_resources); ++i) {
2531 MonoReflectionWin32Resource *win32_res =
2532 (MonoReflectionWin32Resource*)mono_array_addr (win32_resources, MonoReflectionWin32Resource, i);
2536 /* FIXME: BUG: this stores managed references in unmanaged memory */
2537 lang_node = g_new0 (ResTreeNode, 1);
2538 lang_node->id = win32_res->lang_id;
2539 lang_node->win32_res = win32_res;
2541 /* Create type node if neccesary */
2543 for (l = tree->children; l; l = l->next)
2544 if (((ResTreeNode*)(l->data))->id == win32_res->res_type) {
2545 type_node = (ResTreeNode*)l->data;
2550 type_node = g_new0 (ResTreeNode, 1);
2551 type_node->id = win32_res->res_type;
2554 * The resource types have to be sorted otherwise
2555 * Windows Explorer can't display the version information.
2557 tree->children = g_slist_insert_sorted (tree->children,
2558 type_node, resource_tree_compare_by_id);
2561 /* Create res node if neccesary */
2563 for (l = type_node->children; l; l = l->next)
2564 if (((ResTreeNode*)(l->data))->id == win32_res->res_id) {
2565 res_node = (ResTreeNode*)l->data;
2570 res_node = g_new0 (ResTreeNode, 1);
2571 res_node->id = win32_res->res_id;
2572 type_node->children = g_slist_append (type_node->children, res_node);
2575 res_node->children = g_slist_append (res_node->children, lang_node);
2582 * resource_tree_encode:
2584 * Encode the resource tree into the format used in the PE file.
2587 resource_tree_encode (ResTreeNode *node, char *begin, char *p, char **endbuf)
2590 MonoPEResourceDir dir;
2591 MonoPEResourceDirEntry dir_entry;
2592 MonoPEResourceDataEntry data_entry;
2594 guint32 res_id_entries;
2597 * For the format of the resource directory, see the article
2598 * "An In-Depth Look into the Win32 Portable Executable File Format" by
2602 memset (&dir, 0, sizeof (dir));
2603 memset (&dir_entry, 0, sizeof (dir_entry));
2604 memset (&data_entry, 0, sizeof (data_entry));
2606 g_assert (sizeof (dir) == 16);
2607 g_assert (sizeof (dir_entry) == 8);
2608 g_assert (sizeof (data_entry) == 16);
2610 node->offset = p - begin;
2612 /* IMAGE_RESOURCE_DIRECTORY */
2613 res_id_entries = g_slist_length (node->children);
2614 dir.res_id_entries = GUINT16_TO_LE (res_id_entries);
2616 memcpy (p, &dir, sizeof (dir));
2619 /* Reserve space for entries */
2621 p += sizeof (dir_entry) * res_id_entries;
2623 /* Write children */
2624 for (l = node->children; l; l = l->next) {
2625 ResTreeNode *child = (ResTreeNode*)l->data;
2627 if (child->win32_res) {
2630 child->offset = p - begin;
2632 /* IMAGE_RESOURCE_DATA_ENTRY */
2633 data_entry.rde_data_offset = GUINT32_TO_LE (p - begin + sizeof (data_entry));
2634 size = mono_array_length (child->win32_res->res_data);
2635 data_entry.rde_size = GUINT32_TO_LE (size);
2637 memcpy (p, &data_entry, sizeof (data_entry));
2638 p += sizeof (data_entry);
2640 memcpy (p, mono_array_addr (child->win32_res->res_data, char, 0), size);
2643 resource_tree_encode (child, begin, p, &p);
2647 /* IMAGE_RESOURCE_ENTRY */
2648 for (l = node->children; l; l = l->next) {
2649 ResTreeNode *child = (ResTreeNode*)l->data;
2651 MONO_PE_RES_DIR_ENTRY_SET_NAME (dir_entry, FALSE, child->id);
2652 MONO_PE_RES_DIR_ENTRY_SET_DIR (dir_entry, !child->win32_res, child->offset);
2654 memcpy (entries, &dir_entry, sizeof (dir_entry));
2655 entries += sizeof (dir_entry);
2662 resource_tree_free (ResTreeNode * node)
2665 for (list = node->children; list; list = list->next)
2666 resource_tree_free ((ResTreeNode*)list->data);
2667 g_slist_free(node->children);
2672 assembly_add_win32_resources (MonoDynamicImage *assembly, MonoReflectionAssemblyBuilder *assemblyb)
2677 MonoReflectionWin32Resource *win32_res;
2680 if (!assemblyb->win32_resources)
2684 * Resources are stored in a three level tree inside the PE file.
2685 * - level one contains a node for each type of resource
2686 * - level two contains a node for each resource
2687 * - level three contains a node for each instance of a resource for a
2688 * specific language.
2691 tree = resource_tree_create (assemblyb->win32_resources);
2693 /* Estimate the size of the encoded tree */
2695 for (i = 0; i < mono_array_length (assemblyb->win32_resources); ++i) {
2696 win32_res = (MonoReflectionWin32Resource*)mono_array_addr (assemblyb->win32_resources, MonoReflectionWin32Resource, i);
2697 size += mono_array_length (win32_res->res_data);
2699 /* Directory structure */
2700 size += mono_array_length (assemblyb->win32_resources) * 256;
2701 p = buf = (char *)g_malloc (size);
2703 resource_tree_encode (tree, p, p, &p);
2705 g_assert (p - buf <= size);
2707 assembly->win32_res = (char *)g_malloc (p - buf);
2708 assembly->win32_res_size = p - buf;
2709 memcpy (assembly->win32_res, buf, p - buf);
2712 resource_tree_free (tree);
2716 fixup_resource_directory (char *res_section, char *p, guint32 rva)
2718 MonoPEResourceDir *dir = (MonoPEResourceDir*)p;
2721 p += sizeof (MonoPEResourceDir);
2722 for (i = 0; i < GUINT16_FROM_LE (dir->res_named_entries) + GUINT16_FROM_LE (dir->res_id_entries); ++i) {
2723 MonoPEResourceDirEntry *dir_entry = (MonoPEResourceDirEntry*)p;
2724 char *child = res_section + MONO_PE_RES_DIR_ENTRY_DIR_OFFSET (*dir_entry);
2725 if (MONO_PE_RES_DIR_ENTRY_IS_DIR (*dir_entry)) {
2726 fixup_resource_directory (res_section, child, rva);
2728 MonoPEResourceDataEntry *data_entry = (MonoPEResourceDataEntry*)child;
2729 data_entry->rde_data_offset = GUINT32_TO_LE (GUINT32_FROM_LE (data_entry->rde_data_offset) + rva);
2732 p += sizeof (MonoPEResourceDirEntry);
2737 checked_write_file (HANDLE f, gconstpointer buffer, guint32 numbytes)
2740 if (!WriteFile (f, buffer, numbytes, &dummy, NULL))
2741 g_error ("WriteFile returned %d\n", GetLastError ());
2745 * mono_image_create_pefile:
2746 * @mb: a module builder object
2748 * This function creates the PE-COFF header, the image sections, the CLI header * etc. all the data is written in
2749 * assembly->pefile where it can be easily retrieved later in chunks.
2752 mono_image_create_pefile (MonoReflectionModuleBuilder *mb, HANDLE file, MonoError *error)
2754 MonoMSDOSHeader *msdos;
2755 MonoDotNetHeader *header;
2756 MonoSectionTable *section;
2757 MonoCLIHeader *cli_header;
2758 guint32 size, image_size, virtual_base, text_offset;
2759 guint32 header_start, section_start, file_offset, virtual_offset;
2760 MonoDynamicImage *assembly;
2761 MonoReflectionAssemblyBuilder *assemblyb;
2762 MonoDynamicStream pefile_stream = {0};
2763 MonoDynamicStream *pefile = &pefile_stream;
2765 guint32 *rva, value;
2767 static const unsigned char msheader[] = {
2768 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
2769 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2770 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2771 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
2772 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68,
2773 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f,
2774 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,
2775 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
2778 mono_error_init (error);
2780 assemblyb = mb->assemblyb;
2782 mono_reflection_dynimage_basic_init (assemblyb);
2783 assembly = mb->dynamic_image;
2785 assembly->pe_kind = assemblyb->pe_kind;
2786 assembly->machine = assemblyb->machine;
2787 ((MonoDynamicImage*)assemblyb->dynamic_assembly->assembly.image)->pe_kind = assemblyb->pe_kind;
2788 ((MonoDynamicImage*)assemblyb->dynamic_assembly->assembly.image)->machine = assemblyb->machine;
2790 if (!mono_image_build_metadata (mb, error))
2794 if (mb->is_main && assemblyb->resources) {
2795 int len = mono_array_length (assemblyb->resources);
2796 for (i = 0; i < len; ++i) {
2797 if (!assembly_add_resource (mb, assembly, (MonoReflectionResource*)mono_array_addr (assemblyb->resources, MonoReflectionResource, i), error))
2802 if (mb->resources) {
2803 int len = mono_array_length (mb->resources);
2804 for (i = 0; i < len; ++i) {
2805 if (!assembly_add_resource (mb, assembly, (MonoReflectionResource*)mono_array_addr (mb->resources, MonoReflectionResource, i), error))
2810 if (!build_compressed_metadata (assembly, error))
2814 assembly_add_win32_resources (assembly, assemblyb);
2816 nsections = calc_section_size (assembly);
2818 /* The DOS header and stub */
2819 g_assert (sizeof (MonoMSDOSHeader) == sizeof (msheader));
2820 mono_image_add_stream_data (pefile, (char*)msheader, sizeof (msheader));
2822 /* the dotnet header */
2823 header_start = mono_image_add_stream_zero (pefile, sizeof (MonoDotNetHeader));
2825 /* the section tables */
2826 section_start = mono_image_add_stream_zero (pefile, sizeof (MonoSectionTable) * nsections);
2828 file_offset = section_start + sizeof (MonoSectionTable) * nsections;
2829 virtual_offset = VIRT_ALIGN;
2832 for (i = 0; i < MONO_SECTION_MAX; ++i) {
2833 if (!assembly->sections [i].size)
2836 file_offset += FILE_ALIGN - 1;
2837 file_offset &= ~(FILE_ALIGN - 1);
2838 virtual_offset += VIRT_ALIGN - 1;
2839 virtual_offset &= ~(VIRT_ALIGN - 1);
2841 assembly->sections [i].offset = file_offset;
2842 assembly->sections [i].rva = virtual_offset;
2844 file_offset += assembly->sections [i].size;
2845 virtual_offset += assembly->sections [i].size;
2846 image_size += (assembly->sections [i].size + VIRT_ALIGN - 1) & ~(VIRT_ALIGN - 1);
2849 file_offset += FILE_ALIGN - 1;
2850 file_offset &= ~(FILE_ALIGN - 1);
2852 image_size += section_start + sizeof (MonoSectionTable) * nsections;
2854 /* back-patch info */
2855 msdos = (MonoMSDOSHeader*)pefile->data;
2856 msdos->pe_offset = GUINT32_FROM_LE (sizeof (MonoMSDOSHeader));
2858 header = (MonoDotNetHeader*)(pefile->data + header_start);
2859 header->pesig [0] = 'P';
2860 header->pesig [1] = 'E';
2862 header->coff.coff_machine = GUINT16_FROM_LE (assemblyb->machine);
2863 header->coff.coff_sections = GUINT16_FROM_LE (nsections);
2864 header->coff.coff_time = GUINT32_FROM_LE (time (NULL));
2865 header->coff.coff_opt_header_size = GUINT16_FROM_LE (sizeof (MonoDotNetHeader) - sizeof (MonoCOFFHeader) - 4);
2866 if (assemblyb->pekind == 1) {
2868 header->coff.coff_attributes = GUINT16_FROM_LE (0x210e);
2871 header->coff.coff_attributes = GUINT16_FROM_LE (0x010e);
2874 virtual_base = 0x400000; /* FIXME: 0x10000000 if a DLL */
2876 header->pe.pe_magic = GUINT16_FROM_LE (0x10B);
2877 header->pe.pe_major = 6;
2878 header->pe.pe_minor = 0;
2879 size = assembly->sections [MONO_SECTION_TEXT].size;
2880 size += FILE_ALIGN - 1;
2881 size &= ~(FILE_ALIGN - 1);
2882 header->pe.pe_code_size = GUINT32_FROM_LE(size);
2883 size = assembly->sections [MONO_SECTION_RSRC].size;
2884 size += FILE_ALIGN - 1;
2885 size &= ~(FILE_ALIGN - 1);
2886 header->pe.pe_data_size = GUINT32_FROM_LE(size);
2887 g_assert (START_TEXT_RVA == assembly->sections [MONO_SECTION_TEXT].rva);
2888 header->pe.pe_rva_code_base = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_TEXT].rva);
2889 header->pe.pe_rva_data_base = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].rva);
2890 /* pe_rva_entry_point always at the beginning of the text section */
2891 header->pe.pe_rva_entry_point = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_TEXT].rva);
2893 header->nt.pe_image_base = GUINT32_FROM_LE (virtual_base);
2894 header->nt.pe_section_align = GUINT32_FROM_LE (VIRT_ALIGN);
2895 header->nt.pe_file_alignment = GUINT32_FROM_LE (FILE_ALIGN);
2896 header->nt.pe_os_major = GUINT16_FROM_LE (4);
2897 header->nt.pe_os_minor = GUINT16_FROM_LE (0);
2898 header->nt.pe_subsys_major = GUINT16_FROM_LE (4);
2899 size = section_start;
2900 size += FILE_ALIGN - 1;
2901 size &= ~(FILE_ALIGN - 1);
2902 header->nt.pe_header_size = GUINT32_FROM_LE (size);
2904 size += VIRT_ALIGN - 1;
2905 size &= ~(VIRT_ALIGN - 1);
2906 header->nt.pe_image_size = GUINT32_FROM_LE (size);
2909 // Translate the PEFileKind value to the value expected by the Windows loader
2915 // PEFileKinds.Dll == 1
2916 // PEFileKinds.ConsoleApplication == 2
2917 // PEFileKinds.WindowApplication == 3
2920 // IMAGE_SUBSYSTEM_WINDOWS_GUI 2 // Image runs in the Windows GUI subsystem.
2921 // IMAGE_SUBSYSTEM_WINDOWS_CUI 3 // Image runs in the Windows character subsystem.
2923 if (assemblyb->pekind == 3)
2928 header->nt.pe_subsys_required = GUINT16_FROM_LE (kind);
2930 header->nt.pe_stack_reserve = GUINT32_FROM_LE (0x00100000);
2931 header->nt.pe_stack_commit = GUINT32_FROM_LE (0x00001000);
2932 header->nt.pe_heap_reserve = GUINT32_FROM_LE (0x00100000);
2933 header->nt.pe_heap_commit = GUINT32_FROM_LE (0x00001000);
2934 header->nt.pe_loader_flags = GUINT32_FROM_LE (0);
2935 header->nt.pe_data_dir_count = GUINT32_FROM_LE (16);
2937 /* fill data directory entries */
2939 header->datadir.pe_resource_table.size = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].size);
2940 header->datadir.pe_resource_table.rva = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].rva);
2942 header->datadir.pe_reloc_table.size = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RELOC].size);
2943 header->datadir.pe_reloc_table.rva = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RELOC].rva);
2945 header->datadir.pe_cli_header.size = GUINT32_FROM_LE (72);
2946 header->datadir.pe_cli_header.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->cli_header_offset);
2947 header->datadir.pe_iat.size = GUINT32_FROM_LE (8);
2948 header->datadir.pe_iat.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->iat_offset);
2949 /* patch entrypoint name */
2950 if (assemblyb->pekind == 1)
2951 memcpy (assembly->code.data + assembly->imp_names_offset + 2, "_CorDllMain", 12);
2953 memcpy (assembly->code.data + assembly->imp_names_offset + 2, "_CorExeMain", 12);
2954 /* patch imported function RVA name */
2955 rva = (guint32*)(assembly->code.data + assembly->iat_offset);
2956 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->imp_names_offset);
2958 /* the import table */
2959 header->datadir.pe_import_table.size = GUINT32_FROM_LE (79); /* FIXME: magic number? */
2960 header->datadir.pe_import_table.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->idt_offset);
2961 /* patch imported dll RVA name and other entries in the dir */
2962 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, name_rva));
2963 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->imp_names_offset + 14); /* 14 is hint+strlen+1 of func name */
2964 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, import_address_table_rva));
2965 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->iat_offset);
2966 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, import_lookup_table));
2967 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->ilt_offset);
2969 p = (guchar*)(assembly->code.data + assembly->ilt_offset);
2970 value = (assembly->text_rva + assembly->imp_names_offset);
2971 *p++ = (value) & 0xff;
2972 *p++ = (value >> 8) & (0xff);
2973 *p++ = (value >> 16) & (0xff);
2974 *p++ = (value >> 24) & (0xff);
2976 /* the CLI header info */
2977 cli_header = (MonoCLIHeader*)(assembly->code.data + assembly->cli_header_offset);
2978 cli_header->ch_size = GUINT32_FROM_LE (72);
2979 cli_header->ch_runtime_major = GUINT16_FROM_LE (2);
2980 cli_header->ch_runtime_minor = GUINT16_FROM_LE (5);
2981 cli_header->ch_flags = GUINT32_FROM_LE (assemblyb->pe_kind);
2982 if (assemblyb->entry_point) {
2983 guint32 table_idx = 0;
2984 if (!strcmp (assemblyb->entry_point->object.vtable->klass->name, "MethodBuilder")) {
2985 MonoReflectionMethodBuilder *methodb = (MonoReflectionMethodBuilder*)assemblyb->entry_point;
2986 table_idx = methodb->table_idx;
2988 table_idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, assemblyb->entry_point->method));
2990 cli_header->ch_entry_point = GUINT32_FROM_LE (table_idx | MONO_TOKEN_METHOD_DEF);
2992 cli_header->ch_entry_point = GUINT32_FROM_LE (0);
2994 /* The embedded managed resources */
2995 text_offset = assembly->text_rva + assembly->code.index;
2996 cli_header->ch_resources.rva = GUINT32_FROM_LE (text_offset);
2997 cli_header->ch_resources.size = GUINT32_FROM_LE (assembly->resources.index);
2998 text_offset += assembly->resources.index;
2999 cli_header->ch_metadata.rva = GUINT32_FROM_LE (text_offset);
3000 cli_header->ch_metadata.size = GUINT32_FROM_LE (assembly->meta_size);
3001 text_offset += assembly->meta_size;
3002 if (assembly->strong_name_size) {
3003 cli_header->ch_strong_name.rva = GUINT32_FROM_LE (text_offset);
3004 cli_header->ch_strong_name.size = GUINT32_FROM_LE (assembly->strong_name_size);
3005 text_offset += assembly->strong_name_size;
3008 /* write the section tables and section content */
3009 section = (MonoSectionTable*)(pefile->data + section_start);
3010 for (i = 0; i < MONO_SECTION_MAX; ++i) {
3011 static const char section_names [][7] = {
3012 ".text", ".rsrc", ".reloc"
3014 if (!assembly->sections [i].size)
3016 strcpy (section->st_name, section_names [i]);
3017 /*g_print ("output section %s (%d), size: %d\n", section->st_name, i, assembly->sections [i].size);*/
3018 section->st_virtual_address = GUINT32_FROM_LE (assembly->sections [i].rva);
3019 section->st_virtual_size = GUINT32_FROM_LE (assembly->sections [i].size);
3020 section->st_raw_data_size = GUINT32_FROM_LE (GUINT32_TO_LE (section->st_virtual_size) + (FILE_ALIGN - 1));
3021 section->st_raw_data_size &= GUINT32_FROM_LE (~(FILE_ALIGN - 1));
3022 section->st_raw_data_ptr = GUINT32_FROM_LE (assembly->sections [i].offset);
3023 section->st_flags = GUINT32_FROM_LE (assembly->sections [i].attrs);
3027 checked_write_file (file, pefile->data, pefile->index);
3029 mono_dynamic_stream_reset (pefile);
3031 for (i = 0; i < MONO_SECTION_MAX; ++i) {
3032 if (!assembly->sections [i].size)
3035 if (SetFilePointer (file, assembly->sections [i].offset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
3036 g_error ("SetFilePointer returned %d\n", GetLastError ());
3039 case MONO_SECTION_TEXT:
3040 /* patch entry point */
3041 p = (guchar*)(assembly->code.data + 2);
3042 value = (virtual_base + assembly->text_rva + assembly->iat_offset);
3043 *p++ = (value) & 0xff;
3044 *p++ = (value >> 8) & 0xff;
3045 *p++ = (value >> 16) & 0xff;
3046 *p++ = (value >> 24) & 0xff;
3048 checked_write_file (file, assembly->code.data, assembly->code.index);
3049 checked_write_file (file, assembly->resources.data, assembly->resources.index);
3050 checked_write_file (file, assembly->image.raw_metadata, assembly->meta_size);
3051 checked_write_file (file, assembly->strong_name, assembly->strong_name_size);
3054 g_free (assembly->image.raw_metadata);
3056 case MONO_SECTION_RELOC: {
3060 guint16 type_and_offset;
3064 g_assert (sizeof (reloc) == 12);
3066 reloc.page_rva = GUINT32_FROM_LE (assembly->text_rva);
3067 reloc.block_size = GUINT32_FROM_LE (12);
3070 * the entrypoint is always at the start of the text section
3071 * 3 is IMAGE_REL_BASED_HIGHLOW
3072 * 2 is patch_size_rva - text_rva
3074 reloc.type_and_offset = GUINT16_FROM_LE ((3 << 12) + (2));
3077 checked_write_file (file, &reloc, sizeof (reloc));
3081 case MONO_SECTION_RSRC:
3082 if (assembly->win32_res) {
3084 /* Fixup the offsets in the IMAGE_RESOURCE_DATA_ENTRY structures */
3085 fixup_resource_directory (assembly->win32_res, assembly->win32_res, assembly->sections [i].rva);
3086 checked_write_file (file, assembly->win32_res, assembly->win32_res_size);
3090 g_assert_not_reached ();
3094 /* check that the file is properly padded */
3095 if (SetFilePointer (file, file_offset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
3096 g_error ("SetFilePointer returned %d\n", GetLastError ());
3097 if (! SetEndOfFile (file))
3098 g_error ("SetEndOfFile returned %d\n", GetLastError ());
3100 mono_dynamic_stream_reset (&assembly->code);
3101 mono_dynamic_stream_reset (&assembly->us);
3102 mono_dynamic_stream_reset (&assembly->blob);
3103 mono_dynamic_stream_reset (&assembly->guid);
3104 mono_dynamic_stream_reset (&assembly->sheap);
3106 g_hash_table_foreach (assembly->blob_cache, (GHFunc)g_free, NULL);
3107 g_hash_table_destroy (assembly->blob_cache);
3108 assembly->blob_cache = NULL;
3113 #else /* DISABLE_REFLECTION_EMIT_SAVE */
3116 mono_image_create_pefile (MonoReflectionModuleBuilder *mb, HANDLE file, MonoError *error)
3118 g_assert_not_reached ();
3121 #endif /* DISABLE_REFLECTION_EMIT_SAVE */