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 MonoClassExt *ext = mono_class_get_ext (klass);
1221 if (ext && ext->nested_classes) {
1224 for (tmp = ext->nested_classes; tmp; tmp = tmp->next)
1225 mono_image_fill_export_table_from_class (domain, (MonoClass *)tmp->data, module_index, table->next_idx - 1, assembly);
1232 mono_image_fill_export_table (MonoDomain *domain, MonoReflectionTypeBuilder *tb,
1233 guint32 module_index, guint32 parent_index, MonoDynamicImage *assembly,
1239 mono_error_init (error);
1241 MonoType *t = mono_reflection_type_get_handle ((MonoReflectionType*)tb, error);
1242 return_if_nok (error);
1244 klass = mono_class_from_mono_type (t);
1246 klass->type_token = mono_metadata_make_token (MONO_TABLE_TYPEDEF, tb->table_idx);
1248 idx = mono_image_fill_export_table_from_class (domain, klass, module_index,
1249 parent_index, assembly);
1253 * We need to do this ourselves since klass->nested_classes is not set up.
1256 for (i = 0; i < mono_array_length (tb->subtypes); ++i) {
1257 mono_image_fill_export_table (domain, mono_array_get (tb->subtypes, MonoReflectionTypeBuilder*, i), module_index, idx, assembly, error);
1258 return_if_nok (error);
1264 mono_image_fill_export_table_from_module (MonoDomain *domain, MonoReflectionModule *module,
1265 guint32 module_index, MonoDynamicImage *assembly)
1267 MonoImage *image = module->image;
1271 t = &image->tables [MONO_TABLE_TYPEDEF];
1273 for (i = 0; i < t->rows; ++i) {
1275 MonoClass *klass = mono_class_get_checked (image, mono_metadata_make_token (MONO_TABLE_TYPEDEF, i + 1), &error);
1276 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
1278 if (mono_class_is_public (klass))
1279 mono_image_fill_export_table_from_class (domain, klass, module_index, 0, assembly);
1284 add_exported_type (MonoReflectionAssemblyBuilder *assemblyb, MonoDynamicImage *assembly, MonoClass *klass, guint32 parent_index)
1286 MonoDynamicTable *table;
1288 guint32 scope, scope_idx, impl, current_idx;
1289 gboolean forwarder = TRUE;
1290 gpointer iter = NULL;
1293 if (klass->nested_in) {
1294 impl = (parent_index << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_EXP_TYPE;
1297 scope = mono_reflection_resolution_scope_from_image (assembly, klass->image);
1298 g_assert ((scope & MONO_RESOLUTION_SCOPE_MASK) == MONO_RESOLUTION_SCOPE_ASSEMBLYREF);
1299 scope_idx = scope >> MONO_RESOLUTION_SCOPE_BITS;
1300 impl = (scope_idx << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_ASSEMBLYREF;
1303 table = &assembly->tables [MONO_TABLE_EXPORTEDTYPE];
1306 alloc_table (table, table->rows);
1307 current_idx = table->next_idx;
1308 values = table->values + current_idx * MONO_EXP_TYPE_SIZE;
1310 values [MONO_EXP_TYPE_FLAGS] = forwarder ? TYPE_ATTRIBUTE_FORWARDER : 0;
1311 values [MONO_EXP_TYPE_TYPEDEF] = 0;
1312 values [MONO_EXP_TYPE_IMPLEMENTATION] = impl;
1313 values [MONO_EXP_TYPE_NAME] = string_heap_insert (&assembly->sheap, klass->name);
1314 values [MONO_EXP_TYPE_NAMESPACE] = string_heap_insert (&assembly->sheap, klass->name_space);
1318 while ((nested = mono_class_get_nested_types (klass, &iter)))
1319 add_exported_type (assemblyb, assembly, nested, current_idx);
1323 mono_image_fill_export_table_from_type_forwarders (MonoReflectionAssemblyBuilder *assemblyb, MonoDynamicImage *assembly)
1329 if (!assemblyb->type_forwarders)
1332 for (i = 0; i < mono_array_length (assemblyb->type_forwarders); ++i) {
1333 MonoReflectionType *t = mono_array_get (assemblyb->type_forwarders, MonoReflectionType *, i);
1338 type = mono_reflection_type_get_handle (t, &error);
1339 mono_error_assert_ok (&error);
1342 klass = mono_class_from_mono_type (type);
1344 add_exported_type (assemblyb, assembly, klass, 0);
1348 #define align_pointer(base,p)\
1350 guint32 __diff = (unsigned char*)(p)-(unsigned char*)(base);\
1352 (p) += 4 - (__diff & 3);\
1356 compare_constants (const void *a, const void *b)
1358 const guint32 *a_values = (const guint32 *)a;
1359 const guint32 *b_values = (const guint32 *)b;
1360 return a_values [MONO_CONSTANT_PARENT] - b_values [MONO_CONSTANT_PARENT];
1364 compare_semantics (const void *a, const void *b)
1366 const guint32 *a_values = (const guint32 *)a;
1367 const guint32 *b_values = (const guint32 *)b;
1368 int assoc = a_values [MONO_METHOD_SEMA_ASSOCIATION] - b_values [MONO_METHOD_SEMA_ASSOCIATION];
1371 return a_values [MONO_METHOD_SEMA_SEMANTICS] - b_values [MONO_METHOD_SEMA_SEMANTICS];
1375 compare_custom_attrs (const void *a, const void *b)
1377 const guint32 *a_values = (const guint32 *)a;
1378 const guint32 *b_values = (const guint32 *)b;
1380 return a_values [MONO_CUSTOM_ATTR_PARENT] - b_values [MONO_CUSTOM_ATTR_PARENT];
1384 compare_field_marshal (const void *a, const void *b)
1386 const guint32 *a_values = (const guint32 *)a;
1387 const guint32 *b_values = (const guint32 *)b;
1389 return a_values [MONO_FIELD_MARSHAL_PARENT] - b_values [MONO_FIELD_MARSHAL_PARENT];
1393 compare_nested (const void *a, const void *b)
1395 const guint32 *a_values = (const guint32 *)a;
1396 const guint32 *b_values = (const guint32 *)b;
1398 return a_values [MONO_NESTED_CLASS_NESTED] - b_values [MONO_NESTED_CLASS_NESTED];
1402 compare_genericparam (const void *a, const void *b)
1405 const GenericParamTableEntry **a_entry = (const GenericParamTableEntry **) a;
1406 const GenericParamTableEntry **b_entry = (const GenericParamTableEntry **) b;
1408 if ((*b_entry)->owner == (*a_entry)->owner) {
1409 MonoType *a_type = mono_reflection_type_get_handle ((MonoReflectionType*)(*a_entry)->gparam, &error);
1410 mono_error_assert_ok (&error);
1411 MonoType *b_type = mono_reflection_type_get_handle ((MonoReflectionType*)(*b_entry)->gparam, &error);
1412 mono_error_assert_ok (&error);
1414 mono_type_get_generic_param_num (a_type) -
1415 mono_type_get_generic_param_num (b_type);
1417 return (*a_entry)->owner - (*b_entry)->owner;
1421 compare_declsecurity_attrs (const void *a, const void *b)
1423 const guint32 *a_values = (const guint32 *)a;
1424 const guint32 *b_values = (const guint32 *)b;
1426 return a_values [MONO_DECL_SECURITY_PARENT] - b_values [MONO_DECL_SECURITY_PARENT];
1430 compare_interface_impl (const void *a, const void *b)
1432 const guint32 *a_values = (const guint32 *)a;
1433 const guint32 *b_values = (const guint32 *)b;
1435 int klass = a_values [MONO_INTERFACEIMPL_CLASS] - b_values [MONO_INTERFACEIMPL_CLASS];
1439 return a_values [MONO_INTERFACEIMPL_INTERFACE] - b_values [MONO_INTERFACEIMPL_INTERFACE];
1444 MonoDynamicStream *stream;
1448 * build_compressed_metadata() fills in the blob of data that represents the
1449 * raw metadata as it will be saved in the PE file. The five streams are output
1450 * and the metadata tables are comnpressed from the guint32 array representation,
1451 * to the compressed on-disk format.
1454 build_compressed_metadata (MonoDynamicImage *assembly, MonoError *error)
1456 MonoDynamicTable *table;
1458 guint64 valid_mask = 0;
1459 guint64 sorted_mask;
1460 guint32 heapt_size = 0;
1461 guint32 meta_size = 256; /* allow for header and other stuff */
1462 guint32 table_offset;
1463 guint32 ntables = 0;
1469 struct StreamDesc stream_desc [5];
1471 mono_error_init (error);
1473 qsort (assembly->gen_params->pdata, assembly->gen_params->len, sizeof (gpointer), compare_genericparam);
1474 for (i = 0; i < assembly->gen_params->len; i++) {
1475 GenericParamTableEntry *entry = (GenericParamTableEntry *)g_ptr_array_index (assembly->gen_params, i);
1476 if (!write_generic_param_entry (assembly, entry, error))
1480 stream_desc [0].name = "#~";
1481 stream_desc [0].stream = &assembly->tstream;
1482 stream_desc [1].name = "#Strings";
1483 stream_desc [1].stream = &assembly->sheap;
1484 stream_desc [2].name = "#US";
1485 stream_desc [2].stream = &assembly->us;
1486 stream_desc [3].name = "#Blob";
1487 stream_desc [3].stream = &assembly->blob;
1488 stream_desc [4].name = "#GUID";
1489 stream_desc [4].stream = &assembly->guid;
1491 /* tables that are sorted */
1492 sorted_mask = ((guint64)1 << MONO_TABLE_CONSTANT) | ((guint64)1 << MONO_TABLE_FIELDMARSHAL)
1493 | ((guint64)1 << MONO_TABLE_METHODSEMANTICS) | ((guint64)1 << MONO_TABLE_CLASSLAYOUT)
1494 | ((guint64)1 << MONO_TABLE_FIELDLAYOUT) | ((guint64)1 << MONO_TABLE_FIELDRVA)
1495 | ((guint64)1 << MONO_TABLE_IMPLMAP) | ((guint64)1 << MONO_TABLE_NESTEDCLASS)
1496 | ((guint64)1 << MONO_TABLE_METHODIMPL) | ((guint64)1 << MONO_TABLE_CUSTOMATTRIBUTE)
1497 | ((guint64)1 << MONO_TABLE_DECLSECURITY) | ((guint64)1 << MONO_TABLE_GENERICPARAM)
1498 | ((guint64)1 << MONO_TABLE_INTERFACEIMPL);
1500 /* Compute table sizes */
1501 /* the MonoImage has already been created in mono_reflection_dynimage_basic_init() */
1502 meta = &assembly->image;
1504 /* sizes should be multiple of 4 */
1505 mono_dynstream_data_align (&assembly->blob);
1506 mono_dynstream_data_align (&assembly->guid);
1507 mono_dynstream_data_align (&assembly->sheap);
1508 mono_dynstream_data_align (&assembly->us);
1510 /* Setup the info used by compute_sizes () */
1511 meta->idx_blob_wide = assembly->blob.index >= 65536 ? 1 : 0;
1512 meta->idx_guid_wide = assembly->guid.index >= 65536 ? 1 : 0;
1513 meta->idx_string_wide = assembly->sheap.index >= 65536 ? 1 : 0;
1515 meta_size += assembly->blob.index;
1516 meta_size += assembly->guid.index;
1517 meta_size += assembly->sheap.index;
1518 meta_size += assembly->us.index;
1520 for (i=0; i < MONO_TABLE_NUM; ++i)
1521 meta->tables [i].rows = assembly->tables [i].rows;
1523 for (i = 0; i < MONO_TABLE_NUM; i++){
1524 if (meta->tables [i].rows == 0)
1526 valid_mask |= (guint64)1 << i;
1528 meta->tables [i].row_size = mono_metadata_compute_size (
1529 meta, i, &meta->tables [i].size_bitfield);
1530 heapt_size += meta->tables [i].row_size * meta->tables [i].rows;
1532 heapt_size += 24; /* #~ header size */
1533 heapt_size += ntables * 4;
1534 /* make multiple of 4 */
1537 meta_size += heapt_size;
1538 meta->raw_metadata = (char *)g_malloc0 (meta_size);
1539 p = (unsigned char*)meta->raw_metadata;
1540 /* the metadata signature */
1541 *p++ = 'B'; *p++ = 'S'; *p++ = 'J'; *p++ = 'B';
1542 /* version numbers and 4 bytes reserved */
1543 int16val = (guint16*)p;
1544 *int16val++ = GUINT16_TO_LE (meta->md_version_major);
1545 *int16val = GUINT16_TO_LE (meta->md_version_minor);
1547 /* version string */
1548 int32val = (guint32*)p;
1549 *int32val = GUINT32_TO_LE ((strlen (meta->version) + 3) & (~3)); /* needs to be multiple of 4 */
1551 memcpy (p, meta->version, strlen (meta->version));
1552 p += GUINT32_FROM_LE (*int32val);
1553 align_pointer (meta->raw_metadata, p);
1554 int16val = (guint16*)p;
1555 *int16val++ = GUINT16_TO_LE (0); /* flags must be 0 */
1556 *int16val = GUINT16_TO_LE (5); /* number of streams */
1560 * write the stream info.
1562 table_offset = (p - (unsigned char*)meta->raw_metadata) + 5 * 8 + 40; /* room needed for stream headers */
1563 table_offset += 3; table_offset &= ~3;
1565 assembly->tstream.index = heapt_size;
1566 for (i = 0; i < 5; ++i) {
1567 int32val = (guint32*)p;
1568 stream_desc [i].stream->offset = table_offset;
1569 *int32val++ = GUINT32_TO_LE (table_offset);
1570 *int32val = GUINT32_TO_LE (stream_desc [i].stream->index);
1571 table_offset += GUINT32_FROM_LE (*int32val);
1572 table_offset += 3; table_offset &= ~3;
1574 strcpy ((char*)p, stream_desc [i].name);
1575 p += strlen (stream_desc [i].name) + 1;
1576 align_pointer (meta->raw_metadata, p);
1579 * now copy the data, the table stream header and contents goes first.
1581 g_assert ((p - (unsigned char*)meta->raw_metadata) < assembly->tstream.offset);
1582 p = (guchar*)meta->raw_metadata + assembly->tstream.offset;
1583 int32val = (guint32*)p;
1584 *int32val = GUINT32_TO_LE (0); /* reserved */
1587 *p++ = 2; /* version */
1590 if (meta->idx_string_wide)
1592 if (meta->idx_guid_wide)
1594 if (meta->idx_blob_wide)
1597 *p++ = 1; /* reserved */
1598 int64val = (guint64*)p;
1599 *int64val++ = GUINT64_TO_LE (valid_mask);
1600 *int64val++ = GUINT64_TO_LE (valid_mask & sorted_mask); /* bitvector of sorted tables */
1602 int32val = (guint32*)p;
1603 for (i = 0; i < MONO_TABLE_NUM; i++){
1604 if (meta->tables [i].rows == 0)
1606 *int32val++ = GUINT32_TO_LE (meta->tables [i].rows);
1608 p = (unsigned char*)int32val;
1610 /* sort the tables that still need sorting */
1611 table = &assembly->tables [MONO_TABLE_CONSTANT];
1613 qsort (table->values + MONO_CONSTANT_SIZE, table->rows, sizeof (guint32) * MONO_CONSTANT_SIZE, compare_constants);
1614 table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
1616 qsort (table->values + MONO_METHOD_SEMA_SIZE, table->rows, sizeof (guint32) * MONO_METHOD_SEMA_SIZE, compare_semantics);
1617 table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1619 qsort (table->values + MONO_CUSTOM_ATTR_SIZE, table->rows, sizeof (guint32) * MONO_CUSTOM_ATTR_SIZE, compare_custom_attrs);
1620 table = &assembly->tables [MONO_TABLE_FIELDMARSHAL];
1622 qsort (table->values + MONO_FIELD_MARSHAL_SIZE, table->rows, sizeof (guint32) * MONO_FIELD_MARSHAL_SIZE, compare_field_marshal);
1623 table = &assembly->tables [MONO_TABLE_NESTEDCLASS];
1625 qsort (table->values + MONO_NESTED_CLASS_SIZE, table->rows, sizeof (guint32) * MONO_NESTED_CLASS_SIZE, compare_nested);
1626 /* Section 21.11 DeclSecurity in Partition II doesn't specify this to be sorted by MS implementation requires it */
1627 table = &assembly->tables [MONO_TABLE_DECLSECURITY];
1629 qsort (table->values + MONO_DECL_SECURITY_SIZE, table->rows, sizeof (guint32) * MONO_DECL_SECURITY_SIZE, compare_declsecurity_attrs);
1630 table = &assembly->tables [MONO_TABLE_INTERFACEIMPL];
1632 qsort (table->values + MONO_INTERFACEIMPL_SIZE, table->rows, sizeof (guint32) * MONO_INTERFACEIMPL_SIZE, compare_interface_impl);
1634 /* compress the tables */
1635 for (i = 0; i < MONO_TABLE_NUM; i++){
1638 guint32 bitfield = meta->tables [i].size_bitfield;
1639 if (!meta->tables [i].rows)
1641 if (assembly->tables [i].columns != mono_metadata_table_count (bitfield))
1642 g_error ("col count mismatch in %d: %d %d", i, assembly->tables [i].columns, mono_metadata_table_count (bitfield));
1643 meta->tables [i].base = (char*)p;
1644 for (row = 1; row <= meta->tables [i].rows; ++row) {
1645 values = assembly->tables [i].values + row * assembly->tables [i].columns;
1646 for (col = 0; col < assembly->tables [i].columns; ++col) {
1647 switch (mono_metadata_table_size (bitfield, col)) {
1649 *p++ = values [col];
1652 *p++ = values [col] & 0xff;
1653 *p++ = (values [col] >> 8) & 0xff;
1656 *p++ = values [col] & 0xff;
1657 *p++ = (values [col] >> 8) & 0xff;
1658 *p++ = (values [col] >> 16) & 0xff;
1659 *p++ = (values [col] >> 24) & 0xff;
1662 g_assert_not_reached ();
1666 g_assert ((p - (const unsigned char*)meta->tables [i].base) == (meta->tables [i].rows * meta->tables [i].row_size));
1669 g_assert (assembly->guid.offset + assembly->guid.index < meta_size);
1670 memcpy (meta->raw_metadata + assembly->sheap.offset, assembly->sheap.data, assembly->sheap.index);
1671 memcpy (meta->raw_metadata + assembly->us.offset, assembly->us.data, assembly->us.index);
1672 memcpy (meta->raw_metadata + assembly->blob.offset, assembly->blob.data, assembly->blob.index);
1673 memcpy (meta->raw_metadata + assembly->guid.offset, assembly->guid.data, assembly->guid.index);
1675 assembly->meta_size = assembly->guid.offset + assembly->guid.index;
1681 * Some tables in metadata need to be sorted according to some criteria, but
1682 * when methods and fields are first created with reflection, they may be assigned a token
1683 * that doesn't correspond to the final token they will get assigned after the sorting.
1684 * ILGenerator.cs keeps a fixup table that maps the position of tokens in the IL code stream
1685 * with the reflection objects that represent them. Once all the tables are set up, the
1686 * reflection objects will contains the correct table index. fixup_method() will fixup the
1687 * tokens for the method with ILGenerator @ilgen.
1690 fixup_method (MonoReflectionILGen *ilgen, gpointer value, MonoDynamicImage *assembly)
1692 guint32 code_idx = GPOINTER_TO_UINT (value);
1693 MonoReflectionILTokenInfo *iltoken;
1694 MonoReflectionTypeBuilder *tb;
1695 MonoReflectionArrayMethod *am;
1697 unsigned char *target;
1699 for (i = 0; i < ilgen->num_token_fixups; ++i) {
1700 iltoken = (MonoReflectionILTokenInfo *)mono_array_addr_with_size (ilgen->token_fixups, sizeof (MonoReflectionILTokenInfo), i);
1701 target = (guchar*)assembly->code.data + code_idx + iltoken->code_pos;
1702 switch (target [3]) {
1703 case MONO_TABLE_FIELD:
1704 if (!strcmp (iltoken->member->vtable->klass->name, "FieldBuilder")) {
1705 g_assert_not_reached ();
1706 } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoField")) {
1707 MonoClassField *f = ((MonoReflectionField*)iltoken->member)->field;
1708 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->field_to_table_idx, f));
1710 g_assert_not_reached ();
1713 case MONO_TABLE_METHOD:
1714 if (!strcmp (iltoken->member->vtable->klass->name, "MethodBuilder")) {
1715 g_assert_not_reached ();
1716 } else if (!strcmp (iltoken->member->vtable->klass->name, "ConstructorBuilder")) {
1717 g_assert_not_reached ();
1718 } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoMethod") ||
1719 !strcmp (iltoken->member->vtable->klass->name, "MonoCMethod")) {
1720 MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
1721 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, m));
1723 g_assert_not_reached ();
1726 case MONO_TABLE_TYPEDEF:
1727 if (!strcmp (iltoken->member->vtable->klass->name, "TypeBuilder")) {
1728 g_assert_not_reached ();
1729 } else if (!strcmp (iltoken->member->vtable->klass->name, "RuntimeType")) {
1730 MonoClass *k = mono_class_from_mono_type (((MonoReflectionType*)iltoken->member)->type);
1731 MonoObject *obj = mono_class_get_ref_info (k);
1733 g_assert (!strcmp (obj->vtable->klass->name, "TypeBuilder"));
1734 tb = (MonoReflectionTypeBuilder*)obj;
1735 idx = tb->table_idx;
1737 g_assert_not_reached ();
1740 case MONO_TABLE_MEMBERREF:
1741 if (!strcmp (iltoken->member->vtable->klass->name, "MonoArrayMethod")) {
1742 am = (MonoReflectionArrayMethod*)iltoken->member;
1743 idx = am->table_idx;
1744 } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoMethod") ||
1745 !strcmp (iltoken->member->vtable->klass->name, "MonoCMethod")) {
1746 MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
1747 g_assert (mono_class_is_ginst (m->klass) || mono_class_is_gtd (m->klass));
1749 } else if (!strcmp (iltoken->member->vtable->klass->name, "FieldBuilder")) {
1750 g_assert_not_reached ();
1752 } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoField")) {
1754 } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodBuilder") ||
1755 !strcmp (iltoken->member->vtable->klass->name, "ConstructorBuilder")) {
1756 g_assert_not_reached ();
1758 } else if (!strcmp (iltoken->member->vtable->klass->name, "FieldOnTypeBuilderInst")) {
1759 g_assert_not_reached ();
1761 } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodOnTypeBuilderInst")) {
1762 g_assert_not_reached ();
1764 } else if (!strcmp (iltoken->member->vtable->klass->name, "ConstructorOnTypeBuilderInst")) {
1765 g_assert_not_reached ();
1768 g_assert_not_reached ();
1771 case MONO_TABLE_METHODSPEC:
1772 if (!strcmp (iltoken->member->vtable->klass->name, "MonoMethod")) {
1773 MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
1774 g_assert (mono_method_signature (m)->generic_param_count);
1776 } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodBuilder")) {
1777 g_assert_not_reached ();
1779 } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodOnTypeBuilderInst")) {
1780 g_assert_not_reached ();
1783 g_assert_not_reached ();
1786 case MONO_TABLE_TYPESPEC:
1787 if (!strcmp (iltoken->member->vtable->klass->name, "RuntimeType")) {
1790 g_assert_not_reached ();
1794 g_error ("got unexpected table 0x%02x in fixup", target [3]);
1796 target [0] = idx & 0xff;
1797 target [1] = (idx >> 8) & 0xff;
1798 target [2] = (idx >> 16) & 0xff;
1805 * The CUSTOM_ATTRIBUTE table might contain METHODDEF tokens whose final
1806 * value is not known when the table is emitted.
1809 fixup_cattrs (MonoDynamicImage *assembly)
1811 MonoDynamicTable *table;
1813 guint32 type, i, idx, token;
1816 table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1818 for (i = 0; i < table->rows; ++i) {
1819 values = table->values + ((i + 1) * MONO_CUSTOM_ATTR_SIZE);
1821 type = values [MONO_CUSTOM_ATTR_TYPE];
1822 if ((type & MONO_CUSTOM_ATTR_TYPE_MASK) == MONO_CUSTOM_ATTR_TYPE_METHODDEF) {
1823 idx = type >> MONO_CUSTOM_ATTR_TYPE_BITS;
1824 token = mono_metadata_make_token (MONO_TABLE_METHOD, idx);
1825 ctor = (MonoObject *)mono_g_hash_table_lookup (assembly->remapped_tokens, GUINT_TO_POINTER (token));
1828 if (!strcmp (ctor->vtable->klass->name, "MonoCMethod")) {
1829 MonoMethod *m = ((MonoReflectionMethod*)ctor)->method;
1830 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, m));
1831 values [MONO_CUSTOM_ATTR_TYPE] = (idx << MONO_CUSTOM_ATTR_TYPE_BITS) | MONO_CUSTOM_ATTR_TYPE_METHODDEF;
1832 } else if (!strcmp (ctor->vtable->klass->name, "ConstructorBuilder")) {
1833 MonoMethod *m = ((MonoReflectionCtorBuilder*)ctor)->mhandle;
1834 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, m));
1835 values [MONO_CUSTOM_ATTR_TYPE] = (idx << MONO_CUSTOM_ATTR_TYPE_BITS) | MONO_CUSTOM_ATTR_TYPE_METHODDEF;
1842 assembly_add_resource_manifest (MonoReflectionModuleBuilder *mb, MonoDynamicImage *assembly, MonoReflectionResource *rsrc, guint32 implementation, MonoError *error)
1844 MonoDynamicTable *table;
1847 mono_error_init (error);
1849 table = &assembly->tables [MONO_TABLE_MANIFESTRESOURCE];
1851 alloc_table (table, table->rows);
1852 values = table->values + table->next_idx * MONO_MANIFEST_SIZE;
1853 values [MONO_MANIFEST_OFFSET] = rsrc->offset;
1854 values [MONO_MANIFEST_FLAGS] = rsrc->attrs;
1855 values [MONO_MANIFEST_NAME] = string_heap_insert_mstring (&assembly->sheap, rsrc->name, error);
1856 return_val_if_nok (error, FALSE);
1857 values [MONO_MANIFEST_IMPLEMENTATION] = implementation;
1863 assembly_add_resource (MonoReflectionModuleBuilder *mb, MonoDynamicImage *assembly, MonoReflectionResource *rsrc, MonoError *error)
1865 MonoDynamicTable *table;
1869 char *b = blob_size;
1871 guint32 idx, offset;
1873 mono_error_init (error);
1875 if (rsrc->filename) {
1876 name = mono_string_to_utf8_checked (rsrc->filename, error);
1877 return_val_if_nok (error, FALSE);
1878 sname = g_path_get_basename (name);
1880 table = &assembly->tables [MONO_TABLE_FILE];
1882 alloc_table (table, table->rows);
1883 values = table->values + table->next_idx * MONO_FILE_SIZE;
1884 values [MONO_FILE_FLAGS] = FILE_CONTAINS_NO_METADATA;
1885 values [MONO_FILE_NAME] = string_heap_insert (&assembly->sheap, sname);
1888 mono_sha1_get_digest_from_file (name, hash);
1889 mono_metadata_encode_value (20, b, &b);
1890 values [MONO_FILE_HASH_VALUE] = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
1891 mono_image_add_stream_data (&assembly->blob, (char*)hash, 20);
1893 idx = table->next_idx++;
1895 idx = MONO_IMPLEMENTATION_FILE | (idx << MONO_IMPLEMENTATION_BITS);
1901 data = mono_array_addr (rsrc->data, char, 0);
1902 len = mono_array_length (rsrc->data);
1908 sizebuf [0] = offset; sizebuf [1] = offset >> 8;
1909 sizebuf [2] = offset >> 16; sizebuf [3] = offset >> 24;
1910 rsrc->offset = mono_image_add_stream_data (&assembly->resources, sizebuf, 4);
1911 mono_image_add_stream_data (&assembly->resources, data, len);
1915 * The entry should be emitted into the MANIFESTRESOURCE table of
1916 * the main module, but that needs to reference the FILE table
1917 * which isn't emitted yet.
1924 return assembly_add_resource_manifest (mb, assembly, rsrc, idx, error);
1928 set_version_from_string (MonoString *version, guint32 *values, MonoError *error)
1930 gchar *ver, *p, *str;
1933 mono_error_init (error);
1935 values [MONO_ASSEMBLY_MAJOR_VERSION] = 0;
1936 values [MONO_ASSEMBLY_MINOR_VERSION] = 0;
1937 values [MONO_ASSEMBLY_REV_NUMBER] = 0;
1938 values [MONO_ASSEMBLY_BUILD_NUMBER] = 0;
1941 ver = str = mono_string_to_utf8_checked (version, error);
1942 return_val_if_nok (error, FALSE);
1943 for (i = 0; i < 4; ++i) {
1944 values [MONO_ASSEMBLY_MAJOR_VERSION + i] = strtol (ver, &p, 10);
1950 /* handle Revision and Build */
1961 load_public_key (MonoArray *pkey, MonoDynamicImage *assembly) {
1965 char *b = blob_size;
1970 len = mono_array_length (pkey);
1971 mono_metadata_encode_value (len, b, &b);
1972 token = mono_image_add_stream_data (&assembly->blob, blob_size, b - blob_size);
1973 mono_image_add_stream_data (&assembly->blob, mono_array_addr (pkey, char, 0), len);
1975 assembly->public_key = (guint8 *)g_malloc (len);
1976 memcpy (assembly->public_key, mono_array_addr (pkey, char, 0), len);
1977 assembly->public_key_len = len;
1979 /* Special case: check for ECMA key (16 bytes) */
1980 if ((len == MONO_ECMA_KEY_LENGTH) && mono_is_ecma_key (mono_array_addr (pkey, char, 0), len)) {
1981 /* In this case we must reserve 128 bytes (1024 bits) for the signature */
1982 assembly->strong_name_size = MONO_DEFAULT_PUBLIC_KEY_LENGTH;
1983 } else if (len >= MONO_PUBLIC_KEY_HEADER_LENGTH + MONO_MINIMUM_PUBLIC_KEY_LENGTH) {
1984 /* minimum key size (in 2.0) is 384 bits */
1985 assembly->strong_name_size = len - MONO_PUBLIC_KEY_HEADER_LENGTH;
1987 /* FIXME - verifier */
1988 g_warning ("Invalid public key length: %d bits (total: %d)", (int)MONO_PUBLIC_KEY_BIT_SIZE (len), (int)len);
1989 assembly->strong_name_size = MONO_DEFAULT_PUBLIC_KEY_LENGTH; /* to be safe */
1991 assembly->strong_name = (char *)g_malloc0 (assembly->strong_name_size);
1997 mono_image_emit_manifest (MonoReflectionModuleBuilder *moduleb, MonoError *error)
1999 MonoDynamicTable *table;
2000 MonoDynamicImage *assembly;
2001 MonoReflectionAssemblyBuilder *assemblyb;
2005 guint32 module_index;
2007 mono_error_init (error);
2009 assemblyb = moduleb->assemblyb;
2010 assembly = moduleb->dynamic_image;
2011 domain = mono_object_domain (assemblyb);
2013 /* Emit ASSEMBLY table */
2014 table = &assembly->tables [MONO_TABLE_ASSEMBLY];
2015 alloc_table (table, 1);
2016 values = table->values + MONO_ASSEMBLY_SIZE;
2017 values [MONO_ASSEMBLY_HASH_ALG] = assemblyb->algid? assemblyb->algid: ASSEMBLY_HASH_SHA1;
2018 values [MONO_ASSEMBLY_NAME] = string_heap_insert_mstring (&assembly->sheap, assemblyb->name, error);
2019 return_val_if_nok (error, FALSE);
2020 if (assemblyb->culture) {
2021 values [MONO_ASSEMBLY_CULTURE] = string_heap_insert_mstring (&assembly->sheap, assemblyb->culture, error);
2022 return_val_if_nok (error, FALSE);
2024 values [MONO_ASSEMBLY_CULTURE] = string_heap_insert (&assembly->sheap, "");
2026 values [MONO_ASSEMBLY_PUBLIC_KEY] = load_public_key (assemblyb->public_key, assembly);
2027 values [MONO_ASSEMBLY_FLAGS] = assemblyb->flags;
2028 if (!set_version_from_string (assemblyb->version, values, error))
2031 /* Emit FILE + EXPORTED_TYPE table */
2033 for (i = 0; i < mono_array_length (assemblyb->modules); ++i) {
2035 MonoReflectionModuleBuilder *file_module =
2036 mono_array_get (assemblyb->modules, MonoReflectionModuleBuilder*, i);
2037 if (file_module != moduleb) {
2038 if (!mono_image_fill_file_table (domain, (MonoReflectionModule*)file_module, assembly, error))
2041 if (file_module->types) {
2042 for (j = 0; j < file_module->num_types; ++j) {
2043 MonoReflectionTypeBuilder *tb = mono_array_get (file_module->types, MonoReflectionTypeBuilder*, j);
2044 mono_image_fill_export_table (domain, tb, module_index, 0, assembly, error);
2045 return_val_if_nok (error, FALSE);
2050 if (assemblyb->loaded_modules) {
2051 for (i = 0; i < mono_array_length (assemblyb->loaded_modules); ++i) {
2052 MonoReflectionModule *file_module =
2053 mono_array_get (assemblyb->loaded_modules, MonoReflectionModule*, i);
2054 if (!mono_image_fill_file_table (domain, file_module, assembly, error))
2057 mono_image_fill_export_table_from_module (domain, file_module, module_index, assembly);
2060 if (assemblyb->type_forwarders)
2061 mono_image_fill_export_table_from_type_forwarders (assemblyb, assembly);
2063 /* Emit MANIFESTRESOURCE table */
2065 for (i = 0; i < mono_array_length (assemblyb->modules); ++i) {
2067 MonoReflectionModuleBuilder *file_module =
2068 mono_array_get (assemblyb->modules, MonoReflectionModuleBuilder*, i);
2069 /* The table for the main module is emitted later */
2070 if (file_module != moduleb) {
2072 if (file_module->resources) {
2073 int len = mono_array_length (file_module->resources);
2074 for (j = 0; j < len; ++j) {
2075 MonoReflectionResource* res = (MonoReflectionResource*)mono_array_addr (file_module->resources, MonoReflectionResource, j);
2076 if (!assembly_add_resource_manifest (file_module, assembly, res, MONO_IMPLEMENTATION_FILE | (module_index << MONO_IMPLEMENTATION_BITS), error))
2085 #ifndef DISABLE_REFLECTION_EMIT_SAVE
2088 * Insert into the metadata tables all the info about the TypeBuilder tb.
2089 * Data in the tables is inserted in a predefined order, since some tables need to be sorted.
2092 mono_image_get_type_info (MonoDomain *domain, MonoReflectionTypeBuilder *tb, MonoDynamicImage *assembly, MonoError *error)
2094 MonoDynamicTable *table;
2096 int i, is_object = 0, is_system = 0;
2099 mono_error_init (error);
2101 table = &assembly->tables [MONO_TABLE_TYPEDEF];
2102 values = table->values + tb->table_idx * MONO_TYPEDEF_SIZE;
2103 values [MONO_TYPEDEF_FLAGS] = tb->attrs;
2104 n = mono_string_to_utf8_checked (tb->name, error);
2105 return_val_if_nok (error, FALSE);
2106 if (strcmp (n, "Object") == 0)
2108 values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, n);
2110 n = mono_string_to_utf8_checked (tb->nspace, error);
2111 return_val_if_nok (error, FALSE);
2112 if (strcmp (n, "System") == 0)
2114 values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, n);
2116 if (tb->parent && !(is_system && is_object) &&
2117 !(tb->attrs & TYPE_ATTRIBUTE_INTERFACE)) { /* interfaces don't have a parent */
2118 MonoType *parent_type = mono_reflection_type_get_handle ((MonoReflectionType*)tb->parent, error);
2119 return_val_if_nok (error, FALSE);
2120 values [MONO_TYPEDEF_EXTENDS] = mono_image_typedef_or_ref (assembly, parent_type);
2122 values [MONO_TYPEDEF_EXTENDS] = 0;
2124 values [MONO_TYPEDEF_FIELD_LIST] = assembly->tables [MONO_TABLE_FIELD].next_idx;
2125 values [MONO_TYPEDEF_METHOD_LIST] = assembly->tables [MONO_TABLE_METHOD].next_idx;
2128 * if we have explicitlayout or sequentiallayouts, output data in the
2129 * ClassLayout table.
2131 if (((tb->attrs & TYPE_ATTRIBUTE_LAYOUT_MASK) != TYPE_ATTRIBUTE_AUTO_LAYOUT) &&
2132 ((tb->class_size > 0) || (tb->packing_size > 0))) {
2133 table = &assembly->tables [MONO_TABLE_CLASSLAYOUT];
2135 alloc_table (table, table->rows);
2136 values = table->values + table->rows * MONO_CLASS_LAYOUT_SIZE;
2137 values [MONO_CLASS_LAYOUT_PARENT] = tb->table_idx;
2138 values [MONO_CLASS_LAYOUT_CLASS_SIZE] = tb->class_size;
2139 values [MONO_CLASS_LAYOUT_PACKING_SIZE] = tb->packing_size;
2142 /* handle interfaces */
2143 if (tb->interfaces) {
2144 table = &assembly->tables [MONO_TABLE_INTERFACEIMPL];
2146 table->rows += mono_array_length (tb->interfaces);
2147 alloc_table (table, table->rows);
2148 values = table->values + (i + 1) * MONO_INTERFACEIMPL_SIZE;
2149 for (i = 0; i < mono_array_length (tb->interfaces); ++i) {
2150 MonoReflectionType* iface = (MonoReflectionType*) mono_array_get (tb->interfaces, gpointer, i);
2151 MonoType *iface_type = mono_reflection_type_get_handle (iface, error);
2152 return_val_if_nok (error, FALSE);
2153 values [MONO_INTERFACEIMPL_CLASS] = tb->table_idx;
2154 values [MONO_INTERFACEIMPL_INTERFACE] = mono_image_typedef_or_ref (assembly, iface_type);
2155 values += MONO_INTERFACEIMPL_SIZE;
2161 table = &assembly->tables [MONO_TABLE_FIELD];
2162 table->rows += tb->num_fields;
2163 alloc_table (table, table->rows);
2164 for (i = 0; i < tb->num_fields; ++i) {
2165 mono_image_get_field_info (
2166 mono_array_get (tb->fields, MonoReflectionFieldBuilder*, i), assembly, error);
2167 return_val_if_nok (error, FALSE);
2171 /* handle constructors */
2173 table = &assembly->tables [MONO_TABLE_METHOD];
2174 table->rows += mono_array_length (tb->ctors);
2175 alloc_table (table, table->rows);
2176 for (i = 0; i < mono_array_length (tb->ctors); ++i) {
2177 if (!mono_image_get_ctor_info (domain,
2178 mono_array_get (tb->ctors, MonoReflectionCtorBuilder*, i),
2184 /* handle methods */
2186 table = &assembly->tables [MONO_TABLE_METHOD];
2187 table->rows += tb->num_methods;
2188 alloc_table (table, table->rows);
2189 for (i = 0; i < tb->num_methods; ++i) {
2190 if (!mono_image_get_method_info (
2191 mono_array_get (tb->methods, MonoReflectionMethodBuilder*, i), assembly, error))
2196 /* Do the same with properties etc.. */
2197 if (tb->events && mono_array_length (tb->events)) {
2198 table = &assembly->tables [MONO_TABLE_EVENT];
2199 table->rows += mono_array_length (tb->events);
2200 alloc_table (table, table->rows);
2201 table = &assembly->tables [MONO_TABLE_EVENTMAP];
2203 alloc_table (table, table->rows);
2204 values = table->values + table->rows * MONO_EVENT_MAP_SIZE;
2205 values [MONO_EVENT_MAP_PARENT] = tb->table_idx;
2206 values [MONO_EVENT_MAP_EVENTLIST] = assembly->tables [MONO_TABLE_EVENT].next_idx;
2207 for (i = 0; i < mono_array_length (tb->events); ++i) {
2208 mono_image_get_event_info (
2209 mono_array_get (tb->events, MonoReflectionEventBuilder*, i), assembly, error);
2210 return_val_if_nok (error, FALSE);
2213 if (tb->properties && mono_array_length (tb->properties)) {
2214 table = &assembly->tables [MONO_TABLE_PROPERTY];
2215 table->rows += mono_array_length (tb->properties);
2216 alloc_table (table, table->rows);
2217 table = &assembly->tables [MONO_TABLE_PROPERTYMAP];
2219 alloc_table (table, table->rows);
2220 values = table->values + table->rows * MONO_PROPERTY_MAP_SIZE;
2221 values [MONO_PROPERTY_MAP_PARENT] = tb->table_idx;
2222 values [MONO_PROPERTY_MAP_PROPERTY_LIST] = assembly->tables [MONO_TABLE_PROPERTY].next_idx;
2223 for (i = 0; i < mono_array_length (tb->properties); ++i) {
2224 mono_image_get_property_info (
2225 mono_array_get (tb->properties, MonoReflectionPropertyBuilder*, i), assembly, error);
2226 return_val_if_nok (error, FALSE);
2230 /* handle generic parameters */
2231 if (tb->generic_params) {
2232 table = &assembly->tables [MONO_TABLE_GENERICPARAM];
2233 table->rows += mono_array_length (tb->generic_params);
2234 alloc_table (table, table->rows);
2235 for (i = 0; i < mono_array_length (tb->generic_params); ++i) {
2236 guint32 owner = MONO_TYPEORMETHOD_TYPE | (tb->table_idx << MONO_TYPEORMETHOD_BITS);
2238 mono_image_get_generic_param_info (
2239 mono_array_get (tb->generic_params, MonoReflectionGenericParam*, i), owner, assembly);
2243 mono_image_add_decl_security (assembly,
2244 mono_metadata_make_token (MONO_TABLE_TYPEDEF, tb->table_idx), tb->permissions);
2247 MonoDynamicTable *ntable;
2249 ntable = &assembly->tables [MONO_TABLE_NESTEDCLASS];
2250 ntable->rows += mono_array_length (tb->subtypes);
2251 alloc_table (ntable, ntable->rows);
2252 values = ntable->values + ntable->next_idx * MONO_NESTED_CLASS_SIZE;
2254 for (i = 0; i < mono_array_length (tb->subtypes); ++i) {
2255 MonoReflectionTypeBuilder *subtype = mono_array_get (tb->subtypes, MonoReflectionTypeBuilder*, i);
2257 values [MONO_NESTED_CLASS_NESTED] = subtype->table_idx;
2258 values [MONO_NESTED_CLASS_ENCLOSING] = tb->table_idx;
2259 /*g_print ("nesting %s (%d) in %s (%d) (rows %d/%d)\n",
2260 mono_string_to_utf8 (subtype->name), subtype->table_idx,
2261 mono_string_to_utf8 (tb->name), tb->table_idx,
2262 ntable->next_idx, ntable->rows);*/
2263 values += MONO_NESTED_CLASS_SIZE;
2273 * mono_image_build_metadata() will fill the info in all the needed metadata tables
2274 * for the modulebuilder @moduleb.
2275 * At the end of the process, method and field tokens are fixed up and the
2276 * on-disk compressed metadata representation is created.
2277 * Return TRUE on success, or FALSE on failure and sets @error
2280 mono_image_build_metadata (MonoReflectionModuleBuilder *moduleb, MonoError *error)
2282 MonoDynamicTable *table;
2283 MonoDynamicImage *assembly;
2284 MonoReflectionAssemblyBuilder *assemblyb;
2290 mono_error_init (error);
2292 assemblyb = moduleb->assemblyb;
2293 assembly = moduleb->dynamic_image;
2294 domain = mono_object_domain (assemblyb);
2296 if (assembly->text_rva)
2299 assembly->text_rva = START_TEXT_RVA;
2301 if (moduleb->is_main) {
2302 mono_image_emit_manifest (moduleb, error);
2303 return_val_if_nok (error, FALSE);
2306 table = &assembly->tables [MONO_TABLE_TYPEDEF];
2307 table->rows = 1; /* .<Module> */
2309 alloc_table (table, table->rows);
2311 * Set the first entry.
2313 values = table->values + table->columns;
2314 values [MONO_TYPEDEF_FLAGS] = 0;
2315 values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, "<Module>") ;
2316 values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, "") ;
2317 values [MONO_TYPEDEF_EXTENDS] = 0;
2318 values [MONO_TYPEDEF_FIELD_LIST] = 1;
2319 values [MONO_TYPEDEF_METHOD_LIST] = 1;
2322 * handle global methods
2323 * FIXME: test what to do when global methods are defined in multiple modules.
2325 if (moduleb->global_methods) {
2326 table = &assembly->tables [MONO_TABLE_METHOD];
2327 table->rows += mono_array_length (moduleb->global_methods);
2328 alloc_table (table, table->rows);
2329 for (i = 0; i < mono_array_length (moduleb->global_methods); ++i) {
2330 if (!mono_image_get_method_info (
2331 mono_array_get (moduleb->global_methods, MonoReflectionMethodBuilder*, i), assembly, error))
2335 if (moduleb->global_fields) {
2336 table = &assembly->tables [MONO_TABLE_FIELD];
2337 table->rows += mono_array_length (moduleb->global_fields);
2338 alloc_table (table, table->rows);
2339 for (i = 0; i < mono_array_length (moduleb->global_fields); ++i) {
2340 mono_image_get_field_info (
2341 mono_array_get (moduleb->global_fields, MonoReflectionFieldBuilder*, i), assembly,
2348 table = &assembly->tables [MONO_TABLE_MODULE];
2349 alloc_table (table, 1);
2350 mono_image_fill_module_table (domain, moduleb, assembly, error);
2354 /* Collect all types into a list sorted by their table_idx */
2355 mono_ptr_array_init (types, moduleb->num_types, MONO_ROOT_SOURCE_REFLECTION, "dynamic module types list");
2358 for (i = 0; i < moduleb->num_types; ++i) {
2359 MonoReflectionTypeBuilder *type = mono_array_get (moduleb->types, MonoReflectionTypeBuilder*, i);
2360 collect_types (&types, type);
2363 mono_ptr_array_sort (types, (int (*)(const void *, const void *))compare_types_by_table_idx);
2364 table = &assembly->tables [MONO_TABLE_TYPEDEF];
2365 table->rows += mono_ptr_array_size (types);
2366 alloc_table (table, table->rows);
2369 * Emit type names + namespaces at one place inside the string heap,
2370 * so load_class_names () needs to touch fewer pages.
2372 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2373 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2374 string_heap_insert_mstring (&assembly->sheap, tb->nspace, error);
2378 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2379 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2380 string_heap_insert_mstring (&assembly->sheap, tb->name, error);
2385 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2386 MonoReflectionTypeBuilder *type = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2387 if (!mono_image_get_type_info (domain, type, assembly, error))
2392 * table->rows is already set above and in mono_image_fill_module_table.
2394 /* add all the custom attributes at the end, once all the indexes are stable */
2395 if (!mono_image_add_cattrs (assembly, 1, MONO_CUSTOM_ATTR_ASSEMBLY, assemblyb->cattrs, error))
2398 /* CAS assembly permissions */
2399 if (assemblyb->permissions_minimum)
2400 mono_image_add_decl_security (assembly, mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1), assemblyb->permissions_minimum);
2401 if (assemblyb->permissions_optional)
2402 mono_image_add_decl_security (assembly, mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1), assemblyb->permissions_optional);
2403 if (assemblyb->permissions_refused)
2404 mono_image_add_decl_security (assembly, mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1), assemblyb->permissions_refused);
2406 if (!module_add_cattrs (assembly, moduleb, error))
2410 mono_g_hash_table_foreach (assembly->token_fixups, (GHFunc)fixup_method, assembly);
2412 /* Create the MethodImpl table. We do this after emitting all methods so we already know
2413 * the final tokens and don't need another fixup pass. */
2415 if (moduleb->global_methods) {
2416 for (i = 0; i < mono_array_length (moduleb->global_methods); ++i) {
2417 MonoReflectionMethodBuilder *mb = mono_array_get (
2418 moduleb->global_methods, MonoReflectionMethodBuilder*, i);
2419 if (!mono_image_add_methodimpl (assembly, mb, error))
2424 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2425 MonoReflectionTypeBuilder *type = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2426 if (type->methods) {
2427 for (j = 0; j < type->num_methods; ++j) {
2428 MonoReflectionMethodBuilder *mb = mono_array_get (
2429 type->methods, MonoReflectionMethodBuilder*, j);
2431 if (!mono_image_add_methodimpl (assembly, mb, error))
2437 fixup_cattrs (assembly);
2440 mono_ptr_array_destroy (types);
2443 return mono_error_ok (error);
2446 #else /* DISABLE_REFLECTION_EMIT_SAVE */
2449 mono_image_build_metadata (MonoReflectionModuleBuilder *moduleb, MonoError *error)
2451 g_error ("This mono runtime was configured with --enable-minimal=reflection_emit_save, so saving of dynamic assemblies is not supported.");
2454 #endif /* DISABLE_REFLECTION_EMIT_SAVE */
2456 #ifndef DISABLE_REFLECTION_EMIT_SAVE
2459 calc_section_size (MonoDynamicImage *assembly)
2463 /* alignment constraints */
2464 mono_image_add_stream_zero (&assembly->code, 4 - (assembly->code.index % 4));
2465 g_assert ((assembly->code.index % 4) == 0);
2466 assembly->meta_size += 3;
2467 assembly->meta_size &= ~3;
2468 mono_image_add_stream_zero (&assembly->resources, 4 - (assembly->resources.index % 4));
2469 g_assert ((assembly->resources.index % 4) == 0);
2471 assembly->sections [MONO_SECTION_TEXT].size = assembly->meta_size + assembly->code.index + assembly->resources.index + assembly->strong_name_size;
2472 assembly->sections [MONO_SECTION_TEXT].attrs = SECT_FLAGS_HAS_CODE | SECT_FLAGS_MEM_EXECUTE | SECT_FLAGS_MEM_READ;
2475 if (assembly->win32_res) {
2476 guint32 res_size = (assembly->win32_res_size + 3) & ~3;
2478 assembly->sections [MONO_SECTION_RSRC].size = res_size;
2479 assembly->sections [MONO_SECTION_RSRC].attrs = SECT_FLAGS_HAS_INITIALIZED_DATA | SECT_FLAGS_MEM_READ;
2483 assembly->sections [MONO_SECTION_RELOC].size = 12;
2484 assembly->sections [MONO_SECTION_RELOC].attrs = SECT_FLAGS_MEM_READ | SECT_FLAGS_MEM_DISCARDABLE | SECT_FLAGS_HAS_INITIALIZED_DATA;
2494 MonoReflectionWin32Resource *win32_res; /* Only for leaf nodes */
2498 resource_tree_compare_by_id (gconstpointer a, gconstpointer b)
2500 ResTreeNode *t1 = (ResTreeNode*)a;
2501 ResTreeNode *t2 = (ResTreeNode*)b;
2503 return t1->id - t2->id;
2507 * resource_tree_create:
2509 * Organize the resources into a resource tree.
2511 static ResTreeNode *
2512 resource_tree_create (MonoArray *win32_resources)
2514 ResTreeNode *tree, *res_node, *type_node, *lang_node;
2518 tree = g_new0 (ResTreeNode, 1);
2520 for (i = 0; i < mono_array_length (win32_resources); ++i) {
2521 MonoReflectionWin32Resource *win32_res =
2522 (MonoReflectionWin32Resource*)mono_array_addr (win32_resources, MonoReflectionWin32Resource, i);
2526 /* FIXME: BUG: this stores managed references in unmanaged memory */
2527 lang_node = g_new0 (ResTreeNode, 1);
2528 lang_node->id = win32_res->lang_id;
2529 lang_node->win32_res = win32_res;
2531 /* Create type node if neccesary */
2533 for (l = tree->children; l; l = l->next)
2534 if (((ResTreeNode*)(l->data))->id == win32_res->res_type) {
2535 type_node = (ResTreeNode*)l->data;
2540 type_node = g_new0 (ResTreeNode, 1);
2541 type_node->id = win32_res->res_type;
2544 * The resource types have to be sorted otherwise
2545 * Windows Explorer can't display the version information.
2547 tree->children = g_slist_insert_sorted (tree->children,
2548 type_node, resource_tree_compare_by_id);
2551 /* Create res node if neccesary */
2553 for (l = type_node->children; l; l = l->next)
2554 if (((ResTreeNode*)(l->data))->id == win32_res->res_id) {
2555 res_node = (ResTreeNode*)l->data;
2560 res_node = g_new0 (ResTreeNode, 1);
2561 res_node->id = win32_res->res_id;
2562 type_node->children = g_slist_append (type_node->children, res_node);
2565 res_node->children = g_slist_append (res_node->children, lang_node);
2572 * resource_tree_encode:
2574 * Encode the resource tree into the format used in the PE file.
2577 resource_tree_encode (ResTreeNode *node, char *begin, char *p, char **endbuf)
2580 MonoPEResourceDir dir;
2581 MonoPEResourceDirEntry dir_entry;
2582 MonoPEResourceDataEntry data_entry;
2584 guint32 res_id_entries;
2587 * For the format of the resource directory, see the article
2588 * "An In-Depth Look into the Win32 Portable Executable File Format" by
2592 memset (&dir, 0, sizeof (dir));
2593 memset (&dir_entry, 0, sizeof (dir_entry));
2594 memset (&data_entry, 0, sizeof (data_entry));
2596 g_assert (sizeof (dir) == 16);
2597 g_assert (sizeof (dir_entry) == 8);
2598 g_assert (sizeof (data_entry) == 16);
2600 node->offset = p - begin;
2602 /* IMAGE_RESOURCE_DIRECTORY */
2603 res_id_entries = g_slist_length (node->children);
2604 dir.res_id_entries = GUINT16_TO_LE (res_id_entries);
2606 memcpy (p, &dir, sizeof (dir));
2609 /* Reserve space for entries */
2611 p += sizeof (dir_entry) * res_id_entries;
2613 /* Write children */
2614 for (l = node->children; l; l = l->next) {
2615 ResTreeNode *child = (ResTreeNode*)l->data;
2617 if (child->win32_res) {
2620 child->offset = p - begin;
2622 /* IMAGE_RESOURCE_DATA_ENTRY */
2623 data_entry.rde_data_offset = GUINT32_TO_LE (p - begin + sizeof (data_entry));
2624 size = mono_array_length (child->win32_res->res_data);
2625 data_entry.rde_size = GUINT32_TO_LE (size);
2627 memcpy (p, &data_entry, sizeof (data_entry));
2628 p += sizeof (data_entry);
2630 memcpy (p, mono_array_addr (child->win32_res->res_data, char, 0), size);
2633 resource_tree_encode (child, begin, p, &p);
2637 /* IMAGE_RESOURCE_ENTRY */
2638 for (l = node->children; l; l = l->next) {
2639 ResTreeNode *child = (ResTreeNode*)l->data;
2641 MONO_PE_RES_DIR_ENTRY_SET_NAME (dir_entry, FALSE, child->id);
2642 MONO_PE_RES_DIR_ENTRY_SET_DIR (dir_entry, !child->win32_res, child->offset);
2644 memcpy (entries, &dir_entry, sizeof (dir_entry));
2645 entries += sizeof (dir_entry);
2652 resource_tree_free (ResTreeNode * node)
2655 for (list = node->children; list; list = list->next)
2656 resource_tree_free ((ResTreeNode*)list->data);
2657 g_slist_free(node->children);
2662 assembly_add_win32_resources (MonoDynamicImage *assembly, MonoReflectionAssemblyBuilder *assemblyb)
2667 MonoReflectionWin32Resource *win32_res;
2670 if (!assemblyb->win32_resources)
2674 * Resources are stored in a three level tree inside the PE file.
2675 * - level one contains a node for each type of resource
2676 * - level two contains a node for each resource
2677 * - level three contains a node for each instance of a resource for a
2678 * specific language.
2681 tree = resource_tree_create (assemblyb->win32_resources);
2683 /* Estimate the size of the encoded tree */
2685 for (i = 0; i < mono_array_length (assemblyb->win32_resources); ++i) {
2686 win32_res = (MonoReflectionWin32Resource*)mono_array_addr (assemblyb->win32_resources, MonoReflectionWin32Resource, i);
2687 size += mono_array_length (win32_res->res_data);
2689 /* Directory structure */
2690 size += mono_array_length (assemblyb->win32_resources) * 256;
2691 p = buf = (char *)g_malloc (size);
2693 resource_tree_encode (tree, p, p, &p);
2695 g_assert (p - buf <= size);
2697 assembly->win32_res = (char *)g_malloc (p - buf);
2698 assembly->win32_res_size = p - buf;
2699 memcpy (assembly->win32_res, buf, p - buf);
2702 resource_tree_free (tree);
2706 fixup_resource_directory (char *res_section, char *p, guint32 rva)
2708 MonoPEResourceDir *dir = (MonoPEResourceDir*)p;
2711 p += sizeof (MonoPEResourceDir);
2712 for (i = 0; i < GUINT16_FROM_LE (dir->res_named_entries) + GUINT16_FROM_LE (dir->res_id_entries); ++i) {
2713 MonoPEResourceDirEntry *dir_entry = (MonoPEResourceDirEntry*)p;
2714 char *child = res_section + MONO_PE_RES_DIR_ENTRY_DIR_OFFSET (*dir_entry);
2715 if (MONO_PE_RES_DIR_ENTRY_IS_DIR (*dir_entry)) {
2716 fixup_resource_directory (res_section, child, rva);
2718 MonoPEResourceDataEntry *data_entry = (MonoPEResourceDataEntry*)child;
2719 data_entry->rde_data_offset = GUINT32_TO_LE (GUINT32_FROM_LE (data_entry->rde_data_offset) + rva);
2722 p += sizeof (MonoPEResourceDirEntry);
2727 checked_write_file (HANDLE f, gconstpointer buffer, guint32 numbytes)
2730 if (!WriteFile (f, buffer, numbytes, &dummy, NULL))
2731 g_error ("WriteFile returned %d\n", GetLastError ());
2735 * mono_image_create_pefile:
2736 * @mb: a module builder object
2738 * This function creates the PE-COFF header, the image sections, the CLI header * etc. all the data is written in
2739 * assembly->pefile where it can be easily retrieved later in chunks.
2742 mono_image_create_pefile (MonoReflectionModuleBuilder *mb, HANDLE file, MonoError *error)
2744 MonoMSDOSHeader *msdos;
2745 MonoDotNetHeader *header;
2746 MonoSectionTable *section;
2747 MonoCLIHeader *cli_header;
2748 guint32 size, image_size, virtual_base, text_offset;
2749 guint32 header_start, section_start, file_offset, virtual_offset;
2750 MonoDynamicImage *assembly;
2751 MonoReflectionAssemblyBuilder *assemblyb;
2752 MonoDynamicStream pefile_stream = {0};
2753 MonoDynamicStream *pefile = &pefile_stream;
2755 guint32 *rva, value;
2757 static const unsigned char msheader[] = {
2758 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
2759 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2760 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2761 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
2762 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68,
2763 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f,
2764 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,
2765 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
2768 mono_error_init (error);
2770 assemblyb = mb->assemblyb;
2772 mono_reflection_dynimage_basic_init (assemblyb);
2773 assembly = mb->dynamic_image;
2775 assembly->pe_kind = assemblyb->pe_kind;
2776 assembly->machine = assemblyb->machine;
2777 ((MonoDynamicImage*)assemblyb->dynamic_assembly->assembly.image)->pe_kind = assemblyb->pe_kind;
2778 ((MonoDynamicImage*)assemblyb->dynamic_assembly->assembly.image)->machine = assemblyb->machine;
2780 if (!mono_image_build_metadata (mb, error))
2784 if (mb->is_main && assemblyb->resources) {
2785 int len = mono_array_length (assemblyb->resources);
2786 for (i = 0; i < len; ++i) {
2787 if (!assembly_add_resource (mb, assembly, (MonoReflectionResource*)mono_array_addr (assemblyb->resources, MonoReflectionResource, i), error))
2792 if (mb->resources) {
2793 int len = mono_array_length (mb->resources);
2794 for (i = 0; i < len; ++i) {
2795 if (!assembly_add_resource (mb, assembly, (MonoReflectionResource*)mono_array_addr (mb->resources, MonoReflectionResource, i), error))
2800 if (!build_compressed_metadata (assembly, error))
2804 assembly_add_win32_resources (assembly, assemblyb);
2806 nsections = calc_section_size (assembly);
2808 /* The DOS header and stub */
2809 g_assert (sizeof (MonoMSDOSHeader) == sizeof (msheader));
2810 mono_image_add_stream_data (pefile, (char*)msheader, sizeof (msheader));
2812 /* the dotnet header */
2813 header_start = mono_image_add_stream_zero (pefile, sizeof (MonoDotNetHeader));
2815 /* the section tables */
2816 section_start = mono_image_add_stream_zero (pefile, sizeof (MonoSectionTable) * nsections);
2818 file_offset = section_start + sizeof (MonoSectionTable) * nsections;
2819 virtual_offset = VIRT_ALIGN;
2822 for (i = 0; i < MONO_SECTION_MAX; ++i) {
2823 if (!assembly->sections [i].size)
2826 file_offset += FILE_ALIGN - 1;
2827 file_offset &= ~(FILE_ALIGN - 1);
2828 virtual_offset += VIRT_ALIGN - 1;
2829 virtual_offset &= ~(VIRT_ALIGN - 1);
2831 assembly->sections [i].offset = file_offset;
2832 assembly->sections [i].rva = virtual_offset;
2834 file_offset += assembly->sections [i].size;
2835 virtual_offset += assembly->sections [i].size;
2836 image_size += (assembly->sections [i].size + VIRT_ALIGN - 1) & ~(VIRT_ALIGN - 1);
2839 file_offset += FILE_ALIGN - 1;
2840 file_offset &= ~(FILE_ALIGN - 1);
2842 image_size += section_start + sizeof (MonoSectionTable) * nsections;
2844 /* back-patch info */
2845 msdos = (MonoMSDOSHeader*)pefile->data;
2846 msdos->pe_offset = GUINT32_FROM_LE (sizeof (MonoMSDOSHeader));
2848 header = (MonoDotNetHeader*)(pefile->data + header_start);
2849 header->pesig [0] = 'P';
2850 header->pesig [1] = 'E';
2852 header->coff.coff_machine = GUINT16_FROM_LE (assemblyb->machine);
2853 header->coff.coff_sections = GUINT16_FROM_LE (nsections);
2854 header->coff.coff_time = GUINT32_FROM_LE (time (NULL));
2855 header->coff.coff_opt_header_size = GUINT16_FROM_LE (sizeof (MonoDotNetHeader) - sizeof (MonoCOFFHeader) - 4);
2856 if (assemblyb->pekind == 1) {
2858 header->coff.coff_attributes = GUINT16_FROM_LE (0x210e);
2861 header->coff.coff_attributes = GUINT16_FROM_LE (0x010e);
2864 virtual_base = 0x400000; /* FIXME: 0x10000000 if a DLL */
2866 header->pe.pe_magic = GUINT16_FROM_LE (0x10B);
2867 header->pe.pe_major = 6;
2868 header->pe.pe_minor = 0;
2869 size = assembly->sections [MONO_SECTION_TEXT].size;
2870 size += FILE_ALIGN - 1;
2871 size &= ~(FILE_ALIGN - 1);
2872 header->pe.pe_code_size = GUINT32_FROM_LE(size);
2873 size = assembly->sections [MONO_SECTION_RSRC].size;
2874 size += FILE_ALIGN - 1;
2875 size &= ~(FILE_ALIGN - 1);
2876 header->pe.pe_data_size = GUINT32_FROM_LE(size);
2877 g_assert (START_TEXT_RVA == assembly->sections [MONO_SECTION_TEXT].rva);
2878 header->pe.pe_rva_code_base = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_TEXT].rva);
2879 header->pe.pe_rva_data_base = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].rva);
2880 /* pe_rva_entry_point always at the beginning of the text section */
2881 header->pe.pe_rva_entry_point = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_TEXT].rva);
2883 header->nt.pe_image_base = GUINT32_FROM_LE (virtual_base);
2884 header->nt.pe_section_align = GUINT32_FROM_LE (VIRT_ALIGN);
2885 header->nt.pe_file_alignment = GUINT32_FROM_LE (FILE_ALIGN);
2886 header->nt.pe_os_major = GUINT16_FROM_LE (4);
2887 header->nt.pe_os_minor = GUINT16_FROM_LE (0);
2888 header->nt.pe_subsys_major = GUINT16_FROM_LE (4);
2889 size = section_start;
2890 size += FILE_ALIGN - 1;
2891 size &= ~(FILE_ALIGN - 1);
2892 header->nt.pe_header_size = GUINT32_FROM_LE (size);
2894 size += VIRT_ALIGN - 1;
2895 size &= ~(VIRT_ALIGN - 1);
2896 header->nt.pe_image_size = GUINT32_FROM_LE (size);
2899 // Translate the PEFileKind value to the value expected by the Windows loader
2905 // PEFileKinds.Dll == 1
2906 // PEFileKinds.ConsoleApplication == 2
2907 // PEFileKinds.WindowApplication == 3
2910 // IMAGE_SUBSYSTEM_WINDOWS_GUI 2 // Image runs in the Windows GUI subsystem.
2911 // IMAGE_SUBSYSTEM_WINDOWS_CUI 3 // Image runs in the Windows character subsystem.
2913 if (assemblyb->pekind == 3)
2918 header->nt.pe_subsys_required = GUINT16_FROM_LE (kind);
2920 header->nt.pe_stack_reserve = GUINT32_FROM_LE (0x00100000);
2921 header->nt.pe_stack_commit = GUINT32_FROM_LE (0x00001000);
2922 header->nt.pe_heap_reserve = GUINT32_FROM_LE (0x00100000);
2923 header->nt.pe_heap_commit = GUINT32_FROM_LE (0x00001000);
2924 header->nt.pe_loader_flags = GUINT32_FROM_LE (0);
2925 header->nt.pe_data_dir_count = GUINT32_FROM_LE (16);
2927 /* fill data directory entries */
2929 header->datadir.pe_resource_table.size = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].size);
2930 header->datadir.pe_resource_table.rva = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].rva);
2932 header->datadir.pe_reloc_table.size = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RELOC].size);
2933 header->datadir.pe_reloc_table.rva = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RELOC].rva);
2935 header->datadir.pe_cli_header.size = GUINT32_FROM_LE (72);
2936 header->datadir.pe_cli_header.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->cli_header_offset);
2937 header->datadir.pe_iat.size = GUINT32_FROM_LE (8);
2938 header->datadir.pe_iat.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->iat_offset);
2939 /* patch entrypoint name */
2940 if (assemblyb->pekind == 1)
2941 memcpy (assembly->code.data + assembly->imp_names_offset + 2, "_CorDllMain", 12);
2943 memcpy (assembly->code.data + assembly->imp_names_offset + 2, "_CorExeMain", 12);
2944 /* patch imported function RVA name */
2945 rva = (guint32*)(assembly->code.data + assembly->iat_offset);
2946 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->imp_names_offset);
2948 /* the import table */
2949 header->datadir.pe_import_table.size = GUINT32_FROM_LE (79); /* FIXME: magic number? */
2950 header->datadir.pe_import_table.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->idt_offset);
2951 /* patch imported dll RVA name and other entries in the dir */
2952 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, name_rva));
2953 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->imp_names_offset + 14); /* 14 is hint+strlen+1 of func name */
2954 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, import_address_table_rva));
2955 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->iat_offset);
2956 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, import_lookup_table));
2957 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->ilt_offset);
2959 p = (guchar*)(assembly->code.data + assembly->ilt_offset);
2960 value = (assembly->text_rva + assembly->imp_names_offset);
2961 *p++ = (value) & 0xff;
2962 *p++ = (value >> 8) & (0xff);
2963 *p++ = (value >> 16) & (0xff);
2964 *p++ = (value >> 24) & (0xff);
2966 /* the CLI header info */
2967 cli_header = (MonoCLIHeader*)(assembly->code.data + assembly->cli_header_offset);
2968 cli_header->ch_size = GUINT32_FROM_LE (72);
2969 cli_header->ch_runtime_major = GUINT16_FROM_LE (2);
2970 cli_header->ch_runtime_minor = GUINT16_FROM_LE (5);
2971 cli_header->ch_flags = GUINT32_FROM_LE (assemblyb->pe_kind);
2972 if (assemblyb->entry_point) {
2973 guint32 table_idx = 0;
2974 if (!strcmp (assemblyb->entry_point->object.vtable->klass->name, "MethodBuilder")) {
2975 MonoReflectionMethodBuilder *methodb = (MonoReflectionMethodBuilder*)assemblyb->entry_point;
2976 table_idx = methodb->table_idx;
2978 table_idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, assemblyb->entry_point->method));
2980 cli_header->ch_entry_point = GUINT32_FROM_LE (table_idx | MONO_TOKEN_METHOD_DEF);
2982 cli_header->ch_entry_point = GUINT32_FROM_LE (0);
2984 /* The embedded managed resources */
2985 text_offset = assembly->text_rva + assembly->code.index;
2986 cli_header->ch_resources.rva = GUINT32_FROM_LE (text_offset);
2987 cli_header->ch_resources.size = GUINT32_FROM_LE (assembly->resources.index);
2988 text_offset += assembly->resources.index;
2989 cli_header->ch_metadata.rva = GUINT32_FROM_LE (text_offset);
2990 cli_header->ch_metadata.size = GUINT32_FROM_LE (assembly->meta_size);
2991 text_offset += assembly->meta_size;
2992 if (assembly->strong_name_size) {
2993 cli_header->ch_strong_name.rva = GUINT32_FROM_LE (text_offset);
2994 cli_header->ch_strong_name.size = GUINT32_FROM_LE (assembly->strong_name_size);
2995 text_offset += assembly->strong_name_size;
2998 /* write the section tables and section content */
2999 section = (MonoSectionTable*)(pefile->data + section_start);
3000 for (i = 0; i < MONO_SECTION_MAX; ++i) {
3001 static const char section_names [][7] = {
3002 ".text", ".rsrc", ".reloc"
3004 if (!assembly->sections [i].size)
3006 strcpy (section->st_name, section_names [i]);
3007 /*g_print ("output section %s (%d), size: %d\n", section->st_name, i, assembly->sections [i].size);*/
3008 section->st_virtual_address = GUINT32_FROM_LE (assembly->sections [i].rva);
3009 section->st_virtual_size = GUINT32_FROM_LE (assembly->sections [i].size);
3010 section->st_raw_data_size = GUINT32_FROM_LE (GUINT32_TO_LE (section->st_virtual_size) + (FILE_ALIGN - 1));
3011 section->st_raw_data_size &= GUINT32_FROM_LE (~(FILE_ALIGN - 1));
3012 section->st_raw_data_ptr = GUINT32_FROM_LE (assembly->sections [i].offset);
3013 section->st_flags = GUINT32_FROM_LE (assembly->sections [i].attrs);
3017 checked_write_file (file, pefile->data, pefile->index);
3019 mono_dynamic_stream_reset (pefile);
3021 for (i = 0; i < MONO_SECTION_MAX; ++i) {
3022 if (!assembly->sections [i].size)
3025 if (SetFilePointer (file, assembly->sections [i].offset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
3026 g_error ("SetFilePointer returned %d\n", GetLastError ());
3029 case MONO_SECTION_TEXT:
3030 /* patch entry point */
3031 p = (guchar*)(assembly->code.data + 2);
3032 value = (virtual_base + assembly->text_rva + assembly->iat_offset);
3033 *p++ = (value) & 0xff;
3034 *p++ = (value >> 8) & 0xff;
3035 *p++ = (value >> 16) & 0xff;
3036 *p++ = (value >> 24) & 0xff;
3038 checked_write_file (file, assembly->code.data, assembly->code.index);
3039 checked_write_file (file, assembly->resources.data, assembly->resources.index);
3040 checked_write_file (file, assembly->image.raw_metadata, assembly->meta_size);
3041 checked_write_file (file, assembly->strong_name, assembly->strong_name_size);
3044 g_free (assembly->image.raw_metadata);
3046 case MONO_SECTION_RELOC: {
3050 guint16 type_and_offset;
3054 g_assert (sizeof (reloc) == 12);
3056 reloc.page_rva = GUINT32_FROM_LE (assembly->text_rva);
3057 reloc.block_size = GUINT32_FROM_LE (12);
3060 * the entrypoint is always at the start of the text section
3061 * 3 is IMAGE_REL_BASED_HIGHLOW
3062 * 2 is patch_size_rva - text_rva
3064 reloc.type_and_offset = GUINT16_FROM_LE ((3 << 12) + (2));
3067 checked_write_file (file, &reloc, sizeof (reloc));
3071 case MONO_SECTION_RSRC:
3072 if (assembly->win32_res) {
3074 /* Fixup the offsets in the IMAGE_RESOURCE_DATA_ENTRY structures */
3075 fixup_resource_directory (assembly->win32_res, assembly->win32_res, assembly->sections [i].rva);
3076 checked_write_file (file, assembly->win32_res, assembly->win32_res_size);
3080 g_assert_not_reached ();
3084 /* check that the file is properly padded */
3085 if (SetFilePointer (file, file_offset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
3086 g_error ("SetFilePointer returned %d\n", GetLastError ());
3087 if (! SetEndOfFile (file))
3088 g_error ("SetEndOfFile returned %d\n", GetLastError ());
3090 mono_dynamic_stream_reset (&assembly->code);
3091 mono_dynamic_stream_reset (&assembly->us);
3092 mono_dynamic_stream_reset (&assembly->blob);
3093 mono_dynamic_stream_reset (&assembly->guid);
3094 mono_dynamic_stream_reset (&assembly->sheap);
3096 g_hash_table_foreach (assembly->blob_cache, (GHFunc)g_free, NULL);
3097 g_hash_table_destroy (assembly->blob_cache);
3098 assembly->blob_cache = NULL;
3103 #else /* DISABLE_REFLECTION_EMIT_SAVE */
3106 mono_image_create_pefile (MonoReflectionModuleBuilder *mb, HANDLE file, MonoError *error)
3108 g_assert_not_reached ();
3111 #endif /* DISABLE_REFLECTION_EMIT_SAVE */