3 * Routine for saving an image to a file.
7 * Paolo Molaro (lupus@ximian.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2011 Rodrigo Kumpera
12 * Copyright 2016 Microsoft
14 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
20 #include "mono/metadata/dynamic-image-internals.h"
21 #include "mono/metadata/dynamic-stream-internals.h"
22 #include "mono/metadata/mono-ptr-array.h"
23 #include "mono/metadata/object-internals.h"
24 #include "mono/metadata/sre-internals.h"
25 #include "mono/metadata/security-manager.h"
26 #include "mono/metadata/tabledefs.h"
27 #include "mono/metadata/tokentype.h"
28 #include "mono/metadata/w32file.h"
29 #include "mono/metadata/w32error.h"
31 #include "mono/utils/checked-build.h"
32 #include "mono/utils/mono-digest.h"
33 #include "mono/utils/mono-error-internals.h"
34 #include "mono/utils/w32api.h"
36 #define TEXT_OFFSET 512
37 #define CLI_H_SIZE 136
38 #define FILE_ALIGN 512
39 #define VIRT_ALIGN 8192
40 #define START_TEXT_RVA 0x00002000
42 static void mono_image_get_generic_param_info (MonoReflectionGenericParam *gparam, guint32 owner, MonoDynamicImage *assembly);
45 alloc_table (MonoDynamicTable *table, guint nrows)
47 mono_dynimage_alloc_table (table, nrows);
51 string_heap_insert (MonoDynamicStream *sh, const char *str)
53 return mono_dynstream_insert_string (sh, str);
57 string_heap_insert_mstring (MonoDynamicStream *sh, MonoString *str, MonoError *error)
59 return mono_dynstream_insert_mstring (sh, str, error);
63 mono_image_add_stream_data (MonoDynamicStream *stream, const char *data, guint32 len)
65 return mono_dynstream_add_data (stream, data, len);
69 mono_image_add_stream_zero (MonoDynamicStream *stream, guint32 len)
71 return mono_dynstream_add_zero (stream, len);
75 stream_data_align (MonoDynamicStream *stream)
77 mono_dynstream_data_align (stream);
81 mono_image_typedef_or_ref (MonoDynamicImage *assembly, MonoType *type)
83 return mono_dynimage_encode_typedef_or_ref_full (assembly, type, TRUE);
87 find_index_in_table (MonoDynamicImage *assembly, int table_idx, int col, guint32 token)
89 MONO_REQ_GC_NEUTRAL_MODE;
92 MonoDynamicTable *table;
95 table = &assembly->tables [table_idx];
97 g_assert (col < table->columns);
99 values = table->values + table->columns;
100 for (i = 1; i <= table->rows; ++i) {
101 if (values [col] == token)
103 values += table->columns;
109 * Copy len * nelem bytes from val to dest, swapping bytes to LE if necessary.
110 * dest may be misaligned.
113 swap_with_size (char *dest, const char* val, int len, int nelem) {
114 MONO_REQ_GC_NEUTRAL_MODE;
115 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
118 for (elem = 0; elem < nelem; ++elem) {
144 g_assert_not_reached ();
150 memcpy (dest, val, len * nelem);
155 add_mono_string_to_blob_cached (MonoDynamicImage *assembly, MonoString *str)
157 MONO_REQ_GC_UNSAFE_MODE;
161 guint32 idx = 0, len;
163 len = str->length * 2;
164 mono_metadata_encode_value (len, b, &b);
165 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
167 char *swapped = g_malloc (2 * mono_string_length (str));
168 const char *p = (const char*)mono_string_chars (str);
170 swap_with_size (swapped, p, 2, mono_string_length (str));
171 idx = mono_dynamic_image_add_to_blob_cached (assembly, blob_size, b-blob_size, swapped, len);
175 idx = mono_dynamic_image_add_to_blob_cached (assembly, blob_size, b-blob_size, (char*)mono_string_chars (str), len);
181 image_create_token_raw (MonoDynamicImage *assembly, MonoObject* obj_raw, gboolean create_methodspec, gboolean register_token, MonoError *error)
183 HANDLE_FUNCTION_ENTER (); /* FIXME callers of image_create_token_raw should use handles */
185 MONO_HANDLE_DCL (MonoObject, obj);
186 guint32 result = mono_image_create_token (assembly, obj, create_methodspec, register_token, error);
187 HANDLE_FUNCTION_RETURN_VAL (result);
192 * idx is the table index of the object
193 * type is one of MONO_CUSTOM_ATTR_*
196 mono_image_add_cattrs (MonoDynamicImage *assembly, guint32 idx, guint32 type, MonoArray *cattrs, MonoError *error)
198 MONO_REQ_GC_UNSAFE_MODE;
200 MonoDynamicTable *table;
201 MonoReflectionCustomAttr *cattr;
203 guint32 count, i, token;
209 /* it is legal to pass a NULL cattrs: we avoid to use the if in a lot of places */
212 count = mono_array_length (cattrs);
213 table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
214 table->rows += count;
215 alloc_table (table, table->rows);
216 values = table->values + table->next_idx * MONO_CUSTOM_ATTR_SIZE;
217 idx <<= MONO_CUSTOM_ATTR_BITS;
219 for (i = 0; i < count; ++i) {
220 cattr = (MonoReflectionCustomAttr*)mono_array_get (cattrs, gpointer, i);
221 values [MONO_CUSTOM_ATTR_PARENT] = idx;
222 g_assert (cattr->ctor != NULL);
223 if (mono_is_sre_ctor_builder (mono_object_class (cattr->ctor))) {
224 MonoReflectionCtorBuilder *ctor = (MonoReflectionCtorBuilder*)cattr->ctor;
225 MonoMethod *method = ctor->mhandle;
226 if (method->klass->image == &assembly->image)
227 token = MONO_TOKEN_METHOD_DEF | ((MonoReflectionCtorBuilder*)cattr->ctor)->table_idx;
229 token = mono_image_get_methodref_token (assembly, method, FALSE);
231 token = image_create_token_raw (assembly, (MonoObject*)cattr->ctor, FALSE, FALSE, error); /* FIXME use handles */
232 if (!mono_error_ok (error)) goto fail;
234 type = mono_metadata_token_index (token);
235 type <<= MONO_CUSTOM_ATTR_TYPE_BITS;
236 switch (mono_metadata_token_table (token)) {
237 case MONO_TABLE_METHOD:
238 type |= MONO_CUSTOM_ATTR_TYPE_METHODDEF;
240 * fixup_cattrs () needs to fix this up. We can't use image->tokens, since it contains the old token for the
241 * method, not the one returned by mono_image_create_token ().
243 mono_g_hash_table_insert (assembly->remapped_tokens, GUINT_TO_POINTER (token), cattr->ctor);
245 case MONO_TABLE_MEMBERREF:
246 type |= MONO_CUSTOM_ATTR_TYPE_MEMBERREF;
249 g_warning ("got wrong token in custom attr");
252 values [MONO_CUSTOM_ATTR_TYPE] = type;
254 mono_metadata_encode_value (mono_array_length (cattr->data), p, &p);
255 values [MONO_CUSTOM_ATTR_VALUE] = mono_dynamic_image_add_to_blob_cached (assembly, blob_size, p - blob_size,
256 mono_array_addr (cattr->data, char, 0), mono_array_length (cattr->data));
257 values += MONO_CUSTOM_ATTR_SIZE;
268 mono_image_add_decl_security (MonoDynamicImage *assembly, guint32 parent_token, MonoArray *permissions)
270 MONO_REQ_GC_UNSAFE_MODE;
272 MonoDynamicTable *table;
274 guint32 count, i, idx;
275 MonoReflectionPermissionSet *perm;
280 count = mono_array_length (permissions);
281 table = &assembly->tables [MONO_TABLE_DECLSECURITY];
282 table->rows += count;
283 alloc_table (table, table->rows);
285 for (i = 0; i < mono_array_length (permissions); ++i) {
286 perm = (MonoReflectionPermissionSet*)mono_array_addr (permissions, MonoReflectionPermissionSet, i);
288 values = table->values + table->next_idx * MONO_DECL_SECURITY_SIZE;
290 idx = mono_metadata_token_index (parent_token);
291 idx <<= MONO_HAS_DECL_SECURITY_BITS;
292 switch (mono_metadata_token_table (parent_token)) {
293 case MONO_TABLE_TYPEDEF:
294 idx |= MONO_HAS_DECL_SECURITY_TYPEDEF;
296 case MONO_TABLE_METHOD:
297 idx |= MONO_HAS_DECL_SECURITY_METHODDEF;
299 case MONO_TABLE_ASSEMBLY:
300 idx |= MONO_HAS_DECL_SECURITY_ASSEMBLY;
303 g_assert_not_reached ();
306 values [MONO_DECL_SECURITY_ACTION] = perm->action;
307 values [MONO_DECL_SECURITY_PARENT] = idx;
308 values [MONO_DECL_SECURITY_PERMISSIONSET] = add_mono_string_to_blob_cached (assembly, perm->pset);
315 * method_encode_code:
317 * @assembly the assembly
318 * @mb the managed MethodBuilder
319 * @error set on error
321 * Note that the return value is not sensible if @error is set.
324 method_encode_code (MonoDynamicImage *assembly, ReflectionMethodBuilder *mb, MonoError *error)
326 MONO_REQ_GC_UNSAFE_MODE;
332 gint32 num_locals = 0;
333 gint32 num_exception = 0;
336 char fat_header [12];
339 guint32 local_sig = 0;
340 guint32 header_size = 12;
345 if ((mb->attrs & (METHOD_ATTRIBUTE_PINVOKE_IMPL | METHOD_ATTRIBUTE_ABSTRACT)) ||
346 (mb->iattrs & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)))
350 g_print ("Encode method %s\n", mono_string_to_utf8 (mb->name));*/
352 code = mb->ilgen->code;
353 code_size = mb->ilgen->code_len;
354 max_stack = mb->ilgen->max_stack;
355 num_locals = mb->ilgen->locals ? mono_array_length (mb->ilgen->locals) : 0;
356 if (mb->ilgen->ex_handlers)
357 num_exception = mono_reflection_method_count_clauses (mb->ilgen);
361 MonoError inner_error;
362 char *name = mono_string_to_utf8_checked (mb->name, &inner_error);
363 if (!is_ok (&inner_error)) {
364 name = g_strdup ("");
365 mono_error_cleanup (&inner_error);
367 char *str = g_strdup_printf ("Method %s does not have any IL associated", name);
368 mono_error_set_argument (error, NULL, "a method does not have any IL associated");
374 code_size = mono_array_length (code);
375 max_stack = 8; /* we probably need to run a verifier on the code... */
378 stream_data_align (&assembly->code);
380 /* check for exceptions, maxstack, locals */
381 maybe_small = (max_stack <= 8) && (!num_locals) && (!num_exception);
383 if (code_size < 64 && !(code_size & 1)) {
384 flags = (code_size << 2) | 0x2;
385 } else if (code_size < 32 && (code_size & 1)) {
386 flags = (code_size << 2) | 0x6; /* LAMESPEC: see metadata.c */
390 idx = mono_image_add_stream_data (&assembly->code, &flags, 1);
391 /* add to the fixup todo list */
392 if (mb->ilgen && mb->ilgen->num_token_fixups)
393 mono_g_hash_table_insert (assembly->token_fixups, mb->ilgen, GUINT_TO_POINTER (idx + 1));
394 mono_image_add_stream_data (&assembly->code, mono_array_addr (code, char, 0), code_size);
395 return assembly->text_rva + idx;
399 local_sig = MONO_TOKEN_SIGNATURE | mono_dynimage_encode_locals (assembly, mb->ilgen, error);
400 return_val_if_nok (error, 0);
403 * FIXME: need to set also the header size in fat_flags.
404 * (and more sects and init locals flags)
408 fat_flags |= METHOD_HEADER_MORE_SECTS;
410 fat_flags |= METHOD_HEADER_INIT_LOCALS;
411 fat_header [0] = fat_flags;
412 fat_header [1] = (header_size / 4 ) << 4;
413 short_value = GUINT16_TO_LE (max_stack);
414 memcpy (fat_header + 2, &short_value, 2);
415 int_value = GUINT32_TO_LE (code_size);
416 memcpy (fat_header + 4, &int_value, 4);
417 int_value = GUINT32_TO_LE (local_sig);
418 memcpy (fat_header + 8, &int_value, 4);
419 idx = mono_image_add_stream_data (&assembly->code, fat_header, 12);
420 /* add to the fixup todo list */
421 if (mb->ilgen && mb->ilgen->num_token_fixups)
422 mono_g_hash_table_insert (assembly->token_fixups, mb->ilgen, GUINT_TO_POINTER (idx + 12));
424 mono_image_add_stream_data (&assembly->code, mono_array_addr (code, char, 0), code_size);
426 unsigned char sheader [4];
427 MonoILExceptionInfo * ex_info;
428 MonoILExceptionBlock * ex_block;
431 stream_data_align (&assembly->code);
432 /* always use fat format for now */
433 sheader [0] = METHOD_HEADER_SECTION_FAT_FORMAT | METHOD_HEADER_SECTION_EHTABLE;
434 num_exception *= 6 * sizeof (guint32);
435 num_exception += 4; /* include the size of the header */
436 sheader [1] = num_exception & 0xff;
437 sheader [2] = (num_exception >> 8) & 0xff;
438 sheader [3] = (num_exception >> 16) & 0xff;
439 mono_image_add_stream_data (&assembly->code, (char*)sheader, 4);
440 /* fat header, so we are already aligned */
442 for (i = mono_array_length (mb->ilgen->ex_handlers) - 1; i >= 0; --i) {
443 ex_info = (MonoILExceptionInfo *)mono_array_addr (mb->ilgen->ex_handlers, MonoILExceptionInfo, i);
444 if (ex_info->handlers) {
445 int finally_start = ex_info->start + ex_info->len;
446 for (j = 0; j < mono_array_length (ex_info->handlers); ++j) {
448 ex_block = (MonoILExceptionBlock*)mono_array_addr (ex_info->handlers, MonoILExceptionBlock, j);
450 val = GUINT32_TO_LE (ex_block->type);
451 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
453 val = GUINT32_TO_LE (ex_info->start);
454 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
455 /* need fault, too, probably */
456 if (ex_block->type == MONO_EXCEPTION_CLAUSE_FINALLY)
457 val = GUINT32_TO_LE (finally_start - ex_info->start);
459 val = GUINT32_TO_LE (ex_info->len);
460 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
462 val = GUINT32_TO_LE (ex_block->start);
463 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
465 val = GUINT32_TO_LE (ex_block->len);
466 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
467 finally_start = ex_block->start + ex_block->len;
468 if (ex_block->extype) {
469 MonoType *extype = mono_reflection_type_get_handle ((MonoReflectionType*)ex_block->extype, error);
470 return_val_if_nok (error, 0);
472 val = mono_metadata_token_from_dor (mono_image_typedef_or_ref (assembly, extype));
474 if (ex_block->type == MONO_EXCEPTION_CLAUSE_FILTER)
475 val = ex_block->filter_offset;
479 val = GUINT32_TO_LE (val);
480 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
481 /*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",
482 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);*/
485 g_error ("No clauses for ex info block %d", i);
489 return assembly->text_rva + idx;
493 * Fill in the MethodDef and ParamDef tables for a method.
494 * This is used for both normal methods and constructors.
497 mono_image_basic_method (ReflectionMethodBuilder *mb, MonoDynamicImage *assembly, MonoError *error)
499 MONO_REQ_GC_UNSAFE_MODE;
501 MonoDynamicTable *table;
507 /* room in this table is already allocated */
508 table = &assembly->tables [MONO_TABLE_METHOD];
509 *mb->table_idx = table->next_idx ++;
510 g_hash_table_insert (assembly->method_to_table_idx, mb->mhandle, GUINT_TO_POINTER ((*mb->table_idx)));
511 values = table->values + *mb->table_idx * MONO_METHOD_SIZE;
512 values [MONO_METHOD_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->name, error);
513 return_val_if_nok (error, FALSE);
514 values [MONO_METHOD_FLAGS] = mb->attrs;
515 values [MONO_METHOD_IMPLFLAGS] = mb->iattrs;
516 values [MONO_METHOD_SIGNATURE] = mono_dynimage_encode_method_builder_signature (assembly, mb, error);
517 return_val_if_nok (error, FALSE);
518 values [MONO_METHOD_RVA] = method_encode_code (assembly, mb, error);
519 return_val_if_nok (error, FALSE);
521 table = &assembly->tables [MONO_TABLE_PARAM];
522 values [MONO_METHOD_PARAMLIST] = table->next_idx;
524 mono_image_add_decl_security (assembly,
525 mono_metadata_make_token (MONO_TABLE_METHOD, *mb->table_idx), mb->permissions);
528 MonoDynamicTable *mtable;
531 mtable = &assembly->tables [MONO_TABLE_FIELDMARSHAL];
532 mvalues = mtable->values + mtable->next_idx * MONO_FIELD_MARSHAL_SIZE;
535 for (i = 0; i < mono_array_length (mb->pinfo); ++i) {
536 if (mono_array_get (mb->pinfo, gpointer, i))
539 table->rows += count;
540 alloc_table (table, table->rows);
541 values = table->values + table->next_idx * MONO_PARAM_SIZE;
542 for (i = 0; i < mono_array_length (mb->pinfo); ++i) {
543 MonoReflectionParamBuilder *pb;
544 if ((pb = mono_array_get (mb->pinfo, MonoReflectionParamBuilder*, i))) {
545 values [MONO_PARAM_FLAGS] = pb->attrs;
546 values [MONO_PARAM_SEQUENCE] = i;
547 if (pb->name != NULL) {
548 values [MONO_PARAM_NAME] = string_heap_insert_mstring (&assembly->sheap, pb->name, error);
549 return_val_if_nok (error, FALSE);
551 values [MONO_PARAM_NAME] = 0;
553 values += MONO_PARAM_SIZE;
554 if (pb->marshal_info) {
556 alloc_table (mtable, mtable->rows);
557 mvalues = mtable->values + mtable->rows * MONO_FIELD_MARSHAL_SIZE;
558 mvalues [MONO_FIELD_MARSHAL_PARENT] = (table->next_idx << MONO_HAS_FIELD_MARSHAL_BITS) | MONO_HAS_FIELD_MARSHAL_PARAMDEF;
559 mvalues [MONO_FIELD_MARSHAL_NATIVE_TYPE] = mono_dynimage_save_encode_marshal_blob (assembly, pb->marshal_info, error);
560 return_val_if_nok (error, FALSE);
562 pb->table_idx = table->next_idx++;
563 if (pb->attrs & PARAM_ATTRIBUTE_HAS_DEFAULT) {
564 guint32 field_type = 0;
565 mtable = &assembly->tables [MONO_TABLE_CONSTANT];
567 alloc_table (mtable, mtable->rows);
568 mvalues = mtable->values + mtable->rows * MONO_CONSTANT_SIZE;
569 mvalues [MONO_CONSTANT_PARENT] = MONO_HASCONSTANT_PARAM | (pb->table_idx << MONO_HASCONSTANT_BITS);
570 mvalues [MONO_CONSTANT_VALUE] = mono_dynimage_encode_constant (assembly, pb->def_value, &field_type);
571 mvalues [MONO_CONSTANT_TYPE] = field_type;
572 mvalues [MONO_CONSTANT_PADDING] = 0;
582 mono_image_add_methodimpl (MonoDynamicImage *assembly, MonoReflectionMethodBuilder *mb, MonoError *error)
584 MONO_REQ_GC_UNSAFE_MODE;
586 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mb->type;
587 MonoDynamicTable *table;
590 MonoReflectionMethod *m;
595 if (!mb->override_methods)
598 for (i = 0; i < mono_array_length (mb->override_methods); ++i) {
599 m = mono_array_get (mb->override_methods, MonoReflectionMethod*, i);
601 table = &assembly->tables [MONO_TABLE_METHODIMPL];
603 alloc_table (table, table->rows);
604 values = table->values + table->rows * MONO_METHODIMPL_SIZE;
605 values [MONO_METHODIMPL_CLASS] = tb->table_idx;
606 values [MONO_METHODIMPL_BODY] = MONO_METHODDEFORREF_METHODDEF | (mb->table_idx << MONO_METHODDEFORREF_BITS);
608 tok = image_create_token_raw (assembly, (MonoObject*)m, FALSE, FALSE, error); /* FIXME use handles */
609 return_val_if_nok (error, FALSE);
611 switch (mono_metadata_token_table (tok)) {
612 case MONO_TABLE_MEMBERREF:
613 tok = (mono_metadata_token_index (tok) << MONO_METHODDEFORREF_BITS ) | MONO_METHODDEFORREF_METHODREF;
615 case MONO_TABLE_METHOD:
616 tok = (mono_metadata_token_index (tok) << MONO_METHODDEFORREF_BITS ) | MONO_METHODDEFORREF_METHODDEF;
619 g_assert_not_reached ();
621 values [MONO_METHODIMPL_DECLARATION] = tok;
627 #ifndef DISABLE_REFLECTION_EMIT
629 mono_image_get_method_info (MonoReflectionMethodBuilder *mb, MonoDynamicImage *assembly, MonoError *error)
631 MONO_REQ_GC_UNSAFE_MODE;
633 MonoDynamicTable *table;
635 ReflectionMethodBuilder rmb;
640 if (!mono_reflection_methodbuilder_from_method_builder (&rmb, mb, error) ||
641 !mono_image_basic_method (&rmb, assembly, error))
644 mb->table_idx = *rmb.table_idx;
646 if (mb->dll) { /* It's a P/Invoke method */
648 /* map CharSet values to on-disk values */
649 int ncharset = (mb->charset ? (mb->charset - 1) * 2 : 0);
650 int extra_flags = mb->extra_flags;
651 table = &assembly->tables [MONO_TABLE_IMPLMAP];
653 alloc_table (table, table->rows);
654 values = table->values + table->rows * MONO_IMPLMAP_SIZE;
656 values [MONO_IMPLMAP_FLAGS] = (mb->native_cc << 8) | ncharset | extra_flags;
657 values [MONO_IMPLMAP_MEMBER] = (mb->table_idx << 1) | 1; /* memberforwarded: method */
659 values [MONO_IMPLMAP_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->dllentry, error);
660 return_val_if_nok (error, FALSE);
662 values [MONO_IMPLMAP_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->name, error);
663 return_val_if_nok (error, FALSE);
665 moduleref = string_heap_insert_mstring (&assembly->sheap, mb->dll, error);
666 return_val_if_nok (error, FALSE);
667 if (!(values [MONO_IMPLMAP_SCOPE] = find_index_in_table (assembly, MONO_TABLE_MODULEREF, MONO_MODULEREF_NAME, moduleref))) {
668 table = &assembly->tables [MONO_TABLE_MODULEREF];
670 alloc_table (table, table->rows);
671 table->values [table->rows * MONO_MODULEREF_SIZE + MONO_MODULEREF_NAME] = moduleref;
672 values [MONO_IMPLMAP_SCOPE] = table->rows;
676 if (mb->generic_params) {
677 table = &assembly->tables [MONO_TABLE_GENERICPARAM];
678 table->rows += mono_array_length (mb->generic_params);
679 alloc_table (table, table->rows);
680 for (i = 0; i < mono_array_length (mb->generic_params); ++i) {
681 guint32 owner = MONO_TYPEORMETHOD_METHOD | (mb->table_idx << MONO_TYPEORMETHOD_BITS);
683 mono_image_get_generic_param_info (
684 (MonoReflectionGenericParam *)mono_array_get (mb->generic_params, gpointer, i), owner, assembly);
692 mono_image_get_ctor_info (MonoDomain *domain, MonoReflectionCtorBuilder *mb, MonoDynamicImage *assembly, MonoError *error)
694 MONO_REQ_GC_UNSAFE_MODE;
696 ReflectionMethodBuilder rmb;
698 if (!mono_reflection_methodbuilder_from_ctor_builder (&rmb, mb, error))
701 if (!mono_image_basic_method (&rmb, assembly, error))
704 mb->table_idx = *rmb.table_idx;
711 mono_image_get_field_info (MonoReflectionFieldBuilder *fb, MonoDynamicImage *assembly, MonoError *error)
713 MONO_REQ_GC_UNSAFE_MODE;
717 MonoDynamicTable *table;
720 /* maybe this fixup should be done in the C# code */
721 if (fb->attrs & FIELD_ATTRIBUTE_LITERAL)
722 fb->attrs |= FIELD_ATTRIBUTE_HAS_DEFAULT;
723 table = &assembly->tables [MONO_TABLE_FIELD];
724 fb->table_idx = table->next_idx ++;
725 g_hash_table_insert (assembly->field_to_table_idx, fb->handle, GUINT_TO_POINTER (fb->table_idx));
726 values = table->values + fb->table_idx * MONO_FIELD_SIZE;
727 values [MONO_FIELD_NAME] = string_heap_insert_mstring (&assembly->sheap, fb->name, error);
728 return_if_nok (error);
729 values [MONO_FIELD_FLAGS] = fb->attrs;
730 values [MONO_FIELD_SIGNATURE] = mono_dynimage_encode_field_signature (assembly, fb, error);
731 return_if_nok (error);
733 if (fb->offset != -1) {
734 table = &assembly->tables [MONO_TABLE_FIELDLAYOUT];
736 alloc_table (table, table->rows);
737 values = table->values + table->rows * MONO_FIELD_LAYOUT_SIZE;
738 values [MONO_FIELD_LAYOUT_FIELD] = fb->table_idx;
739 values [MONO_FIELD_LAYOUT_OFFSET] = fb->offset;
741 if (fb->attrs & FIELD_ATTRIBUTE_LITERAL) {
742 MonoTypeEnum field_type = (MonoTypeEnum)0;
743 table = &assembly->tables [MONO_TABLE_CONSTANT];
745 alloc_table (table, table->rows);
746 values = table->values + table->rows * MONO_CONSTANT_SIZE;
747 values [MONO_CONSTANT_PARENT] = MONO_HASCONSTANT_FIEDDEF | (fb->table_idx << MONO_HASCONSTANT_BITS);
748 values [MONO_CONSTANT_VALUE] = mono_dynimage_encode_constant (assembly, fb->def_value, &field_type);
749 values [MONO_CONSTANT_TYPE] = field_type;
750 values [MONO_CONSTANT_PADDING] = 0;
752 if (fb->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA) {
754 table = &assembly->tables [MONO_TABLE_FIELDRVA];
756 alloc_table (table, table->rows);
757 values = table->values + table->rows * MONO_FIELD_RVA_SIZE;
758 values [MONO_FIELD_RVA_FIELD] = fb->table_idx;
760 * We store it in the code section because it's simpler for now.
763 if (mono_array_length (fb->rva_data) >= 10)
764 stream_data_align (&assembly->code);
765 rva_idx = mono_image_add_stream_data (&assembly->code, mono_array_addr (fb->rva_data, char, 0), mono_array_length (fb->rva_data));
767 rva_idx = mono_image_add_stream_zero (&assembly->code, mono_class_value_size (fb->handle->parent, NULL));
768 values [MONO_FIELD_RVA_RVA] = rva_idx + assembly->text_rva;
770 if (fb->marshal_info) {
771 table = &assembly->tables [MONO_TABLE_FIELDMARSHAL];
773 alloc_table (table, table->rows);
774 values = table->values + table->rows * MONO_FIELD_MARSHAL_SIZE;
775 values [MONO_FIELD_MARSHAL_PARENT] = (fb->table_idx << MONO_HAS_FIELD_MARSHAL_BITS) | MONO_HAS_FIELD_MARSHAL_FIELDSREF;
776 values [MONO_FIELD_MARSHAL_NATIVE_TYPE] = mono_dynimage_save_encode_marshal_blob (assembly, fb->marshal_info, error);
777 return_if_nok (error);
782 mono_image_get_property_info (MonoReflectionPropertyBuilder *pb, MonoDynamicImage *assembly, MonoError *error)
784 MONO_REQ_GC_UNSAFE_MODE;
788 MonoDynamicTable *table;
790 guint num_methods = 0;
794 * we need to set things in the following tables:
795 * PROPERTYMAP (info already filled in _get_type_info ())
796 * PROPERTY (rows already preallocated in _get_type_info ())
797 * METHOD (method info already done with the generic method code)
801 table = &assembly->tables [MONO_TABLE_PROPERTY];
802 pb->table_idx = table->next_idx ++;
803 values = table->values + pb->table_idx * MONO_PROPERTY_SIZE;
804 values [MONO_PROPERTY_NAME] = string_heap_insert_mstring (&assembly->sheap, pb->name, error);
805 return_if_nok (error);
806 values [MONO_PROPERTY_FLAGS] = pb->attrs;
807 values [MONO_PROPERTY_TYPE] = mono_dynimage_save_encode_property_signature (assembly, pb, error);
808 return_if_nok (error);
811 /* FIXME: we still don't handle 'other' methods */
812 if (pb->get_method) num_methods ++;
813 if (pb->set_method) num_methods ++;
815 table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
816 table->rows += num_methods;
817 alloc_table (table, table->rows);
819 if (pb->get_method) {
820 semaidx = table->next_idx ++;
821 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
822 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_GETTER;
823 values [MONO_METHOD_SEMA_METHOD] = pb->get_method->table_idx;
824 values [MONO_METHOD_SEMA_ASSOCIATION] = (pb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_PROPERTY;
826 if (pb->set_method) {
827 semaidx = table->next_idx ++;
828 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
829 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_SETTER;
830 values [MONO_METHOD_SEMA_METHOD] = pb->set_method->table_idx;
831 values [MONO_METHOD_SEMA_ASSOCIATION] = (pb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_PROPERTY;
833 if (pb->attrs & PROPERTY_ATTRIBUTE_HAS_DEFAULT) {
834 MonoTypeEnum field_type = (MonoTypeEnum)0;
835 table = &assembly->tables [MONO_TABLE_CONSTANT];
837 alloc_table (table, table->rows);
838 values = table->values + table->rows * MONO_CONSTANT_SIZE;
839 values [MONO_CONSTANT_PARENT] = MONO_HASCONSTANT_PROPERTY | (pb->table_idx << MONO_HASCONSTANT_BITS);
840 values [MONO_CONSTANT_VALUE] = mono_dynimage_encode_constant (assembly, pb->def_value, &field_type);
841 values [MONO_CONSTANT_TYPE] = field_type;
842 values [MONO_CONSTANT_PADDING] = 0;
847 mono_image_get_event_info (MonoReflectionEventBuilder *eb, MonoDynamicImage *assembly, MonoError *error)
849 MONO_REQ_GC_UNSAFE_MODE;
851 MonoDynamicTable *table;
853 guint num_methods = 0;
857 * we need to set things in the following tables:
858 * EVENTMAP (info already filled in _get_type_info ())
859 * EVENT (rows already preallocated in _get_type_info ())
860 * METHOD (method info already done with the generic method code)
863 table = &assembly->tables [MONO_TABLE_EVENT];
864 eb->table_idx = table->next_idx ++;
865 values = table->values + eb->table_idx * MONO_EVENT_SIZE;
866 values [MONO_EVENT_NAME] = string_heap_insert_mstring (&assembly->sheap, eb->name, error);
867 return_if_nok (error);
868 values [MONO_EVENT_FLAGS] = eb->attrs;
869 MonoType *ebtype = mono_reflection_type_get_handle (eb->type, error);
870 return_if_nok (error);
871 values [MONO_EVENT_TYPE] = mono_image_typedef_or_ref (assembly, ebtype);
874 * FIXME: we still don't handle 'other' methods
876 if (eb->add_method) num_methods ++;
877 if (eb->remove_method) num_methods ++;
878 if (eb->raise_method) num_methods ++;
880 table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
881 table->rows += num_methods;
882 alloc_table (table, table->rows);
884 if (eb->add_method) {
885 semaidx = table->next_idx ++;
886 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
887 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_ADD_ON;
888 values [MONO_METHOD_SEMA_METHOD] = eb->add_method->table_idx;
889 values [MONO_METHOD_SEMA_ASSOCIATION] = (eb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_EVENT;
891 if (eb->remove_method) {
892 semaidx = table->next_idx ++;
893 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
894 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_REMOVE_ON;
895 values [MONO_METHOD_SEMA_METHOD] = eb->remove_method->table_idx;
896 values [MONO_METHOD_SEMA_ASSOCIATION] = (eb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_EVENT;
898 if (eb->raise_method) {
899 semaidx = table->next_idx ++;
900 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
901 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_FIRE;
902 values [MONO_METHOD_SEMA_METHOD] = eb->raise_method->table_idx;
903 values [MONO_METHOD_SEMA_ASSOCIATION] = (eb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_EVENT;
908 encode_constraints (MonoReflectionGenericParam *gparam, guint32 owner, MonoDynamicImage *assembly, MonoError *error)
910 MONO_REQ_GC_UNSAFE_MODE;
914 MonoDynamicTable *table;
915 guint32 num_constraints, i;
919 table = &assembly->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
920 num_constraints = gparam->iface_constraints ?
921 mono_array_length (gparam->iface_constraints) : 0;
922 table->rows += num_constraints;
923 if (gparam->base_type)
925 alloc_table (table, table->rows);
927 if (gparam->base_type) {
928 table_idx = table->next_idx ++;
929 values = table->values + table_idx * MONO_GENPARCONSTRAINT_SIZE;
931 MonoType *gpbasetype = mono_reflection_type_get_handle (gparam->base_type, error);
932 return_if_nok (error);
933 values [MONO_GENPARCONSTRAINT_GENERICPAR] = owner;
934 values [MONO_GENPARCONSTRAINT_CONSTRAINT] = mono_image_typedef_or_ref (assembly, gpbasetype);
937 for (i = 0; i < num_constraints; i++) {
938 MonoReflectionType *constraint = (MonoReflectionType *)mono_array_get (
939 gparam->iface_constraints, gpointer, i);
941 table_idx = table->next_idx ++;
942 values = table->values + table_idx * MONO_GENPARCONSTRAINT_SIZE;
944 MonoType *constraint_type = mono_reflection_type_get_handle (constraint, error);
945 return_if_nok (error);
947 values [MONO_GENPARCONSTRAINT_GENERICPAR] = owner;
948 values [MONO_GENPARCONSTRAINT_CONSTRAINT] = mono_image_typedef_or_ref (assembly, constraint_type);
953 mono_image_get_generic_param_info (MonoReflectionGenericParam *gparam, guint32 owner, MonoDynamicImage *assembly)
955 MONO_REQ_GC_UNSAFE_MODE;
957 GenericParamTableEntry *entry;
960 * The GenericParam table must be sorted according to the `owner' field.
961 * We need to do this sorting prior to writing the GenericParamConstraint
962 * table, since we have to use the final GenericParam table indices there
963 * and they must also be sorted.
966 entry = g_new0 (GenericParamTableEntry, 1);
967 entry->owner = owner;
968 /* FIXME: track where gen_params should be freed and remove the GC root as well */
969 MONO_GC_REGISTER_ROOT_IF_MOVING (entry->gparam, MONO_ROOT_SOURCE_REFLECTION, "reflection generic parameter");
970 entry->gparam = gparam;
972 g_ptr_array_add (assembly->gen_params, entry);
976 write_generic_param_entry (MonoDynamicImage *assembly, GenericParamTableEntry *entry, MonoError *error)
978 MONO_REQ_GC_UNSAFE_MODE;
980 MonoDynamicTable *table;
981 MonoGenericParam *param;
987 table = &assembly->tables [MONO_TABLE_GENERICPARAM];
988 table_idx = table->next_idx ++;
989 values = table->values + table_idx * MONO_GENERICPARAM_SIZE;
991 MonoType *gparam_type = mono_reflection_type_get_handle ((MonoReflectionType*)entry->gparam, error);
992 return_val_if_nok (error, FALSE);
994 param = gparam_type->data.generic_param;
996 values [MONO_GENERICPARAM_OWNER] = entry->owner;
997 values [MONO_GENERICPARAM_FLAGS] = entry->gparam->attrs;
998 values [MONO_GENERICPARAM_NUMBER] = mono_generic_param_num (param);
999 values [MONO_GENERICPARAM_NAME] = string_heap_insert (&assembly->sheap, mono_generic_param_info (param)->name);
1001 if (!mono_image_add_cattrs (assembly, table_idx, MONO_CUSTOM_ATTR_GENERICPAR, entry->gparam->cattrs, error))
1004 encode_constraints (entry->gparam, table_idx, assembly, error);
1005 return_val_if_nok (error, FALSE);
1011 collect_types (MonoPtrArray *types, MonoReflectionTypeBuilder *type)
1015 mono_ptr_array_append (*types, type);
1017 if (!type->subtypes)
1020 for (i = 0; i < mono_array_length (type->subtypes); ++i) {
1021 MonoReflectionTypeBuilder *subtype = mono_array_get (type->subtypes, MonoReflectionTypeBuilder*, i);
1022 collect_types (types, subtype);
1027 compare_types_by_table_idx (MonoReflectionTypeBuilder **type1, MonoReflectionTypeBuilder **type2)
1029 if ((*type1)->table_idx < (*type2)->table_idx)
1032 if ((*type1)->table_idx > (*type2)->table_idx)
1039 params_add_cattrs (MonoDynamicImage *assembly, MonoArray *pinfo, MonoError *error) {
1045 for (i = 0; i < mono_array_length (pinfo); ++i) {
1046 MonoReflectionParamBuilder *pb;
1047 pb = mono_array_get (pinfo, MonoReflectionParamBuilder *, i);
1050 if (!mono_image_add_cattrs (assembly, pb->table_idx, MONO_CUSTOM_ATTR_PARAMDEF, pb->cattrs, error))
1058 type_add_cattrs (MonoDynamicImage *assembly, MonoReflectionTypeBuilder *tb, MonoError *error) {
1063 if (!mono_image_add_cattrs (assembly, tb->table_idx, MONO_CUSTOM_ATTR_TYPEDEF, tb->cattrs, error))
1066 for (i = 0; i < tb->num_fields; ++i) {
1067 MonoReflectionFieldBuilder* fb;
1068 fb = mono_array_get (tb->fields, MonoReflectionFieldBuilder*, i);
1069 if (!mono_image_add_cattrs (assembly, fb->table_idx, MONO_CUSTOM_ATTR_FIELDDEF, fb->cattrs, error))
1074 for (i = 0; i < mono_array_length (tb->events); ++i) {
1075 MonoReflectionEventBuilder* eb;
1076 eb = mono_array_get (tb->events, MonoReflectionEventBuilder*, i);
1077 if (!mono_image_add_cattrs (assembly, eb->table_idx, MONO_CUSTOM_ATTR_EVENT, eb->cattrs, error))
1081 if (tb->properties) {
1082 for (i = 0; i < mono_array_length (tb->properties); ++i) {
1083 MonoReflectionPropertyBuilder* pb;
1084 pb = mono_array_get (tb->properties, MonoReflectionPropertyBuilder*, i);
1085 if (!mono_image_add_cattrs (assembly, pb->table_idx, MONO_CUSTOM_ATTR_PROPERTY, pb->cattrs, error))
1090 for (i = 0; i < mono_array_length (tb->ctors); ++i) {
1091 MonoReflectionCtorBuilder* cb;
1092 cb = mono_array_get (tb->ctors, MonoReflectionCtorBuilder*, i);
1093 if (!mono_image_add_cattrs (assembly, cb->table_idx, MONO_CUSTOM_ATTR_METHODDEF, cb->cattrs, error) ||
1094 !params_add_cattrs (assembly, cb->pinfo, error))
1100 for (i = 0; i < tb->num_methods; ++i) {
1101 MonoReflectionMethodBuilder* mb;
1102 mb = mono_array_get (tb->methods, MonoReflectionMethodBuilder*, i);
1103 if (!mono_image_add_cattrs (assembly, mb->table_idx, MONO_CUSTOM_ATTR_METHODDEF, mb->cattrs, error) ||
1104 !params_add_cattrs (assembly, mb->pinfo, error))
1110 for (i = 0; i < mono_array_length (tb->subtypes); ++i) {
1111 if (!type_add_cattrs (assembly, mono_array_get (tb->subtypes, MonoReflectionTypeBuilder*, i), error))
1120 module_add_cattrs (MonoDynamicImage *assembly, MonoReflectionModuleBuilder *moduleb, MonoError *error)
1126 if (!mono_image_add_cattrs (assembly, moduleb->table_idx, MONO_CUSTOM_ATTR_MODULE, moduleb->cattrs, error))
1129 if (moduleb->global_methods) {
1130 for (i = 0; i < mono_array_length (moduleb->global_methods); ++i) {
1131 MonoReflectionMethodBuilder* mb = mono_array_get (moduleb->global_methods, MonoReflectionMethodBuilder*, i);
1132 if (!mono_image_add_cattrs (assembly, mb->table_idx, MONO_CUSTOM_ATTR_METHODDEF, mb->cattrs, error) ||
1133 !params_add_cattrs (assembly, mb->pinfo, error))
1138 if (moduleb->global_fields) {
1139 for (i = 0; i < mono_array_length (moduleb->global_fields); ++i) {
1140 MonoReflectionFieldBuilder *fb = mono_array_get (moduleb->global_fields, MonoReflectionFieldBuilder*, i);
1141 if (!mono_image_add_cattrs (assembly, fb->table_idx, MONO_CUSTOM_ATTR_FIELDDEF, fb->cattrs, error))
1146 if (moduleb->types) {
1147 for (i = 0; i < moduleb->num_types; ++i) {
1148 if (!type_add_cattrs (assembly, mono_array_get (moduleb->types, MonoReflectionTypeBuilder*, i), error))
1157 mono_image_fill_file_table (MonoDomain *domain, MonoReflectionModule *module, MonoDynamicImage *assembly, MonoError *error)
1159 MonoDynamicTable *table;
1163 char *b = blob_size;
1168 table = &assembly->tables [MONO_TABLE_FILE];
1170 alloc_table (table, table->rows);
1171 values = table->values + table->next_idx * MONO_FILE_SIZE;
1172 values [MONO_FILE_FLAGS] = FILE_CONTAINS_METADATA;
1173 values [MONO_FILE_NAME] = string_heap_insert (&assembly->sheap, module->image->module_name);
1174 if (image_is_dynamic (module->image)) {
1175 /* This depends on the fact that the main module is emitted last */
1176 dir = mono_string_to_utf8_checked (((MonoReflectionModuleBuilder*)module)->assemblyb->dir, error);
1177 return_val_if_nok (error, FALSE);
1178 path = g_strdup_printf ("%s%c%s", dir, G_DIR_SEPARATOR, module->image->module_name);
1181 path = g_strdup (module->image->name);
1183 mono_sha1_get_digest_from_file (path, hash);
1186 mono_metadata_encode_value (20, b, &b);
1187 values [MONO_FILE_HASH_VALUE] = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
1188 mono_image_add_stream_data (&assembly->blob, (char*)hash, 20);
1194 mono_image_fill_module_table (MonoDomain *domain, MonoReflectionModuleBuilder *mb, MonoDynamicImage *assembly, MonoError *error)
1196 MonoDynamicTable *table;
1201 table = &assembly->tables [MONO_TABLE_MODULE];
1202 mb->table_idx = table->next_idx ++;
1203 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->module.name, error);
1204 return_if_nok (error);
1205 i = mono_image_add_stream_data (&assembly->guid, mono_array_addr (mb->guid, char, 0), 16);
1208 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_GENERATION] = 0;
1209 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_MVID] = i;
1210 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_ENC] = 0;
1211 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_ENCBASE] = 0;
1215 mono_image_fill_export_table_from_class (MonoDomain *domain, MonoClass *klass,
1216 guint32 module_index, guint32 parent_index, MonoDynamicImage *assembly)
1218 MonoDynamicTable *table;
1222 visib = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_VISIBILITY_MASK;
1223 if (! ((visib & TYPE_ATTRIBUTE_PUBLIC) || (visib & TYPE_ATTRIBUTE_NESTED_PUBLIC)))
1226 table = &assembly->tables [MONO_TABLE_EXPORTEDTYPE];
1228 alloc_table (table, table->rows);
1229 values = table->values + table->next_idx * MONO_EXP_TYPE_SIZE;
1231 values [MONO_EXP_TYPE_FLAGS] = mono_class_get_flags (klass);
1232 values [MONO_EXP_TYPE_TYPEDEF] = klass->type_token;
1233 if (klass->nested_in)
1234 values [MONO_EXP_TYPE_IMPLEMENTATION] = (parent_index << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_EXP_TYPE;
1236 values [MONO_EXP_TYPE_IMPLEMENTATION] = (module_index << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_FILE;
1237 values [MONO_EXP_TYPE_NAME] = string_heap_insert (&assembly->sheap, klass->name);
1238 values [MONO_EXP_TYPE_NAMESPACE] = string_heap_insert (&assembly->sheap, klass->name_space);
1240 res = table->next_idx;
1244 /* Emit nested types */
1245 GList *nested_classes = mono_class_get_nested_classes_property (klass);
1247 for (tmp = nested_classes; tmp; tmp = tmp->next)
1248 mono_image_fill_export_table_from_class (domain, (MonoClass *)tmp->data, module_index, table->next_idx - 1, assembly);
1254 mono_image_fill_export_table (MonoDomain *domain, MonoReflectionTypeBuilder *tb,
1255 guint32 module_index, guint32 parent_index, MonoDynamicImage *assembly,
1263 MonoType *t = mono_reflection_type_get_handle ((MonoReflectionType*)tb, error);
1264 return_if_nok (error);
1266 klass = mono_class_from_mono_type (t);
1268 klass->type_token = mono_metadata_make_token (MONO_TABLE_TYPEDEF, tb->table_idx);
1270 idx = mono_image_fill_export_table_from_class (domain, klass, module_index,
1271 parent_index, assembly);
1275 * We need to do this ourselves since klass->nested_classes is not set up.
1278 for (i = 0; i < mono_array_length (tb->subtypes); ++i) {
1279 mono_image_fill_export_table (domain, mono_array_get (tb->subtypes, MonoReflectionTypeBuilder*, i), module_index, idx, assembly, error);
1280 return_if_nok (error);
1286 mono_image_fill_export_table_from_module (MonoDomain *domain, MonoReflectionModule *module,
1287 guint32 module_index, MonoDynamicImage *assembly)
1289 MonoImage *image = module->image;
1293 t = &image->tables [MONO_TABLE_TYPEDEF];
1295 for (i = 0; i < t->rows; ++i) {
1297 MonoClass *klass = mono_class_get_checked (image, mono_metadata_make_token (MONO_TABLE_TYPEDEF, i + 1), &error);
1298 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
1300 if (mono_class_is_public (klass))
1301 mono_image_fill_export_table_from_class (domain, klass, module_index, 0, assembly);
1306 add_exported_type (MonoReflectionAssemblyBuilder *assemblyb, MonoDynamicImage *assembly, MonoClass *klass, guint32 parent_index)
1308 MonoDynamicTable *table;
1310 guint32 scope, scope_idx, impl, current_idx;
1311 gboolean forwarder = TRUE;
1312 gpointer iter = NULL;
1315 if (klass->nested_in) {
1316 impl = (parent_index << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_EXP_TYPE;
1319 scope = mono_reflection_resolution_scope_from_image (assembly, klass->image);
1320 g_assert ((scope & MONO_RESOLUTION_SCOPE_MASK) == MONO_RESOLUTION_SCOPE_ASSEMBLYREF);
1321 scope_idx = scope >> MONO_RESOLUTION_SCOPE_BITS;
1322 impl = (scope_idx << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_ASSEMBLYREF;
1325 table = &assembly->tables [MONO_TABLE_EXPORTEDTYPE];
1328 alloc_table (table, table->rows);
1329 current_idx = table->next_idx;
1330 values = table->values + current_idx * MONO_EXP_TYPE_SIZE;
1332 values [MONO_EXP_TYPE_FLAGS] = forwarder ? TYPE_ATTRIBUTE_FORWARDER : 0;
1333 values [MONO_EXP_TYPE_TYPEDEF] = 0;
1334 values [MONO_EXP_TYPE_IMPLEMENTATION] = impl;
1335 values [MONO_EXP_TYPE_NAME] = string_heap_insert (&assembly->sheap, klass->name);
1336 values [MONO_EXP_TYPE_NAMESPACE] = string_heap_insert (&assembly->sheap, klass->name_space);
1340 while ((nested = mono_class_get_nested_types (klass, &iter)))
1341 add_exported_type (assemblyb, assembly, nested, current_idx);
1345 mono_image_fill_export_table_from_type_forwarders (MonoReflectionAssemblyBuilder *assemblyb, MonoDynamicImage *assembly)
1351 if (!assemblyb->type_forwarders)
1354 for (i = 0; i < mono_array_length (assemblyb->type_forwarders); ++i) {
1355 MonoReflectionType *t = mono_array_get (assemblyb->type_forwarders, MonoReflectionType *, i);
1360 type = mono_reflection_type_get_handle (t, &error);
1361 mono_error_assert_ok (&error);
1364 klass = mono_class_from_mono_type (type);
1366 add_exported_type (assemblyb, assembly, klass, 0);
1370 #define align_pointer(base,p)\
1372 guint32 __diff = (unsigned char*)(p)-(unsigned char*)(base);\
1374 (p) += 4 - (__diff & 3);\
1378 compare_constants (const void *a, const void *b)
1380 const guint32 *a_values = (const guint32 *)a;
1381 const guint32 *b_values = (const guint32 *)b;
1382 return a_values [MONO_CONSTANT_PARENT] - b_values [MONO_CONSTANT_PARENT];
1386 compare_semantics (const void *a, const void *b)
1388 const guint32 *a_values = (const guint32 *)a;
1389 const guint32 *b_values = (const guint32 *)b;
1390 int assoc = a_values [MONO_METHOD_SEMA_ASSOCIATION] - b_values [MONO_METHOD_SEMA_ASSOCIATION];
1393 return a_values [MONO_METHOD_SEMA_SEMANTICS] - b_values [MONO_METHOD_SEMA_SEMANTICS];
1397 compare_custom_attrs (const void *a, const void *b)
1399 const guint32 *a_values = (const guint32 *)a;
1400 const guint32 *b_values = (const guint32 *)b;
1402 return a_values [MONO_CUSTOM_ATTR_PARENT] - b_values [MONO_CUSTOM_ATTR_PARENT];
1406 compare_field_marshal (const void *a, const void *b)
1408 const guint32 *a_values = (const guint32 *)a;
1409 const guint32 *b_values = (const guint32 *)b;
1411 return a_values [MONO_FIELD_MARSHAL_PARENT] - b_values [MONO_FIELD_MARSHAL_PARENT];
1415 compare_nested (const void *a, const void *b)
1417 const guint32 *a_values = (const guint32 *)a;
1418 const guint32 *b_values = (const guint32 *)b;
1420 return a_values [MONO_NESTED_CLASS_NESTED] - b_values [MONO_NESTED_CLASS_NESTED];
1424 compare_genericparam (const void *a, const void *b)
1427 const GenericParamTableEntry **a_entry = (const GenericParamTableEntry **) a;
1428 const GenericParamTableEntry **b_entry = (const GenericParamTableEntry **) b;
1430 if ((*b_entry)->owner == (*a_entry)->owner) {
1431 MonoType *a_type = mono_reflection_type_get_handle ((MonoReflectionType*)(*a_entry)->gparam, &error);
1432 mono_error_assert_ok (&error);
1433 MonoType *b_type = mono_reflection_type_get_handle ((MonoReflectionType*)(*b_entry)->gparam, &error);
1434 mono_error_assert_ok (&error);
1436 mono_type_get_generic_param_num (a_type) -
1437 mono_type_get_generic_param_num (b_type);
1439 return (*a_entry)->owner - (*b_entry)->owner;
1443 compare_declsecurity_attrs (const void *a, const void *b)
1445 const guint32 *a_values = (const guint32 *)a;
1446 const guint32 *b_values = (const guint32 *)b;
1448 return a_values [MONO_DECL_SECURITY_PARENT] - b_values [MONO_DECL_SECURITY_PARENT];
1452 compare_interface_impl (const void *a, const void *b)
1454 const guint32 *a_values = (const guint32 *)a;
1455 const guint32 *b_values = (const guint32 *)b;
1457 int klass = a_values [MONO_INTERFACEIMPL_CLASS] - b_values [MONO_INTERFACEIMPL_CLASS];
1461 return a_values [MONO_INTERFACEIMPL_INTERFACE] - b_values [MONO_INTERFACEIMPL_INTERFACE];
1466 MonoDynamicStream *stream;
1470 * build_compressed_metadata() fills in the blob of data that represents the
1471 * raw metadata as it will be saved in the PE file. The five streams are output
1472 * and the metadata tables are comnpressed from the guint32 array representation,
1473 * to the compressed on-disk format.
1476 build_compressed_metadata (MonoDynamicImage *assembly, MonoError *error)
1478 MonoDynamicTable *table;
1480 guint64 valid_mask = 0;
1481 guint64 sorted_mask;
1482 guint32 heapt_size = 0;
1483 guint32 meta_size = 256; /* allow for header and other stuff */
1484 guint32 table_offset;
1485 guint32 ntables = 0;
1491 struct StreamDesc stream_desc [5];
1495 qsort (assembly->gen_params->pdata, assembly->gen_params->len, sizeof (gpointer), compare_genericparam);
1496 for (i = 0; i < assembly->gen_params->len; i++) {
1497 GenericParamTableEntry *entry = (GenericParamTableEntry *)g_ptr_array_index (assembly->gen_params, i);
1498 if (!write_generic_param_entry (assembly, entry, error))
1502 stream_desc [0].name = "#~";
1503 stream_desc [0].stream = &assembly->tstream;
1504 stream_desc [1].name = "#Strings";
1505 stream_desc [1].stream = &assembly->sheap;
1506 stream_desc [2].name = "#US";
1507 stream_desc [2].stream = &assembly->us;
1508 stream_desc [3].name = "#Blob";
1509 stream_desc [3].stream = &assembly->blob;
1510 stream_desc [4].name = "#GUID";
1511 stream_desc [4].stream = &assembly->guid;
1513 /* tables that are sorted */
1514 sorted_mask = ((guint64)1 << MONO_TABLE_CONSTANT) | ((guint64)1 << MONO_TABLE_FIELDMARSHAL)
1515 | ((guint64)1 << MONO_TABLE_METHODSEMANTICS) | ((guint64)1 << MONO_TABLE_CLASSLAYOUT)
1516 | ((guint64)1 << MONO_TABLE_FIELDLAYOUT) | ((guint64)1 << MONO_TABLE_FIELDRVA)
1517 | ((guint64)1 << MONO_TABLE_IMPLMAP) | ((guint64)1 << MONO_TABLE_NESTEDCLASS)
1518 | ((guint64)1 << MONO_TABLE_METHODIMPL) | ((guint64)1 << MONO_TABLE_CUSTOMATTRIBUTE)
1519 | ((guint64)1 << MONO_TABLE_DECLSECURITY) | ((guint64)1 << MONO_TABLE_GENERICPARAM)
1520 | ((guint64)1 << MONO_TABLE_INTERFACEIMPL);
1522 /* Compute table sizes */
1523 /* the MonoImage has already been created in mono_reflection_dynimage_basic_init() */
1524 meta = &assembly->image;
1526 /* sizes should be multiple of 4 */
1527 mono_dynstream_data_align (&assembly->blob);
1528 mono_dynstream_data_align (&assembly->guid);
1529 mono_dynstream_data_align (&assembly->sheap);
1530 mono_dynstream_data_align (&assembly->us);
1532 /* Setup the info used by compute_sizes () */
1533 meta->idx_blob_wide = assembly->blob.index >= 65536 ? 1 : 0;
1534 meta->idx_guid_wide = assembly->guid.index >= 65536 ? 1 : 0;
1535 meta->idx_string_wide = assembly->sheap.index >= 65536 ? 1 : 0;
1537 meta_size += assembly->blob.index;
1538 meta_size += assembly->guid.index;
1539 meta_size += assembly->sheap.index;
1540 meta_size += assembly->us.index;
1542 for (i=0; i < MONO_TABLE_NUM; ++i)
1543 meta->tables [i].rows = assembly->tables [i].rows;
1545 for (i = 0; i < MONO_TABLE_NUM; i++){
1546 if (meta->tables [i].rows == 0)
1548 valid_mask |= (guint64)1 << i;
1550 meta->tables [i].row_size = mono_metadata_compute_size (
1551 meta, i, &meta->tables [i].size_bitfield);
1552 heapt_size += meta->tables [i].row_size * meta->tables [i].rows;
1554 heapt_size += 24; /* #~ header size */
1555 heapt_size += ntables * 4;
1556 /* make multiple of 4 */
1559 meta_size += heapt_size;
1560 meta->raw_metadata = (char *)g_malloc0 (meta_size);
1561 p = (unsigned char*)meta->raw_metadata;
1562 /* the metadata signature */
1563 *p++ = 'B'; *p++ = 'S'; *p++ = 'J'; *p++ = 'B';
1564 /* version numbers and 4 bytes reserved */
1565 int16val = (guint16*)p;
1566 *int16val++ = GUINT16_TO_LE (meta->md_version_major);
1567 *int16val = GUINT16_TO_LE (meta->md_version_minor);
1569 /* version string */
1570 int32val = (guint32*)p;
1571 *int32val = GUINT32_TO_LE ((strlen (meta->version) + 3) & (~3)); /* needs to be multiple of 4 */
1573 memcpy (p, meta->version, strlen (meta->version));
1574 p += GUINT32_FROM_LE (*int32val);
1575 align_pointer (meta->raw_metadata, p);
1576 int16val = (guint16*)p;
1577 *int16val++ = GUINT16_TO_LE (0); /* flags must be 0 */
1578 *int16val = GUINT16_TO_LE (5); /* number of streams */
1582 * write the stream info.
1584 table_offset = (p - (unsigned char*)meta->raw_metadata) + 5 * 8 + 40; /* room needed for stream headers */
1585 table_offset += 3; table_offset &= ~3;
1587 assembly->tstream.index = heapt_size;
1588 for (i = 0; i < 5; ++i) {
1589 int32val = (guint32*)p;
1590 stream_desc [i].stream->offset = table_offset;
1591 *int32val++ = GUINT32_TO_LE (table_offset);
1592 *int32val = GUINT32_TO_LE (stream_desc [i].stream->index);
1593 table_offset += GUINT32_FROM_LE (*int32val);
1594 table_offset += 3; table_offset &= ~3;
1596 strcpy ((char*)p, stream_desc [i].name);
1597 p += strlen (stream_desc [i].name) + 1;
1598 align_pointer (meta->raw_metadata, p);
1601 * now copy the data, the table stream header and contents goes first.
1603 g_assert ((p - (unsigned char*)meta->raw_metadata) < assembly->tstream.offset);
1604 p = (guchar*)meta->raw_metadata + assembly->tstream.offset;
1605 int32val = (guint32*)p;
1606 *int32val = GUINT32_TO_LE (0); /* reserved */
1609 *p++ = 2; /* version */
1612 if (meta->idx_string_wide)
1614 if (meta->idx_guid_wide)
1616 if (meta->idx_blob_wide)
1619 *p++ = 1; /* reserved */
1620 int64val = (guint64*)p;
1621 *int64val++ = GUINT64_TO_LE (valid_mask);
1622 *int64val++ = GUINT64_TO_LE (valid_mask & sorted_mask); /* bitvector of sorted tables */
1624 int32val = (guint32*)p;
1625 for (i = 0; i < MONO_TABLE_NUM; i++){
1626 if (meta->tables [i].rows == 0)
1628 *int32val++ = GUINT32_TO_LE (meta->tables [i].rows);
1630 p = (unsigned char*)int32val;
1632 /* sort the tables that still need sorting */
1633 table = &assembly->tables [MONO_TABLE_CONSTANT];
1635 qsort (table->values + MONO_CONSTANT_SIZE, table->rows, sizeof (guint32) * MONO_CONSTANT_SIZE, compare_constants);
1636 table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
1638 qsort (table->values + MONO_METHOD_SEMA_SIZE, table->rows, sizeof (guint32) * MONO_METHOD_SEMA_SIZE, compare_semantics);
1639 table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1641 qsort (table->values + MONO_CUSTOM_ATTR_SIZE, table->rows, sizeof (guint32) * MONO_CUSTOM_ATTR_SIZE, compare_custom_attrs);
1642 table = &assembly->tables [MONO_TABLE_FIELDMARSHAL];
1644 qsort (table->values + MONO_FIELD_MARSHAL_SIZE, table->rows, sizeof (guint32) * MONO_FIELD_MARSHAL_SIZE, compare_field_marshal);
1645 table = &assembly->tables [MONO_TABLE_NESTEDCLASS];
1647 qsort (table->values + MONO_NESTED_CLASS_SIZE, table->rows, sizeof (guint32) * MONO_NESTED_CLASS_SIZE, compare_nested);
1648 /* Section 21.11 DeclSecurity in Partition II doesn't specify this to be sorted by MS implementation requires it */
1649 table = &assembly->tables [MONO_TABLE_DECLSECURITY];
1651 qsort (table->values + MONO_DECL_SECURITY_SIZE, table->rows, sizeof (guint32) * MONO_DECL_SECURITY_SIZE, compare_declsecurity_attrs);
1652 table = &assembly->tables [MONO_TABLE_INTERFACEIMPL];
1654 qsort (table->values + MONO_INTERFACEIMPL_SIZE, table->rows, sizeof (guint32) * MONO_INTERFACEIMPL_SIZE, compare_interface_impl);
1656 /* compress the tables */
1657 for (i = 0; i < MONO_TABLE_NUM; i++){
1660 guint32 bitfield = meta->tables [i].size_bitfield;
1661 if (!meta->tables [i].rows)
1663 if (assembly->tables [i].columns != mono_metadata_table_count (bitfield))
1664 g_error ("col count mismatch in %d: %d %d", i, assembly->tables [i].columns, mono_metadata_table_count (bitfield));
1665 meta->tables [i].base = (char*)p;
1666 for (row = 1; row <= meta->tables [i].rows; ++row) {
1667 values = assembly->tables [i].values + row * assembly->tables [i].columns;
1668 for (col = 0; col < assembly->tables [i].columns; ++col) {
1669 switch (mono_metadata_table_size (bitfield, col)) {
1671 *p++ = values [col];
1674 *p++ = values [col] & 0xff;
1675 *p++ = (values [col] >> 8) & 0xff;
1678 *p++ = values [col] & 0xff;
1679 *p++ = (values [col] >> 8) & 0xff;
1680 *p++ = (values [col] >> 16) & 0xff;
1681 *p++ = (values [col] >> 24) & 0xff;
1684 g_assert_not_reached ();
1688 g_assert ((p - (const unsigned char*)meta->tables [i].base) == (meta->tables [i].rows * meta->tables [i].row_size));
1691 g_assert (assembly->guid.offset + assembly->guid.index < meta_size);
1692 memcpy (meta->raw_metadata + assembly->sheap.offset, assembly->sheap.data, assembly->sheap.index);
1693 memcpy (meta->raw_metadata + assembly->us.offset, assembly->us.data, assembly->us.index);
1694 memcpy (meta->raw_metadata + assembly->blob.offset, assembly->blob.data, assembly->blob.index);
1695 memcpy (meta->raw_metadata + assembly->guid.offset, assembly->guid.data, assembly->guid.index);
1697 assembly->meta_size = assembly->guid.offset + assembly->guid.index;
1703 * Some tables in metadata need to be sorted according to some criteria, but
1704 * when methods and fields are first created with reflection, they may be assigned a token
1705 * that doesn't correspond to the final token they will get assigned after the sorting.
1706 * ILGenerator.cs keeps a fixup table that maps the position of tokens in the IL code stream
1707 * with the reflection objects that represent them. Once all the tables are set up, the
1708 * reflection objects will contains the correct table index. fixup_method() will fixup the
1709 * tokens for the method with ILGenerator @ilgen.
1712 fixup_method (MonoReflectionILGen *ilgen, gpointer value, MonoDynamicImage *assembly)
1714 guint32 code_idx = GPOINTER_TO_UINT (value);
1715 MonoReflectionILTokenInfo *iltoken;
1716 MonoReflectionTypeBuilder *tb;
1717 MonoReflectionArrayMethod *am;
1719 unsigned char *target;
1721 for (i = 0; i < ilgen->num_token_fixups; ++i) {
1722 iltoken = (MonoReflectionILTokenInfo *)mono_array_addr_with_size (ilgen->token_fixups, sizeof (MonoReflectionILTokenInfo), i);
1723 target = (guchar*)assembly->code.data + code_idx + iltoken->code_pos;
1724 switch (target [3]) {
1725 case MONO_TABLE_FIELD:
1726 if (!strcmp (iltoken->member->vtable->klass->name, "FieldBuilder")) {
1727 g_assert_not_reached ();
1728 } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoField")) {
1729 MonoClassField *f = ((MonoReflectionField*)iltoken->member)->field;
1730 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->field_to_table_idx, f));
1732 g_assert_not_reached ();
1735 case MONO_TABLE_METHOD:
1736 if (!strcmp (iltoken->member->vtable->klass->name, "MethodBuilder")) {
1737 g_assert_not_reached ();
1738 } else if (!strcmp (iltoken->member->vtable->klass->name, "ConstructorBuilder")) {
1739 g_assert_not_reached ();
1740 } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoMethod") ||
1741 !strcmp (iltoken->member->vtable->klass->name, "MonoCMethod")) {
1742 MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
1743 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, m));
1745 g_assert_not_reached ();
1748 case MONO_TABLE_TYPEDEF:
1749 if (!strcmp (iltoken->member->vtable->klass->name, "TypeBuilder")) {
1750 g_assert_not_reached ();
1751 } else if (!strcmp (iltoken->member->vtable->klass->name, "RuntimeType")) {
1752 MonoClass *k = mono_class_from_mono_type (((MonoReflectionType*)iltoken->member)->type);
1753 MonoObject *obj = mono_class_get_ref_info_raw (k); /* FIXME use handles */
1755 g_assert (!strcmp (mono_object_class (obj)->name, "TypeBuilder"));
1756 tb = (MonoReflectionTypeBuilder*)obj;
1757 idx = tb->table_idx;
1759 g_assert_not_reached ();
1762 case MONO_TABLE_MEMBERREF:
1763 if (!strcmp (iltoken->member->vtable->klass->name, "MonoArrayMethod")) {
1764 am = (MonoReflectionArrayMethod*)iltoken->member;
1765 idx = am->table_idx;
1766 } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoMethod") ||
1767 !strcmp (iltoken->member->vtable->klass->name, "MonoCMethod")) {
1768 MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
1769 g_assert (mono_class_is_ginst (m->klass) || mono_class_is_gtd (m->klass));
1771 } else if (!strcmp (iltoken->member->vtable->klass->name, "FieldBuilder")) {
1772 g_assert_not_reached ();
1774 } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoField")) {
1776 } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodBuilder") ||
1777 !strcmp (iltoken->member->vtable->klass->name, "ConstructorBuilder")) {
1778 g_assert_not_reached ();
1780 } else if (!strcmp (iltoken->member->vtable->klass->name, "FieldOnTypeBuilderInst")) {
1781 g_assert_not_reached ();
1783 } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodOnTypeBuilderInst")) {
1784 g_assert_not_reached ();
1786 } else if (!strcmp (iltoken->member->vtable->klass->name, "ConstructorOnTypeBuilderInst")) {
1787 g_assert_not_reached ();
1790 g_assert_not_reached ();
1793 case MONO_TABLE_METHODSPEC:
1794 if (!strcmp (iltoken->member->vtable->klass->name, "MonoMethod")) {
1795 MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
1796 g_assert (mono_method_signature (m)->generic_param_count);
1798 } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodBuilder")) {
1799 g_assert_not_reached ();
1801 } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodOnTypeBuilderInst")) {
1802 g_assert_not_reached ();
1805 g_assert_not_reached ();
1808 case MONO_TABLE_TYPESPEC:
1809 if (!strcmp (iltoken->member->vtable->klass->name, "RuntimeType")) {
1812 g_assert_not_reached ();
1816 g_error ("got unexpected table 0x%02x in fixup", target [3]);
1818 target [0] = idx & 0xff;
1819 target [1] = (idx >> 8) & 0xff;
1820 target [2] = (idx >> 16) & 0xff;
1827 * The CUSTOM_ATTRIBUTE table might contain METHODDEF tokens whose final
1828 * value is not known when the table is emitted.
1831 fixup_cattrs (MonoDynamicImage *assembly)
1833 MonoDynamicTable *table;
1835 guint32 type, i, idx, token;
1838 table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1840 for (i = 0; i < table->rows; ++i) {
1841 values = table->values + ((i + 1) * MONO_CUSTOM_ATTR_SIZE);
1843 type = values [MONO_CUSTOM_ATTR_TYPE];
1844 if ((type & MONO_CUSTOM_ATTR_TYPE_MASK) == MONO_CUSTOM_ATTR_TYPE_METHODDEF) {
1845 idx = type >> MONO_CUSTOM_ATTR_TYPE_BITS;
1846 token = mono_metadata_make_token (MONO_TABLE_METHOD, idx);
1847 ctor = (MonoObject *)mono_g_hash_table_lookup (assembly->remapped_tokens, GUINT_TO_POINTER (token));
1850 if (!strcmp (ctor->vtable->klass->name, "MonoCMethod")) {
1851 MonoMethod *m = ((MonoReflectionMethod*)ctor)->method;
1852 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, m));
1853 values [MONO_CUSTOM_ATTR_TYPE] = (idx << MONO_CUSTOM_ATTR_TYPE_BITS) | MONO_CUSTOM_ATTR_TYPE_METHODDEF;
1854 } else if (!strcmp (ctor->vtable->klass->name, "ConstructorBuilder")) {
1855 MonoMethod *m = ((MonoReflectionCtorBuilder*)ctor)->mhandle;
1856 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, m));
1857 values [MONO_CUSTOM_ATTR_TYPE] = (idx << MONO_CUSTOM_ATTR_TYPE_BITS) | MONO_CUSTOM_ATTR_TYPE_METHODDEF;
1864 assembly_add_resource_manifest (MonoReflectionModuleBuilder *mb, MonoDynamicImage *assembly, MonoReflectionResource *rsrc, guint32 implementation, MonoError *error)
1866 MonoDynamicTable *table;
1871 table = &assembly->tables [MONO_TABLE_MANIFESTRESOURCE];
1873 alloc_table (table, table->rows);
1874 values = table->values + table->next_idx * MONO_MANIFEST_SIZE;
1875 values [MONO_MANIFEST_OFFSET] = rsrc->offset;
1876 values [MONO_MANIFEST_FLAGS] = rsrc->attrs;
1877 values [MONO_MANIFEST_NAME] = string_heap_insert_mstring (&assembly->sheap, rsrc->name, error);
1878 return_val_if_nok (error, FALSE);
1879 values [MONO_MANIFEST_IMPLEMENTATION] = implementation;
1885 assembly_add_resource (MonoReflectionModuleBuilder *mb, MonoDynamicImage *assembly, MonoReflectionResource *rsrc, MonoError *error)
1887 MonoDynamicTable *table;
1891 char *b = blob_size;
1893 guint32 idx, offset;
1897 if (rsrc->filename) {
1898 name = mono_string_to_utf8_checked (rsrc->filename, error);
1899 return_val_if_nok (error, FALSE);
1900 sname = g_path_get_basename (name);
1902 table = &assembly->tables [MONO_TABLE_FILE];
1904 alloc_table (table, table->rows);
1905 values = table->values + table->next_idx * MONO_FILE_SIZE;
1906 values [MONO_FILE_FLAGS] = FILE_CONTAINS_NO_METADATA;
1907 values [MONO_FILE_NAME] = string_heap_insert (&assembly->sheap, sname);
1910 mono_sha1_get_digest_from_file (name, hash);
1911 mono_metadata_encode_value (20, b, &b);
1912 values [MONO_FILE_HASH_VALUE] = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
1913 mono_image_add_stream_data (&assembly->blob, (char*)hash, 20);
1915 idx = table->next_idx++;
1917 idx = MONO_IMPLEMENTATION_FILE | (idx << MONO_IMPLEMENTATION_BITS);
1923 data = mono_array_addr (rsrc->data, char, 0);
1924 len = mono_array_length (rsrc->data);
1930 sizebuf [0] = offset; sizebuf [1] = offset >> 8;
1931 sizebuf [2] = offset >> 16; sizebuf [3] = offset >> 24;
1932 rsrc->offset = mono_image_add_stream_data (&assembly->resources, sizebuf, 4);
1933 mono_image_add_stream_data (&assembly->resources, data, len);
1937 * The entry should be emitted into the MANIFESTRESOURCE table of
1938 * the main module, but that needs to reference the FILE table
1939 * which isn't emitted yet.
1946 return assembly_add_resource_manifest (mb, assembly, rsrc, idx, error);
1950 set_version_from_string (MonoString *version, guint32 *values, MonoError *error)
1952 gchar *ver, *p, *str;
1957 values [MONO_ASSEMBLY_MAJOR_VERSION] = 0;
1958 values [MONO_ASSEMBLY_MINOR_VERSION] = 0;
1959 values [MONO_ASSEMBLY_REV_NUMBER] = 0;
1960 values [MONO_ASSEMBLY_BUILD_NUMBER] = 0;
1963 ver = str = mono_string_to_utf8_checked (version, error);
1964 return_val_if_nok (error, FALSE);
1965 for (i = 0; i < 4; ++i) {
1966 values [MONO_ASSEMBLY_MAJOR_VERSION + i] = strtol (ver, &p, 10);
1972 /* handle Revision and Build */
1983 load_public_key (MonoArray *pkey, MonoDynamicImage *assembly) {
1987 char *b = blob_size;
1992 len = mono_array_length (pkey);
1993 mono_metadata_encode_value (len, b, &b);
1994 token = mono_image_add_stream_data (&assembly->blob, blob_size, b - blob_size);
1995 mono_image_add_stream_data (&assembly->blob, mono_array_addr (pkey, char, 0), len);
1997 assembly->public_key = (guint8 *)g_malloc (len);
1998 memcpy (assembly->public_key, mono_array_addr (pkey, char, 0), len);
1999 assembly->public_key_len = len;
2001 /* Special case: check for ECMA key (16 bytes) */
2002 if ((len == MONO_ECMA_KEY_LENGTH) && mono_is_ecma_key (mono_array_addr (pkey, char, 0), len)) {
2003 /* In this case we must reserve 128 bytes (1024 bits) for the signature */
2004 assembly->strong_name_size = MONO_DEFAULT_PUBLIC_KEY_LENGTH;
2005 } else if (len >= MONO_PUBLIC_KEY_HEADER_LENGTH + MONO_MINIMUM_PUBLIC_KEY_LENGTH) {
2006 /* minimum key size (in 2.0) is 384 bits */
2007 assembly->strong_name_size = len - MONO_PUBLIC_KEY_HEADER_LENGTH;
2009 /* FIXME - verifier */
2010 g_warning ("Invalid public key length: %d bits (total: %d)", (int)MONO_PUBLIC_KEY_BIT_SIZE (len), (int)len);
2011 assembly->strong_name_size = MONO_DEFAULT_PUBLIC_KEY_LENGTH; /* to be safe */
2013 assembly->strong_name = (char *)g_malloc0 (assembly->strong_name_size);
2019 mono_image_emit_manifest (MonoReflectionModuleBuilder *moduleb, MonoError *error)
2021 MonoDynamicTable *table;
2022 MonoDynamicImage *assembly;
2023 MonoReflectionAssemblyBuilder *assemblyb;
2027 guint32 module_index;
2031 assemblyb = moduleb->assemblyb;
2032 assembly = moduleb->dynamic_image;
2033 domain = mono_object_domain (assemblyb);
2035 /* Emit ASSEMBLY table */
2036 table = &assembly->tables [MONO_TABLE_ASSEMBLY];
2037 alloc_table (table, 1);
2038 values = table->values + MONO_ASSEMBLY_SIZE;
2039 values [MONO_ASSEMBLY_HASH_ALG] = assemblyb->algid? assemblyb->algid: ASSEMBLY_HASH_SHA1;
2040 values [MONO_ASSEMBLY_NAME] = string_heap_insert_mstring (&assembly->sheap, assemblyb->name, error);
2041 return_val_if_nok (error, FALSE);
2042 if (assemblyb->culture) {
2043 values [MONO_ASSEMBLY_CULTURE] = string_heap_insert_mstring (&assembly->sheap, assemblyb->culture, error);
2044 return_val_if_nok (error, FALSE);
2046 values [MONO_ASSEMBLY_CULTURE] = string_heap_insert (&assembly->sheap, "");
2048 values [MONO_ASSEMBLY_PUBLIC_KEY] = load_public_key (assemblyb->public_key, assembly);
2049 values [MONO_ASSEMBLY_FLAGS] = assemblyb->flags;
2050 if (!set_version_from_string (assemblyb->version, values, error))
2053 /* Emit FILE + EXPORTED_TYPE table */
2055 for (i = 0; i < mono_array_length (assemblyb->modules); ++i) {
2057 MonoReflectionModuleBuilder *file_module =
2058 mono_array_get (assemblyb->modules, MonoReflectionModuleBuilder*, i);
2059 if (file_module != moduleb) {
2060 if (!mono_image_fill_file_table (domain, (MonoReflectionModule*)file_module, assembly, error))
2063 if (file_module->types) {
2064 for (j = 0; j < file_module->num_types; ++j) {
2065 MonoReflectionTypeBuilder *tb = mono_array_get (file_module->types, MonoReflectionTypeBuilder*, j);
2066 mono_image_fill_export_table (domain, tb, module_index, 0, assembly, error);
2067 return_val_if_nok (error, FALSE);
2072 if (assemblyb->loaded_modules) {
2073 for (i = 0; i < mono_array_length (assemblyb->loaded_modules); ++i) {
2074 MonoReflectionModule *file_module =
2075 mono_array_get (assemblyb->loaded_modules, MonoReflectionModule*, i);
2076 if (!mono_image_fill_file_table (domain, file_module, assembly, error))
2079 mono_image_fill_export_table_from_module (domain, file_module, module_index, assembly);
2082 if (assemblyb->type_forwarders)
2083 mono_image_fill_export_table_from_type_forwarders (assemblyb, assembly);
2085 /* Emit MANIFESTRESOURCE table */
2087 for (i = 0; i < mono_array_length (assemblyb->modules); ++i) {
2089 MonoReflectionModuleBuilder *file_module =
2090 mono_array_get (assemblyb->modules, MonoReflectionModuleBuilder*, i);
2091 /* The table for the main module is emitted later */
2092 if (file_module != moduleb) {
2094 if (file_module->resources) {
2095 int len = mono_array_length (file_module->resources);
2096 for (j = 0; j < len; ++j) {
2097 MonoReflectionResource* res = (MonoReflectionResource*)mono_array_addr (file_module->resources, MonoReflectionResource, j);
2098 if (!assembly_add_resource_manifest (file_module, assembly, res, MONO_IMPLEMENTATION_FILE | (module_index << MONO_IMPLEMENTATION_BITS), error))
2107 #ifndef DISABLE_REFLECTION_EMIT_SAVE
2110 * Insert into the metadata tables all the info about the TypeBuilder tb.
2111 * Data in the tables is inserted in a predefined order, since some tables need to be sorted.
2114 mono_image_get_type_info (MonoDomain *domain, MonoReflectionTypeBuilder *tb, MonoDynamicImage *assembly, MonoError *error)
2116 MonoDynamicTable *table;
2118 int i, is_object = 0, is_system = 0;
2123 table = &assembly->tables [MONO_TABLE_TYPEDEF];
2124 values = table->values + tb->table_idx * MONO_TYPEDEF_SIZE;
2125 values [MONO_TYPEDEF_FLAGS] = tb->attrs;
2126 n = mono_string_to_utf8_checked (tb->name, error);
2127 return_val_if_nok (error, FALSE);
2128 if (strcmp (n, "Object") == 0)
2130 values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, n);
2132 n = mono_string_to_utf8_checked (tb->nspace, error);
2133 return_val_if_nok (error, FALSE);
2134 if (strcmp (n, "System") == 0)
2136 values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, n);
2138 if (tb->parent && !(is_system && is_object) &&
2139 !(tb->attrs & TYPE_ATTRIBUTE_INTERFACE)) { /* interfaces don't have a parent */
2140 MonoType *parent_type = mono_reflection_type_get_handle ((MonoReflectionType*)tb->parent, error);
2141 return_val_if_nok (error, FALSE);
2142 values [MONO_TYPEDEF_EXTENDS] = mono_image_typedef_or_ref (assembly, parent_type);
2144 values [MONO_TYPEDEF_EXTENDS] = 0;
2146 values [MONO_TYPEDEF_FIELD_LIST] = assembly->tables [MONO_TABLE_FIELD].next_idx;
2147 values [MONO_TYPEDEF_METHOD_LIST] = assembly->tables [MONO_TABLE_METHOD].next_idx;
2150 * if we have explicitlayout or sequentiallayouts, output data in the
2151 * ClassLayout table.
2153 if (((tb->attrs & TYPE_ATTRIBUTE_LAYOUT_MASK) != TYPE_ATTRIBUTE_AUTO_LAYOUT) &&
2154 ((tb->class_size > 0) || (tb->packing_size > 0))) {
2155 table = &assembly->tables [MONO_TABLE_CLASSLAYOUT];
2157 alloc_table (table, table->rows);
2158 values = table->values + table->rows * MONO_CLASS_LAYOUT_SIZE;
2159 values [MONO_CLASS_LAYOUT_PARENT] = tb->table_idx;
2160 values [MONO_CLASS_LAYOUT_CLASS_SIZE] = tb->class_size;
2161 values [MONO_CLASS_LAYOUT_PACKING_SIZE] = tb->packing_size;
2164 /* handle interfaces */
2165 if (tb->interfaces) {
2166 table = &assembly->tables [MONO_TABLE_INTERFACEIMPL];
2168 table->rows += mono_array_length (tb->interfaces);
2169 alloc_table (table, table->rows);
2170 values = table->values + (i + 1) * MONO_INTERFACEIMPL_SIZE;
2171 for (i = 0; i < mono_array_length (tb->interfaces); ++i) {
2172 MonoReflectionType* iface = (MonoReflectionType*) mono_array_get (tb->interfaces, gpointer, i);
2173 MonoType *iface_type = mono_reflection_type_get_handle (iface, error);
2174 return_val_if_nok (error, FALSE);
2175 values [MONO_INTERFACEIMPL_CLASS] = tb->table_idx;
2176 values [MONO_INTERFACEIMPL_INTERFACE] = mono_image_typedef_or_ref (assembly, iface_type);
2177 values += MONO_INTERFACEIMPL_SIZE;
2183 table = &assembly->tables [MONO_TABLE_FIELD];
2184 table->rows += tb->num_fields;
2185 alloc_table (table, table->rows);
2186 for (i = 0; i < tb->num_fields; ++i) {
2187 mono_image_get_field_info (
2188 mono_array_get (tb->fields, MonoReflectionFieldBuilder*, i), assembly, error);
2189 return_val_if_nok (error, FALSE);
2193 /* handle constructors */
2195 table = &assembly->tables [MONO_TABLE_METHOD];
2196 table->rows += mono_array_length (tb->ctors);
2197 alloc_table (table, table->rows);
2198 for (i = 0; i < mono_array_length (tb->ctors); ++i) {
2199 if (!mono_image_get_ctor_info (domain,
2200 mono_array_get (tb->ctors, MonoReflectionCtorBuilder*, i),
2206 /* handle methods */
2208 table = &assembly->tables [MONO_TABLE_METHOD];
2209 table->rows += tb->num_methods;
2210 alloc_table (table, table->rows);
2211 for (i = 0; i < tb->num_methods; ++i) {
2212 if (!mono_image_get_method_info (
2213 mono_array_get (tb->methods, MonoReflectionMethodBuilder*, i), assembly, error))
2218 /* Do the same with properties etc.. */
2219 if (tb->events && mono_array_length (tb->events)) {
2220 table = &assembly->tables [MONO_TABLE_EVENT];
2221 table->rows += mono_array_length (tb->events);
2222 alloc_table (table, table->rows);
2223 table = &assembly->tables [MONO_TABLE_EVENTMAP];
2225 alloc_table (table, table->rows);
2226 values = table->values + table->rows * MONO_EVENT_MAP_SIZE;
2227 values [MONO_EVENT_MAP_PARENT] = tb->table_idx;
2228 values [MONO_EVENT_MAP_EVENTLIST] = assembly->tables [MONO_TABLE_EVENT].next_idx;
2229 for (i = 0; i < mono_array_length (tb->events); ++i) {
2230 mono_image_get_event_info (
2231 mono_array_get (tb->events, MonoReflectionEventBuilder*, i), assembly, error);
2232 return_val_if_nok (error, FALSE);
2235 if (tb->properties && mono_array_length (tb->properties)) {
2236 table = &assembly->tables [MONO_TABLE_PROPERTY];
2237 table->rows += mono_array_length (tb->properties);
2238 alloc_table (table, table->rows);
2239 table = &assembly->tables [MONO_TABLE_PROPERTYMAP];
2241 alloc_table (table, table->rows);
2242 values = table->values + table->rows * MONO_PROPERTY_MAP_SIZE;
2243 values [MONO_PROPERTY_MAP_PARENT] = tb->table_idx;
2244 values [MONO_PROPERTY_MAP_PROPERTY_LIST] = assembly->tables [MONO_TABLE_PROPERTY].next_idx;
2245 for (i = 0; i < mono_array_length (tb->properties); ++i) {
2246 mono_image_get_property_info (
2247 mono_array_get (tb->properties, MonoReflectionPropertyBuilder*, i), assembly, error);
2248 return_val_if_nok (error, FALSE);
2252 /* handle generic parameters */
2253 if (tb->generic_params) {
2254 table = &assembly->tables [MONO_TABLE_GENERICPARAM];
2255 table->rows += mono_array_length (tb->generic_params);
2256 alloc_table (table, table->rows);
2257 for (i = 0; i < mono_array_length (tb->generic_params); ++i) {
2258 guint32 owner = MONO_TYPEORMETHOD_TYPE | (tb->table_idx << MONO_TYPEORMETHOD_BITS);
2260 mono_image_get_generic_param_info (
2261 mono_array_get (tb->generic_params, MonoReflectionGenericParam*, i), owner, assembly);
2265 mono_image_add_decl_security (assembly,
2266 mono_metadata_make_token (MONO_TABLE_TYPEDEF, tb->table_idx), tb->permissions);
2269 MonoDynamicTable *ntable;
2271 ntable = &assembly->tables [MONO_TABLE_NESTEDCLASS];
2272 ntable->rows += mono_array_length (tb->subtypes);
2273 alloc_table (ntable, ntable->rows);
2274 values = ntable->values + ntable->next_idx * MONO_NESTED_CLASS_SIZE;
2276 for (i = 0; i < mono_array_length (tb->subtypes); ++i) {
2277 MonoReflectionTypeBuilder *subtype = mono_array_get (tb->subtypes, MonoReflectionTypeBuilder*, i);
2279 values [MONO_NESTED_CLASS_NESTED] = subtype->table_idx;
2280 values [MONO_NESTED_CLASS_ENCLOSING] = tb->table_idx;
2281 /*g_print ("nesting %s (%d) in %s (%d) (rows %d/%d)\n",
2282 mono_string_to_utf8 (subtype->name), subtype->table_idx,
2283 mono_string_to_utf8 (tb->name), tb->table_idx,
2284 ntable->next_idx, ntable->rows);*/
2285 values += MONO_NESTED_CLASS_SIZE;
2295 * mono_image_build_metadata() will fill the info in all the needed metadata tables
2296 * for the modulebuilder @moduleb.
2297 * At the end of the process, method and field tokens are fixed up and the
2298 * on-disk compressed metadata representation is created.
2299 * Return TRUE on success, or FALSE on failure and sets @error
2302 mono_image_build_metadata (MonoReflectionModuleBuilder *moduleb, MonoError *error)
2304 MonoDynamicTable *table;
2305 MonoDynamicImage *assembly;
2306 MonoReflectionAssemblyBuilder *assemblyb;
2314 assemblyb = moduleb->assemblyb;
2315 assembly = moduleb->dynamic_image;
2316 domain = mono_object_domain (assemblyb);
2318 if (assembly->text_rva)
2321 assembly->text_rva = START_TEXT_RVA;
2323 if (moduleb->is_main) {
2324 mono_image_emit_manifest (moduleb, error);
2325 return_val_if_nok (error, FALSE);
2328 table = &assembly->tables [MONO_TABLE_TYPEDEF];
2329 table->rows = 1; /* .<Module> */
2331 alloc_table (table, table->rows);
2333 * Set the first entry.
2335 values = table->values + table->columns;
2336 values [MONO_TYPEDEF_FLAGS] = 0;
2337 values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, "<Module>") ;
2338 values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, "") ;
2339 values [MONO_TYPEDEF_EXTENDS] = 0;
2340 values [MONO_TYPEDEF_FIELD_LIST] = 1;
2341 values [MONO_TYPEDEF_METHOD_LIST] = 1;
2344 * handle global methods
2345 * FIXME: test what to do when global methods are defined in multiple modules.
2347 if (moduleb->global_methods) {
2348 table = &assembly->tables [MONO_TABLE_METHOD];
2349 table->rows += mono_array_length (moduleb->global_methods);
2350 alloc_table (table, table->rows);
2351 for (i = 0; i < mono_array_length (moduleb->global_methods); ++i) {
2352 if (!mono_image_get_method_info (
2353 mono_array_get (moduleb->global_methods, MonoReflectionMethodBuilder*, i), assembly, error))
2357 if (moduleb->global_fields) {
2358 table = &assembly->tables [MONO_TABLE_FIELD];
2359 table->rows += mono_array_length (moduleb->global_fields);
2360 alloc_table (table, table->rows);
2361 for (i = 0; i < mono_array_length (moduleb->global_fields); ++i) {
2362 mono_image_get_field_info (
2363 mono_array_get (moduleb->global_fields, MonoReflectionFieldBuilder*, i), assembly,
2370 table = &assembly->tables [MONO_TABLE_MODULE];
2371 alloc_table (table, 1);
2372 mono_image_fill_module_table (domain, moduleb, assembly, error);
2376 /* Collect all types into a list sorted by their table_idx */
2377 mono_ptr_array_init (types, moduleb->num_types, MONO_ROOT_SOURCE_REFLECTION, "dynamic module types list");
2380 for (i = 0; i < moduleb->num_types; ++i) {
2381 MonoReflectionTypeBuilder *type = mono_array_get (moduleb->types, MonoReflectionTypeBuilder*, i);
2382 collect_types (&types, type);
2385 mono_ptr_array_sort (types, (int (*)(const void *, const void *))compare_types_by_table_idx);
2386 table = &assembly->tables [MONO_TABLE_TYPEDEF];
2387 table->rows += mono_ptr_array_size (types);
2388 alloc_table (table, table->rows);
2391 * Emit type names + namespaces at one place inside the string heap,
2392 * so load_class_names () needs to touch fewer pages.
2394 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2395 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2396 string_heap_insert_mstring (&assembly->sheap, tb->nspace, error);
2400 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2401 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2402 string_heap_insert_mstring (&assembly->sheap, tb->name, error);
2407 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2408 MonoReflectionTypeBuilder *type = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2409 if (!mono_image_get_type_info (domain, type, assembly, error))
2414 * table->rows is already set above and in mono_image_fill_module_table.
2416 /* add all the custom attributes at the end, once all the indexes are stable */
2417 if (!mono_image_add_cattrs (assembly, 1, MONO_CUSTOM_ATTR_ASSEMBLY, assemblyb->cattrs, error))
2420 /* CAS assembly permissions */
2421 if (assemblyb->permissions_minimum)
2422 mono_image_add_decl_security (assembly, mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1), assemblyb->permissions_minimum);
2423 if (assemblyb->permissions_optional)
2424 mono_image_add_decl_security (assembly, mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1), assemblyb->permissions_optional);
2425 if (assemblyb->permissions_refused)
2426 mono_image_add_decl_security (assembly, mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1), assemblyb->permissions_refused);
2428 if (!module_add_cattrs (assembly, moduleb, error))
2432 mono_g_hash_table_foreach (assembly->token_fixups, (GHFunc)fixup_method, assembly);
2434 /* Create the MethodImpl table. We do this after emitting all methods so we already know
2435 * the final tokens and don't need another fixup pass. */
2437 if (moduleb->global_methods) {
2438 for (i = 0; i < mono_array_length (moduleb->global_methods); ++i) {
2439 MonoReflectionMethodBuilder *mb = mono_array_get (
2440 moduleb->global_methods, MonoReflectionMethodBuilder*, i);
2441 if (!mono_image_add_methodimpl (assembly, mb, error))
2446 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2447 MonoReflectionTypeBuilder *type = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2448 if (type->methods) {
2449 for (j = 0; j < type->num_methods; ++j) {
2450 MonoReflectionMethodBuilder *mb = mono_array_get (
2451 type->methods, MonoReflectionMethodBuilder*, j);
2453 if (!mono_image_add_methodimpl (assembly, mb, error))
2459 fixup_cattrs (assembly);
2462 mono_ptr_array_destroy (types);
2465 return mono_error_ok (error);
2468 #else /* DISABLE_REFLECTION_EMIT_SAVE */
2471 mono_image_build_metadata (MonoReflectionModuleBuilder *moduleb, MonoError *error)
2473 g_error ("This mono runtime was configured with --enable-minimal=reflection_emit_save, so saving of dynamic assemblies is not supported.");
2476 #endif /* DISABLE_REFLECTION_EMIT_SAVE */
2478 #ifndef DISABLE_REFLECTION_EMIT_SAVE
2481 calc_section_size (MonoDynamicImage *assembly)
2485 /* alignment constraints */
2486 mono_image_add_stream_zero (&assembly->code, 4 - (assembly->code.index % 4));
2487 g_assert ((assembly->code.index % 4) == 0);
2488 assembly->meta_size += 3;
2489 assembly->meta_size &= ~3;
2490 mono_image_add_stream_zero (&assembly->resources, 4 - (assembly->resources.index % 4));
2491 g_assert ((assembly->resources.index % 4) == 0);
2493 assembly->sections [MONO_SECTION_TEXT].size = assembly->meta_size + assembly->code.index + assembly->resources.index + assembly->strong_name_size;
2494 assembly->sections [MONO_SECTION_TEXT].attrs = SECT_FLAGS_HAS_CODE | SECT_FLAGS_MEM_EXECUTE | SECT_FLAGS_MEM_READ;
2497 if (assembly->win32_res) {
2498 guint32 res_size = (assembly->win32_res_size + 3) & ~3;
2500 assembly->sections [MONO_SECTION_RSRC].size = res_size;
2501 assembly->sections [MONO_SECTION_RSRC].attrs = SECT_FLAGS_HAS_INITIALIZED_DATA | SECT_FLAGS_MEM_READ;
2505 assembly->sections [MONO_SECTION_RELOC].size = 12;
2506 assembly->sections [MONO_SECTION_RELOC].attrs = SECT_FLAGS_MEM_READ | SECT_FLAGS_MEM_DISCARDABLE | SECT_FLAGS_HAS_INITIALIZED_DATA;
2516 MonoReflectionWin32Resource *win32_res; /* Only for leaf nodes */
2520 resource_tree_compare_by_id (gconstpointer a, gconstpointer b)
2522 ResTreeNode *t1 = (ResTreeNode*)a;
2523 ResTreeNode *t2 = (ResTreeNode*)b;
2525 return t1->id - t2->id;
2529 * resource_tree_create:
2531 * Organize the resources into a resource tree.
2533 static ResTreeNode *
2534 resource_tree_create (MonoArray *win32_resources)
2536 ResTreeNode *tree, *res_node, *type_node, *lang_node;
2540 tree = g_new0 (ResTreeNode, 1);
2542 for (i = 0; i < mono_array_length (win32_resources); ++i) {
2543 MonoReflectionWin32Resource *win32_res =
2544 (MonoReflectionWin32Resource*)mono_array_addr (win32_resources, MonoReflectionWin32Resource, i);
2548 /* FIXME: BUG: this stores managed references in unmanaged memory */
2549 lang_node = g_new0 (ResTreeNode, 1);
2550 lang_node->id = win32_res->lang_id;
2551 lang_node->win32_res = win32_res;
2553 /* Create type node if neccesary */
2555 for (l = tree->children; l; l = l->next)
2556 if (((ResTreeNode*)(l->data))->id == win32_res->res_type) {
2557 type_node = (ResTreeNode*)l->data;
2562 type_node = g_new0 (ResTreeNode, 1);
2563 type_node->id = win32_res->res_type;
2566 * The resource types have to be sorted otherwise
2567 * Windows Explorer can't display the version information.
2569 tree->children = g_slist_insert_sorted (tree->children,
2570 type_node, resource_tree_compare_by_id);
2573 /* Create res node if neccesary */
2575 for (l = type_node->children; l; l = l->next)
2576 if (((ResTreeNode*)(l->data))->id == win32_res->res_id) {
2577 res_node = (ResTreeNode*)l->data;
2582 res_node = g_new0 (ResTreeNode, 1);
2583 res_node->id = win32_res->res_id;
2584 type_node->children = g_slist_append (type_node->children, res_node);
2587 res_node->children = g_slist_append (res_node->children, lang_node);
2594 * resource_tree_encode:
2596 * Encode the resource tree into the format used in the PE file.
2599 resource_tree_encode (ResTreeNode *node, char *begin, char *p, char **endbuf)
2602 MonoPEResourceDir dir;
2603 MonoPEResourceDirEntry dir_entry;
2604 MonoPEResourceDataEntry data_entry;
2606 guint32 res_id_entries;
2609 * For the format of the resource directory, see the article
2610 * "An In-Depth Look into the Win32 Portable Executable File Format" by
2614 memset (&dir, 0, sizeof (dir));
2615 memset (&dir_entry, 0, sizeof (dir_entry));
2616 memset (&data_entry, 0, sizeof (data_entry));
2618 g_assert (sizeof (dir) == 16);
2619 g_assert (sizeof (dir_entry) == 8);
2620 g_assert (sizeof (data_entry) == 16);
2622 node->offset = p - begin;
2624 /* IMAGE_RESOURCE_DIRECTORY */
2625 res_id_entries = g_slist_length (node->children);
2626 dir.res_id_entries = GUINT16_TO_LE (res_id_entries);
2628 memcpy (p, &dir, sizeof (dir));
2631 /* Reserve space for entries */
2633 p += sizeof (dir_entry) * res_id_entries;
2635 /* Write children */
2636 for (l = node->children; l; l = l->next) {
2637 ResTreeNode *child = (ResTreeNode*)l->data;
2639 if (child->win32_res) {
2642 child->offset = p - begin;
2644 /* IMAGE_RESOURCE_DATA_ENTRY */
2645 data_entry.rde_data_offset = GUINT32_TO_LE (p - begin + sizeof (data_entry));
2646 size = mono_array_length (child->win32_res->res_data);
2647 data_entry.rde_size = GUINT32_TO_LE (size);
2649 memcpy (p, &data_entry, sizeof (data_entry));
2650 p += sizeof (data_entry);
2652 memcpy (p, mono_array_addr (child->win32_res->res_data, char, 0), size);
2655 resource_tree_encode (child, begin, p, &p);
2659 /* IMAGE_RESOURCE_ENTRY */
2660 for (l = node->children; l; l = l->next) {
2661 ResTreeNode *child = (ResTreeNode*)l->data;
2663 MONO_PE_RES_DIR_ENTRY_SET_NAME (dir_entry, FALSE, child->id);
2664 MONO_PE_RES_DIR_ENTRY_SET_DIR (dir_entry, !child->win32_res, child->offset);
2666 memcpy (entries, &dir_entry, sizeof (dir_entry));
2667 entries += sizeof (dir_entry);
2674 resource_tree_free (ResTreeNode * node)
2677 for (list = node->children; list; list = list->next)
2678 resource_tree_free ((ResTreeNode*)list->data);
2679 g_slist_free(node->children);
2684 assembly_add_win32_resources (MonoDynamicImage *assembly, MonoReflectionAssemblyBuilder *assemblyb)
2689 MonoReflectionWin32Resource *win32_res;
2692 if (!assemblyb->win32_resources)
2696 * Resources are stored in a three level tree inside the PE file.
2697 * - level one contains a node for each type of resource
2698 * - level two contains a node for each resource
2699 * - level three contains a node for each instance of a resource for a
2700 * specific language.
2703 tree = resource_tree_create (assemblyb->win32_resources);
2705 /* Estimate the size of the encoded tree */
2707 for (i = 0; i < mono_array_length (assemblyb->win32_resources); ++i) {
2708 win32_res = (MonoReflectionWin32Resource*)mono_array_addr (assemblyb->win32_resources, MonoReflectionWin32Resource, i);
2709 size += mono_array_length (win32_res->res_data);
2711 /* Directory structure */
2712 size += mono_array_length (assemblyb->win32_resources) * 256;
2713 p = buf = (char *)g_malloc (size);
2715 resource_tree_encode (tree, p, p, &p);
2717 g_assert (p - buf <= size);
2719 assembly->win32_res = (char *)g_malloc (p - buf);
2720 assembly->win32_res_size = p - buf;
2721 memcpy (assembly->win32_res, buf, p - buf);
2724 resource_tree_free (tree);
2728 fixup_resource_directory (char *res_section, char *p, guint32 rva)
2730 MonoPEResourceDir *dir = (MonoPEResourceDir*)p;
2733 p += sizeof (MonoPEResourceDir);
2734 for (i = 0; i < GUINT16_FROM_LE (dir->res_named_entries) + GUINT16_FROM_LE (dir->res_id_entries); ++i) {
2735 MonoPEResourceDirEntry *dir_entry = (MonoPEResourceDirEntry*)p;
2736 char *child = res_section + MONO_PE_RES_DIR_ENTRY_DIR_OFFSET (*dir_entry);
2737 if (MONO_PE_RES_DIR_ENTRY_IS_DIR (*dir_entry)) {
2738 fixup_resource_directory (res_section, child, rva);
2740 MonoPEResourceDataEntry *data_entry = (MonoPEResourceDataEntry*)child;
2741 data_entry->rde_data_offset = GUINT32_TO_LE (GUINT32_FROM_LE (data_entry->rde_data_offset) + rva);
2744 p += sizeof (MonoPEResourceDirEntry);
2749 checked_write_file (HANDLE f, gconstpointer buffer, guint32 numbytes)
2752 if (!mono_w32file_write (f, buffer, numbytes, &dummy))
2753 g_error ("mono_w32file_write returned %d\n", mono_w32error_get_last ());
2757 * mono_image_create_pefile:
2758 * @mb: a module builder object
2760 * This function creates the PE-COFF header, the image sections, the CLI header * etc. all the data is written in
2761 * assembly->pefile where it can be easily retrieved later in chunks.
2764 mono_image_create_pefile (MonoReflectionModuleBuilder *mb, HANDLE file, MonoError *error)
2766 MonoMSDOSHeader *msdos;
2767 MonoDotNetHeader *header;
2768 MonoSectionTable *section;
2769 MonoCLIHeader *cli_header;
2770 guint32 size, image_size, virtual_base, text_offset;
2771 guint32 header_start, section_start, file_offset, virtual_offset;
2772 MonoDynamicImage *assembly;
2773 MonoReflectionAssemblyBuilder *assemblyb;
2774 MonoDynamicStream pefile_stream = {0};
2775 MonoDynamicStream *pefile = &pefile_stream;
2777 guint32 *rva, value;
2779 static const unsigned char msheader[] = {
2780 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
2781 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2782 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2783 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
2784 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68,
2785 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f,
2786 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,
2787 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
2792 assemblyb = mb->assemblyb;
2794 mono_reflection_dynimage_basic_init (assemblyb);
2795 assembly = mb->dynamic_image;
2797 assembly->pe_kind = assemblyb->pe_kind;
2798 assembly->machine = assemblyb->machine;
2799 ((MonoDynamicImage*)assemblyb->dynamic_assembly->assembly.image)->pe_kind = assemblyb->pe_kind;
2800 ((MonoDynamicImage*)assemblyb->dynamic_assembly->assembly.image)->machine = assemblyb->machine;
2802 if (!mono_image_build_metadata (mb, error))
2806 if (mb->is_main && assemblyb->resources) {
2807 int len = mono_array_length (assemblyb->resources);
2808 for (i = 0; i < len; ++i) {
2809 if (!assembly_add_resource (mb, assembly, (MonoReflectionResource*)mono_array_addr (assemblyb->resources, MonoReflectionResource, i), error))
2814 if (mb->resources) {
2815 int len = mono_array_length (mb->resources);
2816 for (i = 0; i < len; ++i) {
2817 if (!assembly_add_resource (mb, assembly, (MonoReflectionResource*)mono_array_addr (mb->resources, MonoReflectionResource, i), error))
2822 if (!build_compressed_metadata (assembly, error))
2826 assembly_add_win32_resources (assembly, assemblyb);
2828 nsections = calc_section_size (assembly);
2830 /* The DOS header and stub */
2831 g_assert (sizeof (MonoMSDOSHeader) == sizeof (msheader));
2832 mono_image_add_stream_data (pefile, (char*)msheader, sizeof (msheader));
2834 /* the dotnet header */
2835 header_start = mono_image_add_stream_zero (pefile, sizeof (MonoDotNetHeader));
2837 /* the section tables */
2838 section_start = mono_image_add_stream_zero (pefile, sizeof (MonoSectionTable) * nsections);
2840 file_offset = section_start + sizeof (MonoSectionTable) * nsections;
2841 virtual_offset = VIRT_ALIGN;
2844 for (i = 0; i < MONO_SECTION_MAX; ++i) {
2845 if (!assembly->sections [i].size)
2848 file_offset += FILE_ALIGN - 1;
2849 file_offset &= ~(FILE_ALIGN - 1);
2850 virtual_offset += VIRT_ALIGN - 1;
2851 virtual_offset &= ~(VIRT_ALIGN - 1);
2853 assembly->sections [i].offset = file_offset;
2854 assembly->sections [i].rva = virtual_offset;
2856 file_offset += assembly->sections [i].size;
2857 virtual_offset += assembly->sections [i].size;
2858 image_size += (assembly->sections [i].size + VIRT_ALIGN - 1) & ~(VIRT_ALIGN - 1);
2861 file_offset += FILE_ALIGN - 1;
2862 file_offset &= ~(FILE_ALIGN - 1);
2864 image_size += section_start + sizeof (MonoSectionTable) * nsections;
2866 /* back-patch info */
2867 msdos = (MonoMSDOSHeader*)pefile->data;
2868 msdos->pe_offset = GUINT32_FROM_LE (sizeof (MonoMSDOSHeader));
2870 header = (MonoDotNetHeader*)(pefile->data + header_start);
2871 header->pesig [0] = 'P';
2872 header->pesig [1] = 'E';
2874 header->coff.coff_machine = GUINT16_FROM_LE (assemblyb->machine);
2875 header->coff.coff_sections = GUINT16_FROM_LE (nsections);
2876 header->coff.coff_time = GUINT32_FROM_LE (time (NULL));
2877 header->coff.coff_opt_header_size = GUINT16_FROM_LE (sizeof (MonoDotNetHeader) - sizeof (MonoCOFFHeader) - 4);
2878 if (assemblyb->pekind == 1) {
2880 header->coff.coff_attributes = GUINT16_FROM_LE (0x210e);
2883 header->coff.coff_attributes = GUINT16_FROM_LE (0x010e);
2886 virtual_base = 0x400000; /* FIXME: 0x10000000 if a DLL */
2888 header->pe.pe_magic = GUINT16_FROM_LE (0x10B);
2889 header->pe.pe_major = 6;
2890 header->pe.pe_minor = 0;
2891 size = assembly->sections [MONO_SECTION_TEXT].size;
2892 size += FILE_ALIGN - 1;
2893 size &= ~(FILE_ALIGN - 1);
2894 header->pe.pe_code_size = GUINT32_FROM_LE(size);
2895 size = assembly->sections [MONO_SECTION_RSRC].size;
2896 size += FILE_ALIGN - 1;
2897 size &= ~(FILE_ALIGN - 1);
2898 header->pe.pe_data_size = GUINT32_FROM_LE(size);
2899 g_assert (START_TEXT_RVA == assembly->sections [MONO_SECTION_TEXT].rva);
2900 header->pe.pe_rva_code_base = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_TEXT].rva);
2901 header->pe.pe_rva_data_base = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].rva);
2902 /* pe_rva_entry_point always at the beginning of the text section */
2903 header->pe.pe_rva_entry_point = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_TEXT].rva);
2905 header->nt.pe_image_base = GUINT32_FROM_LE (virtual_base);
2906 header->nt.pe_section_align = GUINT32_FROM_LE (VIRT_ALIGN);
2907 header->nt.pe_file_alignment = GUINT32_FROM_LE (FILE_ALIGN);
2908 header->nt.pe_os_major = GUINT16_FROM_LE (4);
2909 header->nt.pe_os_minor = GUINT16_FROM_LE (0);
2910 header->nt.pe_subsys_major = GUINT16_FROM_LE (4);
2911 size = section_start;
2912 size += FILE_ALIGN - 1;
2913 size &= ~(FILE_ALIGN - 1);
2914 header->nt.pe_header_size = GUINT32_FROM_LE (size);
2916 size += VIRT_ALIGN - 1;
2917 size &= ~(VIRT_ALIGN - 1);
2918 header->nt.pe_image_size = GUINT32_FROM_LE (size);
2921 // Translate the PEFileKind value to the value expected by the Windows loader
2927 // PEFileKinds.Dll == 1
2928 // PEFileKinds.ConsoleApplication == 2
2929 // PEFileKinds.WindowApplication == 3
2932 // IMAGE_SUBSYSTEM_WINDOWS_GUI 2 // Image runs in the Windows GUI subsystem.
2933 // IMAGE_SUBSYSTEM_WINDOWS_CUI 3 // Image runs in the Windows character subsystem.
2935 if (assemblyb->pekind == 3)
2940 header->nt.pe_subsys_required = GUINT16_FROM_LE (kind);
2942 header->nt.pe_stack_reserve = GUINT32_FROM_LE (0x00100000);
2943 header->nt.pe_stack_commit = GUINT32_FROM_LE (0x00001000);
2944 header->nt.pe_heap_reserve = GUINT32_FROM_LE (0x00100000);
2945 header->nt.pe_heap_commit = GUINT32_FROM_LE (0x00001000);
2946 header->nt.pe_loader_flags = GUINT32_FROM_LE (0);
2947 header->nt.pe_data_dir_count = GUINT32_FROM_LE (16);
2949 /* fill data directory entries */
2951 header->datadir.pe_resource_table.size = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].size);
2952 header->datadir.pe_resource_table.rva = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].rva);
2954 header->datadir.pe_reloc_table.size = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RELOC].size);
2955 header->datadir.pe_reloc_table.rva = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RELOC].rva);
2957 header->datadir.pe_cli_header.size = GUINT32_FROM_LE (72);
2958 header->datadir.pe_cli_header.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->cli_header_offset);
2959 header->datadir.pe_iat.size = GUINT32_FROM_LE (8);
2960 header->datadir.pe_iat.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->iat_offset);
2961 /* patch entrypoint name */
2962 if (assemblyb->pekind == 1)
2963 memcpy (assembly->code.data + assembly->imp_names_offset + 2, "_CorDllMain", 12);
2965 memcpy (assembly->code.data + assembly->imp_names_offset + 2, "_CorExeMain", 12);
2966 /* patch imported function RVA name */
2967 rva = (guint32*)(assembly->code.data + assembly->iat_offset);
2968 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->imp_names_offset);
2970 /* the import table */
2971 header->datadir.pe_import_table.size = GUINT32_FROM_LE (79); /* FIXME: magic number? */
2972 header->datadir.pe_import_table.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->idt_offset);
2973 /* patch imported dll RVA name and other entries in the dir */
2974 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, name_rva));
2975 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->imp_names_offset + 14); /* 14 is hint+strlen+1 of func name */
2976 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, import_address_table_rva));
2977 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->iat_offset);
2978 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, import_lookup_table));
2979 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->ilt_offset);
2981 p = (guchar*)(assembly->code.data + assembly->ilt_offset);
2982 value = (assembly->text_rva + assembly->imp_names_offset);
2983 *p++ = (value) & 0xff;
2984 *p++ = (value >> 8) & (0xff);
2985 *p++ = (value >> 16) & (0xff);
2986 *p++ = (value >> 24) & (0xff);
2988 /* the CLI header info */
2989 cli_header = (MonoCLIHeader*)(assembly->code.data + assembly->cli_header_offset);
2990 cli_header->ch_size = GUINT32_FROM_LE (72);
2991 cli_header->ch_runtime_major = GUINT16_FROM_LE (2);
2992 cli_header->ch_runtime_minor = GUINT16_FROM_LE (5);
2993 cli_header->ch_flags = GUINT32_FROM_LE (assemblyb->pe_kind);
2994 if (assemblyb->entry_point) {
2995 guint32 table_idx = 0;
2996 if (!strcmp (assemblyb->entry_point->object.vtable->klass->name, "MethodBuilder")) {
2997 MonoReflectionMethodBuilder *methodb = (MonoReflectionMethodBuilder*)assemblyb->entry_point;
2998 table_idx = methodb->table_idx;
3000 table_idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, assemblyb->entry_point->method));
3002 cli_header->ch_entry_point = GUINT32_FROM_LE (table_idx | MONO_TOKEN_METHOD_DEF);
3004 cli_header->ch_entry_point = GUINT32_FROM_LE (0);
3006 /* The embedded managed resources */
3007 text_offset = assembly->text_rva + assembly->code.index;
3008 cli_header->ch_resources.rva = GUINT32_FROM_LE (text_offset);
3009 cli_header->ch_resources.size = GUINT32_FROM_LE (assembly->resources.index);
3010 text_offset += assembly->resources.index;
3011 cli_header->ch_metadata.rva = GUINT32_FROM_LE (text_offset);
3012 cli_header->ch_metadata.size = GUINT32_FROM_LE (assembly->meta_size);
3013 text_offset += assembly->meta_size;
3014 if (assembly->strong_name_size) {
3015 cli_header->ch_strong_name.rva = GUINT32_FROM_LE (text_offset);
3016 cli_header->ch_strong_name.size = GUINT32_FROM_LE (assembly->strong_name_size);
3017 text_offset += assembly->strong_name_size;
3020 /* write the section tables and section content */
3021 section = (MonoSectionTable*)(pefile->data + section_start);
3022 for (i = 0; i < MONO_SECTION_MAX; ++i) {
3023 static const char section_names [][7] = {
3024 ".text", ".rsrc", ".reloc"
3026 if (!assembly->sections [i].size)
3028 strcpy (section->st_name, section_names [i]);
3029 /*g_print ("output section %s (%d), size: %d\n", section->st_name, i, assembly->sections [i].size);*/
3030 section->st_virtual_address = GUINT32_FROM_LE (assembly->sections [i].rva);
3031 section->st_virtual_size = GUINT32_FROM_LE (assembly->sections [i].size);
3032 section->st_raw_data_size = GUINT32_FROM_LE (GUINT32_TO_LE (section->st_virtual_size) + (FILE_ALIGN - 1));
3033 section->st_raw_data_size &= GUINT32_FROM_LE (~(FILE_ALIGN - 1));
3034 section->st_raw_data_ptr = GUINT32_FROM_LE (assembly->sections [i].offset);
3035 section->st_flags = GUINT32_FROM_LE (assembly->sections [i].attrs);
3039 checked_write_file (file, pefile->data, pefile->index);
3041 mono_dynamic_stream_reset (pefile);
3043 for (i = 0; i < MONO_SECTION_MAX; ++i) {
3044 if (!assembly->sections [i].size)
3047 if (mono_w32file_seek (file, assembly->sections [i].offset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
3048 g_error ("mono_w32file_seek returned %d\n", mono_w32error_get_last ());
3051 case MONO_SECTION_TEXT:
3052 /* patch entry point */
3053 p = (guchar*)(assembly->code.data + 2);
3054 value = (virtual_base + assembly->text_rva + assembly->iat_offset);
3055 *p++ = (value) & 0xff;
3056 *p++ = (value >> 8) & 0xff;
3057 *p++ = (value >> 16) & 0xff;
3058 *p++ = (value >> 24) & 0xff;
3060 checked_write_file (file, assembly->code.data, assembly->code.index);
3061 checked_write_file (file, assembly->resources.data, assembly->resources.index);
3062 checked_write_file (file, assembly->image.raw_metadata, assembly->meta_size);
3063 checked_write_file (file, assembly->strong_name, assembly->strong_name_size);
3066 g_free (assembly->image.raw_metadata);
3068 case MONO_SECTION_RELOC: {
3072 guint16 type_and_offset;
3076 g_assert (sizeof (reloc) == 12);
3078 reloc.page_rva = GUINT32_FROM_LE (assembly->text_rva);
3079 reloc.block_size = GUINT32_FROM_LE (12);
3082 * the entrypoint is always at the start of the text section
3083 * 3 is IMAGE_REL_BASED_HIGHLOW
3084 * 2 is patch_size_rva - text_rva
3086 reloc.type_and_offset = GUINT16_FROM_LE ((3 << 12) + (2));
3089 checked_write_file (file, &reloc, sizeof (reloc));
3093 case MONO_SECTION_RSRC:
3094 if (assembly->win32_res) {
3096 /* Fixup the offsets in the IMAGE_RESOURCE_DATA_ENTRY structures */
3097 fixup_resource_directory (assembly->win32_res, assembly->win32_res, assembly->sections [i].rva);
3098 checked_write_file (file, assembly->win32_res, assembly->win32_res_size);
3102 g_assert_not_reached ();
3106 /* check that the file is properly padded */
3107 if (mono_w32file_seek (file, file_offset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
3108 g_error ("mono_w32file_seek returned %d\n", mono_w32error_get_last ());
3109 if (! mono_w32file_truncate (file))
3110 g_error ("mono_w32file_truncate returned %d\n", mono_w32error_get_last ());
3112 mono_dynamic_stream_reset (&assembly->code);
3113 mono_dynamic_stream_reset (&assembly->us);
3114 mono_dynamic_stream_reset (&assembly->blob);
3115 mono_dynamic_stream_reset (&assembly->guid);
3116 mono_dynamic_stream_reset (&assembly->sheap);
3118 g_hash_table_foreach (assembly->blob_cache, (GHFunc)g_free, NULL);
3119 g_hash_table_destroy (assembly->blob_cache);
3120 assembly->blob_cache = NULL;
3125 #else /* DISABLE_REFLECTION_EMIT_SAVE */
3128 mono_image_create_pefile (MonoReflectionModuleBuilder *mb, HANDLE file, MonoError *error)
3130 g_assert_not_reached ();
3133 #endif /* DISABLE_REFLECTION_EMIT_SAVE */