2 * sre-save.c: Routine for saving an image to a file.
6 * Paolo Molaro (lupus@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
10 * Copyright 2011 Rodrigo Kumpera
11 * Copyright 2016 Microsoft
13 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
19 #include "mono/metadata/dynamic-image-internals.h"
20 #include "mono/metadata/dynamic-stream-internals.h"
21 #include "mono/metadata/mono-ptr-array.h"
22 #include "mono/metadata/object-internals.h"
23 #include "mono/metadata/sre-internals.h"
24 #include "mono/metadata/security-manager.h"
25 #include "mono/metadata/tabledefs.h"
26 #include "mono/metadata/tokentype.h"
28 #include "mono/utils/checked-build.h"
29 #include "mono/utils/mono-digest.h"
30 #include "mono/utils/mono-error-internals.h"
32 #define TEXT_OFFSET 512
33 #define CLI_H_SIZE 136
34 #define FILE_ALIGN 512
35 #define VIRT_ALIGN 8192
36 #define START_TEXT_RVA 0x00002000
38 static void mono_image_get_generic_param_info (MonoReflectionGenericParam *gparam, guint32 owner, MonoDynamicImage *assembly);
41 alloc_table (MonoDynamicTable *table, guint nrows)
43 mono_dynimage_alloc_table (table, nrows);
47 string_heap_insert (MonoDynamicStream *sh, const char *str)
49 return mono_dynstream_insert_string (sh, str);
53 string_heap_insert_mstring (MonoDynamicStream *sh, MonoString *str, MonoError *error)
55 return mono_dynstream_insert_mstring (sh, str, error);
59 mono_image_add_stream_data (MonoDynamicStream *stream, const char *data, guint32 len)
61 return mono_dynstream_add_data (stream, data, len);
65 mono_image_add_stream_zero (MonoDynamicStream *stream, guint32 len)
67 return mono_dynstream_add_zero (stream, len);
71 stream_data_align (MonoDynamicStream *stream)
73 mono_dynstream_data_align (stream);
77 mono_image_typedef_or_ref (MonoDynamicImage *assembly, MonoType *type)
79 return mono_dynimage_encode_typedef_or_ref_full (assembly, type, TRUE);
83 find_index_in_table (MonoDynamicImage *assembly, int table_idx, int col, guint32 token)
85 MONO_REQ_GC_NEUTRAL_MODE;
88 MonoDynamicTable *table;
91 table = &assembly->tables [table_idx];
93 g_assert (col < table->columns);
95 values = table->values + table->columns;
96 for (i = 1; i <= table->rows; ++i) {
97 if (values [col] == token)
99 values += table->columns;
105 * Copy len * nelem bytes from val to dest, swapping bytes to LE if necessary.
106 * dest may be misaligned.
109 swap_with_size (char *dest, const char* val, int len, int nelem) {
110 MONO_REQ_GC_NEUTRAL_MODE;
111 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
114 for (elem = 0; elem < nelem; ++elem) {
140 g_assert_not_reached ();
146 memcpy (dest, val, len * nelem);
151 add_mono_string_to_blob_cached (MonoDynamicImage *assembly, MonoString *str)
153 MONO_REQ_GC_UNSAFE_MODE;
157 guint32 idx = 0, len;
159 len = str->length * 2;
160 mono_metadata_encode_value (len, b, &b);
161 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
163 char *swapped = g_malloc (2 * mono_string_length (str));
164 const char *p = (const char*)mono_string_chars (str);
166 swap_with_size (swapped, p, 2, mono_string_length (str));
167 idx = mono_dynamic_image_add_to_blob_cached (assembly, blob_size, b-blob_size, swapped, len);
171 idx = mono_dynamic_image_add_to_blob_cached (assembly, blob_size, b-blob_size, (char*)mono_string_chars (str), len);
177 * idx is the table index of the object
178 * type is one of MONO_CUSTOM_ATTR_*
181 mono_image_add_cattrs (MonoDynamicImage *assembly, guint32 idx, guint32 type, MonoArray *cattrs, MonoError *error)
183 MONO_REQ_GC_UNSAFE_MODE;
185 MonoDynamicTable *table;
186 MonoReflectionCustomAttr *cattr;
188 guint32 count, i, token;
192 mono_error_init (error);
194 /* it is legal to pass a NULL cattrs: we avoid to use the if in a lot of places */
197 count = mono_array_length (cattrs);
198 table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
199 table->rows += count;
200 alloc_table (table, table->rows);
201 values = table->values + table->next_idx * MONO_CUSTOM_ATTR_SIZE;
202 idx <<= MONO_CUSTOM_ATTR_BITS;
204 for (i = 0; i < count; ++i) {
205 cattr = (MonoReflectionCustomAttr*)mono_array_get (cattrs, gpointer, i);
206 values [MONO_CUSTOM_ATTR_PARENT] = idx;
207 token = mono_image_create_token (assembly, (MonoObject*)cattr->ctor, FALSE, FALSE, error);
208 if (!mono_error_ok (error)) goto fail;
209 type = mono_metadata_token_index (token);
210 type <<= MONO_CUSTOM_ATTR_TYPE_BITS;
211 switch (mono_metadata_token_table (token)) {
212 case MONO_TABLE_METHOD:
213 type |= MONO_CUSTOM_ATTR_TYPE_METHODDEF;
215 * fixup_cattrs () needs to fix this up. We can't use image->tokens, since it contains the old token for the
216 * method, not the one returned by mono_image_create_token ().
218 mono_g_hash_table_insert (assembly->remapped_tokens, GUINT_TO_POINTER (token), cattr->ctor);
220 case MONO_TABLE_MEMBERREF:
221 type |= MONO_CUSTOM_ATTR_TYPE_MEMBERREF;
224 g_warning ("got wrong token in custom attr");
227 values [MONO_CUSTOM_ATTR_TYPE] = type;
229 mono_metadata_encode_value (mono_array_length (cattr->data), p, &p);
230 values [MONO_CUSTOM_ATTR_VALUE] = mono_dynamic_image_add_to_blob_cached (assembly, blob_size, p - blob_size,
231 mono_array_addr (cattr->data, char, 0), mono_array_length (cattr->data));
232 values += MONO_CUSTOM_ATTR_SIZE;
243 mono_image_add_decl_security (MonoDynamicImage *assembly, guint32 parent_token, MonoArray *permissions)
245 MONO_REQ_GC_UNSAFE_MODE;
247 MonoDynamicTable *table;
249 guint32 count, i, idx;
250 MonoReflectionPermissionSet *perm;
255 count = mono_array_length (permissions);
256 table = &assembly->tables [MONO_TABLE_DECLSECURITY];
257 table->rows += count;
258 alloc_table (table, table->rows);
260 for (i = 0; i < mono_array_length (permissions); ++i) {
261 perm = (MonoReflectionPermissionSet*)mono_array_addr (permissions, MonoReflectionPermissionSet, i);
263 values = table->values + table->next_idx * MONO_DECL_SECURITY_SIZE;
265 idx = mono_metadata_token_index (parent_token);
266 idx <<= MONO_HAS_DECL_SECURITY_BITS;
267 switch (mono_metadata_token_table (parent_token)) {
268 case MONO_TABLE_TYPEDEF:
269 idx |= MONO_HAS_DECL_SECURITY_TYPEDEF;
271 case MONO_TABLE_METHOD:
272 idx |= MONO_HAS_DECL_SECURITY_METHODDEF;
274 case MONO_TABLE_ASSEMBLY:
275 idx |= MONO_HAS_DECL_SECURITY_ASSEMBLY;
278 g_assert_not_reached ();
281 values [MONO_DECL_SECURITY_ACTION] = perm->action;
282 values [MONO_DECL_SECURITY_PARENT] = idx;
283 values [MONO_DECL_SECURITY_PERMISSIONSET] = add_mono_string_to_blob_cached (assembly, perm->pset);
290 * method_encode_code:
292 * @assembly the assembly
293 * @mb the managed MethodBuilder
294 * @error set on error
296 * Note that the return value is not sensible if @error is set.
299 method_encode_code (MonoDynamicImage *assembly, ReflectionMethodBuilder *mb, MonoError *error)
301 MONO_REQ_GC_UNSAFE_MODE;
307 gint32 num_locals = 0;
308 gint32 num_exception = 0;
311 char fat_header [12];
314 guint32 local_sig = 0;
315 guint32 header_size = 12;
318 mono_error_init (error);
320 if ((mb->attrs & (METHOD_ATTRIBUTE_PINVOKE_IMPL | METHOD_ATTRIBUTE_ABSTRACT)) ||
321 (mb->iattrs & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)))
325 g_print ("Encode method %s\n", mono_string_to_utf8 (mb->name));*/
327 code = mb->ilgen->code;
328 code_size = mb->ilgen->code_len;
329 max_stack = mb->ilgen->max_stack;
330 num_locals = mb->ilgen->locals ? mono_array_length (mb->ilgen->locals) : 0;
331 if (mb->ilgen->ex_handlers)
332 num_exception = mono_reflection_method_count_clauses (mb->ilgen);
336 MonoError inner_error;
337 char *name = mono_string_to_utf8_checked (mb->name, &inner_error);
338 if (!is_ok (&inner_error)) {
339 name = g_strdup ("");
340 mono_error_cleanup (&inner_error);
342 char *str = g_strdup_printf ("Method %s does not have any IL associated", name);
343 mono_error_set_argument (error, NULL, "a method does not have any IL associated");
349 code_size = mono_array_length (code);
350 max_stack = 8; /* we probably need to run a verifier on the code... */
353 stream_data_align (&assembly->code);
355 /* check for exceptions, maxstack, locals */
356 maybe_small = (max_stack <= 8) && (!num_locals) && (!num_exception);
358 if (code_size < 64 && !(code_size & 1)) {
359 flags = (code_size << 2) | 0x2;
360 } else if (code_size < 32 && (code_size & 1)) {
361 flags = (code_size << 2) | 0x6; /* LAMESPEC: see metadata.c */
365 idx = mono_image_add_stream_data (&assembly->code, &flags, 1);
366 /* add to the fixup todo list */
367 if (mb->ilgen && mb->ilgen->num_token_fixups)
368 mono_g_hash_table_insert (assembly->token_fixups, mb->ilgen, GUINT_TO_POINTER (idx + 1));
369 mono_image_add_stream_data (&assembly->code, mono_array_addr (code, char, 0), code_size);
370 return assembly->text_rva + idx;
374 local_sig = MONO_TOKEN_SIGNATURE | mono_dynimage_encode_locals (assembly, mb->ilgen, error);
375 return_val_if_nok (error, 0);
378 * FIXME: need to set also the header size in fat_flags.
379 * (and more sects and init locals flags)
383 fat_flags |= METHOD_HEADER_MORE_SECTS;
385 fat_flags |= METHOD_HEADER_INIT_LOCALS;
386 fat_header [0] = fat_flags;
387 fat_header [1] = (header_size / 4 ) << 4;
388 short_value = GUINT16_TO_LE (max_stack);
389 memcpy (fat_header + 2, &short_value, 2);
390 int_value = GUINT32_TO_LE (code_size);
391 memcpy (fat_header + 4, &int_value, 4);
392 int_value = GUINT32_TO_LE (local_sig);
393 memcpy (fat_header + 8, &int_value, 4);
394 idx = mono_image_add_stream_data (&assembly->code, fat_header, 12);
395 /* add to the fixup todo list */
396 if (mb->ilgen && mb->ilgen->num_token_fixups)
397 mono_g_hash_table_insert (assembly->token_fixups, mb->ilgen, GUINT_TO_POINTER (idx + 12));
399 mono_image_add_stream_data (&assembly->code, mono_array_addr (code, char, 0), code_size);
401 unsigned char sheader [4];
402 MonoILExceptionInfo * ex_info;
403 MonoILExceptionBlock * ex_block;
406 stream_data_align (&assembly->code);
407 /* always use fat format for now */
408 sheader [0] = METHOD_HEADER_SECTION_FAT_FORMAT | METHOD_HEADER_SECTION_EHTABLE;
409 num_exception *= 6 * sizeof (guint32);
410 num_exception += 4; /* include the size of the header */
411 sheader [1] = num_exception & 0xff;
412 sheader [2] = (num_exception >> 8) & 0xff;
413 sheader [3] = (num_exception >> 16) & 0xff;
414 mono_image_add_stream_data (&assembly->code, (char*)sheader, 4);
415 /* fat header, so we are already aligned */
417 for (i = mono_array_length (mb->ilgen->ex_handlers) - 1; i >= 0; --i) {
418 ex_info = (MonoILExceptionInfo *)mono_array_addr (mb->ilgen->ex_handlers, MonoILExceptionInfo, i);
419 if (ex_info->handlers) {
420 int finally_start = ex_info->start + ex_info->len;
421 for (j = 0; j < mono_array_length (ex_info->handlers); ++j) {
423 ex_block = (MonoILExceptionBlock*)mono_array_addr (ex_info->handlers, MonoILExceptionBlock, j);
425 val = GUINT32_TO_LE (ex_block->type);
426 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
428 val = GUINT32_TO_LE (ex_info->start);
429 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
430 /* need fault, too, probably */
431 if (ex_block->type == MONO_EXCEPTION_CLAUSE_FINALLY)
432 val = GUINT32_TO_LE (finally_start - ex_info->start);
434 val = GUINT32_TO_LE (ex_info->len);
435 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
437 val = GUINT32_TO_LE (ex_block->start);
438 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
440 val = GUINT32_TO_LE (ex_block->len);
441 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
442 finally_start = ex_block->start + ex_block->len;
443 if (ex_block->extype) {
444 MonoType *extype = mono_reflection_type_get_handle ((MonoReflectionType*)ex_block->extype, error);
445 return_val_if_nok (error, 0);
447 val = mono_metadata_token_from_dor (mono_image_typedef_or_ref (assembly, extype));
449 if (ex_block->type == MONO_EXCEPTION_CLAUSE_FILTER)
450 val = ex_block->filter_offset;
454 val = GUINT32_TO_LE (val);
455 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
456 /*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",
457 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);*/
460 g_error ("No clauses for ex info block %d", i);
464 return assembly->text_rva + idx;
468 * Fill in the MethodDef and ParamDef tables for a method.
469 * This is used for both normal methods and constructors.
472 mono_image_basic_method (ReflectionMethodBuilder *mb, MonoDynamicImage *assembly, MonoError *error)
474 MONO_REQ_GC_UNSAFE_MODE;
476 MonoDynamicTable *table;
480 mono_error_init (error);
482 /* room in this table is already allocated */
483 table = &assembly->tables [MONO_TABLE_METHOD];
484 *mb->table_idx = table->next_idx ++;
485 g_hash_table_insert (assembly->method_to_table_idx, mb->mhandle, GUINT_TO_POINTER ((*mb->table_idx)));
486 values = table->values + *mb->table_idx * MONO_METHOD_SIZE;
487 values [MONO_METHOD_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->name, error);
488 return_val_if_nok (error, FALSE);
489 values [MONO_METHOD_FLAGS] = mb->attrs;
490 values [MONO_METHOD_IMPLFLAGS] = mb->iattrs;
491 values [MONO_METHOD_SIGNATURE] = mono_dynimage_encode_method_builder_signature (assembly, mb, error);
492 return_val_if_nok (error, FALSE);
493 values [MONO_METHOD_RVA] = method_encode_code (assembly, mb, error);
494 return_val_if_nok (error, FALSE);
496 table = &assembly->tables [MONO_TABLE_PARAM];
497 values [MONO_METHOD_PARAMLIST] = table->next_idx;
499 mono_image_add_decl_security (assembly,
500 mono_metadata_make_token (MONO_TABLE_METHOD, *mb->table_idx), mb->permissions);
503 MonoDynamicTable *mtable;
506 mtable = &assembly->tables [MONO_TABLE_FIELDMARSHAL];
507 mvalues = mtable->values + mtable->next_idx * MONO_FIELD_MARSHAL_SIZE;
510 for (i = 0; i < mono_array_length (mb->pinfo); ++i) {
511 if (mono_array_get (mb->pinfo, gpointer, i))
514 table->rows += count;
515 alloc_table (table, table->rows);
516 values = table->values + table->next_idx * MONO_PARAM_SIZE;
517 for (i = 0; i < mono_array_length (mb->pinfo); ++i) {
518 MonoReflectionParamBuilder *pb;
519 if ((pb = mono_array_get (mb->pinfo, MonoReflectionParamBuilder*, i))) {
520 values [MONO_PARAM_FLAGS] = pb->attrs;
521 values [MONO_PARAM_SEQUENCE] = i;
522 if (pb->name != NULL) {
523 values [MONO_PARAM_NAME] = string_heap_insert_mstring (&assembly->sheap, pb->name, error);
524 return_val_if_nok (error, FALSE);
526 values [MONO_PARAM_NAME] = 0;
528 values += MONO_PARAM_SIZE;
529 if (pb->marshal_info) {
531 alloc_table (mtable, mtable->rows);
532 mvalues = mtable->values + mtable->rows * MONO_FIELD_MARSHAL_SIZE;
533 mvalues [MONO_FIELD_MARSHAL_PARENT] = (table->next_idx << MONO_HAS_FIELD_MARSHAL_BITS) | MONO_HAS_FIELD_MARSHAL_PARAMDEF;
534 mvalues [MONO_FIELD_MARSHAL_NATIVE_TYPE] = mono_dynimage_save_encode_marshal_blob (assembly, pb->marshal_info, error);
535 return_val_if_nok (error, FALSE);
537 pb->table_idx = table->next_idx++;
538 if (pb->attrs & PARAM_ATTRIBUTE_HAS_DEFAULT) {
539 guint32 field_type = 0;
540 mtable = &assembly->tables [MONO_TABLE_CONSTANT];
542 alloc_table (mtable, mtable->rows);
543 mvalues = mtable->values + mtable->rows * MONO_CONSTANT_SIZE;
544 mvalues [MONO_CONSTANT_PARENT] = MONO_HASCONSTANT_PARAM | (pb->table_idx << MONO_HASCONSTANT_BITS);
545 mvalues [MONO_CONSTANT_VALUE] = mono_dynimage_encode_constant (assembly, pb->def_value, &field_type);
546 mvalues [MONO_CONSTANT_TYPE] = field_type;
547 mvalues [MONO_CONSTANT_PADDING] = 0;
557 mono_image_add_methodimpl (MonoDynamicImage *assembly, MonoReflectionMethodBuilder *mb, MonoError *error)
559 MONO_REQ_GC_UNSAFE_MODE;
561 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mb->type;
562 MonoDynamicTable *table;
565 MonoReflectionMethod *m;
568 mono_error_init (error);
570 if (!mb->override_methods)
573 for (i = 0; i < mono_array_length (mb->override_methods); ++i) {
574 m = mono_array_get (mb->override_methods, MonoReflectionMethod*, i);
576 table = &assembly->tables [MONO_TABLE_METHODIMPL];
578 alloc_table (table, table->rows);
579 values = table->values + table->rows * MONO_METHODIMPL_SIZE;
580 values [MONO_METHODIMPL_CLASS] = tb->table_idx;
581 values [MONO_METHODIMPL_BODY] = MONO_METHODDEFORREF_METHODDEF | (mb->table_idx << MONO_METHODDEFORREF_BITS);
583 tok = mono_image_create_token (assembly, (MonoObject*)m, FALSE, FALSE, error);
584 return_val_if_nok (error, FALSE);
586 switch (mono_metadata_token_table (tok)) {
587 case MONO_TABLE_MEMBERREF:
588 tok = (mono_metadata_token_index (tok) << MONO_METHODDEFORREF_BITS ) | MONO_METHODDEFORREF_METHODREF;
590 case MONO_TABLE_METHOD:
591 tok = (mono_metadata_token_index (tok) << MONO_METHODDEFORREF_BITS ) | MONO_METHODDEFORREF_METHODDEF;
594 g_assert_not_reached ();
596 values [MONO_METHODIMPL_DECLARATION] = tok;
602 #ifndef DISABLE_REFLECTION_EMIT
604 mono_image_get_method_info (MonoReflectionMethodBuilder *mb, MonoDynamicImage *assembly, MonoError *error)
606 MONO_REQ_GC_UNSAFE_MODE;
608 MonoDynamicTable *table;
610 ReflectionMethodBuilder rmb;
613 mono_error_init (error);
615 if (!mono_reflection_methodbuilder_from_method_builder (&rmb, mb, error) ||
616 !mono_image_basic_method (&rmb, assembly, error))
619 mb->table_idx = *rmb.table_idx;
621 if (mb->dll) { /* It's a P/Invoke method */
623 /* map CharSet values to on-disk values */
624 int ncharset = (mb->charset ? (mb->charset - 1) * 2 : 0);
625 int extra_flags = mb->extra_flags;
626 table = &assembly->tables [MONO_TABLE_IMPLMAP];
628 alloc_table (table, table->rows);
629 values = table->values + table->rows * MONO_IMPLMAP_SIZE;
631 values [MONO_IMPLMAP_FLAGS] = (mb->native_cc << 8) | ncharset | extra_flags;
632 values [MONO_IMPLMAP_MEMBER] = (mb->table_idx << 1) | 1; /* memberforwarded: method */
634 values [MONO_IMPLMAP_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->dllentry, error);
635 return_val_if_nok (error, FALSE);
637 values [MONO_IMPLMAP_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->name, error);
638 return_val_if_nok (error, FALSE);
640 moduleref = string_heap_insert_mstring (&assembly->sheap, mb->dll, error);
641 return_val_if_nok (error, FALSE);
642 if (!(values [MONO_IMPLMAP_SCOPE] = find_index_in_table (assembly, MONO_TABLE_MODULEREF, MONO_MODULEREF_NAME, moduleref))) {
643 table = &assembly->tables [MONO_TABLE_MODULEREF];
645 alloc_table (table, table->rows);
646 table->values [table->rows * MONO_MODULEREF_SIZE + MONO_MODULEREF_NAME] = moduleref;
647 values [MONO_IMPLMAP_SCOPE] = table->rows;
651 if (mb->generic_params) {
652 table = &assembly->tables [MONO_TABLE_GENERICPARAM];
653 table->rows += mono_array_length (mb->generic_params);
654 alloc_table (table, table->rows);
655 for (i = 0; i < mono_array_length (mb->generic_params); ++i) {
656 guint32 owner = MONO_TYPEORMETHOD_METHOD | (mb->table_idx << MONO_TYPEORMETHOD_BITS);
658 mono_image_get_generic_param_info (
659 (MonoReflectionGenericParam *)mono_array_get (mb->generic_params, gpointer, i), owner, assembly);
667 mono_image_get_ctor_info (MonoDomain *domain, MonoReflectionCtorBuilder *mb, MonoDynamicImage *assembly, MonoError *error)
669 MONO_REQ_GC_UNSAFE_MODE;
671 ReflectionMethodBuilder rmb;
673 if (!mono_reflection_methodbuilder_from_ctor_builder (&rmb, mb, error))
676 if (!mono_image_basic_method (&rmb, assembly, error))
679 mb->table_idx = *rmb.table_idx;
686 mono_image_get_field_info (MonoReflectionFieldBuilder *fb, MonoDynamicImage *assembly, MonoError *error)
688 MONO_REQ_GC_UNSAFE_MODE;
690 mono_error_init (error);
692 MonoDynamicTable *table;
695 /* maybe this fixup should be done in the C# code */
696 if (fb->attrs & FIELD_ATTRIBUTE_LITERAL)
697 fb->attrs |= FIELD_ATTRIBUTE_HAS_DEFAULT;
698 table = &assembly->tables [MONO_TABLE_FIELD];
699 fb->table_idx = table->next_idx ++;
700 g_hash_table_insert (assembly->field_to_table_idx, fb->handle, GUINT_TO_POINTER (fb->table_idx));
701 values = table->values + fb->table_idx * MONO_FIELD_SIZE;
702 values [MONO_FIELD_NAME] = string_heap_insert_mstring (&assembly->sheap, fb->name, error);
703 return_if_nok (error);
704 values [MONO_FIELD_FLAGS] = fb->attrs;
705 values [MONO_FIELD_SIGNATURE] = mono_dynimage_encode_field_signature (assembly, fb, error);
706 return_if_nok (error);
708 if (fb->offset != -1) {
709 table = &assembly->tables [MONO_TABLE_FIELDLAYOUT];
711 alloc_table (table, table->rows);
712 values = table->values + table->rows * MONO_FIELD_LAYOUT_SIZE;
713 values [MONO_FIELD_LAYOUT_FIELD] = fb->table_idx;
714 values [MONO_FIELD_LAYOUT_OFFSET] = fb->offset;
716 if (fb->attrs & FIELD_ATTRIBUTE_LITERAL) {
717 MonoTypeEnum field_type = (MonoTypeEnum)0;
718 table = &assembly->tables [MONO_TABLE_CONSTANT];
720 alloc_table (table, table->rows);
721 values = table->values + table->rows * MONO_CONSTANT_SIZE;
722 values [MONO_CONSTANT_PARENT] = MONO_HASCONSTANT_FIEDDEF | (fb->table_idx << MONO_HASCONSTANT_BITS);
723 values [MONO_CONSTANT_VALUE] = mono_dynimage_encode_constant (assembly, fb->def_value, &field_type);
724 values [MONO_CONSTANT_TYPE] = field_type;
725 values [MONO_CONSTANT_PADDING] = 0;
727 if (fb->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA) {
729 table = &assembly->tables [MONO_TABLE_FIELDRVA];
731 alloc_table (table, table->rows);
732 values = table->values + table->rows * MONO_FIELD_RVA_SIZE;
733 values [MONO_FIELD_RVA_FIELD] = fb->table_idx;
735 * We store it in the code section because it's simpler for now.
738 if (mono_array_length (fb->rva_data) >= 10)
739 stream_data_align (&assembly->code);
740 rva_idx = mono_image_add_stream_data (&assembly->code, mono_array_addr (fb->rva_data, char, 0), mono_array_length (fb->rva_data));
742 rva_idx = mono_image_add_stream_zero (&assembly->code, mono_class_value_size (fb->handle->parent, NULL));
743 values [MONO_FIELD_RVA_RVA] = rva_idx + assembly->text_rva;
745 if (fb->marshal_info) {
746 table = &assembly->tables [MONO_TABLE_FIELDMARSHAL];
748 alloc_table (table, table->rows);
749 values = table->values + table->rows * MONO_FIELD_MARSHAL_SIZE;
750 values [MONO_FIELD_MARSHAL_PARENT] = (fb->table_idx << MONO_HAS_FIELD_MARSHAL_BITS) | MONO_HAS_FIELD_MARSHAL_FIELDSREF;
751 values [MONO_FIELD_MARSHAL_NATIVE_TYPE] = mono_dynimage_save_encode_marshal_blob (assembly, fb->marshal_info, error);
752 return_if_nok (error);
757 mono_image_get_property_info (MonoReflectionPropertyBuilder *pb, MonoDynamicImage *assembly, MonoError *error)
759 MONO_REQ_GC_UNSAFE_MODE;
761 mono_error_init (error);
763 MonoDynamicTable *table;
765 guint num_methods = 0;
769 * we need to set things in the following tables:
770 * PROPERTYMAP (info already filled in _get_type_info ())
771 * PROPERTY (rows already preallocated in _get_type_info ())
772 * METHOD (method info already done with the generic method code)
776 table = &assembly->tables [MONO_TABLE_PROPERTY];
777 pb->table_idx = table->next_idx ++;
778 values = table->values + pb->table_idx * MONO_PROPERTY_SIZE;
779 values [MONO_PROPERTY_NAME] = string_heap_insert_mstring (&assembly->sheap, pb->name, error);
780 return_if_nok (error);
781 values [MONO_PROPERTY_FLAGS] = pb->attrs;
782 values [MONO_PROPERTY_TYPE] = mono_dynimage_save_encode_property_signature (assembly, pb, error);
783 return_if_nok (error);
786 /* FIXME: we still don't handle 'other' methods */
787 if (pb->get_method) num_methods ++;
788 if (pb->set_method) num_methods ++;
790 table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
791 table->rows += num_methods;
792 alloc_table (table, table->rows);
794 if (pb->get_method) {
795 semaidx = table->next_idx ++;
796 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
797 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_GETTER;
798 values [MONO_METHOD_SEMA_METHOD] = pb->get_method->table_idx;
799 values [MONO_METHOD_SEMA_ASSOCIATION] = (pb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_PROPERTY;
801 if (pb->set_method) {
802 semaidx = table->next_idx ++;
803 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
804 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_SETTER;
805 values [MONO_METHOD_SEMA_METHOD] = pb->set_method->table_idx;
806 values [MONO_METHOD_SEMA_ASSOCIATION] = (pb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_PROPERTY;
808 if (pb->attrs & PROPERTY_ATTRIBUTE_HAS_DEFAULT) {
809 MonoTypeEnum field_type = (MonoTypeEnum)0;
810 table = &assembly->tables [MONO_TABLE_CONSTANT];
812 alloc_table (table, table->rows);
813 values = table->values + table->rows * MONO_CONSTANT_SIZE;
814 values [MONO_CONSTANT_PARENT] = MONO_HASCONSTANT_PROPERTY | (pb->table_idx << MONO_HASCONSTANT_BITS);
815 values [MONO_CONSTANT_VALUE] = mono_dynimage_encode_constant (assembly, pb->def_value, &field_type);
816 values [MONO_CONSTANT_TYPE] = field_type;
817 values [MONO_CONSTANT_PADDING] = 0;
822 mono_image_get_event_info (MonoReflectionEventBuilder *eb, MonoDynamicImage *assembly, MonoError *error)
824 MONO_REQ_GC_UNSAFE_MODE;
826 MonoDynamicTable *table;
828 guint num_methods = 0;
832 * we need to set things in the following tables:
833 * EVENTMAP (info already filled in _get_type_info ())
834 * EVENT (rows already preallocated in _get_type_info ())
835 * METHOD (method info already done with the generic method code)
838 table = &assembly->tables [MONO_TABLE_EVENT];
839 eb->table_idx = table->next_idx ++;
840 values = table->values + eb->table_idx * MONO_EVENT_SIZE;
841 values [MONO_EVENT_NAME] = string_heap_insert_mstring (&assembly->sheap, eb->name, error);
842 return_if_nok (error);
843 values [MONO_EVENT_FLAGS] = eb->attrs;
844 MonoType *ebtype = mono_reflection_type_get_handle (eb->type, error);
845 return_if_nok (error);
846 values [MONO_EVENT_TYPE] = mono_image_typedef_or_ref (assembly, ebtype);
849 * FIXME: we still don't handle 'other' methods
851 if (eb->add_method) num_methods ++;
852 if (eb->remove_method) num_methods ++;
853 if (eb->raise_method) num_methods ++;
855 table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
856 table->rows += num_methods;
857 alloc_table (table, table->rows);
859 if (eb->add_method) {
860 semaidx = table->next_idx ++;
861 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
862 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_ADD_ON;
863 values [MONO_METHOD_SEMA_METHOD] = eb->add_method->table_idx;
864 values [MONO_METHOD_SEMA_ASSOCIATION] = (eb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_EVENT;
866 if (eb->remove_method) {
867 semaidx = table->next_idx ++;
868 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
869 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_REMOVE_ON;
870 values [MONO_METHOD_SEMA_METHOD] = eb->remove_method->table_idx;
871 values [MONO_METHOD_SEMA_ASSOCIATION] = (eb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_EVENT;
873 if (eb->raise_method) {
874 semaidx = table->next_idx ++;
875 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
876 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_FIRE;
877 values [MONO_METHOD_SEMA_METHOD] = eb->raise_method->table_idx;
878 values [MONO_METHOD_SEMA_ASSOCIATION] = (eb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_EVENT;
883 encode_constraints (MonoReflectionGenericParam *gparam, guint32 owner, MonoDynamicImage *assembly, MonoError *error)
885 MONO_REQ_GC_UNSAFE_MODE;
887 mono_error_init (error);
889 MonoDynamicTable *table;
890 guint32 num_constraints, i;
894 table = &assembly->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
895 num_constraints = gparam->iface_constraints ?
896 mono_array_length (gparam->iface_constraints) : 0;
897 table->rows += num_constraints;
898 if (gparam->base_type)
900 alloc_table (table, table->rows);
902 if (gparam->base_type) {
903 table_idx = table->next_idx ++;
904 values = table->values + table_idx * MONO_GENPARCONSTRAINT_SIZE;
906 MonoType *gpbasetype = mono_reflection_type_get_handle (gparam->base_type, error);
907 return_if_nok (error);
908 values [MONO_GENPARCONSTRAINT_GENERICPAR] = owner;
909 values [MONO_GENPARCONSTRAINT_CONSTRAINT] = mono_image_typedef_or_ref (assembly, gpbasetype);
912 for (i = 0; i < num_constraints; i++) {
913 MonoReflectionType *constraint = (MonoReflectionType *)mono_array_get (
914 gparam->iface_constraints, gpointer, i);
916 table_idx = table->next_idx ++;
917 values = table->values + table_idx * MONO_GENPARCONSTRAINT_SIZE;
919 MonoType *constraint_type = mono_reflection_type_get_handle (constraint, error);
920 return_if_nok (error);
922 values [MONO_GENPARCONSTRAINT_GENERICPAR] = owner;
923 values [MONO_GENPARCONSTRAINT_CONSTRAINT] = mono_image_typedef_or_ref (assembly, constraint_type);
928 mono_image_get_generic_param_info (MonoReflectionGenericParam *gparam, guint32 owner, MonoDynamicImage *assembly)
930 MONO_REQ_GC_UNSAFE_MODE;
932 GenericParamTableEntry *entry;
935 * The GenericParam table must be sorted according to the `owner' field.
936 * We need to do this sorting prior to writing the GenericParamConstraint
937 * table, since we have to use the final GenericParam table indices there
938 * and they must also be sorted.
941 entry = g_new0 (GenericParamTableEntry, 1);
942 entry->owner = owner;
943 /* FIXME: track where gen_params should be freed and remove the GC root as well */
944 MONO_GC_REGISTER_ROOT_IF_MOVING (entry->gparam, MONO_ROOT_SOURCE_REFLECTION, "reflection generic parameter");
945 entry->gparam = gparam;
947 g_ptr_array_add (assembly->gen_params, entry);
951 write_generic_param_entry (MonoDynamicImage *assembly, GenericParamTableEntry *entry, MonoError *error)
953 MONO_REQ_GC_UNSAFE_MODE;
955 MonoDynamicTable *table;
956 MonoGenericParam *param;
960 mono_error_init (error);
962 table = &assembly->tables [MONO_TABLE_GENERICPARAM];
963 table_idx = table->next_idx ++;
964 values = table->values + table_idx * MONO_GENERICPARAM_SIZE;
966 MonoType *gparam_type = mono_reflection_type_get_handle ((MonoReflectionType*)entry->gparam, error);
967 return_val_if_nok (error, FALSE);
969 param = gparam_type->data.generic_param;
971 values [MONO_GENERICPARAM_OWNER] = entry->owner;
972 values [MONO_GENERICPARAM_FLAGS] = entry->gparam->attrs;
973 values [MONO_GENERICPARAM_NUMBER] = mono_generic_param_num (param);
974 values [MONO_GENERICPARAM_NAME] = string_heap_insert (&assembly->sheap, mono_generic_param_info (param)->name);
976 if (!mono_image_add_cattrs (assembly, table_idx, MONO_CUSTOM_ATTR_GENERICPAR, entry->gparam->cattrs, error))
979 encode_constraints (entry->gparam, table_idx, assembly, error);
980 return_val_if_nok (error, FALSE);
986 collect_types (MonoPtrArray *types, MonoReflectionTypeBuilder *type)
990 mono_ptr_array_append (*types, type);
995 for (i = 0; i < mono_array_length (type->subtypes); ++i) {
996 MonoReflectionTypeBuilder *subtype = mono_array_get (type->subtypes, MonoReflectionTypeBuilder*, i);
997 collect_types (types, subtype);
1002 compare_types_by_table_idx (MonoReflectionTypeBuilder **type1, MonoReflectionTypeBuilder **type2)
1004 if ((*type1)->table_idx < (*type2)->table_idx)
1007 if ((*type1)->table_idx > (*type2)->table_idx)
1014 params_add_cattrs (MonoDynamicImage *assembly, MonoArray *pinfo, MonoError *error) {
1017 mono_error_init (error);
1020 for (i = 0; i < mono_array_length (pinfo); ++i) {
1021 MonoReflectionParamBuilder *pb;
1022 pb = mono_array_get (pinfo, MonoReflectionParamBuilder *, i);
1025 if (!mono_image_add_cattrs (assembly, pb->table_idx, MONO_CUSTOM_ATTR_PARAMDEF, pb->cattrs, error))
1033 type_add_cattrs (MonoDynamicImage *assembly, MonoReflectionTypeBuilder *tb, MonoError *error) {
1036 mono_error_init (error);
1038 if (!mono_image_add_cattrs (assembly, tb->table_idx, MONO_CUSTOM_ATTR_TYPEDEF, tb->cattrs, error))
1041 for (i = 0; i < tb->num_fields; ++i) {
1042 MonoReflectionFieldBuilder* fb;
1043 fb = mono_array_get (tb->fields, MonoReflectionFieldBuilder*, i);
1044 if (!mono_image_add_cattrs (assembly, fb->table_idx, MONO_CUSTOM_ATTR_FIELDDEF, fb->cattrs, error))
1049 for (i = 0; i < mono_array_length (tb->events); ++i) {
1050 MonoReflectionEventBuilder* eb;
1051 eb = mono_array_get (tb->events, MonoReflectionEventBuilder*, i);
1052 if (!mono_image_add_cattrs (assembly, eb->table_idx, MONO_CUSTOM_ATTR_EVENT, eb->cattrs, error))
1056 if (tb->properties) {
1057 for (i = 0; i < mono_array_length (tb->properties); ++i) {
1058 MonoReflectionPropertyBuilder* pb;
1059 pb = mono_array_get (tb->properties, MonoReflectionPropertyBuilder*, i);
1060 if (!mono_image_add_cattrs (assembly, pb->table_idx, MONO_CUSTOM_ATTR_PROPERTY, pb->cattrs, error))
1065 for (i = 0; i < mono_array_length (tb->ctors); ++i) {
1066 MonoReflectionCtorBuilder* cb;
1067 cb = mono_array_get (tb->ctors, MonoReflectionCtorBuilder*, i);
1068 if (!mono_image_add_cattrs (assembly, cb->table_idx, MONO_CUSTOM_ATTR_METHODDEF, cb->cattrs, error) ||
1069 !params_add_cattrs (assembly, cb->pinfo, error))
1075 for (i = 0; i < tb->num_methods; ++i) {
1076 MonoReflectionMethodBuilder* mb;
1077 mb = mono_array_get (tb->methods, MonoReflectionMethodBuilder*, i);
1078 if (!mono_image_add_cattrs (assembly, mb->table_idx, MONO_CUSTOM_ATTR_METHODDEF, mb->cattrs, error) ||
1079 !params_add_cattrs (assembly, mb->pinfo, error))
1085 for (i = 0; i < mono_array_length (tb->subtypes); ++i) {
1086 if (!type_add_cattrs (assembly, mono_array_get (tb->subtypes, MonoReflectionTypeBuilder*, i), error))
1095 module_add_cattrs (MonoDynamicImage *assembly, MonoReflectionModuleBuilder *moduleb, MonoError *error)
1099 mono_error_init (error);
1101 if (!mono_image_add_cattrs (assembly, moduleb->table_idx, MONO_CUSTOM_ATTR_MODULE, moduleb->cattrs, error))
1104 if (moduleb->global_methods) {
1105 for (i = 0; i < mono_array_length (moduleb->global_methods); ++i) {
1106 MonoReflectionMethodBuilder* mb = mono_array_get (moduleb->global_methods, MonoReflectionMethodBuilder*, i);
1107 if (!mono_image_add_cattrs (assembly, mb->table_idx, MONO_CUSTOM_ATTR_METHODDEF, mb->cattrs, error) ||
1108 !params_add_cattrs (assembly, mb->pinfo, error))
1113 if (moduleb->global_fields) {
1114 for (i = 0; i < mono_array_length (moduleb->global_fields); ++i) {
1115 MonoReflectionFieldBuilder *fb = mono_array_get (moduleb->global_fields, MonoReflectionFieldBuilder*, i);
1116 if (!mono_image_add_cattrs (assembly, fb->table_idx, MONO_CUSTOM_ATTR_FIELDDEF, fb->cattrs, error))
1121 if (moduleb->types) {
1122 for (i = 0; i < moduleb->num_types; ++i) {
1123 if (!type_add_cattrs (assembly, mono_array_get (moduleb->types, MonoReflectionTypeBuilder*, i), error))
1132 mono_image_fill_file_table (MonoDomain *domain, MonoReflectionModule *module, MonoDynamicImage *assembly, MonoError *error)
1134 MonoDynamicTable *table;
1138 char *b = blob_size;
1141 mono_error_init (error);
1143 table = &assembly->tables [MONO_TABLE_FILE];
1145 alloc_table (table, table->rows);
1146 values = table->values + table->next_idx * MONO_FILE_SIZE;
1147 values [MONO_FILE_FLAGS] = FILE_CONTAINS_METADATA;
1148 values [MONO_FILE_NAME] = string_heap_insert (&assembly->sheap, module->image->module_name);
1149 if (image_is_dynamic (module->image)) {
1150 /* This depends on the fact that the main module is emitted last */
1151 dir = mono_string_to_utf8_checked (((MonoReflectionModuleBuilder*)module)->assemblyb->dir, error);
1152 return_val_if_nok (error, FALSE);
1153 path = g_strdup_printf ("%s%c%s", dir, G_DIR_SEPARATOR, module->image->module_name);
1156 path = g_strdup (module->image->name);
1158 mono_sha1_get_digest_from_file (path, hash);
1161 mono_metadata_encode_value (20, b, &b);
1162 values [MONO_FILE_HASH_VALUE] = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
1163 mono_image_add_stream_data (&assembly->blob, (char*)hash, 20);
1169 mono_image_fill_module_table (MonoDomain *domain, MonoReflectionModuleBuilder *mb, MonoDynamicImage *assembly, MonoError *error)
1171 MonoDynamicTable *table;
1174 mono_error_init (error);
1176 table = &assembly->tables [MONO_TABLE_MODULE];
1177 mb->table_idx = table->next_idx ++;
1178 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->module.name, error);
1179 return_if_nok (error);
1180 i = mono_image_add_stream_data (&assembly->guid, mono_array_addr (mb->guid, char, 0), 16);
1183 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_GENERATION] = 0;
1184 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_MVID] = i;
1185 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_ENC] = 0;
1186 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_ENCBASE] = 0;
1190 mono_image_fill_export_table_from_class (MonoDomain *domain, MonoClass *klass,
1191 guint32 module_index, guint32 parent_index, MonoDynamicImage *assembly)
1193 MonoDynamicTable *table;
1197 visib = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_VISIBILITY_MASK;
1198 if (! ((visib & TYPE_ATTRIBUTE_PUBLIC) || (visib & TYPE_ATTRIBUTE_NESTED_PUBLIC)))
1201 table = &assembly->tables [MONO_TABLE_EXPORTEDTYPE];
1203 alloc_table (table, table->rows);
1204 values = table->values + table->next_idx * MONO_EXP_TYPE_SIZE;
1206 values [MONO_EXP_TYPE_FLAGS] = mono_class_get_flags (klass);
1207 values [MONO_EXP_TYPE_TYPEDEF] = klass->type_token;
1208 if (klass->nested_in)
1209 values [MONO_EXP_TYPE_IMPLEMENTATION] = (parent_index << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_EXP_TYPE;
1211 values [MONO_EXP_TYPE_IMPLEMENTATION] = (module_index << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_FILE;
1212 values [MONO_EXP_TYPE_NAME] = string_heap_insert (&assembly->sheap, klass->name);
1213 values [MONO_EXP_TYPE_NAMESPACE] = string_heap_insert (&assembly->sheap, klass->name_space);
1215 res = table->next_idx;
1219 /* Emit nested types */
1220 GList *nested_classes = mono_class_get_nested_classes_property (klass);
1222 for (tmp = nested_classes; tmp; tmp = tmp->next)
1223 mono_image_fill_export_table_from_class (domain, (MonoClass *)tmp->data, module_index, table->next_idx - 1, assembly);
1229 mono_image_fill_export_table (MonoDomain *domain, MonoReflectionTypeBuilder *tb,
1230 guint32 module_index, guint32 parent_index, MonoDynamicImage *assembly,
1236 mono_error_init (error);
1238 MonoType *t = mono_reflection_type_get_handle ((MonoReflectionType*)tb, error);
1239 return_if_nok (error);
1241 klass = mono_class_from_mono_type (t);
1243 klass->type_token = mono_metadata_make_token (MONO_TABLE_TYPEDEF, tb->table_idx);
1245 idx = mono_image_fill_export_table_from_class (domain, klass, module_index,
1246 parent_index, assembly);
1250 * We need to do this ourselves since klass->nested_classes is not set up.
1253 for (i = 0; i < mono_array_length (tb->subtypes); ++i) {
1254 mono_image_fill_export_table (domain, mono_array_get (tb->subtypes, MonoReflectionTypeBuilder*, i), module_index, idx, assembly, error);
1255 return_if_nok (error);
1261 mono_image_fill_export_table_from_module (MonoDomain *domain, MonoReflectionModule *module,
1262 guint32 module_index, MonoDynamicImage *assembly)
1264 MonoImage *image = module->image;
1268 t = &image->tables [MONO_TABLE_TYPEDEF];
1270 for (i = 0; i < t->rows; ++i) {
1272 MonoClass *klass = mono_class_get_checked (image, mono_metadata_make_token (MONO_TABLE_TYPEDEF, i + 1), &error);
1273 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
1275 if (mono_class_is_public (klass))
1276 mono_image_fill_export_table_from_class (domain, klass, module_index, 0, assembly);
1281 add_exported_type (MonoReflectionAssemblyBuilder *assemblyb, MonoDynamicImage *assembly, MonoClass *klass, guint32 parent_index)
1283 MonoDynamicTable *table;
1285 guint32 scope, scope_idx, impl, current_idx;
1286 gboolean forwarder = TRUE;
1287 gpointer iter = NULL;
1290 if (klass->nested_in) {
1291 impl = (parent_index << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_EXP_TYPE;
1294 scope = mono_reflection_resolution_scope_from_image (assembly, klass->image);
1295 g_assert ((scope & MONO_RESOLUTION_SCOPE_MASK) == MONO_RESOLUTION_SCOPE_ASSEMBLYREF);
1296 scope_idx = scope >> MONO_RESOLUTION_SCOPE_BITS;
1297 impl = (scope_idx << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_ASSEMBLYREF;
1300 table = &assembly->tables [MONO_TABLE_EXPORTEDTYPE];
1303 alloc_table (table, table->rows);
1304 current_idx = table->next_idx;
1305 values = table->values + current_idx * MONO_EXP_TYPE_SIZE;
1307 values [MONO_EXP_TYPE_FLAGS] = forwarder ? TYPE_ATTRIBUTE_FORWARDER : 0;
1308 values [MONO_EXP_TYPE_TYPEDEF] = 0;
1309 values [MONO_EXP_TYPE_IMPLEMENTATION] = impl;
1310 values [MONO_EXP_TYPE_NAME] = string_heap_insert (&assembly->sheap, klass->name);
1311 values [MONO_EXP_TYPE_NAMESPACE] = string_heap_insert (&assembly->sheap, klass->name_space);
1315 while ((nested = mono_class_get_nested_types (klass, &iter)))
1316 add_exported_type (assemblyb, assembly, nested, current_idx);
1320 mono_image_fill_export_table_from_type_forwarders (MonoReflectionAssemblyBuilder *assemblyb, MonoDynamicImage *assembly)
1326 if (!assemblyb->type_forwarders)
1329 for (i = 0; i < mono_array_length (assemblyb->type_forwarders); ++i) {
1330 MonoReflectionType *t = mono_array_get (assemblyb->type_forwarders, MonoReflectionType *, i);
1335 type = mono_reflection_type_get_handle (t, &error);
1336 mono_error_assert_ok (&error);
1339 klass = mono_class_from_mono_type (type);
1341 add_exported_type (assemblyb, assembly, klass, 0);
1345 #define align_pointer(base,p)\
1347 guint32 __diff = (unsigned char*)(p)-(unsigned char*)(base);\
1349 (p) += 4 - (__diff & 3);\
1353 compare_constants (const void *a, const void *b)
1355 const guint32 *a_values = (const guint32 *)a;
1356 const guint32 *b_values = (const guint32 *)b;
1357 return a_values [MONO_CONSTANT_PARENT] - b_values [MONO_CONSTANT_PARENT];
1361 compare_semantics (const void *a, const void *b)
1363 const guint32 *a_values = (const guint32 *)a;
1364 const guint32 *b_values = (const guint32 *)b;
1365 int assoc = a_values [MONO_METHOD_SEMA_ASSOCIATION] - b_values [MONO_METHOD_SEMA_ASSOCIATION];
1368 return a_values [MONO_METHOD_SEMA_SEMANTICS] - b_values [MONO_METHOD_SEMA_SEMANTICS];
1372 compare_custom_attrs (const void *a, const void *b)
1374 const guint32 *a_values = (const guint32 *)a;
1375 const guint32 *b_values = (const guint32 *)b;
1377 return a_values [MONO_CUSTOM_ATTR_PARENT] - b_values [MONO_CUSTOM_ATTR_PARENT];
1381 compare_field_marshal (const void *a, const void *b)
1383 const guint32 *a_values = (const guint32 *)a;
1384 const guint32 *b_values = (const guint32 *)b;
1386 return a_values [MONO_FIELD_MARSHAL_PARENT] - b_values [MONO_FIELD_MARSHAL_PARENT];
1390 compare_nested (const void *a, const void *b)
1392 const guint32 *a_values = (const guint32 *)a;
1393 const guint32 *b_values = (const guint32 *)b;
1395 return a_values [MONO_NESTED_CLASS_NESTED] - b_values [MONO_NESTED_CLASS_NESTED];
1399 compare_genericparam (const void *a, const void *b)
1402 const GenericParamTableEntry **a_entry = (const GenericParamTableEntry **) a;
1403 const GenericParamTableEntry **b_entry = (const GenericParamTableEntry **) b;
1405 if ((*b_entry)->owner == (*a_entry)->owner) {
1406 MonoType *a_type = mono_reflection_type_get_handle ((MonoReflectionType*)(*a_entry)->gparam, &error);
1407 mono_error_assert_ok (&error);
1408 MonoType *b_type = mono_reflection_type_get_handle ((MonoReflectionType*)(*b_entry)->gparam, &error);
1409 mono_error_assert_ok (&error);
1411 mono_type_get_generic_param_num (a_type) -
1412 mono_type_get_generic_param_num (b_type);
1414 return (*a_entry)->owner - (*b_entry)->owner;
1418 compare_declsecurity_attrs (const void *a, const void *b)
1420 const guint32 *a_values = (const guint32 *)a;
1421 const guint32 *b_values = (const guint32 *)b;
1423 return a_values [MONO_DECL_SECURITY_PARENT] - b_values [MONO_DECL_SECURITY_PARENT];
1427 compare_interface_impl (const void *a, const void *b)
1429 const guint32 *a_values = (const guint32 *)a;
1430 const guint32 *b_values = (const guint32 *)b;
1432 int klass = a_values [MONO_INTERFACEIMPL_CLASS] - b_values [MONO_INTERFACEIMPL_CLASS];
1436 return a_values [MONO_INTERFACEIMPL_INTERFACE] - b_values [MONO_INTERFACEIMPL_INTERFACE];
1441 MonoDynamicStream *stream;
1445 * build_compressed_metadata() fills in the blob of data that represents the
1446 * raw metadata as it will be saved in the PE file. The five streams are output
1447 * and the metadata tables are comnpressed from the guint32 array representation,
1448 * to the compressed on-disk format.
1451 build_compressed_metadata (MonoDynamicImage *assembly, MonoError *error)
1453 MonoDynamicTable *table;
1455 guint64 valid_mask = 0;
1456 guint64 sorted_mask;
1457 guint32 heapt_size = 0;
1458 guint32 meta_size = 256; /* allow for header and other stuff */
1459 guint32 table_offset;
1460 guint32 ntables = 0;
1466 struct StreamDesc stream_desc [5];
1468 mono_error_init (error);
1470 qsort (assembly->gen_params->pdata, assembly->gen_params->len, sizeof (gpointer), compare_genericparam);
1471 for (i = 0; i < assembly->gen_params->len; i++) {
1472 GenericParamTableEntry *entry = (GenericParamTableEntry *)g_ptr_array_index (assembly->gen_params, i);
1473 if (!write_generic_param_entry (assembly, entry, error))
1477 stream_desc [0].name = "#~";
1478 stream_desc [0].stream = &assembly->tstream;
1479 stream_desc [1].name = "#Strings";
1480 stream_desc [1].stream = &assembly->sheap;
1481 stream_desc [2].name = "#US";
1482 stream_desc [2].stream = &assembly->us;
1483 stream_desc [3].name = "#Blob";
1484 stream_desc [3].stream = &assembly->blob;
1485 stream_desc [4].name = "#GUID";
1486 stream_desc [4].stream = &assembly->guid;
1488 /* tables that are sorted */
1489 sorted_mask = ((guint64)1 << MONO_TABLE_CONSTANT) | ((guint64)1 << MONO_TABLE_FIELDMARSHAL)
1490 | ((guint64)1 << MONO_TABLE_METHODSEMANTICS) | ((guint64)1 << MONO_TABLE_CLASSLAYOUT)
1491 | ((guint64)1 << MONO_TABLE_FIELDLAYOUT) | ((guint64)1 << MONO_TABLE_FIELDRVA)
1492 | ((guint64)1 << MONO_TABLE_IMPLMAP) | ((guint64)1 << MONO_TABLE_NESTEDCLASS)
1493 | ((guint64)1 << MONO_TABLE_METHODIMPL) | ((guint64)1 << MONO_TABLE_CUSTOMATTRIBUTE)
1494 | ((guint64)1 << MONO_TABLE_DECLSECURITY) | ((guint64)1 << MONO_TABLE_GENERICPARAM)
1495 | ((guint64)1 << MONO_TABLE_INTERFACEIMPL);
1497 /* Compute table sizes */
1498 /* the MonoImage has already been created in mono_reflection_dynimage_basic_init() */
1499 meta = &assembly->image;
1501 /* sizes should be multiple of 4 */
1502 mono_dynstream_data_align (&assembly->blob);
1503 mono_dynstream_data_align (&assembly->guid);
1504 mono_dynstream_data_align (&assembly->sheap);
1505 mono_dynstream_data_align (&assembly->us);
1507 /* Setup the info used by compute_sizes () */
1508 meta->idx_blob_wide = assembly->blob.index >= 65536 ? 1 : 0;
1509 meta->idx_guid_wide = assembly->guid.index >= 65536 ? 1 : 0;
1510 meta->idx_string_wide = assembly->sheap.index >= 65536 ? 1 : 0;
1512 meta_size += assembly->blob.index;
1513 meta_size += assembly->guid.index;
1514 meta_size += assembly->sheap.index;
1515 meta_size += assembly->us.index;
1517 for (i=0; i < MONO_TABLE_NUM; ++i)
1518 meta->tables [i].rows = assembly->tables [i].rows;
1520 for (i = 0; i < MONO_TABLE_NUM; i++){
1521 if (meta->tables [i].rows == 0)
1523 valid_mask |= (guint64)1 << i;
1525 meta->tables [i].row_size = mono_metadata_compute_size (
1526 meta, i, &meta->tables [i].size_bitfield);
1527 heapt_size += meta->tables [i].row_size * meta->tables [i].rows;
1529 heapt_size += 24; /* #~ header size */
1530 heapt_size += ntables * 4;
1531 /* make multiple of 4 */
1534 meta_size += heapt_size;
1535 meta->raw_metadata = (char *)g_malloc0 (meta_size);
1536 p = (unsigned char*)meta->raw_metadata;
1537 /* the metadata signature */
1538 *p++ = 'B'; *p++ = 'S'; *p++ = 'J'; *p++ = 'B';
1539 /* version numbers and 4 bytes reserved */
1540 int16val = (guint16*)p;
1541 *int16val++ = GUINT16_TO_LE (meta->md_version_major);
1542 *int16val = GUINT16_TO_LE (meta->md_version_minor);
1544 /* version string */
1545 int32val = (guint32*)p;
1546 *int32val = GUINT32_TO_LE ((strlen (meta->version) + 3) & (~3)); /* needs to be multiple of 4 */
1548 memcpy (p, meta->version, strlen (meta->version));
1549 p += GUINT32_FROM_LE (*int32val);
1550 align_pointer (meta->raw_metadata, p);
1551 int16val = (guint16*)p;
1552 *int16val++ = GUINT16_TO_LE (0); /* flags must be 0 */
1553 *int16val = GUINT16_TO_LE (5); /* number of streams */
1557 * write the stream info.
1559 table_offset = (p - (unsigned char*)meta->raw_metadata) + 5 * 8 + 40; /* room needed for stream headers */
1560 table_offset += 3; table_offset &= ~3;
1562 assembly->tstream.index = heapt_size;
1563 for (i = 0; i < 5; ++i) {
1564 int32val = (guint32*)p;
1565 stream_desc [i].stream->offset = table_offset;
1566 *int32val++ = GUINT32_TO_LE (table_offset);
1567 *int32val = GUINT32_TO_LE (stream_desc [i].stream->index);
1568 table_offset += GUINT32_FROM_LE (*int32val);
1569 table_offset += 3; table_offset &= ~3;
1571 strcpy ((char*)p, stream_desc [i].name);
1572 p += strlen (stream_desc [i].name) + 1;
1573 align_pointer (meta->raw_metadata, p);
1576 * now copy the data, the table stream header and contents goes first.
1578 g_assert ((p - (unsigned char*)meta->raw_metadata) < assembly->tstream.offset);
1579 p = (guchar*)meta->raw_metadata + assembly->tstream.offset;
1580 int32val = (guint32*)p;
1581 *int32val = GUINT32_TO_LE (0); /* reserved */
1584 *p++ = 2; /* version */
1587 if (meta->idx_string_wide)
1589 if (meta->idx_guid_wide)
1591 if (meta->idx_blob_wide)
1594 *p++ = 1; /* reserved */
1595 int64val = (guint64*)p;
1596 *int64val++ = GUINT64_TO_LE (valid_mask);
1597 *int64val++ = GUINT64_TO_LE (valid_mask & sorted_mask); /* bitvector of sorted tables */
1599 int32val = (guint32*)p;
1600 for (i = 0; i < MONO_TABLE_NUM; i++){
1601 if (meta->tables [i].rows == 0)
1603 *int32val++ = GUINT32_TO_LE (meta->tables [i].rows);
1605 p = (unsigned char*)int32val;
1607 /* sort the tables that still need sorting */
1608 table = &assembly->tables [MONO_TABLE_CONSTANT];
1610 qsort (table->values + MONO_CONSTANT_SIZE, table->rows, sizeof (guint32) * MONO_CONSTANT_SIZE, compare_constants);
1611 table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
1613 qsort (table->values + MONO_METHOD_SEMA_SIZE, table->rows, sizeof (guint32) * MONO_METHOD_SEMA_SIZE, compare_semantics);
1614 table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1616 qsort (table->values + MONO_CUSTOM_ATTR_SIZE, table->rows, sizeof (guint32) * MONO_CUSTOM_ATTR_SIZE, compare_custom_attrs);
1617 table = &assembly->tables [MONO_TABLE_FIELDMARSHAL];
1619 qsort (table->values + MONO_FIELD_MARSHAL_SIZE, table->rows, sizeof (guint32) * MONO_FIELD_MARSHAL_SIZE, compare_field_marshal);
1620 table = &assembly->tables [MONO_TABLE_NESTEDCLASS];
1622 qsort (table->values + MONO_NESTED_CLASS_SIZE, table->rows, sizeof (guint32) * MONO_NESTED_CLASS_SIZE, compare_nested);
1623 /* Section 21.11 DeclSecurity in Partition II doesn't specify this to be sorted by MS implementation requires it */
1624 table = &assembly->tables [MONO_TABLE_DECLSECURITY];
1626 qsort (table->values + MONO_DECL_SECURITY_SIZE, table->rows, sizeof (guint32) * MONO_DECL_SECURITY_SIZE, compare_declsecurity_attrs);
1627 table = &assembly->tables [MONO_TABLE_INTERFACEIMPL];
1629 qsort (table->values + MONO_INTERFACEIMPL_SIZE, table->rows, sizeof (guint32) * MONO_INTERFACEIMPL_SIZE, compare_interface_impl);
1631 /* compress the tables */
1632 for (i = 0; i < MONO_TABLE_NUM; i++){
1635 guint32 bitfield = meta->tables [i].size_bitfield;
1636 if (!meta->tables [i].rows)
1638 if (assembly->tables [i].columns != mono_metadata_table_count (bitfield))
1639 g_error ("col count mismatch in %d: %d %d", i, assembly->tables [i].columns, mono_metadata_table_count (bitfield));
1640 meta->tables [i].base = (char*)p;
1641 for (row = 1; row <= meta->tables [i].rows; ++row) {
1642 values = assembly->tables [i].values + row * assembly->tables [i].columns;
1643 for (col = 0; col < assembly->tables [i].columns; ++col) {
1644 switch (mono_metadata_table_size (bitfield, col)) {
1646 *p++ = values [col];
1649 *p++ = values [col] & 0xff;
1650 *p++ = (values [col] >> 8) & 0xff;
1653 *p++ = values [col] & 0xff;
1654 *p++ = (values [col] >> 8) & 0xff;
1655 *p++ = (values [col] >> 16) & 0xff;
1656 *p++ = (values [col] >> 24) & 0xff;
1659 g_assert_not_reached ();
1663 g_assert ((p - (const unsigned char*)meta->tables [i].base) == (meta->tables [i].rows * meta->tables [i].row_size));
1666 g_assert (assembly->guid.offset + assembly->guid.index < meta_size);
1667 memcpy (meta->raw_metadata + assembly->sheap.offset, assembly->sheap.data, assembly->sheap.index);
1668 memcpy (meta->raw_metadata + assembly->us.offset, assembly->us.data, assembly->us.index);
1669 memcpy (meta->raw_metadata + assembly->blob.offset, assembly->blob.data, assembly->blob.index);
1670 memcpy (meta->raw_metadata + assembly->guid.offset, assembly->guid.data, assembly->guid.index);
1672 assembly->meta_size = assembly->guid.offset + assembly->guid.index;
1678 * Some tables in metadata need to be sorted according to some criteria, but
1679 * when methods and fields are first created with reflection, they may be assigned a token
1680 * that doesn't correspond to the final token they will get assigned after the sorting.
1681 * ILGenerator.cs keeps a fixup table that maps the position of tokens in the IL code stream
1682 * with the reflection objects that represent them. Once all the tables are set up, the
1683 * reflection objects will contains the correct table index. fixup_method() will fixup the
1684 * tokens for the method with ILGenerator @ilgen.
1687 fixup_method (MonoReflectionILGen *ilgen, gpointer value, MonoDynamicImage *assembly)
1689 guint32 code_idx = GPOINTER_TO_UINT (value);
1690 MonoReflectionILTokenInfo *iltoken;
1691 MonoReflectionTypeBuilder *tb;
1692 MonoReflectionArrayMethod *am;
1694 unsigned char *target;
1696 for (i = 0; i < ilgen->num_token_fixups; ++i) {
1697 iltoken = (MonoReflectionILTokenInfo *)mono_array_addr_with_size (ilgen->token_fixups, sizeof (MonoReflectionILTokenInfo), i);
1698 target = (guchar*)assembly->code.data + code_idx + iltoken->code_pos;
1699 switch (target [3]) {
1700 case MONO_TABLE_FIELD:
1701 if (!strcmp (iltoken->member->vtable->klass->name, "FieldBuilder")) {
1702 g_assert_not_reached ();
1703 } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoField")) {
1704 MonoClassField *f = ((MonoReflectionField*)iltoken->member)->field;
1705 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->field_to_table_idx, f));
1707 g_assert_not_reached ();
1710 case MONO_TABLE_METHOD:
1711 if (!strcmp (iltoken->member->vtable->klass->name, "MethodBuilder")) {
1712 g_assert_not_reached ();
1713 } else if (!strcmp (iltoken->member->vtable->klass->name, "ConstructorBuilder")) {
1714 g_assert_not_reached ();
1715 } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoMethod") ||
1716 !strcmp (iltoken->member->vtable->klass->name, "MonoCMethod")) {
1717 MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
1718 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, m));
1720 g_assert_not_reached ();
1723 case MONO_TABLE_TYPEDEF:
1724 if (!strcmp (iltoken->member->vtable->klass->name, "TypeBuilder")) {
1725 g_assert_not_reached ();
1726 } else if (!strcmp (iltoken->member->vtable->klass->name, "RuntimeType")) {
1727 MonoClass *k = mono_class_from_mono_type (((MonoReflectionType*)iltoken->member)->type);
1728 MonoObject *obj = mono_class_get_ref_info (k);
1730 g_assert (!strcmp (obj->vtable->klass->name, "TypeBuilder"));
1731 tb = (MonoReflectionTypeBuilder*)obj;
1732 idx = tb->table_idx;
1734 g_assert_not_reached ();
1737 case MONO_TABLE_MEMBERREF:
1738 if (!strcmp (iltoken->member->vtable->klass->name, "MonoArrayMethod")) {
1739 am = (MonoReflectionArrayMethod*)iltoken->member;
1740 idx = am->table_idx;
1741 } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoMethod") ||
1742 !strcmp (iltoken->member->vtable->klass->name, "MonoCMethod")) {
1743 MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
1744 g_assert (mono_class_is_ginst (m->klass) || mono_class_is_gtd (m->klass));
1746 } else if (!strcmp (iltoken->member->vtable->klass->name, "FieldBuilder")) {
1747 g_assert_not_reached ();
1749 } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoField")) {
1751 } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodBuilder") ||
1752 !strcmp (iltoken->member->vtable->klass->name, "ConstructorBuilder")) {
1753 g_assert_not_reached ();
1755 } else if (!strcmp (iltoken->member->vtable->klass->name, "FieldOnTypeBuilderInst")) {
1756 g_assert_not_reached ();
1758 } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodOnTypeBuilderInst")) {
1759 g_assert_not_reached ();
1761 } else if (!strcmp (iltoken->member->vtable->klass->name, "ConstructorOnTypeBuilderInst")) {
1762 g_assert_not_reached ();
1765 g_assert_not_reached ();
1768 case MONO_TABLE_METHODSPEC:
1769 if (!strcmp (iltoken->member->vtable->klass->name, "MonoMethod")) {
1770 MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
1771 g_assert (mono_method_signature (m)->generic_param_count);
1773 } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodBuilder")) {
1774 g_assert_not_reached ();
1776 } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodOnTypeBuilderInst")) {
1777 g_assert_not_reached ();
1780 g_assert_not_reached ();
1783 case MONO_TABLE_TYPESPEC:
1784 if (!strcmp (iltoken->member->vtable->klass->name, "RuntimeType")) {
1787 g_assert_not_reached ();
1791 g_error ("got unexpected table 0x%02x in fixup", target [3]);
1793 target [0] = idx & 0xff;
1794 target [1] = (idx >> 8) & 0xff;
1795 target [2] = (idx >> 16) & 0xff;
1802 * The CUSTOM_ATTRIBUTE table might contain METHODDEF tokens whose final
1803 * value is not known when the table is emitted.
1806 fixup_cattrs (MonoDynamicImage *assembly)
1808 MonoDynamicTable *table;
1810 guint32 type, i, idx, token;
1813 table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1815 for (i = 0; i < table->rows; ++i) {
1816 values = table->values + ((i + 1) * MONO_CUSTOM_ATTR_SIZE);
1818 type = values [MONO_CUSTOM_ATTR_TYPE];
1819 if ((type & MONO_CUSTOM_ATTR_TYPE_MASK) == MONO_CUSTOM_ATTR_TYPE_METHODDEF) {
1820 idx = type >> MONO_CUSTOM_ATTR_TYPE_BITS;
1821 token = mono_metadata_make_token (MONO_TABLE_METHOD, idx);
1822 ctor = (MonoObject *)mono_g_hash_table_lookup (assembly->remapped_tokens, GUINT_TO_POINTER (token));
1825 if (!strcmp (ctor->vtable->klass->name, "MonoCMethod")) {
1826 MonoMethod *m = ((MonoReflectionMethod*)ctor)->method;
1827 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, m));
1828 values [MONO_CUSTOM_ATTR_TYPE] = (idx << MONO_CUSTOM_ATTR_TYPE_BITS) | MONO_CUSTOM_ATTR_TYPE_METHODDEF;
1829 } else if (!strcmp (ctor->vtable->klass->name, "ConstructorBuilder")) {
1830 MonoMethod *m = ((MonoReflectionCtorBuilder*)ctor)->mhandle;
1831 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, m));
1832 values [MONO_CUSTOM_ATTR_TYPE] = (idx << MONO_CUSTOM_ATTR_TYPE_BITS) | MONO_CUSTOM_ATTR_TYPE_METHODDEF;
1839 assembly_add_resource_manifest (MonoReflectionModuleBuilder *mb, MonoDynamicImage *assembly, MonoReflectionResource *rsrc, guint32 implementation, MonoError *error)
1841 MonoDynamicTable *table;
1844 mono_error_init (error);
1846 table = &assembly->tables [MONO_TABLE_MANIFESTRESOURCE];
1848 alloc_table (table, table->rows);
1849 values = table->values + table->next_idx * MONO_MANIFEST_SIZE;
1850 values [MONO_MANIFEST_OFFSET] = rsrc->offset;
1851 values [MONO_MANIFEST_FLAGS] = rsrc->attrs;
1852 values [MONO_MANIFEST_NAME] = string_heap_insert_mstring (&assembly->sheap, rsrc->name, error);
1853 return_val_if_nok (error, FALSE);
1854 values [MONO_MANIFEST_IMPLEMENTATION] = implementation;
1860 assembly_add_resource (MonoReflectionModuleBuilder *mb, MonoDynamicImage *assembly, MonoReflectionResource *rsrc, MonoError *error)
1862 MonoDynamicTable *table;
1866 char *b = blob_size;
1868 guint32 idx, offset;
1870 mono_error_init (error);
1872 if (rsrc->filename) {
1873 name = mono_string_to_utf8_checked (rsrc->filename, error);
1874 return_val_if_nok (error, FALSE);
1875 sname = g_path_get_basename (name);
1877 table = &assembly->tables [MONO_TABLE_FILE];
1879 alloc_table (table, table->rows);
1880 values = table->values + table->next_idx * MONO_FILE_SIZE;
1881 values [MONO_FILE_FLAGS] = FILE_CONTAINS_NO_METADATA;
1882 values [MONO_FILE_NAME] = string_heap_insert (&assembly->sheap, sname);
1885 mono_sha1_get_digest_from_file (name, hash);
1886 mono_metadata_encode_value (20, b, &b);
1887 values [MONO_FILE_HASH_VALUE] = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
1888 mono_image_add_stream_data (&assembly->blob, (char*)hash, 20);
1890 idx = table->next_idx++;
1892 idx = MONO_IMPLEMENTATION_FILE | (idx << MONO_IMPLEMENTATION_BITS);
1898 data = mono_array_addr (rsrc->data, char, 0);
1899 len = mono_array_length (rsrc->data);
1905 sizebuf [0] = offset; sizebuf [1] = offset >> 8;
1906 sizebuf [2] = offset >> 16; sizebuf [3] = offset >> 24;
1907 rsrc->offset = mono_image_add_stream_data (&assembly->resources, sizebuf, 4);
1908 mono_image_add_stream_data (&assembly->resources, data, len);
1912 * The entry should be emitted into the MANIFESTRESOURCE table of
1913 * the main module, but that needs to reference the FILE table
1914 * which isn't emitted yet.
1921 return assembly_add_resource_manifest (mb, assembly, rsrc, idx, error);
1925 set_version_from_string (MonoString *version, guint32 *values, MonoError *error)
1927 gchar *ver, *p, *str;
1930 mono_error_init (error);
1932 values [MONO_ASSEMBLY_MAJOR_VERSION] = 0;
1933 values [MONO_ASSEMBLY_MINOR_VERSION] = 0;
1934 values [MONO_ASSEMBLY_REV_NUMBER] = 0;
1935 values [MONO_ASSEMBLY_BUILD_NUMBER] = 0;
1938 ver = str = mono_string_to_utf8_checked (version, error);
1939 return_val_if_nok (error, FALSE);
1940 for (i = 0; i < 4; ++i) {
1941 values [MONO_ASSEMBLY_MAJOR_VERSION + i] = strtol (ver, &p, 10);
1947 /* handle Revision and Build */
1958 load_public_key (MonoArray *pkey, MonoDynamicImage *assembly) {
1962 char *b = blob_size;
1967 len = mono_array_length (pkey);
1968 mono_metadata_encode_value (len, b, &b);
1969 token = mono_image_add_stream_data (&assembly->blob, blob_size, b - blob_size);
1970 mono_image_add_stream_data (&assembly->blob, mono_array_addr (pkey, char, 0), len);
1972 assembly->public_key = (guint8 *)g_malloc (len);
1973 memcpy (assembly->public_key, mono_array_addr (pkey, char, 0), len);
1974 assembly->public_key_len = len;
1976 /* Special case: check for ECMA key (16 bytes) */
1977 if ((len == MONO_ECMA_KEY_LENGTH) && mono_is_ecma_key (mono_array_addr (pkey, char, 0), len)) {
1978 /* In this case we must reserve 128 bytes (1024 bits) for the signature */
1979 assembly->strong_name_size = MONO_DEFAULT_PUBLIC_KEY_LENGTH;
1980 } else if (len >= MONO_PUBLIC_KEY_HEADER_LENGTH + MONO_MINIMUM_PUBLIC_KEY_LENGTH) {
1981 /* minimum key size (in 2.0) is 384 bits */
1982 assembly->strong_name_size = len - MONO_PUBLIC_KEY_HEADER_LENGTH;
1984 /* FIXME - verifier */
1985 g_warning ("Invalid public key length: %d bits (total: %d)", (int)MONO_PUBLIC_KEY_BIT_SIZE (len), (int)len);
1986 assembly->strong_name_size = MONO_DEFAULT_PUBLIC_KEY_LENGTH; /* to be safe */
1988 assembly->strong_name = (char *)g_malloc0 (assembly->strong_name_size);
1994 mono_image_emit_manifest (MonoReflectionModuleBuilder *moduleb, MonoError *error)
1996 MonoDynamicTable *table;
1997 MonoDynamicImage *assembly;
1998 MonoReflectionAssemblyBuilder *assemblyb;
2002 guint32 module_index;
2004 mono_error_init (error);
2006 assemblyb = moduleb->assemblyb;
2007 assembly = moduleb->dynamic_image;
2008 domain = mono_object_domain (assemblyb);
2010 /* Emit ASSEMBLY table */
2011 table = &assembly->tables [MONO_TABLE_ASSEMBLY];
2012 alloc_table (table, 1);
2013 values = table->values + MONO_ASSEMBLY_SIZE;
2014 values [MONO_ASSEMBLY_HASH_ALG] = assemblyb->algid? assemblyb->algid: ASSEMBLY_HASH_SHA1;
2015 values [MONO_ASSEMBLY_NAME] = string_heap_insert_mstring (&assembly->sheap, assemblyb->name, error);
2016 return_val_if_nok (error, FALSE);
2017 if (assemblyb->culture) {
2018 values [MONO_ASSEMBLY_CULTURE] = string_heap_insert_mstring (&assembly->sheap, assemblyb->culture, error);
2019 return_val_if_nok (error, FALSE);
2021 values [MONO_ASSEMBLY_CULTURE] = string_heap_insert (&assembly->sheap, "");
2023 values [MONO_ASSEMBLY_PUBLIC_KEY] = load_public_key (assemblyb->public_key, assembly);
2024 values [MONO_ASSEMBLY_FLAGS] = assemblyb->flags;
2025 if (!set_version_from_string (assemblyb->version, values, error))
2028 /* Emit FILE + EXPORTED_TYPE table */
2030 for (i = 0; i < mono_array_length (assemblyb->modules); ++i) {
2032 MonoReflectionModuleBuilder *file_module =
2033 mono_array_get (assemblyb->modules, MonoReflectionModuleBuilder*, i);
2034 if (file_module != moduleb) {
2035 if (!mono_image_fill_file_table (domain, (MonoReflectionModule*)file_module, assembly, error))
2038 if (file_module->types) {
2039 for (j = 0; j < file_module->num_types; ++j) {
2040 MonoReflectionTypeBuilder *tb = mono_array_get (file_module->types, MonoReflectionTypeBuilder*, j);
2041 mono_image_fill_export_table (domain, tb, module_index, 0, assembly, error);
2042 return_val_if_nok (error, FALSE);
2047 if (assemblyb->loaded_modules) {
2048 for (i = 0; i < mono_array_length (assemblyb->loaded_modules); ++i) {
2049 MonoReflectionModule *file_module =
2050 mono_array_get (assemblyb->loaded_modules, MonoReflectionModule*, i);
2051 if (!mono_image_fill_file_table (domain, file_module, assembly, error))
2054 mono_image_fill_export_table_from_module (domain, file_module, module_index, assembly);
2057 if (assemblyb->type_forwarders)
2058 mono_image_fill_export_table_from_type_forwarders (assemblyb, assembly);
2060 /* Emit MANIFESTRESOURCE table */
2062 for (i = 0; i < mono_array_length (assemblyb->modules); ++i) {
2064 MonoReflectionModuleBuilder *file_module =
2065 mono_array_get (assemblyb->modules, MonoReflectionModuleBuilder*, i);
2066 /* The table for the main module is emitted later */
2067 if (file_module != moduleb) {
2069 if (file_module->resources) {
2070 int len = mono_array_length (file_module->resources);
2071 for (j = 0; j < len; ++j) {
2072 MonoReflectionResource* res = (MonoReflectionResource*)mono_array_addr (file_module->resources, MonoReflectionResource, j);
2073 if (!assembly_add_resource_manifest (file_module, assembly, res, MONO_IMPLEMENTATION_FILE | (module_index << MONO_IMPLEMENTATION_BITS), error))
2082 #ifndef DISABLE_REFLECTION_EMIT_SAVE
2085 * Insert into the metadata tables all the info about the TypeBuilder tb.
2086 * Data in the tables is inserted in a predefined order, since some tables need to be sorted.
2089 mono_image_get_type_info (MonoDomain *domain, MonoReflectionTypeBuilder *tb, MonoDynamicImage *assembly, MonoError *error)
2091 MonoDynamicTable *table;
2093 int i, is_object = 0, is_system = 0;
2096 mono_error_init (error);
2098 table = &assembly->tables [MONO_TABLE_TYPEDEF];
2099 values = table->values + tb->table_idx * MONO_TYPEDEF_SIZE;
2100 values [MONO_TYPEDEF_FLAGS] = tb->attrs;
2101 n = mono_string_to_utf8_checked (tb->name, error);
2102 return_val_if_nok (error, FALSE);
2103 if (strcmp (n, "Object") == 0)
2105 values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, n);
2107 n = mono_string_to_utf8_checked (tb->nspace, error);
2108 return_val_if_nok (error, FALSE);
2109 if (strcmp (n, "System") == 0)
2111 values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, n);
2113 if (tb->parent && !(is_system && is_object) &&
2114 !(tb->attrs & TYPE_ATTRIBUTE_INTERFACE)) { /* interfaces don't have a parent */
2115 MonoType *parent_type = mono_reflection_type_get_handle ((MonoReflectionType*)tb->parent, error);
2116 return_val_if_nok (error, FALSE);
2117 values [MONO_TYPEDEF_EXTENDS] = mono_image_typedef_or_ref (assembly, parent_type);
2119 values [MONO_TYPEDEF_EXTENDS] = 0;
2121 values [MONO_TYPEDEF_FIELD_LIST] = assembly->tables [MONO_TABLE_FIELD].next_idx;
2122 values [MONO_TYPEDEF_METHOD_LIST] = assembly->tables [MONO_TABLE_METHOD].next_idx;
2125 * if we have explicitlayout or sequentiallayouts, output data in the
2126 * ClassLayout table.
2128 if (((tb->attrs & TYPE_ATTRIBUTE_LAYOUT_MASK) != TYPE_ATTRIBUTE_AUTO_LAYOUT) &&
2129 ((tb->class_size > 0) || (tb->packing_size > 0))) {
2130 table = &assembly->tables [MONO_TABLE_CLASSLAYOUT];
2132 alloc_table (table, table->rows);
2133 values = table->values + table->rows * MONO_CLASS_LAYOUT_SIZE;
2134 values [MONO_CLASS_LAYOUT_PARENT] = tb->table_idx;
2135 values [MONO_CLASS_LAYOUT_CLASS_SIZE] = tb->class_size;
2136 values [MONO_CLASS_LAYOUT_PACKING_SIZE] = tb->packing_size;
2139 /* handle interfaces */
2140 if (tb->interfaces) {
2141 table = &assembly->tables [MONO_TABLE_INTERFACEIMPL];
2143 table->rows += mono_array_length (tb->interfaces);
2144 alloc_table (table, table->rows);
2145 values = table->values + (i + 1) * MONO_INTERFACEIMPL_SIZE;
2146 for (i = 0; i < mono_array_length (tb->interfaces); ++i) {
2147 MonoReflectionType* iface = (MonoReflectionType*) mono_array_get (tb->interfaces, gpointer, i);
2148 MonoType *iface_type = mono_reflection_type_get_handle (iface, error);
2149 return_val_if_nok (error, FALSE);
2150 values [MONO_INTERFACEIMPL_CLASS] = tb->table_idx;
2151 values [MONO_INTERFACEIMPL_INTERFACE] = mono_image_typedef_or_ref (assembly, iface_type);
2152 values += MONO_INTERFACEIMPL_SIZE;
2158 table = &assembly->tables [MONO_TABLE_FIELD];
2159 table->rows += tb->num_fields;
2160 alloc_table (table, table->rows);
2161 for (i = 0; i < tb->num_fields; ++i) {
2162 mono_image_get_field_info (
2163 mono_array_get (tb->fields, MonoReflectionFieldBuilder*, i), assembly, error);
2164 return_val_if_nok (error, FALSE);
2168 /* handle constructors */
2170 table = &assembly->tables [MONO_TABLE_METHOD];
2171 table->rows += mono_array_length (tb->ctors);
2172 alloc_table (table, table->rows);
2173 for (i = 0; i < mono_array_length (tb->ctors); ++i) {
2174 if (!mono_image_get_ctor_info (domain,
2175 mono_array_get (tb->ctors, MonoReflectionCtorBuilder*, i),
2181 /* handle methods */
2183 table = &assembly->tables [MONO_TABLE_METHOD];
2184 table->rows += tb->num_methods;
2185 alloc_table (table, table->rows);
2186 for (i = 0; i < tb->num_methods; ++i) {
2187 if (!mono_image_get_method_info (
2188 mono_array_get (tb->methods, MonoReflectionMethodBuilder*, i), assembly, error))
2193 /* Do the same with properties etc.. */
2194 if (tb->events && mono_array_length (tb->events)) {
2195 table = &assembly->tables [MONO_TABLE_EVENT];
2196 table->rows += mono_array_length (tb->events);
2197 alloc_table (table, table->rows);
2198 table = &assembly->tables [MONO_TABLE_EVENTMAP];
2200 alloc_table (table, table->rows);
2201 values = table->values + table->rows * MONO_EVENT_MAP_SIZE;
2202 values [MONO_EVENT_MAP_PARENT] = tb->table_idx;
2203 values [MONO_EVENT_MAP_EVENTLIST] = assembly->tables [MONO_TABLE_EVENT].next_idx;
2204 for (i = 0; i < mono_array_length (tb->events); ++i) {
2205 mono_image_get_event_info (
2206 mono_array_get (tb->events, MonoReflectionEventBuilder*, i), assembly, error);
2207 return_val_if_nok (error, FALSE);
2210 if (tb->properties && mono_array_length (tb->properties)) {
2211 table = &assembly->tables [MONO_TABLE_PROPERTY];
2212 table->rows += mono_array_length (tb->properties);
2213 alloc_table (table, table->rows);
2214 table = &assembly->tables [MONO_TABLE_PROPERTYMAP];
2216 alloc_table (table, table->rows);
2217 values = table->values + table->rows * MONO_PROPERTY_MAP_SIZE;
2218 values [MONO_PROPERTY_MAP_PARENT] = tb->table_idx;
2219 values [MONO_PROPERTY_MAP_PROPERTY_LIST] = assembly->tables [MONO_TABLE_PROPERTY].next_idx;
2220 for (i = 0; i < mono_array_length (tb->properties); ++i) {
2221 mono_image_get_property_info (
2222 mono_array_get (tb->properties, MonoReflectionPropertyBuilder*, i), assembly, error);
2223 return_val_if_nok (error, FALSE);
2227 /* handle generic parameters */
2228 if (tb->generic_params) {
2229 table = &assembly->tables [MONO_TABLE_GENERICPARAM];
2230 table->rows += mono_array_length (tb->generic_params);
2231 alloc_table (table, table->rows);
2232 for (i = 0; i < mono_array_length (tb->generic_params); ++i) {
2233 guint32 owner = MONO_TYPEORMETHOD_TYPE | (tb->table_idx << MONO_TYPEORMETHOD_BITS);
2235 mono_image_get_generic_param_info (
2236 mono_array_get (tb->generic_params, MonoReflectionGenericParam*, i), owner, assembly);
2240 mono_image_add_decl_security (assembly,
2241 mono_metadata_make_token (MONO_TABLE_TYPEDEF, tb->table_idx), tb->permissions);
2244 MonoDynamicTable *ntable;
2246 ntable = &assembly->tables [MONO_TABLE_NESTEDCLASS];
2247 ntable->rows += mono_array_length (tb->subtypes);
2248 alloc_table (ntable, ntable->rows);
2249 values = ntable->values + ntable->next_idx * MONO_NESTED_CLASS_SIZE;
2251 for (i = 0; i < mono_array_length (tb->subtypes); ++i) {
2252 MonoReflectionTypeBuilder *subtype = mono_array_get (tb->subtypes, MonoReflectionTypeBuilder*, i);
2254 values [MONO_NESTED_CLASS_NESTED] = subtype->table_idx;
2255 values [MONO_NESTED_CLASS_ENCLOSING] = tb->table_idx;
2256 /*g_print ("nesting %s (%d) in %s (%d) (rows %d/%d)\n",
2257 mono_string_to_utf8 (subtype->name), subtype->table_idx,
2258 mono_string_to_utf8 (tb->name), tb->table_idx,
2259 ntable->next_idx, ntable->rows);*/
2260 values += MONO_NESTED_CLASS_SIZE;
2270 * mono_image_build_metadata() will fill the info in all the needed metadata tables
2271 * for the modulebuilder @moduleb.
2272 * At the end of the process, method and field tokens are fixed up and the
2273 * on-disk compressed metadata representation is created.
2274 * Return TRUE on success, or FALSE on failure and sets @error
2277 mono_image_build_metadata (MonoReflectionModuleBuilder *moduleb, MonoError *error)
2279 MonoDynamicTable *table;
2280 MonoDynamicImage *assembly;
2281 MonoReflectionAssemblyBuilder *assemblyb;
2287 mono_error_init (error);
2289 assemblyb = moduleb->assemblyb;
2290 assembly = moduleb->dynamic_image;
2291 domain = mono_object_domain (assemblyb);
2293 if (assembly->text_rva)
2296 assembly->text_rva = START_TEXT_RVA;
2298 if (moduleb->is_main) {
2299 mono_image_emit_manifest (moduleb, error);
2300 return_val_if_nok (error, FALSE);
2303 table = &assembly->tables [MONO_TABLE_TYPEDEF];
2304 table->rows = 1; /* .<Module> */
2306 alloc_table (table, table->rows);
2308 * Set the first entry.
2310 values = table->values + table->columns;
2311 values [MONO_TYPEDEF_FLAGS] = 0;
2312 values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, "<Module>") ;
2313 values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, "") ;
2314 values [MONO_TYPEDEF_EXTENDS] = 0;
2315 values [MONO_TYPEDEF_FIELD_LIST] = 1;
2316 values [MONO_TYPEDEF_METHOD_LIST] = 1;
2319 * handle global methods
2320 * FIXME: test what to do when global methods are defined in multiple modules.
2322 if (moduleb->global_methods) {
2323 table = &assembly->tables [MONO_TABLE_METHOD];
2324 table->rows += mono_array_length (moduleb->global_methods);
2325 alloc_table (table, table->rows);
2326 for (i = 0; i < mono_array_length (moduleb->global_methods); ++i) {
2327 if (!mono_image_get_method_info (
2328 mono_array_get (moduleb->global_methods, MonoReflectionMethodBuilder*, i), assembly, error))
2332 if (moduleb->global_fields) {
2333 table = &assembly->tables [MONO_TABLE_FIELD];
2334 table->rows += mono_array_length (moduleb->global_fields);
2335 alloc_table (table, table->rows);
2336 for (i = 0; i < mono_array_length (moduleb->global_fields); ++i) {
2337 mono_image_get_field_info (
2338 mono_array_get (moduleb->global_fields, MonoReflectionFieldBuilder*, i), assembly,
2345 table = &assembly->tables [MONO_TABLE_MODULE];
2346 alloc_table (table, 1);
2347 mono_image_fill_module_table (domain, moduleb, assembly, error);
2351 /* Collect all types into a list sorted by their table_idx */
2352 mono_ptr_array_init (types, moduleb->num_types, MONO_ROOT_SOURCE_REFLECTION, "dynamic module types list");
2355 for (i = 0; i < moduleb->num_types; ++i) {
2356 MonoReflectionTypeBuilder *type = mono_array_get (moduleb->types, MonoReflectionTypeBuilder*, i);
2357 collect_types (&types, type);
2360 mono_ptr_array_sort (types, (int (*)(const void *, const void *))compare_types_by_table_idx);
2361 table = &assembly->tables [MONO_TABLE_TYPEDEF];
2362 table->rows += mono_ptr_array_size (types);
2363 alloc_table (table, table->rows);
2366 * Emit type names + namespaces at one place inside the string heap,
2367 * so load_class_names () needs to touch fewer pages.
2369 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2370 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2371 string_heap_insert_mstring (&assembly->sheap, tb->nspace, error);
2375 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2376 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2377 string_heap_insert_mstring (&assembly->sheap, tb->name, error);
2382 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2383 MonoReflectionTypeBuilder *type = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2384 if (!mono_image_get_type_info (domain, type, assembly, error))
2389 * table->rows is already set above and in mono_image_fill_module_table.
2391 /* add all the custom attributes at the end, once all the indexes are stable */
2392 if (!mono_image_add_cattrs (assembly, 1, MONO_CUSTOM_ATTR_ASSEMBLY, assemblyb->cattrs, error))
2395 /* CAS assembly permissions */
2396 if (assemblyb->permissions_minimum)
2397 mono_image_add_decl_security (assembly, mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1), assemblyb->permissions_minimum);
2398 if (assemblyb->permissions_optional)
2399 mono_image_add_decl_security (assembly, mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1), assemblyb->permissions_optional);
2400 if (assemblyb->permissions_refused)
2401 mono_image_add_decl_security (assembly, mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1), assemblyb->permissions_refused);
2403 if (!module_add_cattrs (assembly, moduleb, error))
2407 mono_g_hash_table_foreach (assembly->token_fixups, (GHFunc)fixup_method, assembly);
2409 /* Create the MethodImpl table. We do this after emitting all methods so we already know
2410 * the final tokens and don't need another fixup pass. */
2412 if (moduleb->global_methods) {
2413 for (i = 0; i < mono_array_length (moduleb->global_methods); ++i) {
2414 MonoReflectionMethodBuilder *mb = mono_array_get (
2415 moduleb->global_methods, MonoReflectionMethodBuilder*, i);
2416 if (!mono_image_add_methodimpl (assembly, mb, error))
2421 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2422 MonoReflectionTypeBuilder *type = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2423 if (type->methods) {
2424 for (j = 0; j < type->num_methods; ++j) {
2425 MonoReflectionMethodBuilder *mb = mono_array_get (
2426 type->methods, MonoReflectionMethodBuilder*, j);
2428 if (!mono_image_add_methodimpl (assembly, mb, error))
2434 fixup_cattrs (assembly);
2437 mono_ptr_array_destroy (types);
2440 return mono_error_ok (error);
2443 #else /* DISABLE_REFLECTION_EMIT_SAVE */
2446 mono_image_build_metadata (MonoReflectionModuleBuilder *moduleb, MonoError *error)
2448 g_error ("This mono runtime was configured with --enable-minimal=reflection_emit_save, so saving of dynamic assemblies is not supported.");
2451 #endif /* DISABLE_REFLECTION_EMIT_SAVE */
2453 #ifndef DISABLE_REFLECTION_EMIT_SAVE
2456 calc_section_size (MonoDynamicImage *assembly)
2460 /* alignment constraints */
2461 mono_image_add_stream_zero (&assembly->code, 4 - (assembly->code.index % 4));
2462 g_assert ((assembly->code.index % 4) == 0);
2463 assembly->meta_size += 3;
2464 assembly->meta_size &= ~3;
2465 mono_image_add_stream_zero (&assembly->resources, 4 - (assembly->resources.index % 4));
2466 g_assert ((assembly->resources.index % 4) == 0);
2468 assembly->sections [MONO_SECTION_TEXT].size = assembly->meta_size + assembly->code.index + assembly->resources.index + assembly->strong_name_size;
2469 assembly->sections [MONO_SECTION_TEXT].attrs = SECT_FLAGS_HAS_CODE | SECT_FLAGS_MEM_EXECUTE | SECT_FLAGS_MEM_READ;
2472 if (assembly->win32_res) {
2473 guint32 res_size = (assembly->win32_res_size + 3) & ~3;
2475 assembly->sections [MONO_SECTION_RSRC].size = res_size;
2476 assembly->sections [MONO_SECTION_RSRC].attrs = SECT_FLAGS_HAS_INITIALIZED_DATA | SECT_FLAGS_MEM_READ;
2480 assembly->sections [MONO_SECTION_RELOC].size = 12;
2481 assembly->sections [MONO_SECTION_RELOC].attrs = SECT_FLAGS_MEM_READ | SECT_FLAGS_MEM_DISCARDABLE | SECT_FLAGS_HAS_INITIALIZED_DATA;
2491 MonoReflectionWin32Resource *win32_res; /* Only for leaf nodes */
2495 resource_tree_compare_by_id (gconstpointer a, gconstpointer b)
2497 ResTreeNode *t1 = (ResTreeNode*)a;
2498 ResTreeNode *t2 = (ResTreeNode*)b;
2500 return t1->id - t2->id;
2504 * resource_tree_create:
2506 * Organize the resources into a resource tree.
2508 static ResTreeNode *
2509 resource_tree_create (MonoArray *win32_resources)
2511 ResTreeNode *tree, *res_node, *type_node, *lang_node;
2515 tree = g_new0 (ResTreeNode, 1);
2517 for (i = 0; i < mono_array_length (win32_resources); ++i) {
2518 MonoReflectionWin32Resource *win32_res =
2519 (MonoReflectionWin32Resource*)mono_array_addr (win32_resources, MonoReflectionWin32Resource, i);
2523 /* FIXME: BUG: this stores managed references in unmanaged memory */
2524 lang_node = g_new0 (ResTreeNode, 1);
2525 lang_node->id = win32_res->lang_id;
2526 lang_node->win32_res = win32_res;
2528 /* Create type node if neccesary */
2530 for (l = tree->children; l; l = l->next)
2531 if (((ResTreeNode*)(l->data))->id == win32_res->res_type) {
2532 type_node = (ResTreeNode*)l->data;
2537 type_node = g_new0 (ResTreeNode, 1);
2538 type_node->id = win32_res->res_type;
2541 * The resource types have to be sorted otherwise
2542 * Windows Explorer can't display the version information.
2544 tree->children = g_slist_insert_sorted (tree->children,
2545 type_node, resource_tree_compare_by_id);
2548 /* Create res node if neccesary */
2550 for (l = type_node->children; l; l = l->next)
2551 if (((ResTreeNode*)(l->data))->id == win32_res->res_id) {
2552 res_node = (ResTreeNode*)l->data;
2557 res_node = g_new0 (ResTreeNode, 1);
2558 res_node->id = win32_res->res_id;
2559 type_node->children = g_slist_append (type_node->children, res_node);
2562 res_node->children = g_slist_append (res_node->children, lang_node);
2569 * resource_tree_encode:
2571 * Encode the resource tree into the format used in the PE file.
2574 resource_tree_encode (ResTreeNode *node, char *begin, char *p, char **endbuf)
2577 MonoPEResourceDir dir;
2578 MonoPEResourceDirEntry dir_entry;
2579 MonoPEResourceDataEntry data_entry;
2581 guint32 res_id_entries;
2584 * For the format of the resource directory, see the article
2585 * "An In-Depth Look into the Win32 Portable Executable File Format" by
2589 memset (&dir, 0, sizeof (dir));
2590 memset (&dir_entry, 0, sizeof (dir_entry));
2591 memset (&data_entry, 0, sizeof (data_entry));
2593 g_assert (sizeof (dir) == 16);
2594 g_assert (sizeof (dir_entry) == 8);
2595 g_assert (sizeof (data_entry) == 16);
2597 node->offset = p - begin;
2599 /* IMAGE_RESOURCE_DIRECTORY */
2600 res_id_entries = g_slist_length (node->children);
2601 dir.res_id_entries = GUINT16_TO_LE (res_id_entries);
2603 memcpy (p, &dir, sizeof (dir));
2606 /* Reserve space for entries */
2608 p += sizeof (dir_entry) * res_id_entries;
2610 /* Write children */
2611 for (l = node->children; l; l = l->next) {
2612 ResTreeNode *child = (ResTreeNode*)l->data;
2614 if (child->win32_res) {
2617 child->offset = p - begin;
2619 /* IMAGE_RESOURCE_DATA_ENTRY */
2620 data_entry.rde_data_offset = GUINT32_TO_LE (p - begin + sizeof (data_entry));
2621 size = mono_array_length (child->win32_res->res_data);
2622 data_entry.rde_size = GUINT32_TO_LE (size);
2624 memcpy (p, &data_entry, sizeof (data_entry));
2625 p += sizeof (data_entry);
2627 memcpy (p, mono_array_addr (child->win32_res->res_data, char, 0), size);
2630 resource_tree_encode (child, begin, p, &p);
2634 /* IMAGE_RESOURCE_ENTRY */
2635 for (l = node->children; l; l = l->next) {
2636 ResTreeNode *child = (ResTreeNode*)l->data;
2638 MONO_PE_RES_DIR_ENTRY_SET_NAME (dir_entry, FALSE, child->id);
2639 MONO_PE_RES_DIR_ENTRY_SET_DIR (dir_entry, !child->win32_res, child->offset);
2641 memcpy (entries, &dir_entry, sizeof (dir_entry));
2642 entries += sizeof (dir_entry);
2649 resource_tree_free (ResTreeNode * node)
2652 for (list = node->children; list; list = list->next)
2653 resource_tree_free ((ResTreeNode*)list->data);
2654 g_slist_free(node->children);
2659 assembly_add_win32_resources (MonoDynamicImage *assembly, MonoReflectionAssemblyBuilder *assemblyb)
2664 MonoReflectionWin32Resource *win32_res;
2667 if (!assemblyb->win32_resources)
2671 * Resources are stored in a three level tree inside the PE file.
2672 * - level one contains a node for each type of resource
2673 * - level two contains a node for each resource
2674 * - level three contains a node for each instance of a resource for a
2675 * specific language.
2678 tree = resource_tree_create (assemblyb->win32_resources);
2680 /* Estimate the size of the encoded tree */
2682 for (i = 0; i < mono_array_length (assemblyb->win32_resources); ++i) {
2683 win32_res = (MonoReflectionWin32Resource*)mono_array_addr (assemblyb->win32_resources, MonoReflectionWin32Resource, i);
2684 size += mono_array_length (win32_res->res_data);
2686 /* Directory structure */
2687 size += mono_array_length (assemblyb->win32_resources) * 256;
2688 p = buf = (char *)g_malloc (size);
2690 resource_tree_encode (tree, p, p, &p);
2692 g_assert (p - buf <= size);
2694 assembly->win32_res = (char *)g_malloc (p - buf);
2695 assembly->win32_res_size = p - buf;
2696 memcpy (assembly->win32_res, buf, p - buf);
2699 resource_tree_free (tree);
2703 fixup_resource_directory (char *res_section, char *p, guint32 rva)
2705 MonoPEResourceDir *dir = (MonoPEResourceDir*)p;
2708 p += sizeof (MonoPEResourceDir);
2709 for (i = 0; i < GUINT16_FROM_LE (dir->res_named_entries) + GUINT16_FROM_LE (dir->res_id_entries); ++i) {
2710 MonoPEResourceDirEntry *dir_entry = (MonoPEResourceDirEntry*)p;
2711 char *child = res_section + MONO_PE_RES_DIR_ENTRY_DIR_OFFSET (*dir_entry);
2712 if (MONO_PE_RES_DIR_ENTRY_IS_DIR (*dir_entry)) {
2713 fixup_resource_directory (res_section, child, rva);
2715 MonoPEResourceDataEntry *data_entry = (MonoPEResourceDataEntry*)child;
2716 data_entry->rde_data_offset = GUINT32_TO_LE (GUINT32_FROM_LE (data_entry->rde_data_offset) + rva);
2719 p += sizeof (MonoPEResourceDirEntry);
2724 checked_write_file (HANDLE f, gconstpointer buffer, guint32 numbytes)
2727 if (!WriteFile (f, buffer, numbytes, &dummy, NULL))
2728 g_error ("WriteFile returned %d\n", GetLastError ());
2732 * mono_image_create_pefile:
2733 * @mb: a module builder object
2735 * This function creates the PE-COFF header, the image sections, the CLI header * etc. all the data is written in
2736 * assembly->pefile where it can be easily retrieved later in chunks.
2739 mono_image_create_pefile (MonoReflectionModuleBuilder *mb, HANDLE file, MonoError *error)
2741 MonoMSDOSHeader *msdos;
2742 MonoDotNetHeader *header;
2743 MonoSectionTable *section;
2744 MonoCLIHeader *cli_header;
2745 guint32 size, image_size, virtual_base, text_offset;
2746 guint32 header_start, section_start, file_offset, virtual_offset;
2747 MonoDynamicImage *assembly;
2748 MonoReflectionAssemblyBuilder *assemblyb;
2749 MonoDynamicStream pefile_stream = {0};
2750 MonoDynamicStream *pefile = &pefile_stream;
2752 guint32 *rva, value;
2754 static const unsigned char msheader[] = {
2755 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
2756 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2757 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2758 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
2759 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68,
2760 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f,
2761 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,
2762 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
2765 mono_error_init (error);
2767 assemblyb = mb->assemblyb;
2769 mono_reflection_dynimage_basic_init (assemblyb);
2770 assembly = mb->dynamic_image;
2772 assembly->pe_kind = assemblyb->pe_kind;
2773 assembly->machine = assemblyb->machine;
2774 ((MonoDynamicImage*)assemblyb->dynamic_assembly->assembly.image)->pe_kind = assemblyb->pe_kind;
2775 ((MonoDynamicImage*)assemblyb->dynamic_assembly->assembly.image)->machine = assemblyb->machine;
2777 if (!mono_image_build_metadata (mb, error))
2781 if (mb->is_main && assemblyb->resources) {
2782 int len = mono_array_length (assemblyb->resources);
2783 for (i = 0; i < len; ++i) {
2784 if (!assembly_add_resource (mb, assembly, (MonoReflectionResource*)mono_array_addr (assemblyb->resources, MonoReflectionResource, i), error))
2789 if (mb->resources) {
2790 int len = mono_array_length (mb->resources);
2791 for (i = 0; i < len; ++i) {
2792 if (!assembly_add_resource (mb, assembly, (MonoReflectionResource*)mono_array_addr (mb->resources, MonoReflectionResource, i), error))
2797 if (!build_compressed_metadata (assembly, error))
2801 assembly_add_win32_resources (assembly, assemblyb);
2803 nsections = calc_section_size (assembly);
2805 /* The DOS header and stub */
2806 g_assert (sizeof (MonoMSDOSHeader) == sizeof (msheader));
2807 mono_image_add_stream_data (pefile, (char*)msheader, sizeof (msheader));
2809 /* the dotnet header */
2810 header_start = mono_image_add_stream_zero (pefile, sizeof (MonoDotNetHeader));
2812 /* the section tables */
2813 section_start = mono_image_add_stream_zero (pefile, sizeof (MonoSectionTable) * nsections);
2815 file_offset = section_start + sizeof (MonoSectionTable) * nsections;
2816 virtual_offset = VIRT_ALIGN;
2819 for (i = 0; i < MONO_SECTION_MAX; ++i) {
2820 if (!assembly->sections [i].size)
2823 file_offset += FILE_ALIGN - 1;
2824 file_offset &= ~(FILE_ALIGN - 1);
2825 virtual_offset += VIRT_ALIGN - 1;
2826 virtual_offset &= ~(VIRT_ALIGN - 1);
2828 assembly->sections [i].offset = file_offset;
2829 assembly->sections [i].rva = virtual_offset;
2831 file_offset += assembly->sections [i].size;
2832 virtual_offset += assembly->sections [i].size;
2833 image_size += (assembly->sections [i].size + VIRT_ALIGN - 1) & ~(VIRT_ALIGN - 1);
2836 file_offset += FILE_ALIGN - 1;
2837 file_offset &= ~(FILE_ALIGN - 1);
2839 image_size += section_start + sizeof (MonoSectionTable) * nsections;
2841 /* back-patch info */
2842 msdos = (MonoMSDOSHeader*)pefile->data;
2843 msdos->pe_offset = GUINT32_FROM_LE (sizeof (MonoMSDOSHeader));
2845 header = (MonoDotNetHeader*)(pefile->data + header_start);
2846 header->pesig [0] = 'P';
2847 header->pesig [1] = 'E';
2849 header->coff.coff_machine = GUINT16_FROM_LE (assemblyb->machine);
2850 header->coff.coff_sections = GUINT16_FROM_LE (nsections);
2851 header->coff.coff_time = GUINT32_FROM_LE (time (NULL));
2852 header->coff.coff_opt_header_size = GUINT16_FROM_LE (sizeof (MonoDotNetHeader) - sizeof (MonoCOFFHeader) - 4);
2853 if (assemblyb->pekind == 1) {
2855 header->coff.coff_attributes = GUINT16_FROM_LE (0x210e);
2858 header->coff.coff_attributes = GUINT16_FROM_LE (0x010e);
2861 virtual_base = 0x400000; /* FIXME: 0x10000000 if a DLL */
2863 header->pe.pe_magic = GUINT16_FROM_LE (0x10B);
2864 header->pe.pe_major = 6;
2865 header->pe.pe_minor = 0;
2866 size = assembly->sections [MONO_SECTION_TEXT].size;
2867 size += FILE_ALIGN - 1;
2868 size &= ~(FILE_ALIGN - 1);
2869 header->pe.pe_code_size = GUINT32_FROM_LE(size);
2870 size = assembly->sections [MONO_SECTION_RSRC].size;
2871 size += FILE_ALIGN - 1;
2872 size &= ~(FILE_ALIGN - 1);
2873 header->pe.pe_data_size = GUINT32_FROM_LE(size);
2874 g_assert (START_TEXT_RVA == assembly->sections [MONO_SECTION_TEXT].rva);
2875 header->pe.pe_rva_code_base = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_TEXT].rva);
2876 header->pe.pe_rva_data_base = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].rva);
2877 /* pe_rva_entry_point always at the beginning of the text section */
2878 header->pe.pe_rva_entry_point = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_TEXT].rva);
2880 header->nt.pe_image_base = GUINT32_FROM_LE (virtual_base);
2881 header->nt.pe_section_align = GUINT32_FROM_LE (VIRT_ALIGN);
2882 header->nt.pe_file_alignment = GUINT32_FROM_LE (FILE_ALIGN);
2883 header->nt.pe_os_major = GUINT16_FROM_LE (4);
2884 header->nt.pe_os_minor = GUINT16_FROM_LE (0);
2885 header->nt.pe_subsys_major = GUINT16_FROM_LE (4);
2886 size = section_start;
2887 size += FILE_ALIGN - 1;
2888 size &= ~(FILE_ALIGN - 1);
2889 header->nt.pe_header_size = GUINT32_FROM_LE (size);
2891 size += VIRT_ALIGN - 1;
2892 size &= ~(VIRT_ALIGN - 1);
2893 header->nt.pe_image_size = GUINT32_FROM_LE (size);
2896 // Translate the PEFileKind value to the value expected by the Windows loader
2902 // PEFileKinds.Dll == 1
2903 // PEFileKinds.ConsoleApplication == 2
2904 // PEFileKinds.WindowApplication == 3
2907 // IMAGE_SUBSYSTEM_WINDOWS_GUI 2 // Image runs in the Windows GUI subsystem.
2908 // IMAGE_SUBSYSTEM_WINDOWS_CUI 3 // Image runs in the Windows character subsystem.
2910 if (assemblyb->pekind == 3)
2915 header->nt.pe_subsys_required = GUINT16_FROM_LE (kind);
2917 header->nt.pe_stack_reserve = GUINT32_FROM_LE (0x00100000);
2918 header->nt.pe_stack_commit = GUINT32_FROM_LE (0x00001000);
2919 header->nt.pe_heap_reserve = GUINT32_FROM_LE (0x00100000);
2920 header->nt.pe_heap_commit = GUINT32_FROM_LE (0x00001000);
2921 header->nt.pe_loader_flags = GUINT32_FROM_LE (0);
2922 header->nt.pe_data_dir_count = GUINT32_FROM_LE (16);
2924 /* fill data directory entries */
2926 header->datadir.pe_resource_table.size = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].size);
2927 header->datadir.pe_resource_table.rva = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].rva);
2929 header->datadir.pe_reloc_table.size = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RELOC].size);
2930 header->datadir.pe_reloc_table.rva = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RELOC].rva);
2932 header->datadir.pe_cli_header.size = GUINT32_FROM_LE (72);
2933 header->datadir.pe_cli_header.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->cli_header_offset);
2934 header->datadir.pe_iat.size = GUINT32_FROM_LE (8);
2935 header->datadir.pe_iat.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->iat_offset);
2936 /* patch entrypoint name */
2937 if (assemblyb->pekind == 1)
2938 memcpy (assembly->code.data + assembly->imp_names_offset + 2, "_CorDllMain", 12);
2940 memcpy (assembly->code.data + assembly->imp_names_offset + 2, "_CorExeMain", 12);
2941 /* patch imported function RVA name */
2942 rva = (guint32*)(assembly->code.data + assembly->iat_offset);
2943 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->imp_names_offset);
2945 /* the import table */
2946 header->datadir.pe_import_table.size = GUINT32_FROM_LE (79); /* FIXME: magic number? */
2947 header->datadir.pe_import_table.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->idt_offset);
2948 /* patch imported dll RVA name and other entries in the dir */
2949 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, name_rva));
2950 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->imp_names_offset + 14); /* 14 is hint+strlen+1 of func name */
2951 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, import_address_table_rva));
2952 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->iat_offset);
2953 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, import_lookup_table));
2954 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->ilt_offset);
2956 p = (guchar*)(assembly->code.data + assembly->ilt_offset);
2957 value = (assembly->text_rva + assembly->imp_names_offset);
2958 *p++ = (value) & 0xff;
2959 *p++ = (value >> 8) & (0xff);
2960 *p++ = (value >> 16) & (0xff);
2961 *p++ = (value >> 24) & (0xff);
2963 /* the CLI header info */
2964 cli_header = (MonoCLIHeader*)(assembly->code.data + assembly->cli_header_offset);
2965 cli_header->ch_size = GUINT32_FROM_LE (72);
2966 cli_header->ch_runtime_major = GUINT16_FROM_LE (2);
2967 cli_header->ch_runtime_minor = GUINT16_FROM_LE (5);
2968 cli_header->ch_flags = GUINT32_FROM_LE (assemblyb->pe_kind);
2969 if (assemblyb->entry_point) {
2970 guint32 table_idx = 0;
2971 if (!strcmp (assemblyb->entry_point->object.vtable->klass->name, "MethodBuilder")) {
2972 MonoReflectionMethodBuilder *methodb = (MonoReflectionMethodBuilder*)assemblyb->entry_point;
2973 table_idx = methodb->table_idx;
2975 table_idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, assemblyb->entry_point->method));
2977 cli_header->ch_entry_point = GUINT32_FROM_LE (table_idx | MONO_TOKEN_METHOD_DEF);
2979 cli_header->ch_entry_point = GUINT32_FROM_LE (0);
2981 /* The embedded managed resources */
2982 text_offset = assembly->text_rva + assembly->code.index;
2983 cli_header->ch_resources.rva = GUINT32_FROM_LE (text_offset);
2984 cli_header->ch_resources.size = GUINT32_FROM_LE (assembly->resources.index);
2985 text_offset += assembly->resources.index;
2986 cli_header->ch_metadata.rva = GUINT32_FROM_LE (text_offset);
2987 cli_header->ch_metadata.size = GUINT32_FROM_LE (assembly->meta_size);
2988 text_offset += assembly->meta_size;
2989 if (assembly->strong_name_size) {
2990 cli_header->ch_strong_name.rva = GUINT32_FROM_LE (text_offset);
2991 cli_header->ch_strong_name.size = GUINT32_FROM_LE (assembly->strong_name_size);
2992 text_offset += assembly->strong_name_size;
2995 /* write the section tables and section content */
2996 section = (MonoSectionTable*)(pefile->data + section_start);
2997 for (i = 0; i < MONO_SECTION_MAX; ++i) {
2998 static const char section_names [][7] = {
2999 ".text", ".rsrc", ".reloc"
3001 if (!assembly->sections [i].size)
3003 strcpy (section->st_name, section_names [i]);
3004 /*g_print ("output section %s (%d), size: %d\n", section->st_name, i, assembly->sections [i].size);*/
3005 section->st_virtual_address = GUINT32_FROM_LE (assembly->sections [i].rva);
3006 section->st_virtual_size = GUINT32_FROM_LE (assembly->sections [i].size);
3007 section->st_raw_data_size = GUINT32_FROM_LE (GUINT32_TO_LE (section->st_virtual_size) + (FILE_ALIGN - 1));
3008 section->st_raw_data_size &= GUINT32_FROM_LE (~(FILE_ALIGN - 1));
3009 section->st_raw_data_ptr = GUINT32_FROM_LE (assembly->sections [i].offset);
3010 section->st_flags = GUINT32_FROM_LE (assembly->sections [i].attrs);
3014 checked_write_file (file, pefile->data, pefile->index);
3016 mono_dynamic_stream_reset (pefile);
3018 for (i = 0; i < MONO_SECTION_MAX; ++i) {
3019 if (!assembly->sections [i].size)
3022 if (SetFilePointer (file, assembly->sections [i].offset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
3023 g_error ("SetFilePointer returned %d\n", GetLastError ());
3026 case MONO_SECTION_TEXT:
3027 /* patch entry point */
3028 p = (guchar*)(assembly->code.data + 2);
3029 value = (virtual_base + assembly->text_rva + assembly->iat_offset);
3030 *p++ = (value) & 0xff;
3031 *p++ = (value >> 8) & 0xff;
3032 *p++ = (value >> 16) & 0xff;
3033 *p++ = (value >> 24) & 0xff;
3035 checked_write_file (file, assembly->code.data, assembly->code.index);
3036 checked_write_file (file, assembly->resources.data, assembly->resources.index);
3037 checked_write_file (file, assembly->image.raw_metadata, assembly->meta_size);
3038 checked_write_file (file, assembly->strong_name, assembly->strong_name_size);
3041 g_free (assembly->image.raw_metadata);
3043 case MONO_SECTION_RELOC: {
3047 guint16 type_and_offset;
3051 g_assert (sizeof (reloc) == 12);
3053 reloc.page_rva = GUINT32_FROM_LE (assembly->text_rva);
3054 reloc.block_size = GUINT32_FROM_LE (12);
3057 * the entrypoint is always at the start of the text section
3058 * 3 is IMAGE_REL_BASED_HIGHLOW
3059 * 2 is patch_size_rva - text_rva
3061 reloc.type_and_offset = GUINT16_FROM_LE ((3 << 12) + (2));
3064 checked_write_file (file, &reloc, sizeof (reloc));
3068 case MONO_SECTION_RSRC:
3069 if (assembly->win32_res) {
3071 /* Fixup the offsets in the IMAGE_RESOURCE_DATA_ENTRY structures */
3072 fixup_resource_directory (assembly->win32_res, assembly->win32_res, assembly->sections [i].rva);
3073 checked_write_file (file, assembly->win32_res, assembly->win32_res_size);
3077 g_assert_not_reached ();
3081 /* check that the file is properly padded */
3082 if (SetFilePointer (file, file_offset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
3083 g_error ("SetFilePointer returned %d\n", GetLastError ());
3084 if (! SetEndOfFile (file))
3085 g_error ("SetEndOfFile returned %d\n", GetLastError ());
3087 mono_dynamic_stream_reset (&assembly->code);
3088 mono_dynamic_stream_reset (&assembly->us);
3089 mono_dynamic_stream_reset (&assembly->blob);
3090 mono_dynamic_stream_reset (&assembly->guid);
3091 mono_dynamic_stream_reset (&assembly->sheap);
3093 g_hash_table_foreach (assembly->blob_cache, (GHFunc)g_free, NULL);
3094 g_hash_table_destroy (assembly->blob_cache);
3095 assembly->blob_cache = NULL;
3100 #else /* DISABLE_REFLECTION_EMIT_SAVE */
3103 mono_image_create_pefile (MonoReflectionModuleBuilder *mb, HANDLE file, MonoError *error)
3105 g_assert_not_reached ();
3108 #endif /* DISABLE_REFLECTION_EMIT_SAVE */