3 * Routine for saving an image to a file.
7 * Paolo Molaro (lupus@ximian.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2011 Rodrigo Kumpera
12 * Copyright 2016 Microsoft
14 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
20 #include "mono/metadata/dynamic-image-internals.h"
21 #include "mono/metadata/dynamic-stream-internals.h"
22 #include "mono/metadata/mono-ptr-array.h"
23 #include "mono/metadata/mono-hash-internals.h"
24 #include "mono/metadata/object-internals.h"
25 #include "mono/metadata/sre-internals.h"
26 #include "mono/metadata/security-manager.h"
27 #include "mono/metadata/tabledefs.h"
28 #include "mono/metadata/tokentype.h"
29 #include "mono/metadata/w32file.h"
30 #include "mono/metadata/w32error.h"
32 #include "mono/utils/checked-build.h"
33 #include "mono/utils/mono-digest.h"
34 #include "mono/utils/mono-error-internals.h"
35 #include "mono/utils/w32api.h"
37 #define TEXT_OFFSET 512
38 #define CLI_H_SIZE 136
39 #define FILE_ALIGN 512
40 #define VIRT_ALIGN 8192
41 #define START_TEXT_RVA 0x00002000
43 static void mono_image_get_generic_param_info (MonoReflectionGenericParam
*gparam
, guint32 owner
, MonoDynamicImage
*assembly
);
46 alloc_table (MonoDynamicTable
*table
, guint nrows
)
48 mono_dynimage_alloc_table (table
, nrows
);
52 string_heap_insert (MonoDynamicStream
*sh
, const char *str
)
54 return mono_dynstream_insert_string (sh
, str
);
58 string_heap_insert_mstring (MonoDynamicStream
*sh
, MonoString
*str
, MonoError
*error
)
60 return mono_dynstream_insert_mstring (sh
, str
, error
);
64 mono_image_add_stream_data (MonoDynamicStream
*stream
, const char *data
, guint32 len
)
66 return mono_dynstream_add_data (stream
, data
, len
);
70 mono_image_add_stream_zero (MonoDynamicStream
*stream
, guint32 len
)
72 return mono_dynstream_add_zero (stream
, len
);
76 stream_data_align (MonoDynamicStream
*stream
)
78 mono_dynstream_data_align (stream
);
82 mono_image_typedef_or_ref (MonoDynamicImage
*assembly
, MonoType
*type
)
84 return mono_dynimage_encode_typedef_or_ref_full (assembly
, type
, TRUE
);
88 find_index_in_table (MonoDynamicImage
*assembly
, int table_idx
, int col
, guint32 token
)
90 MONO_REQ_GC_NEUTRAL_MODE
;
93 MonoDynamicTable
*table
;
96 table
= &assembly
->tables
[table_idx
];
98 g_assert (col
< table
->columns
);
100 values
= table
->values
+ table
->columns
;
101 for (i
= 1; i
<= table
->rows
; ++i
) {
102 if (values
[col
] == token
)
104 values
+= table
->columns
;
110 * Copy len * nelem bytes from val to dest, swapping bytes to LE if necessary.
111 * dest may be misaligned.
114 swap_with_size (char *dest
, const char* val
, int len
, int nelem
) {
115 MONO_REQ_GC_NEUTRAL_MODE
;
116 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
119 for (elem
= 0; elem
< nelem
; ++elem
) {
145 g_assert_not_reached ();
151 memcpy (dest
, val
, len
* nelem
);
156 add_mono_string_to_blob_cached (MonoDynamicImage
*assembly
, MonoString
*str
)
158 MONO_REQ_GC_UNSAFE_MODE
;
162 guint32 idx
= 0, len
;
164 len
= str
->length
* 2;
165 mono_metadata_encode_value (len
, b
, &b
);
166 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
168 char *swapped
= g_malloc (2 * mono_string_length_internal (str
));
169 const char *p
= (const char*)mono_string_chars_internal (str
);
171 swap_with_size (swapped
, p
, 2, mono_string_length_internal (str
));
172 idx
= mono_dynamic_image_add_to_blob_cached (assembly
, blob_size
, b
-blob_size
, swapped
, len
);
176 idx
= mono_dynamic_image_add_to_blob_cached (assembly
, blob_size
, b
-blob_size
, mono_string_chars_internal (str
), len
);
182 image_create_token_raw (MonoDynamicImage
*assembly
, MonoObject
* obj_raw
, gboolean create_methodspec
, gboolean register_token
, MonoError
*error
)
184 HANDLE_FUNCTION_ENTER (); /* FIXME callers of image_create_token_raw should use handles */
186 MONO_HANDLE_DCL (MonoObject
, obj
);
187 guint32 result
= mono_image_create_token (assembly
, obj
, create_methodspec
, register_token
, error
);
188 HANDLE_FUNCTION_RETURN_VAL (result
);
193 * idx is the table index of the object
194 * type is one of MONO_CUSTOM_ATTR_*
197 mono_image_add_cattrs (MonoDynamicImage
*assembly
, guint32 idx
, guint32 type
, MonoArray
*cattrs
, MonoError
*error
)
199 MONO_REQ_GC_UNSAFE_MODE
;
201 MonoDynamicTable
*table
;
202 MonoReflectionCustomAttr
*cattr
;
204 guint32 count
, i
, token
;
210 /* it is legal to pass a NULL cattrs: we avoid to use the if in a lot of places */
213 count
= mono_array_length_internal (cattrs
);
214 table
= &assembly
->tables
[MONO_TABLE_CUSTOMATTRIBUTE
];
215 table
->rows
+= count
;
216 alloc_table (table
, table
->rows
);
217 values
= table
->values
+ table
->next_idx
* MONO_CUSTOM_ATTR_SIZE
;
218 idx
<<= MONO_CUSTOM_ATTR_BITS
;
220 for (i
= 0; i
< count
; ++i
) {
221 cattr
= (MonoReflectionCustomAttr
*)mono_array_get_internal (cattrs
, gpointer
, i
);
222 values
[MONO_CUSTOM_ATTR_PARENT
] = idx
;
223 g_assert (cattr
->ctor
!= NULL
);
224 if (mono_is_sre_ctor_builder (mono_object_class (cattr
->ctor
))) {
225 MonoReflectionCtorBuilder
*ctor
= (MonoReflectionCtorBuilder
*)cattr
->ctor
;
226 MonoMethod
*method
= ctor
->mhandle
;
227 if (m_class_get_image (method
->klass
) == &assembly
->image
)
228 token
= MONO_TOKEN_METHOD_DEF
| ((MonoReflectionCtorBuilder
*)cattr
->ctor
)->table_idx
;
230 token
= mono_image_get_methodref_token (assembly
, method
, FALSE
);
232 token
= image_create_token_raw (assembly
, (MonoObject
*)cattr
->ctor
, FALSE
, FALSE
, error
); /* FIXME use handles */
233 if (!mono_error_ok (error
)) goto fail
;
235 type
= mono_metadata_token_index (token
);
236 type
<<= MONO_CUSTOM_ATTR_TYPE_BITS
;
237 switch (mono_metadata_token_table (token
)) {
238 case MONO_TABLE_METHOD
:
239 type
|= MONO_CUSTOM_ATTR_TYPE_METHODDEF
;
241 * fixup_cattrs () needs to fix this up. We can't use image->tokens, since it contains the old token for the
242 * method, not the one returned by mono_image_create_token ().
244 mono_g_hash_table_insert_internal (assembly
->remapped_tokens
, GUINT_TO_POINTER (token
), cattr
->ctor
);
246 case MONO_TABLE_MEMBERREF
:
247 type
|= MONO_CUSTOM_ATTR_TYPE_MEMBERREF
;
250 g_warning ("got wrong token in custom attr");
253 values
[MONO_CUSTOM_ATTR_TYPE
] = type
;
255 mono_metadata_encode_value (mono_array_length_internal (cattr
->data
), p
, &p
);
256 values
[MONO_CUSTOM_ATTR_VALUE
] = mono_dynamic_image_add_to_blob_cached (assembly
, blob_size
, p
- blob_size
,
257 mono_array_addr_internal (cattr
->data
, char, 0), mono_array_length_internal (cattr
->data
));
258 values
+= MONO_CUSTOM_ATTR_SIZE
;
269 mono_image_add_decl_security (MonoDynamicImage
*assembly
, guint32 parent_token
, MonoArray
*permissions
)
271 MONO_REQ_GC_UNSAFE_MODE
;
273 MonoDynamicTable
*table
;
275 guint32 count
, i
, idx
;
276 MonoReflectionPermissionSet
*perm
;
281 count
= mono_array_length_internal (permissions
);
282 table
= &assembly
->tables
[MONO_TABLE_DECLSECURITY
];
283 table
->rows
+= count
;
284 alloc_table (table
, table
->rows
);
286 for (i
= 0; i
< mono_array_length_internal (permissions
); ++i
) {
287 perm
= (MonoReflectionPermissionSet
*)mono_array_addr_internal (permissions
, MonoReflectionPermissionSet
, i
);
289 values
= table
->values
+ table
->next_idx
* MONO_DECL_SECURITY_SIZE
;
291 idx
= mono_metadata_token_index (parent_token
);
292 idx
<<= MONO_HAS_DECL_SECURITY_BITS
;
293 switch (mono_metadata_token_table (parent_token
)) {
294 case MONO_TABLE_TYPEDEF
:
295 idx
|= MONO_HAS_DECL_SECURITY_TYPEDEF
;
297 case MONO_TABLE_METHOD
:
298 idx
|= MONO_HAS_DECL_SECURITY_METHODDEF
;
300 case MONO_TABLE_ASSEMBLY
:
301 idx
|= MONO_HAS_DECL_SECURITY_ASSEMBLY
;
304 g_assert_not_reached ();
307 values
[MONO_DECL_SECURITY_ACTION
] = perm
->action
;
308 values
[MONO_DECL_SECURITY_PARENT
] = idx
;
309 values
[MONO_DECL_SECURITY_PERMISSIONSET
] = add_mono_string_to_blob_cached (assembly
, perm
->pset
);
316 * method_encode_code:
318 * @assembly the assembly
319 * @mb the managed MethodBuilder
320 * @error set on error
322 * Note that the return value is not sensible if @error is set.
325 method_encode_code (MonoDynamicImage
*assembly
, ReflectionMethodBuilder
*mb
, MonoError
*error
)
327 MONO_REQ_GC_UNSAFE_MODE
;
333 gint32 num_locals
= 0;
334 gint32 num_exception
= 0;
337 char fat_header
[12];
340 guint32 local_sig
= 0;
341 guint32 header_size
= 12;
346 if ((mb
->attrs
& (METHOD_ATTRIBUTE_PINVOKE_IMPL
| METHOD_ATTRIBUTE_ABSTRACT
)) ||
347 (mb
->iattrs
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
)))
351 g_print ("Encode method %s\n", mono_string_to_utf8 (mb->name));*/
353 code
= mb
->ilgen
->code
;
354 code_size
= mb
->ilgen
->code_len
;
355 max_stack
= mb
->ilgen
->max_stack
;
356 num_locals
= mb
->ilgen
->locals
? mono_array_length_internal (mb
->ilgen
->locals
) : 0;
357 if (mb
->ilgen
->ex_handlers
)
358 num_exception
= mono_reflection_method_count_clauses (mb
->ilgen
);
362 ERROR_DECL (inner_error
);
363 char *name
= mono_string_to_utf8_checked_internal (mb
->name
, inner_error
);
364 if (!is_ok (inner_error
))
365 mono_error_set_argument (error
, NULL
, "a method does not have any IL associated");
367 mono_error_set_argument_format (error
, NULL
, "Method %s does not have any IL associated", name
);
368 mono_error_cleanup (inner_error
);
373 code_size
= mono_array_length_internal (code
);
374 max_stack
= 8; /* we probably need to run a verifier on the code... */
377 stream_data_align (&assembly
->code
);
379 /* check for exceptions, maxstack, locals */
380 maybe_small
= (max_stack
<= 8) && (!num_locals
) && (!num_exception
);
382 if (code_size
< 64 && !(code_size
& 1)) {
383 flags
= (code_size
<< 2) | 0x2;
384 } else if (code_size
< 32 && (code_size
& 1)) {
385 flags
= (code_size
<< 2) | 0x6; /* LAMESPEC: see metadata.c */
389 idx
= mono_image_add_stream_data (&assembly
->code
, &flags
, 1);
390 /* add to the fixup todo list */
391 if (mb
->ilgen
&& mb
->ilgen
->num_token_fixups
)
392 mono_g_hash_table_insert_internal (assembly
->token_fixups
, mb
->ilgen
, GUINT_TO_POINTER (idx
+ 1));
393 mono_image_add_stream_data (&assembly
->code
, mono_array_addr_internal (code
, char, 0), code_size
);
394 return assembly
->text_rva
+ idx
;
398 local_sig
= MONO_TOKEN_SIGNATURE
| mono_dynimage_encode_locals (assembly
, mb
->ilgen
, error
);
399 return_val_if_nok (error
, 0);
402 * FIXME: need to set also the header size in fat_flags.
403 * (and more sects and init locals flags)
407 fat_flags
|= METHOD_HEADER_MORE_SECTS
;
409 fat_flags
|= METHOD_HEADER_INIT_LOCALS
;
410 fat_header
[0] = fat_flags
;
411 fat_header
[1] = (header_size
/ 4 ) << 4;
412 short_value
= GUINT16_TO_LE (max_stack
);
413 memcpy (fat_header
+ 2, &short_value
, 2);
414 int_value
= GUINT32_TO_LE (code_size
);
415 memcpy (fat_header
+ 4, &int_value
, 4);
416 int_value
= GUINT32_TO_LE (local_sig
);
417 memcpy (fat_header
+ 8, &int_value
, 4);
418 idx
= mono_image_add_stream_data (&assembly
->code
, fat_header
, 12);
419 /* add to the fixup todo list */
420 if (mb
->ilgen
&& mb
->ilgen
->num_token_fixups
)
421 mono_g_hash_table_insert_internal (assembly
->token_fixups
, mb
->ilgen
, GUINT_TO_POINTER (idx
+ 12));
423 mono_image_add_stream_data (&assembly
->code
, mono_array_addr_internal (code
, char, 0), code_size
);
425 unsigned char sheader
[4];
426 MonoILExceptionInfo
* ex_info
;
427 MonoILExceptionBlock
* ex_block
;
430 stream_data_align (&assembly
->code
);
431 /* always use fat format for now */
432 sheader
[0] = METHOD_HEADER_SECTION_FAT_FORMAT
| METHOD_HEADER_SECTION_EHTABLE
;
433 num_exception
*= 6 * sizeof (guint32
);
434 num_exception
+= 4; /* include the size of the header */
435 sheader
[1] = num_exception
& 0xff;
436 sheader
[2] = (num_exception
>> 8) & 0xff;
437 sheader
[3] = (num_exception
>> 16) & 0xff;
438 mono_image_add_stream_data (&assembly
->code
, (char*)sheader
, 4);
439 /* fat header, so we are already aligned */
441 for (i
= mono_array_length_internal (mb
->ilgen
->ex_handlers
) - 1; i
>= 0; --i
) {
442 ex_info
= (MonoILExceptionInfo
*)mono_array_addr_internal (mb
->ilgen
->ex_handlers
, MonoILExceptionInfo
, i
);
443 if (ex_info
->handlers
) {
444 int finally_start
= ex_info
->start
+ ex_info
->len
;
445 for (j
= 0; j
< mono_array_length_internal (ex_info
->handlers
); ++j
) {
447 ex_block
= (MonoILExceptionBlock
*)mono_array_addr_internal (ex_info
->handlers
, MonoILExceptionBlock
, j
);
449 val
= GUINT32_TO_LE (ex_block
->type
);
450 mono_image_add_stream_data (&assembly
->code
, (char*)&val
, sizeof (guint32
));
452 val
= GUINT32_TO_LE (ex_info
->start
);
453 mono_image_add_stream_data (&assembly
->code
, (char*)&val
, sizeof (guint32
));
454 /* need fault, too, probably */
455 if (ex_block
->type
== MONO_EXCEPTION_CLAUSE_FINALLY
)
456 val
= GUINT32_TO_LE (finally_start
- ex_info
->start
);
458 val
= GUINT32_TO_LE (ex_info
->len
);
459 mono_image_add_stream_data (&assembly
->code
, (char*)&val
, sizeof (guint32
));
461 val
= GUINT32_TO_LE (ex_block
->start
);
462 mono_image_add_stream_data (&assembly
->code
, (char*)&val
, sizeof (guint32
));
464 val
= GUINT32_TO_LE (ex_block
->len
);
465 mono_image_add_stream_data (&assembly
->code
, (char*)&val
, sizeof (guint32
));
466 finally_start
= ex_block
->start
+ ex_block
->len
;
467 if (ex_block
->extype
) {
468 MonoType
*extype
= mono_reflection_type_get_handle ((MonoReflectionType
*)ex_block
->extype
, error
);
469 return_val_if_nok (error
, 0);
471 val
= mono_metadata_token_from_dor (mono_image_typedef_or_ref (assembly
, extype
));
473 if (ex_block
->type
== MONO_EXCEPTION_CLAUSE_FILTER
)
474 val
= ex_block
->filter_offset
;
478 val
= GUINT32_TO_LE (val
);
479 mono_image_add_stream_data (&assembly
->code
, (char*)&val
, sizeof (guint32
));
480 /*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",
481 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);*/
484 g_error ("No clauses for ex info block %d", i
);
488 return assembly
->text_rva
+ idx
;
492 * Fill in the MethodDef and ParamDef tables for a method.
493 * This is used for both normal methods and constructors.
496 mono_image_basic_method (ReflectionMethodBuilder
*mb
, MonoDynamicImage
*assembly
, MonoError
*error
)
498 MONO_REQ_GC_UNSAFE_MODE
;
500 MonoDynamicTable
*table
;
506 /* room in this table is already allocated */
507 table
= &assembly
->tables
[MONO_TABLE_METHOD
];
508 *mb
->table_idx
= table
->next_idx
++;
509 g_hash_table_insert (assembly
->method_to_table_idx
, mb
->mhandle
, GUINT_TO_POINTER ((*mb
->table_idx
)));
510 values
= table
->values
+ *mb
->table_idx
* MONO_METHOD_SIZE
;
511 values
[MONO_METHOD_NAME
] = string_heap_insert_mstring (&assembly
->sheap
, mb
->name
, error
);
512 return_val_if_nok (error
, FALSE
);
513 values
[MONO_METHOD_FLAGS
] = mb
->attrs
;
514 values
[MONO_METHOD_IMPLFLAGS
] = mb
->iattrs
;
515 values
[MONO_METHOD_SIGNATURE
] = mono_dynimage_encode_method_builder_signature (assembly
, mb
, error
);
516 return_val_if_nok (error
, FALSE
);
517 values
[MONO_METHOD_RVA
] = method_encode_code (assembly
, mb
, error
);
518 return_val_if_nok (error
, FALSE
);
520 table
= &assembly
->tables
[MONO_TABLE_PARAM
];
521 values
[MONO_METHOD_PARAMLIST
] = table
->next_idx
;
523 mono_image_add_decl_security (assembly
,
524 mono_metadata_make_token (MONO_TABLE_METHOD
, *mb
->table_idx
), mb
->permissions
);
527 MonoDynamicTable
*mtable
;
530 mtable
= &assembly
->tables
[MONO_TABLE_FIELDMARSHAL
];
531 mvalues
= mtable
->values
+ mtable
->next_idx
* MONO_FIELD_MARSHAL_SIZE
;
534 for (i
= 0; i
< mono_array_length_internal (mb
->pinfo
); ++i
) {
535 if (mono_array_get_internal (mb
->pinfo
, gpointer
, i
))
538 table
->rows
+= count
;
539 alloc_table (table
, table
->rows
);
540 values
= table
->values
+ table
->next_idx
* MONO_PARAM_SIZE
;
541 for (i
= 0; i
< mono_array_length_internal (mb
->pinfo
); ++i
) {
542 MonoReflectionParamBuilder
*pb
;
543 if ((pb
= mono_array_get_internal (mb
->pinfo
, MonoReflectionParamBuilder
*, i
))) {
544 values
[MONO_PARAM_FLAGS
] = pb
->attrs
;
545 values
[MONO_PARAM_SEQUENCE
] = i
;
546 if (pb
->name
!= NULL
) {
547 values
[MONO_PARAM_NAME
] = string_heap_insert_mstring (&assembly
->sheap
, pb
->name
, error
);
548 return_val_if_nok (error
, FALSE
);
550 values
[MONO_PARAM_NAME
] = 0;
552 values
+= MONO_PARAM_SIZE
;
553 if (pb
->marshal_info
) {
555 alloc_table (mtable
, mtable
->rows
);
556 mvalues
= mtable
->values
+ mtable
->rows
* MONO_FIELD_MARSHAL_SIZE
;
557 mvalues
[MONO_FIELD_MARSHAL_PARENT
] = (table
->next_idx
<< MONO_HAS_FIELD_MARSHAL_BITS
) | MONO_HAS_FIELD_MARSHAL_PARAMDEF
;
558 mvalues
[MONO_FIELD_MARSHAL_NATIVE_TYPE
] = mono_dynimage_save_encode_marshal_blob (assembly
, pb
->marshal_info
, error
);
559 return_val_if_nok (error
, FALSE
);
561 pb
->table_idx
= table
->next_idx
++;
562 if (pb
->attrs
& PARAM_ATTRIBUTE_HAS_DEFAULT
) {
563 MonoTypeEnum field_type
= (MonoTypeEnum
)0;
564 mtable
= &assembly
->tables
[MONO_TABLE_CONSTANT
];
566 alloc_table (mtable
, mtable
->rows
);
567 mvalues
= mtable
->values
+ mtable
->rows
* MONO_CONSTANT_SIZE
;
568 mvalues
[MONO_CONSTANT_PARENT
] = MONO_HASCONSTANT_PARAM
| (pb
->table_idx
<< MONO_HASCONSTANT_BITS
);
569 mvalues
[MONO_CONSTANT_VALUE
] = mono_dynimage_encode_constant (assembly
, pb
->def_value
, &field_type
);
570 mvalues
[MONO_CONSTANT_TYPE
] = field_type
;
571 mvalues
[MONO_CONSTANT_PADDING
] = 0;
581 mono_image_add_methodimpl (MonoDynamicImage
*assembly
, MonoReflectionMethodBuilder
*mb
, MonoError
*error
)
583 MONO_REQ_GC_UNSAFE_MODE
;
585 MonoReflectionTypeBuilder
*tb
= (MonoReflectionTypeBuilder
*)mb
->type
;
586 MonoDynamicTable
*table
;
589 MonoReflectionMethod
*m
;
594 if (!mb
->override_methods
)
597 for (i
= 0; i
< mono_array_length_internal (mb
->override_methods
); ++i
) {
598 m
= mono_array_get_internal (mb
->override_methods
, MonoReflectionMethod
*, i
);
600 table
= &assembly
->tables
[MONO_TABLE_METHODIMPL
];
602 alloc_table (table
, table
->rows
);
603 values
= table
->values
+ table
->rows
* MONO_METHODIMPL_SIZE
;
604 values
[MONO_METHODIMPL_CLASS
] = tb
->table_idx
;
605 values
[MONO_METHODIMPL_BODY
] = MONO_METHODDEFORREF_METHODDEF
| (mb
->table_idx
<< MONO_METHODDEFORREF_BITS
);
607 tok
= image_create_token_raw (assembly
, (MonoObject
*)m
, FALSE
, FALSE
, error
); /* FIXME use handles */
608 return_val_if_nok (error
, FALSE
);
610 switch (mono_metadata_token_table (tok
)) {
611 case MONO_TABLE_MEMBERREF
:
612 tok
= (mono_metadata_token_index (tok
) << MONO_METHODDEFORREF_BITS
) | MONO_METHODDEFORREF_METHODREF
;
614 case MONO_TABLE_METHOD
:
615 tok
= (mono_metadata_token_index (tok
) << MONO_METHODDEFORREF_BITS
) | MONO_METHODDEFORREF_METHODDEF
;
618 g_assert_not_reached ();
620 values
[MONO_METHODIMPL_DECLARATION
] = tok
;
626 #ifndef DISABLE_REFLECTION_EMIT
628 mono_image_get_method_info (MonoReflectionMethodBuilder
*mb
, MonoDynamicImage
*assembly
, MonoError
*error
)
630 MONO_REQ_GC_UNSAFE_MODE
;
632 MonoDynamicTable
*table
;
634 ReflectionMethodBuilder rmb
;
639 if (!mono_reflection_methodbuilder_from_method_builder (&rmb
, mb
, error
) ||
640 !mono_image_basic_method (&rmb
, assembly
, error
))
643 mb
->table_idx
= *rmb
.table_idx
;
645 if (mb
->dll
) { /* It's a P/Invoke method */
647 /* map CharSet values to on-disk values */
648 int ncharset
= (mb
->charset
? (mb
->charset
- 1) * 2 : 0);
649 int extra_flags
= mb
->extra_flags
;
650 table
= &assembly
->tables
[MONO_TABLE_IMPLMAP
];
652 alloc_table (table
, table
->rows
);
653 values
= table
->values
+ table
->rows
* MONO_IMPLMAP_SIZE
;
655 values
[MONO_IMPLMAP_FLAGS
] = (mb
->native_cc
<< 8) | ncharset
| extra_flags
;
656 values
[MONO_IMPLMAP_MEMBER
] = (mb
->table_idx
<< 1) | 1; /* memberforwarded: method */
658 values
[MONO_IMPLMAP_NAME
] = string_heap_insert_mstring (&assembly
->sheap
, mb
->dllentry
, error
);
659 return_val_if_nok (error
, FALSE
);
661 values
[MONO_IMPLMAP_NAME
] = string_heap_insert_mstring (&assembly
->sheap
, mb
->name
, error
);
662 return_val_if_nok (error
, FALSE
);
664 moduleref
= string_heap_insert_mstring (&assembly
->sheap
, mb
->dll
, error
);
665 return_val_if_nok (error
, FALSE
);
666 if (!(values
[MONO_IMPLMAP_SCOPE
] = find_index_in_table (assembly
, MONO_TABLE_MODULEREF
, MONO_MODULEREF_NAME
, moduleref
))) {
667 table
= &assembly
->tables
[MONO_TABLE_MODULEREF
];
669 alloc_table (table
, table
->rows
);
670 table
->values
[table
->rows
* MONO_MODULEREF_SIZE
+ MONO_MODULEREF_NAME
] = moduleref
;
671 values
[MONO_IMPLMAP_SCOPE
] = table
->rows
;
675 if (mb
->generic_params
) {
676 table
= &assembly
->tables
[MONO_TABLE_GENERICPARAM
];
677 table
->rows
+= mono_array_length_internal (mb
->generic_params
);
678 alloc_table (table
, table
->rows
);
679 for (i
= 0; i
< mono_array_length_internal (mb
->generic_params
); ++i
) {
680 guint32 owner
= MONO_TYPEORMETHOD_METHOD
| (mb
->table_idx
<< MONO_TYPEORMETHOD_BITS
);
682 mono_image_get_generic_param_info (
683 (MonoReflectionGenericParam
*)mono_array_get_internal (mb
->generic_params
, gpointer
, i
), owner
, assembly
);
691 mono_image_get_ctor_info (MonoDomain
*domain
, MonoReflectionCtorBuilder
*mb
, MonoDynamicImage
*assembly
, MonoError
*error
)
693 MONO_REQ_GC_UNSAFE_MODE
;
695 ReflectionMethodBuilder rmb
;
697 if (!mono_reflection_methodbuilder_from_ctor_builder (&rmb
, mb
, error
))
700 if (!mono_image_basic_method (&rmb
, assembly
, error
))
703 mb
->table_idx
= *rmb
.table_idx
;
710 mono_image_get_field_info (MonoReflectionFieldBuilder
*fb
, MonoDynamicImage
*assembly
, MonoError
*error
)
712 MONO_REQ_GC_UNSAFE_MODE
;
716 MonoDynamicTable
*table
;
719 /* maybe this fixup should be done in the C# code */
720 if (fb
->attrs
& FIELD_ATTRIBUTE_LITERAL
)
721 fb
->attrs
|= FIELD_ATTRIBUTE_HAS_DEFAULT
;
722 table
= &assembly
->tables
[MONO_TABLE_FIELD
];
723 guint32 fb_table_idx
= table
->next_idx
++;
724 g_hash_table_insert (assembly
->field_to_table_idx
, fb
->handle
, GUINT_TO_POINTER (fb_table_idx
));
725 values
= table
->values
+ fb_table_idx
* MONO_FIELD_SIZE
;
726 values
[MONO_FIELD_NAME
] = string_heap_insert_mstring (&assembly
->sheap
, fb
->name
, error
);
727 return_if_nok (error
);
728 values
[MONO_FIELD_FLAGS
] = fb
->attrs
;
729 values
[MONO_FIELD_SIGNATURE
] = mono_dynimage_encode_field_signature (assembly
, fb
, error
);
730 return_if_nok (error
);
732 if (fb
->offset
!= -1) {
733 table
= &assembly
->tables
[MONO_TABLE_FIELDLAYOUT
];
735 alloc_table (table
, table
->rows
);
736 values
= table
->values
+ table
->rows
* MONO_FIELD_LAYOUT_SIZE
;
737 values
[MONO_FIELD_LAYOUT_FIELD
] = fb_table_idx
;
738 values
[MONO_FIELD_LAYOUT_OFFSET
] = fb
->offset
;
740 if (fb
->attrs
& FIELD_ATTRIBUTE_LITERAL
) {
741 MonoTypeEnum field_type
= (MonoTypeEnum
)0;
742 table
= &assembly
->tables
[MONO_TABLE_CONSTANT
];
744 alloc_table (table
, table
->rows
);
745 values
= table
->values
+ table
->rows
* MONO_CONSTANT_SIZE
;
746 values
[MONO_CONSTANT_PARENT
] = MONO_HASCONSTANT_FIEDDEF
| (fb_table_idx
<< MONO_HASCONSTANT_BITS
);
747 values
[MONO_CONSTANT_VALUE
] = mono_dynimage_encode_constant (assembly
, fb
->def_value
, &field_type
);
748 values
[MONO_CONSTANT_TYPE
] = field_type
;
749 values
[MONO_CONSTANT_PADDING
] = 0;
751 if (fb
->attrs
& FIELD_ATTRIBUTE_HAS_FIELD_RVA
) {
753 table
= &assembly
->tables
[MONO_TABLE_FIELDRVA
];
755 alloc_table (table
, table
->rows
);
756 values
= table
->values
+ table
->rows
* MONO_FIELD_RVA_SIZE
;
757 values
[MONO_FIELD_RVA_FIELD
] = fb_table_idx
;
759 * We store it in the code section because it's simpler for now.
762 if (mono_array_length_internal (fb
->rva_data
) >= 10)
763 stream_data_align (&assembly
->code
);
764 rva_idx
= mono_image_add_stream_data (&assembly
->code
, mono_array_addr_internal (fb
->rva_data
, char, 0), mono_array_length_internal (fb
->rva_data
));
766 rva_idx
= mono_image_add_stream_zero (&assembly
->code
, mono_class_value_size (fb
->handle
->parent
, NULL
));
767 values
[MONO_FIELD_RVA_RVA
] = rva_idx
+ assembly
->text_rva
;
769 if (fb
->marshal_info
) {
770 table
= &assembly
->tables
[MONO_TABLE_FIELDMARSHAL
];
772 alloc_table (table
, table
->rows
);
773 values
= table
->values
+ table
->rows
* MONO_FIELD_MARSHAL_SIZE
;
774 values
[MONO_FIELD_MARSHAL_PARENT
] = (fb_table_idx
<< MONO_HAS_FIELD_MARSHAL_BITS
) | MONO_HAS_FIELD_MARSHAL_FIELDSREF
;
775 values
[MONO_FIELD_MARSHAL_NATIVE_TYPE
] = mono_dynimage_save_encode_marshal_blob (assembly
, fb
->marshal_info
, error
);
776 return_if_nok (error
);
781 mono_image_get_property_info (MonoReflectionPropertyBuilder
*pb
, MonoDynamicImage
*assembly
, MonoError
*error
)
783 MONO_REQ_GC_UNSAFE_MODE
;
787 MonoDynamicTable
*table
;
789 guint num_methods
= 0;
793 * we need to set things in the following tables:
794 * PROPERTYMAP (info already filled in _get_type_info ())
795 * PROPERTY (rows already preallocated in _get_type_info ())
796 * METHOD (method info already done with the generic method code)
800 table
= &assembly
->tables
[MONO_TABLE_PROPERTY
];
801 pb
->table_idx
= table
->next_idx
++;
802 values
= table
->values
+ pb
->table_idx
* MONO_PROPERTY_SIZE
;
803 values
[MONO_PROPERTY_NAME
] = string_heap_insert_mstring (&assembly
->sheap
, pb
->name
, error
);
804 return_if_nok (error
);
805 values
[MONO_PROPERTY_FLAGS
] = pb
->attrs
;
806 values
[MONO_PROPERTY_TYPE
] = mono_dynimage_save_encode_property_signature (assembly
, pb
, error
);
807 return_if_nok (error
);
810 /* FIXME: we still don't handle 'other' methods */
811 if (pb
->get_method
) num_methods
++;
812 if (pb
->set_method
) num_methods
++;
814 table
= &assembly
->tables
[MONO_TABLE_METHODSEMANTICS
];
815 table
->rows
+= num_methods
;
816 alloc_table (table
, table
->rows
);
818 if (pb
->get_method
) {
819 semaidx
= table
->next_idx
++;
820 values
= table
->values
+ semaidx
* MONO_METHOD_SEMA_SIZE
;
821 values
[MONO_METHOD_SEMA_SEMANTICS
] = METHOD_SEMANTIC_GETTER
;
822 values
[MONO_METHOD_SEMA_METHOD
] = pb
->get_method
->table_idx
;
823 values
[MONO_METHOD_SEMA_ASSOCIATION
] = (pb
->table_idx
<< MONO_HAS_SEMANTICS_BITS
) | MONO_HAS_SEMANTICS_PROPERTY
;
825 if (pb
->set_method
) {
826 semaidx
= table
->next_idx
++;
827 values
= table
->values
+ semaidx
* MONO_METHOD_SEMA_SIZE
;
828 values
[MONO_METHOD_SEMA_SEMANTICS
] = METHOD_SEMANTIC_SETTER
;
829 values
[MONO_METHOD_SEMA_METHOD
] = pb
->set_method
->table_idx
;
830 values
[MONO_METHOD_SEMA_ASSOCIATION
] = (pb
->table_idx
<< MONO_HAS_SEMANTICS_BITS
) | MONO_HAS_SEMANTICS_PROPERTY
;
832 if (pb
->attrs
& PROPERTY_ATTRIBUTE_HAS_DEFAULT
) {
833 MonoTypeEnum field_type
= (MonoTypeEnum
)0;
834 table
= &assembly
->tables
[MONO_TABLE_CONSTANT
];
836 alloc_table (table
, table
->rows
);
837 values
= table
->values
+ table
->rows
* MONO_CONSTANT_SIZE
;
838 values
[MONO_CONSTANT_PARENT
] = MONO_HASCONSTANT_PROPERTY
| (pb
->table_idx
<< MONO_HASCONSTANT_BITS
);
839 values
[MONO_CONSTANT_VALUE
] = mono_dynimage_encode_constant (assembly
, pb
->def_value
, &field_type
);
840 values
[MONO_CONSTANT_TYPE
] = field_type
;
841 values
[MONO_CONSTANT_PADDING
] = 0;
846 mono_image_get_event_info (MonoReflectionEventBuilder
*eb
, MonoDynamicImage
*assembly
, MonoError
*error
)
848 MONO_REQ_GC_UNSAFE_MODE
;
850 MonoDynamicTable
*table
;
852 guint num_methods
= 0;
856 * we need to set things in the following tables:
857 * EVENTMAP (info already filled in _get_type_info ())
858 * EVENT (rows already preallocated in _get_type_info ())
859 * METHOD (method info already done with the generic method code)
862 table
= &assembly
->tables
[MONO_TABLE_EVENT
];
863 eb
->table_idx
= table
->next_idx
++;
864 values
= table
->values
+ eb
->table_idx
* MONO_EVENT_SIZE
;
865 values
[MONO_EVENT_NAME
] = string_heap_insert_mstring (&assembly
->sheap
, eb
->name
, error
);
866 return_if_nok (error
);
867 values
[MONO_EVENT_FLAGS
] = eb
->attrs
;
868 MonoType
*ebtype
= mono_reflection_type_get_handle (eb
->type
, error
);
869 return_if_nok (error
);
870 values
[MONO_EVENT_TYPE
] = mono_image_typedef_or_ref (assembly
, ebtype
);
873 * FIXME: we still don't handle 'other' methods
875 if (eb
->add_method
) num_methods
++;
876 if (eb
->remove_method
) num_methods
++;
877 if (eb
->raise_method
) num_methods
++;
879 table
= &assembly
->tables
[MONO_TABLE_METHODSEMANTICS
];
880 table
->rows
+= num_methods
;
881 alloc_table (table
, table
->rows
);
883 if (eb
->add_method
) {
884 semaidx
= table
->next_idx
++;
885 values
= table
->values
+ semaidx
* MONO_METHOD_SEMA_SIZE
;
886 values
[MONO_METHOD_SEMA_SEMANTICS
] = METHOD_SEMANTIC_ADD_ON
;
887 values
[MONO_METHOD_SEMA_METHOD
] = eb
->add_method
->table_idx
;
888 values
[MONO_METHOD_SEMA_ASSOCIATION
] = (eb
->table_idx
<< MONO_HAS_SEMANTICS_BITS
) | MONO_HAS_SEMANTICS_EVENT
;
890 if (eb
->remove_method
) {
891 semaidx
= table
->next_idx
++;
892 values
= table
->values
+ semaidx
* MONO_METHOD_SEMA_SIZE
;
893 values
[MONO_METHOD_SEMA_SEMANTICS
] = METHOD_SEMANTIC_REMOVE_ON
;
894 values
[MONO_METHOD_SEMA_METHOD
] = eb
->remove_method
->table_idx
;
895 values
[MONO_METHOD_SEMA_ASSOCIATION
] = (eb
->table_idx
<< MONO_HAS_SEMANTICS_BITS
) | MONO_HAS_SEMANTICS_EVENT
;
897 if (eb
->raise_method
) {
898 semaidx
= table
->next_idx
++;
899 values
= table
->values
+ semaidx
* MONO_METHOD_SEMA_SIZE
;
900 values
[MONO_METHOD_SEMA_SEMANTICS
] = METHOD_SEMANTIC_FIRE
;
901 values
[MONO_METHOD_SEMA_METHOD
] = eb
->raise_method
->table_idx
;
902 values
[MONO_METHOD_SEMA_ASSOCIATION
] = (eb
->table_idx
<< MONO_HAS_SEMANTICS_BITS
) | MONO_HAS_SEMANTICS_EVENT
;
907 encode_constraints (MonoReflectionGenericParam
*gparam
, guint32 owner
, MonoDynamicImage
*assembly
, MonoError
*error
)
909 MONO_REQ_GC_UNSAFE_MODE
;
913 MonoDynamicTable
*table
;
914 guint32 num_constraints
, i
;
918 table
= &assembly
->tables
[MONO_TABLE_GENERICPARAMCONSTRAINT
];
919 num_constraints
= gparam
->iface_constraints
?
920 mono_array_length_internal (gparam
->iface_constraints
) : 0;
921 table
->rows
+= num_constraints
;
922 if (gparam
->base_type
)
924 alloc_table (table
, table
->rows
);
926 if (gparam
->base_type
) {
927 table_idx
= table
->next_idx
++;
928 values
= table
->values
+ table_idx
* MONO_GENPARCONSTRAINT_SIZE
;
930 MonoType
*gpbasetype
= mono_reflection_type_get_handle (gparam
->base_type
, error
);
931 return_if_nok (error
);
932 values
[MONO_GENPARCONSTRAINT_GENERICPAR
] = owner
;
933 values
[MONO_GENPARCONSTRAINT_CONSTRAINT
] = mono_image_typedef_or_ref (assembly
, gpbasetype
);
936 for (i
= 0; i
< num_constraints
; i
++) {
937 MonoReflectionType
*constraint
= (MonoReflectionType
*)mono_array_get_internal (
938 gparam
->iface_constraints
, gpointer
, i
);
940 table_idx
= table
->next_idx
++;
941 values
= table
->values
+ table_idx
* MONO_GENPARCONSTRAINT_SIZE
;
943 MonoType
*constraint_type
= mono_reflection_type_get_handle (constraint
, error
);
944 return_if_nok (error
);
946 values
[MONO_GENPARCONSTRAINT_GENERICPAR
] = owner
;
947 values
[MONO_GENPARCONSTRAINT_CONSTRAINT
] = mono_image_typedef_or_ref (assembly
, constraint_type
);
952 mono_image_get_generic_param_info (MonoReflectionGenericParam
*gparam
, guint32 owner
, MonoDynamicImage
*assembly
)
954 MONO_REQ_GC_UNSAFE_MODE
;
956 GenericParamTableEntry
*entry
;
959 * The GenericParam table must be sorted according to the `owner' field.
960 * We need to do this sorting prior to writing the GenericParamConstraint
961 * table, since we have to use the final GenericParam table indices there
962 * and they must also be sorted.
965 entry
= g_new0 (GenericParamTableEntry
, 1);
966 entry
->owner
= owner
;
967 /* FIXME: track where gen_params should be freed and remove the GC root as well */
968 MONO_GC_REGISTER_ROOT_IF_MOVING (entry
->gparam
, MONO_ROOT_SOURCE_REFLECTION
, NULL
, "Reflection Generic Parameter");
969 entry
->gparam
= gparam
;
971 g_ptr_array_add (assembly
->gen_params
, entry
);
975 write_generic_param_entry (MonoDynamicImage
*assembly
, GenericParamTableEntry
*entry
, MonoError
*error
)
977 MONO_REQ_GC_UNSAFE_MODE
;
979 MonoDynamicTable
*table
;
980 MonoGenericParam
*param
;
986 table
= &assembly
->tables
[MONO_TABLE_GENERICPARAM
];
987 table_idx
= table
->next_idx
++;
988 values
= table
->values
+ table_idx
* MONO_GENERICPARAM_SIZE
;
990 MonoType
*gparam_type
= mono_reflection_type_get_handle ((MonoReflectionType
*)entry
->gparam
, error
);
991 return_val_if_nok (error
, FALSE
);
993 param
= gparam_type
->data
.generic_param
;
995 values
[MONO_GENERICPARAM_OWNER
] = entry
->owner
;
996 values
[MONO_GENERICPARAM_FLAGS
] = entry
->gparam
->attrs
;
997 values
[MONO_GENERICPARAM_NUMBER
] = mono_generic_param_num (param
);
998 values
[MONO_GENERICPARAM_NAME
] = string_heap_insert (&assembly
->sheap
, mono_generic_param_name (param
));
1000 if (!mono_image_add_cattrs (assembly
, table_idx
, MONO_CUSTOM_ATTR_GENERICPAR
, entry
->gparam
->cattrs
, error
))
1003 encode_constraints (entry
->gparam
, table_idx
, assembly
, error
);
1004 return_val_if_nok (error
, FALSE
);
1010 collect_types (MonoPtrArray
*types
, MonoReflectionTypeBuilder
*type
)
1014 mono_ptr_array_append (*types
, type
);
1016 if (!type
->subtypes
)
1019 for (i
= 0; i
< mono_array_length_internal (type
->subtypes
); ++i
) {
1020 MonoReflectionTypeBuilder
*subtype
= mono_array_get_internal (type
->subtypes
, MonoReflectionTypeBuilder
*, i
);
1021 collect_types (types
, subtype
);
1026 compare_types_by_table_idx (MonoReflectionTypeBuilder
**type1
, MonoReflectionTypeBuilder
**type2
)
1028 if ((*type1
)->table_idx
< (*type2
)->table_idx
)
1031 if ((*type1
)->table_idx
> (*type2
)->table_idx
)
1038 params_add_cattrs (MonoDynamicImage
*assembly
, MonoArray
*pinfo
, MonoError
*error
) {
1044 for (i
= 0; i
< mono_array_length_internal (pinfo
); ++i
) {
1045 MonoReflectionParamBuilder
*pb
;
1046 pb
= mono_array_get_internal (pinfo
, MonoReflectionParamBuilder
*, i
);
1049 if (!mono_image_add_cattrs (assembly
, pb
->table_idx
, MONO_CUSTOM_ATTR_PARAMDEF
, pb
->cattrs
, error
))
1057 field_builder_table_index (MonoDynamicImage
* assembly
, MonoReflectionFieldBuilder
*fb
)
1059 return GPOINTER_TO_UINT (g_hash_table_lookup (assembly
->field_to_table_idx
, fb
->handle
));
1063 type_add_cattrs (MonoDynamicImage
*assembly
, MonoReflectionTypeBuilder
*tb
, MonoError
*error
) {
1068 if (!mono_image_add_cattrs (assembly
, tb
->table_idx
, MONO_CUSTOM_ATTR_TYPEDEF
, tb
->cattrs
, error
))
1071 for (i
= 0; i
< tb
->num_fields
; ++i
) {
1072 MonoReflectionFieldBuilder
* fb
;
1073 fb
= mono_array_get_internal (tb
->fields
, MonoReflectionFieldBuilder
*, i
);
1074 if (!mono_image_add_cattrs (assembly
, field_builder_table_index (assembly
, fb
), MONO_CUSTOM_ATTR_FIELDDEF
, fb
->cattrs
, error
))
1079 for (i
= 0; i
< mono_array_length_internal (tb
->events
); ++i
) {
1080 MonoReflectionEventBuilder
* eb
;
1081 eb
= mono_array_get_internal (tb
->events
, MonoReflectionEventBuilder
*, i
);
1082 if (!mono_image_add_cattrs (assembly
, eb
->table_idx
, MONO_CUSTOM_ATTR_EVENT
, eb
->cattrs
, error
))
1086 if (tb
->properties
) {
1087 for (i
= 0; i
< mono_array_length_internal (tb
->properties
); ++i
) {
1088 MonoReflectionPropertyBuilder
* pb
;
1089 pb
= mono_array_get_internal (tb
->properties
, MonoReflectionPropertyBuilder
*, i
);
1090 if (!mono_image_add_cattrs (assembly
, pb
->table_idx
, MONO_CUSTOM_ATTR_PROPERTY
, pb
->cattrs
, error
))
1095 for (i
= 0; i
< mono_array_length_internal (tb
->ctors
); ++i
) {
1096 MonoReflectionCtorBuilder
* cb
;
1097 cb
= mono_array_get_internal (tb
->ctors
, MonoReflectionCtorBuilder
*, i
);
1098 if (!mono_image_add_cattrs (assembly
, cb
->table_idx
, MONO_CUSTOM_ATTR_METHODDEF
, cb
->cattrs
, error
) ||
1099 !params_add_cattrs (assembly
, cb
->pinfo
, error
))
1105 for (i
= 0; i
< tb
->num_methods
; ++i
) {
1106 MonoReflectionMethodBuilder
* mb
;
1107 mb
= mono_array_get_internal (tb
->methods
, MonoReflectionMethodBuilder
*, i
);
1108 if (!mono_image_add_cattrs (assembly
, mb
->table_idx
, MONO_CUSTOM_ATTR_METHODDEF
, mb
->cattrs
, error
) ||
1109 !params_add_cattrs (assembly
, mb
->pinfo
, error
))
1115 for (i
= 0; i
< mono_array_length_internal (tb
->subtypes
); ++i
) {
1116 if (!type_add_cattrs (assembly
, mono_array_get_internal (tb
->subtypes
, MonoReflectionTypeBuilder
*, i
), error
))
1125 module_add_cattrs (MonoDynamicImage
*assembly
, MonoReflectionModuleBuilder
*moduleb
, MonoError
*error
)
1131 if (!mono_image_add_cattrs (assembly
, moduleb
->table_idx
, MONO_CUSTOM_ATTR_MODULE
, moduleb
->cattrs
, error
))
1134 if (moduleb
->global_methods
) {
1135 for (i
= 0; i
< mono_array_length_internal (moduleb
->global_methods
); ++i
) {
1136 MonoReflectionMethodBuilder
* mb
= mono_array_get_internal (moduleb
->global_methods
, MonoReflectionMethodBuilder
*, i
);
1137 if (!mono_image_add_cattrs (assembly
, mb
->table_idx
, MONO_CUSTOM_ATTR_METHODDEF
, mb
->cattrs
, error
) ||
1138 !params_add_cattrs (assembly
, mb
->pinfo
, error
))
1143 if (moduleb
->global_fields
) {
1144 for (i
= 0; i
< mono_array_length_internal (moduleb
->global_fields
); ++i
) {
1145 MonoReflectionFieldBuilder
*fb
= mono_array_get_internal (moduleb
->global_fields
, MonoReflectionFieldBuilder
*, i
);
1146 if (!mono_image_add_cattrs (assembly
, field_builder_table_index (assembly
, fb
), MONO_CUSTOM_ATTR_FIELDDEF
, fb
->cattrs
, error
))
1151 if (moduleb
->types
) {
1152 for (i
= 0; i
< moduleb
->num_types
; ++i
) {
1153 if (!type_add_cattrs (assembly
, mono_array_get_internal (moduleb
->types
, MonoReflectionTypeBuilder
*, i
), error
))
1162 mono_image_fill_file_table (MonoDomain
*domain
, MonoReflectionModule
*module
, MonoDynamicImage
*assembly
, MonoError
*error
)
1164 MonoDynamicTable
*table
;
1168 char *b
= blob_size
;
1173 table
= &assembly
->tables
[MONO_TABLE_FILE
];
1175 alloc_table (table
, table
->rows
);
1176 values
= table
->values
+ table
->next_idx
* MONO_FILE_SIZE
;
1177 values
[MONO_FILE_FLAGS
] = FILE_CONTAINS_METADATA
;
1178 values
[MONO_FILE_NAME
] = string_heap_insert (&assembly
->sheap
, module
->image
->module_name
);
1179 if (image_is_dynamic (module
->image
)) {
1180 /* This depends on the fact that the main module is emitted last */
1181 dir
= mono_string_to_utf8_checked_internal (((MonoReflectionModuleBuilder
*)module
)->assemblyb
->dir
, error
);
1182 return_val_if_nok (error
, FALSE
);
1183 path
= g_strdup_printf ("%s%c%s", dir
, G_DIR_SEPARATOR
, module
->image
->module_name
);
1186 path
= g_strdup (module
->image
->name
);
1188 mono_sha1_get_digest_from_file (path
, hash
);
1191 mono_metadata_encode_value (20, b
, &b
);
1192 values
[MONO_FILE_HASH_VALUE
] = mono_image_add_stream_data (&assembly
->blob
, blob_size
, b
-blob_size
);
1193 mono_image_add_stream_data (&assembly
->blob
, (char*)hash
, 20);
1199 mono_image_fill_module_table (MonoDomain
*domain
, MonoReflectionModuleBuilder
*mb
, MonoDynamicImage
*assembly
, MonoError
*error
)
1201 MonoDynamicTable
*table
;
1206 table
= &assembly
->tables
[MONO_TABLE_MODULE
];
1207 mb
->table_idx
= table
->next_idx
++;
1208 table
->values
[mb
->table_idx
* MONO_MODULE_SIZE
+ MONO_MODULE_NAME
] = string_heap_insert_mstring (&assembly
->sheap
, mb
->module
.name
, error
);
1209 return_if_nok (error
);
1210 i
= mono_image_add_stream_data (&assembly
->guid
, mono_array_addr_internal (mb
->guid
, char, 0), 16);
1213 table
->values
[mb
->table_idx
* MONO_MODULE_SIZE
+ MONO_MODULE_GENERATION
] = 0;
1214 table
->values
[mb
->table_idx
* MONO_MODULE_SIZE
+ MONO_MODULE_MVID
] = i
;
1215 table
->values
[mb
->table_idx
* MONO_MODULE_SIZE
+ MONO_MODULE_ENC
] = 0;
1216 table
->values
[mb
->table_idx
* MONO_MODULE_SIZE
+ MONO_MODULE_ENCBASE
] = 0;
1220 mono_image_fill_export_table_from_class (MonoDomain
*domain
, MonoClass
*klass
,
1221 guint32 module_index
, guint32 parent_index
, MonoDynamicImage
*assembly
)
1223 MonoDynamicTable
*table
;
1227 visib
= mono_class_get_flags (klass
) & TYPE_ATTRIBUTE_VISIBILITY_MASK
;
1228 if (! ((visib
& TYPE_ATTRIBUTE_PUBLIC
) || (visib
& TYPE_ATTRIBUTE_NESTED_PUBLIC
)))
1231 table
= &assembly
->tables
[MONO_TABLE_EXPORTEDTYPE
];
1233 alloc_table (table
, table
->rows
);
1234 values
= table
->values
+ table
->next_idx
* MONO_EXP_TYPE_SIZE
;
1236 values
[MONO_EXP_TYPE_FLAGS
] = mono_class_get_flags (klass
);
1237 values
[MONO_EXP_TYPE_TYPEDEF
] = m_class_get_type_token (klass
);
1238 if (m_class_get_nested_in (klass
))
1239 values
[MONO_EXP_TYPE_IMPLEMENTATION
] = (parent_index
<< MONO_IMPLEMENTATION_BITS
) + MONO_IMPLEMENTATION_EXP_TYPE
;
1241 values
[MONO_EXP_TYPE_IMPLEMENTATION
] = (module_index
<< MONO_IMPLEMENTATION_BITS
) + MONO_IMPLEMENTATION_FILE
;
1242 values
[MONO_EXP_TYPE_NAME
] = string_heap_insert (&assembly
->sheap
, m_class_get_name (klass
));
1243 values
[MONO_EXP_TYPE_NAMESPACE
] = string_heap_insert (&assembly
->sheap
, m_class_get_name_space (klass
));
1245 res
= table
->next_idx
;
1249 /* Emit nested types */
1250 GList
*nested_classes
= mono_class_get_nested_classes_property (klass
);
1252 for (tmp
= nested_classes
; tmp
; tmp
= tmp
->next
)
1253 mono_image_fill_export_table_from_class (domain
, (MonoClass
*)tmp
->data
, module_index
, table
->next_idx
- 1, assembly
);
1259 mono_image_fill_export_table (MonoDomain
*domain
, MonoReflectionTypeBuilder
*tb
,
1260 guint32 module_index
, guint32 parent_index
, MonoDynamicImage
*assembly
,
1268 MonoType
*t
= mono_reflection_type_get_handle ((MonoReflectionType
*)tb
, error
);
1269 return_if_nok (error
);
1271 klass
= mono_class_from_mono_type_internal (t
);
1273 guint32 tb_token
= mono_metadata_make_token (MONO_TABLE_TYPEDEF
, tb
->table_idx
);
1274 if (m_class_get_type_token (klass
) != tb_token
) {
1275 g_error ("TypeBuilder token %08x does not match klass token %08x", tb_token
, m_class_get_type_token (klass
));
1278 idx
= mono_image_fill_export_table_from_class (domain
, klass
, module_index
,
1279 parent_index
, assembly
);
1283 * We need to do this ourselves since klass->nested_classes is not set up.
1286 for (i
= 0; i
< mono_array_length_internal (tb
->subtypes
); ++i
) {
1287 mono_image_fill_export_table (domain
, mono_array_get_internal (tb
->subtypes
, MonoReflectionTypeBuilder
*, i
), module_index
, idx
, assembly
, error
);
1288 return_if_nok (error
);
1294 mono_image_fill_export_table_from_module (MonoDomain
*domain
, MonoReflectionModule
*module
,
1295 guint32 module_index
, MonoDynamicImage
*assembly
)
1297 MonoImage
*image
= module
->image
;
1301 t
= &image
->tables
[MONO_TABLE_TYPEDEF
];
1303 for (i
= 0; i
< t
->rows
; ++i
) {
1305 MonoClass
*klass
= mono_class_get_checked (image
, mono_metadata_make_token (MONO_TABLE_TYPEDEF
, i
+ 1), error
);
1306 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
1308 if (mono_class_is_public (klass
))
1309 mono_image_fill_export_table_from_class (domain
, klass
, module_index
, 0, assembly
);
1314 add_exported_type (MonoReflectionAssemblyBuilder
*assemblyb
, MonoDynamicImage
*assembly
, MonoClass
*klass
, guint32 parent_index
)
1316 MonoDynamicTable
*table
;
1318 guint32 scope
, scope_idx
, impl
, current_idx
;
1319 gboolean forwarder
= TRUE
;
1320 gpointer iter
= NULL
;
1323 if (m_class_get_nested_in (klass
)) {
1324 impl
= (parent_index
<< MONO_IMPLEMENTATION_BITS
) + MONO_IMPLEMENTATION_EXP_TYPE
;
1327 scope
= mono_reflection_resolution_scope_from_image (assembly
, m_class_get_image (klass
));
1328 g_assert ((scope
& MONO_RESOLUTION_SCOPE_MASK
) == MONO_RESOLUTION_SCOPE_ASSEMBLYREF
);
1329 scope_idx
= scope
>> MONO_RESOLUTION_SCOPE_BITS
;
1330 impl
= (scope_idx
<< MONO_IMPLEMENTATION_BITS
) + MONO_IMPLEMENTATION_ASSEMBLYREF
;
1333 table
= &assembly
->tables
[MONO_TABLE_EXPORTEDTYPE
];
1336 alloc_table (table
, table
->rows
);
1337 current_idx
= table
->next_idx
;
1338 values
= table
->values
+ current_idx
* MONO_EXP_TYPE_SIZE
;
1340 values
[MONO_EXP_TYPE_FLAGS
] = forwarder
? TYPE_ATTRIBUTE_FORWARDER
: 0;
1341 values
[MONO_EXP_TYPE_TYPEDEF
] = 0;
1342 values
[MONO_EXP_TYPE_IMPLEMENTATION
] = impl
;
1343 values
[MONO_EXP_TYPE_NAME
] = string_heap_insert (&assembly
->sheap
, m_class_get_name (klass
));
1344 values
[MONO_EXP_TYPE_NAMESPACE
] = string_heap_insert (&assembly
->sheap
, m_class_get_name_space (klass
));
1348 while ((nested
= mono_class_get_nested_types (klass
, &iter
)))
1349 add_exported_type (assemblyb
, assembly
, nested
, current_idx
);
1353 mono_image_fill_export_table_from_type_forwarders (MonoReflectionAssemblyBuilder
*assemblyb
, MonoDynamicImage
*assembly
)
1359 if (!assemblyb
->type_forwarders
)
1362 for (i
= 0; i
< mono_array_length_internal (assemblyb
->type_forwarders
); ++i
) {
1363 MonoReflectionType
*t
= mono_array_get_internal (assemblyb
->type_forwarders
, MonoReflectionType
*, i
);
1368 type
= mono_reflection_type_get_handle (t
, error
);
1369 mono_error_assert_ok (error
);
1372 klass
= mono_class_from_mono_type_internal (type
);
1374 add_exported_type (assemblyb
, assembly
, klass
, 0);
1378 #define align_pointer(base,p)\
1380 guint32 __diff = (unsigned char*)(p)-(unsigned char*)(base);\
1382 (p) += 4 - (__diff & 3);\
1386 compare_constants (const void *a
, const void *b
)
1388 const guint32
*a_values
= (const guint32
*)a
;
1389 const guint32
*b_values
= (const guint32
*)b
;
1390 return a_values
[MONO_CONSTANT_PARENT
] - b_values
[MONO_CONSTANT_PARENT
];
1394 compare_semantics (const void *a
, const void *b
)
1396 const guint32
*a_values
= (const guint32
*)a
;
1397 const guint32
*b_values
= (const guint32
*)b
;
1398 int assoc
= a_values
[MONO_METHOD_SEMA_ASSOCIATION
] - b_values
[MONO_METHOD_SEMA_ASSOCIATION
];
1401 return a_values
[MONO_METHOD_SEMA_SEMANTICS
] - b_values
[MONO_METHOD_SEMA_SEMANTICS
];
1405 compare_custom_attrs (const void *a
, const void *b
)
1407 const guint32
*a_values
= (const guint32
*)a
;
1408 const guint32
*b_values
= (const guint32
*)b
;
1410 return a_values
[MONO_CUSTOM_ATTR_PARENT
] - b_values
[MONO_CUSTOM_ATTR_PARENT
];
1414 compare_field_marshal (const void *a
, const void *b
)
1416 const guint32
*a_values
= (const guint32
*)a
;
1417 const guint32
*b_values
= (const guint32
*)b
;
1419 return a_values
[MONO_FIELD_MARSHAL_PARENT
] - b_values
[MONO_FIELD_MARSHAL_PARENT
];
1423 compare_nested (const void *a
, const void *b
)
1425 const guint32
*a_values
= (const guint32
*)a
;
1426 const guint32
*b_values
= (const guint32
*)b
;
1428 return a_values
[MONO_NESTED_CLASS_NESTED
] - b_values
[MONO_NESTED_CLASS_NESTED
];
1432 compare_genericparam (const void *a
, const void *b
)
1435 const GenericParamTableEntry
**a_entry
= (const GenericParamTableEntry
**) a
;
1436 const GenericParamTableEntry
**b_entry
= (const GenericParamTableEntry
**) b
;
1438 if ((*b_entry
)->owner
== (*a_entry
)->owner
) {
1439 MonoType
*a_type
= mono_reflection_type_get_handle ((MonoReflectionType
*)(*a_entry
)->gparam
, error
);
1440 mono_error_assert_ok (error
);
1441 MonoType
*b_type
= mono_reflection_type_get_handle ((MonoReflectionType
*)(*b_entry
)->gparam
, error
);
1442 mono_error_assert_ok (error
);
1444 mono_type_get_generic_param_num (a_type
) -
1445 mono_type_get_generic_param_num (b_type
);
1447 return (*a_entry
)->owner
- (*b_entry
)->owner
;
1451 compare_declsecurity_attrs (const void *a
, const void *b
)
1453 const guint32
*a_values
= (const guint32
*)a
;
1454 const guint32
*b_values
= (const guint32
*)b
;
1456 return a_values
[MONO_DECL_SECURITY_PARENT
] - b_values
[MONO_DECL_SECURITY_PARENT
];
1460 compare_interface_impl (const void *a
, const void *b
)
1462 const guint32
*a_values
= (const guint32
*)a
;
1463 const guint32
*b_values
= (const guint32
*)b
;
1465 int klass
= a_values
[MONO_INTERFACEIMPL_CLASS
] - b_values
[MONO_INTERFACEIMPL_CLASS
];
1469 return a_values
[MONO_INTERFACEIMPL_INTERFACE
] - b_values
[MONO_INTERFACEIMPL_INTERFACE
];
1474 MonoDynamicStream
*stream
;
1478 * build_compressed_metadata() fills in the blob of data that represents the
1479 * raw metadata as it will be saved in the PE file. The five streams are output
1480 * and the metadata tables are comnpressed from the guint32 array representation,
1481 * to the compressed on-disk format.
1484 build_compressed_metadata (MonoDynamicImage
*assembly
, MonoError
*error
)
1486 MonoDynamicTable
*table
;
1488 guint64 valid_mask
= 0;
1489 guint64 sorted_mask
;
1490 guint32 heapt_size
= 0;
1491 guint32 meta_size
= 256; /* allow for header and other stuff */
1492 guint32 table_offset
;
1493 guint32 ntables
= 0;
1499 struct StreamDesc stream_desc
[5];
1503 qsort (assembly
->gen_params
->pdata
, assembly
->gen_params
->len
, sizeof (gpointer
), compare_genericparam
);
1504 for (i
= 0; i
< assembly
->gen_params
->len
; i
++) {
1505 GenericParamTableEntry
*entry
= (GenericParamTableEntry
*)g_ptr_array_index (assembly
->gen_params
, i
);
1506 if (!write_generic_param_entry (assembly
, entry
, error
))
1510 stream_desc
[0].name
= "#~";
1511 stream_desc
[0].stream
= &assembly
->tstream
;
1512 stream_desc
[1].name
= "#Strings";
1513 stream_desc
[1].stream
= &assembly
->sheap
;
1514 stream_desc
[2].name
= "#US";
1515 stream_desc
[2].stream
= &assembly
->us
;
1516 stream_desc
[3].name
= "#Blob";
1517 stream_desc
[3].stream
= &assembly
->blob
;
1518 stream_desc
[4].name
= "#GUID";
1519 stream_desc
[4].stream
= &assembly
->guid
;
1521 /* tables that are sorted */
1522 sorted_mask
= ((guint64
)1 << MONO_TABLE_CONSTANT
) | ((guint64
)1 << MONO_TABLE_FIELDMARSHAL
)
1523 | ((guint64
)1 << MONO_TABLE_METHODSEMANTICS
) | ((guint64
)1 << MONO_TABLE_CLASSLAYOUT
)
1524 | ((guint64
)1 << MONO_TABLE_FIELDLAYOUT
) | ((guint64
)1 << MONO_TABLE_FIELDRVA
)
1525 | ((guint64
)1 << MONO_TABLE_IMPLMAP
) | ((guint64
)1 << MONO_TABLE_NESTEDCLASS
)
1526 | ((guint64
)1 << MONO_TABLE_METHODIMPL
) | ((guint64
)1 << MONO_TABLE_CUSTOMATTRIBUTE
)
1527 | ((guint64
)1 << MONO_TABLE_DECLSECURITY
) | ((guint64
)1 << MONO_TABLE_GENERICPARAM
)
1528 | ((guint64
)1 << MONO_TABLE_INTERFACEIMPL
);
1530 /* Compute table sizes */
1531 /* the MonoImage has already been created in mono_reflection_dynimage_basic_init() */
1532 meta
= &assembly
->image
;
1534 /* sizes should be multiple of 4 */
1535 mono_dynstream_data_align (&assembly
->blob
);
1536 mono_dynstream_data_align (&assembly
->guid
);
1537 mono_dynstream_data_align (&assembly
->sheap
);
1538 mono_dynstream_data_align (&assembly
->us
);
1540 /* Setup the info used by compute_sizes () */
1541 meta
->idx_blob_wide
= assembly
->blob
.index
>= 65536 ? 1 : 0;
1542 meta
->idx_guid_wide
= assembly
->guid
.index
>= 65536 ? 1 : 0;
1543 meta
->idx_string_wide
= assembly
->sheap
.index
>= 65536 ? 1 : 0;
1545 meta_size
+= assembly
->blob
.index
;
1546 meta_size
+= assembly
->guid
.index
;
1547 meta_size
+= assembly
->sheap
.index
;
1548 meta_size
+= assembly
->us
.index
;
1550 for (i
=0; i
< MONO_TABLE_NUM
; ++i
)
1551 meta
->tables
[i
].rows
= assembly
->tables
[i
].rows
;
1553 for (i
= 0; i
< MONO_TABLE_NUM
; i
++){
1554 if (meta
->tables
[i
].rows
== 0)
1556 valid_mask
|= (guint64
)1 << i
;
1558 meta
->tables
[i
].row_size
= mono_metadata_compute_size (
1559 meta
, i
, &meta
->tables
[i
].size_bitfield
);
1560 heapt_size
+= meta
->tables
[i
].row_size
* meta
->tables
[i
].rows
;
1562 heapt_size
+= 24; /* #~ header size */
1563 heapt_size
+= ntables
* 4;
1564 /* make multiple of 4 */
1567 meta_size
+= heapt_size
;
1568 meta
->raw_metadata
= (char *)g_malloc0 (meta_size
);
1569 p
= (unsigned char*)meta
->raw_metadata
;
1570 /* the metadata signature */
1571 *p
++ = 'B'; *p
++ = 'S'; *p
++ = 'J'; *p
++ = 'B';
1572 /* version numbers and 4 bytes reserved */
1573 int16val
= (guint16
*)p
;
1574 *int16val
++ = GUINT16_TO_LE (meta
->md_version_major
);
1575 *int16val
= GUINT16_TO_LE (meta
->md_version_minor
);
1577 /* version string */
1578 int32val
= (guint32
*)p
;
1579 *int32val
= GUINT32_TO_LE ((strlen (meta
->version
) + 3) & (~3)); /* needs to be multiple of 4 */
1581 memcpy (p
, meta
->version
, strlen (meta
->version
));
1582 p
+= GUINT32_FROM_LE (*int32val
);
1583 align_pointer (meta
->raw_metadata
, p
);
1584 int16val
= (guint16
*)p
;
1585 *int16val
++ = GUINT16_TO_LE (0); /* flags must be 0 */
1586 *int16val
= GUINT16_TO_LE (5); /* number of streams */
1590 * write the stream info.
1592 table_offset
= (p
- (unsigned char*)meta
->raw_metadata
) + 5 * 8 + 40; /* room needed for stream headers */
1593 table_offset
+= 3; table_offset
&= ~3;
1595 assembly
->tstream
.index
= heapt_size
;
1596 for (i
= 0; i
< 5; ++i
) {
1597 int32val
= (guint32
*)p
;
1598 stream_desc
[i
].stream
->offset
= table_offset
;
1599 *int32val
++ = GUINT32_TO_LE (table_offset
);
1600 *int32val
= GUINT32_TO_LE (stream_desc
[i
].stream
->index
);
1601 table_offset
+= GUINT32_FROM_LE (*int32val
);
1602 table_offset
+= 3; table_offset
&= ~3;
1604 strcpy ((char*)p
, stream_desc
[i
].name
);
1605 p
+= strlen (stream_desc
[i
].name
) + 1;
1606 align_pointer (meta
->raw_metadata
, p
);
1609 * now copy the data, the table stream header and contents goes first.
1611 g_assert ((p
- (unsigned char*)meta
->raw_metadata
) < assembly
->tstream
.offset
);
1612 p
= (guchar
*)meta
->raw_metadata
+ assembly
->tstream
.offset
;
1613 int32val
= (guint32
*)p
;
1614 *int32val
= GUINT32_TO_LE (0); /* reserved */
1617 *p
++ = 2; /* version */
1620 if (meta
->idx_string_wide
)
1622 if (meta
->idx_guid_wide
)
1624 if (meta
->idx_blob_wide
)
1627 *p
++ = 1; /* reserved */
1628 int64val
= (guint64
*)p
;
1629 *int64val
++ = GUINT64_TO_LE (valid_mask
);
1630 *int64val
++ = GUINT64_TO_LE (valid_mask
& sorted_mask
); /* bitvector of sorted tables */
1632 int32val
= (guint32
*)p
;
1633 for (i
= 0; i
< MONO_TABLE_NUM
; i
++){
1634 if (meta
->tables
[i
].rows
== 0)
1636 *int32val
++ = GUINT32_TO_LE (meta
->tables
[i
].rows
);
1638 p
= (unsigned char*)int32val
;
1640 /* sort the tables that still need sorting */
1641 table
= &assembly
->tables
[MONO_TABLE_CONSTANT
];
1643 qsort (table
->values
+ MONO_CONSTANT_SIZE
, table
->rows
, sizeof (guint32
) * MONO_CONSTANT_SIZE
, compare_constants
);
1644 table
= &assembly
->tables
[MONO_TABLE_METHODSEMANTICS
];
1646 qsort (table
->values
+ MONO_METHOD_SEMA_SIZE
, table
->rows
, sizeof (guint32
) * MONO_METHOD_SEMA_SIZE
, compare_semantics
);
1647 table
= &assembly
->tables
[MONO_TABLE_CUSTOMATTRIBUTE
];
1649 qsort (table
->values
+ MONO_CUSTOM_ATTR_SIZE
, table
->rows
, sizeof (guint32
) * MONO_CUSTOM_ATTR_SIZE
, compare_custom_attrs
);
1650 table
= &assembly
->tables
[MONO_TABLE_FIELDMARSHAL
];
1652 qsort (table
->values
+ MONO_FIELD_MARSHAL_SIZE
, table
->rows
, sizeof (guint32
) * MONO_FIELD_MARSHAL_SIZE
, compare_field_marshal
);
1653 table
= &assembly
->tables
[MONO_TABLE_NESTEDCLASS
];
1655 qsort (table
->values
+ MONO_NESTED_CLASS_SIZE
, table
->rows
, sizeof (guint32
) * MONO_NESTED_CLASS_SIZE
, compare_nested
);
1656 /* Section 21.11 DeclSecurity in Partition II doesn't specify this to be sorted by MS implementation requires it */
1657 table
= &assembly
->tables
[MONO_TABLE_DECLSECURITY
];
1659 qsort (table
->values
+ MONO_DECL_SECURITY_SIZE
, table
->rows
, sizeof (guint32
) * MONO_DECL_SECURITY_SIZE
, compare_declsecurity_attrs
);
1660 table
= &assembly
->tables
[MONO_TABLE_INTERFACEIMPL
];
1662 qsort (table
->values
+ MONO_INTERFACEIMPL_SIZE
, table
->rows
, sizeof (guint32
) * MONO_INTERFACEIMPL_SIZE
, compare_interface_impl
);
1664 /* compress the tables */
1665 for (i
= 0; i
< MONO_TABLE_NUM
; i
++){
1668 guint32 bitfield
= meta
->tables
[i
].size_bitfield
;
1669 if (!meta
->tables
[i
].rows
)
1671 if (assembly
->tables
[i
].columns
!= mono_metadata_table_count (bitfield
))
1672 g_error ("col count mismatch in %d: %d %d", i
, assembly
->tables
[i
].columns
, mono_metadata_table_count (bitfield
));
1673 meta
->tables
[i
].base
= (char*)p
;
1674 for (row
= 1; row
<= meta
->tables
[i
].rows
; ++row
) {
1675 values
= assembly
->tables
[i
].values
+ row
* assembly
->tables
[i
].columns
;
1676 for (col
= 0; col
< assembly
->tables
[i
].columns
; ++col
) {
1677 switch (mono_metadata_table_size (bitfield
, col
)) {
1679 *p
++ = values
[col
];
1682 *p
++ = values
[col
] & 0xff;
1683 *p
++ = (values
[col
] >> 8) & 0xff;
1686 *p
++ = values
[col
] & 0xff;
1687 *p
++ = (values
[col
] >> 8) & 0xff;
1688 *p
++ = (values
[col
] >> 16) & 0xff;
1689 *p
++ = (values
[col
] >> 24) & 0xff;
1692 g_assert_not_reached ();
1696 g_assert ((p
- (const unsigned char*)meta
->tables
[i
].base
) == (meta
->tables
[i
].rows
* meta
->tables
[i
].row_size
));
1699 g_assert (assembly
->guid
.offset
+ assembly
->guid
.index
< meta_size
);
1700 memcpy (meta
->raw_metadata
+ assembly
->sheap
.offset
, assembly
->sheap
.data
, assembly
->sheap
.index
);
1701 memcpy (meta
->raw_metadata
+ assembly
->us
.offset
, assembly
->us
.data
, assembly
->us
.index
);
1702 memcpy (meta
->raw_metadata
+ assembly
->blob
.offset
, assembly
->blob
.data
, assembly
->blob
.index
);
1703 memcpy (meta
->raw_metadata
+ assembly
->guid
.offset
, assembly
->guid
.data
, assembly
->guid
.index
);
1705 assembly
->meta_size
= assembly
->guid
.offset
+ assembly
->guid
.index
;
1711 * Some tables in metadata need to be sorted according to some criteria, but
1712 * when methods and fields are first created with reflection, they may be assigned a token
1713 * that doesn't correspond to the final token they will get assigned after the sorting.
1714 * ILGenerator.cs keeps a fixup table that maps the position of tokens in the IL code stream
1715 * with the reflection objects that represent them. Once all the tables are set up, the
1716 * reflection objects will contains the correct table index. fixup_method() will fixup the
1717 * tokens for the method with ILGenerator @ilgen.
1720 fixup_method (MonoReflectionILGen
*ilgen
, gpointer value
, MonoDynamicImage
*assembly
)
1722 guint32 code_idx
= GPOINTER_TO_UINT (value
);
1723 MonoReflectionILTokenInfo
*iltoken
;
1724 MonoReflectionTypeBuilder
*tb
;
1725 MonoReflectionArrayMethod
*am
;
1727 unsigned char *target
;
1729 for (i
= 0; i
< ilgen
->num_token_fixups
; ++i
) {
1730 iltoken
= (MonoReflectionILTokenInfo
*)mono_array_addr_with_size_internal (ilgen
->token_fixups
, sizeof (MonoReflectionILTokenInfo
), i
);
1731 target
= (guchar
*)assembly
->code
.data
+ code_idx
+ iltoken
->code_pos
;
1732 MonoClass
*iltoken_member_class
= mono_object_class (iltoken
->member
);
1733 const char *iltoken_member_class_name
= m_class_get_name (iltoken_member_class
);
1734 switch (target
[3]) {
1735 case MONO_TABLE_FIELD
:
1736 if (!strcmp (iltoken_member_class_name
, "FieldBuilder")) {
1737 g_assert_not_reached ();
1738 } else if (!strcmp (iltoken_member_class_name
, "RuntimeFieldInfo")) {
1739 MonoClassField
*f
= ((MonoReflectionField
*)iltoken
->member
)->field
;
1740 idx
= GPOINTER_TO_UINT (g_hash_table_lookup (assembly
->field_to_table_idx
, f
));
1742 g_assert_not_reached ();
1745 case MONO_TABLE_METHOD
:
1746 if (!strcmp (iltoken_member_class_name
, "MethodBuilder")) {
1747 g_assert_not_reached ();
1748 } else if (!strcmp (iltoken_member_class_name
, "ConstructorBuilder")) {
1749 g_assert_not_reached ();
1750 } else if (!strcmp (iltoken_member_class_name
, "RuntimeMethodInfo") ||
1751 !strcmp (iltoken_member_class_name
, "RuntimeConstructorInfo")) {
1752 MonoMethod
*m
= ((MonoReflectionMethod
*)iltoken
->member
)->method
;
1753 idx
= GPOINTER_TO_UINT (g_hash_table_lookup (assembly
->method_to_table_idx
, m
));
1755 g_assert_not_reached ();
1758 case MONO_TABLE_TYPEDEF
:
1759 if (!strcmp (iltoken_member_class_name
, "TypeBuilder")) {
1760 g_assert_not_reached ();
1761 } else if (!strcmp (iltoken_member_class_name
, "RuntimeType")) {
1762 MonoClass
*k
= mono_class_from_mono_type_internal (((MonoReflectionType
*)iltoken
->member
)->type
);
1763 MonoObject
*obj
= &mono_class_get_ref_info_raw (k
)->type
.object
; /* FIXME use handles */
1765 g_assert (!strcmp (m_class_get_name (mono_object_class (obj
)), "TypeBuilder"));
1766 tb
= (MonoReflectionTypeBuilder
*)obj
;
1767 idx
= tb
->table_idx
;
1769 g_assert_not_reached ();
1772 case MONO_TABLE_TYPEREF
:
1773 g_assert (!strcmp (iltoken_member_class_name
, "RuntimeType"));
1775 k
= mono_class_from_mono_type_internal (((MonoReflectionType
*)iltoken
->member
)->type
);
1777 obj
= &mono_class_get_ref_info_raw (k
)->type
.object
; /* FIXME use handles */
1779 g_assert (!strcmp (m_class_get_name (mono_object_class (obj
)), "TypeBuilder"));
1780 g_assert (((MonoReflectionTypeBuilder
*)obj
)->module
->dynamic_image
!= assembly
);
1782 case MONO_TABLE_MEMBERREF
:
1783 if (!strcmp (iltoken_member_class_name
, "MonoArrayMethod")) {
1784 am
= (MonoReflectionArrayMethod
*)iltoken
->member
;
1785 idx
= am
->table_idx
;
1786 } else if (!strcmp (iltoken_member_class_name
, "RuntimeMethodInfo") ||
1787 !strcmp (iltoken_member_class_name
, "RuntimeConstructorInfo")) {
1788 MonoMethod
*m
= ((MonoReflectionMethod
*)iltoken
->member
)->method
;
1789 g_assert (mono_class_is_ginst (m
->klass
) || mono_class_is_gtd (m
->klass
));
1791 } else if (!strcmp (iltoken_member_class_name
, "FieldBuilder")) {
1792 g_assert_not_reached ();
1794 } else if (!strcmp (iltoken_member_class_name
, "RuntimeFieldInfo")) {
1796 } else if (!strcmp (iltoken_member_class_name
, "MethodBuilder") ||
1797 !strcmp (iltoken_member_class_name
, "ConstructorBuilder")) {
1798 g_assert_not_reached ();
1800 } else if (!strcmp (iltoken_member_class_name
, "FieldOnTypeBuilderInst")) {
1801 g_assert_not_reached ();
1803 } else if (!strcmp (iltoken_member_class_name
, "MethodOnTypeBuilderInst")) {
1804 g_assert_not_reached ();
1806 } else if (!strcmp (iltoken_member_class_name
, "ConstructorOnTypeBuilderInst")) {
1807 g_assert_not_reached ();
1810 g_assert_not_reached ();
1813 case MONO_TABLE_METHODSPEC
:
1814 if (!strcmp (iltoken_member_class_name
, "RuntimeMethodInfo")) {
1815 MonoMethod
*m
= ((MonoReflectionMethod
*)iltoken
->member
)->method
;
1816 g_assert (mono_method_signature_internal (m
)->generic_param_count
);
1818 } else if (!strcmp (iltoken_member_class_name
, "MethodBuilder")) {
1819 g_assert_not_reached ();
1821 } else if (!strcmp (iltoken_member_class_name
, "MethodOnTypeBuilderInst")) {
1822 g_assert_not_reached ();
1825 g_assert_not_reached ();
1828 case MONO_TABLE_TYPESPEC
:
1829 if (!strcmp (iltoken_member_class_name
, "RuntimeType")) {
1832 g_assert_not_reached ();
1836 g_error ("got unexpected table 0x%02x in fixup", target
[3]);
1838 target
[0] = idx
& 0xff;
1839 target
[1] = (idx
>> 8) & 0xff;
1840 target
[2] = (idx
>> 16) & 0xff;
1847 * The CUSTOM_ATTRIBUTE table might contain METHODDEF tokens whose final
1848 * value is not known when the table is emitted.
1851 fixup_cattrs (MonoDynamicImage
*assembly
)
1853 MonoDynamicTable
*table
;
1855 guint32 type
, i
, idx
, token
;
1858 table
= &assembly
->tables
[MONO_TABLE_CUSTOMATTRIBUTE
];
1860 for (i
= 0; i
< table
->rows
; ++i
) {
1861 values
= table
->values
+ ((i
+ 1) * MONO_CUSTOM_ATTR_SIZE
);
1863 type
= values
[MONO_CUSTOM_ATTR_TYPE
];
1864 if ((type
& MONO_CUSTOM_ATTR_TYPE_MASK
) == MONO_CUSTOM_ATTR_TYPE_METHODDEF
) {
1865 idx
= type
>> MONO_CUSTOM_ATTR_TYPE_BITS
;
1866 token
= mono_metadata_make_token (MONO_TABLE_METHOD
, idx
);
1867 ctor
= (MonoObject
*)mono_g_hash_table_lookup (assembly
->remapped_tokens
, GUINT_TO_POINTER (token
));
1870 if (!strcmp (m_class_get_name (mono_object_class (ctor
)), "RuntimeConstructorInfo")) {
1871 MonoMethod
*m
= ((MonoReflectionMethod
*)ctor
)->method
;
1872 idx
= GPOINTER_TO_UINT (g_hash_table_lookup (assembly
->method_to_table_idx
, m
));
1873 values
[MONO_CUSTOM_ATTR_TYPE
] = (idx
<< MONO_CUSTOM_ATTR_TYPE_BITS
) | MONO_CUSTOM_ATTR_TYPE_METHODDEF
;
1874 } else if (!strcmp (m_class_get_name (mono_object_class (ctor
)), "ConstructorBuilder")) {
1875 MonoMethod
*m
= ((MonoReflectionCtorBuilder
*)ctor
)->mhandle
;
1876 idx
= GPOINTER_TO_UINT (g_hash_table_lookup (assembly
->method_to_table_idx
, m
));
1877 values
[MONO_CUSTOM_ATTR_TYPE
] = (idx
<< MONO_CUSTOM_ATTR_TYPE_BITS
) | MONO_CUSTOM_ATTR_TYPE_METHODDEF
;
1884 assembly_add_resource_manifest (MonoReflectionModuleBuilder
*mb
, MonoDynamicImage
*assembly
, MonoReflectionResource
*rsrc
, guint32 implementation
, MonoError
*error
)
1886 MonoDynamicTable
*table
;
1891 table
= &assembly
->tables
[MONO_TABLE_MANIFESTRESOURCE
];
1893 alloc_table (table
, table
->rows
);
1894 values
= table
->values
+ table
->next_idx
* MONO_MANIFEST_SIZE
;
1895 values
[MONO_MANIFEST_OFFSET
] = rsrc
->offset
;
1896 values
[MONO_MANIFEST_FLAGS
] = rsrc
->attrs
;
1897 values
[MONO_MANIFEST_NAME
] = string_heap_insert_mstring (&assembly
->sheap
, rsrc
->name
, error
);
1898 return_val_if_nok (error
, FALSE
);
1899 values
[MONO_MANIFEST_IMPLEMENTATION
] = implementation
;
1905 assembly_add_resource (MonoReflectionModuleBuilder
*mb
, MonoDynamicImage
*assembly
, MonoReflectionResource
*rsrc
, MonoError
*error
)
1907 MonoDynamicTable
*table
;
1911 char *b
= blob_size
;
1913 guint32 idx
, offset
;
1917 if (rsrc
->filename
) {
1918 name
= mono_string_to_utf8_checked_internal (rsrc
->filename
, error
);
1919 return_val_if_nok (error
, FALSE
);
1920 sname
= g_path_get_basename (name
);
1922 table
= &assembly
->tables
[MONO_TABLE_FILE
];
1924 alloc_table (table
, table
->rows
);
1925 values
= table
->values
+ table
->next_idx
* MONO_FILE_SIZE
;
1926 values
[MONO_FILE_FLAGS
] = FILE_CONTAINS_NO_METADATA
;
1927 values
[MONO_FILE_NAME
] = string_heap_insert (&assembly
->sheap
, sname
);
1930 mono_sha1_get_digest_from_file (name
, hash
);
1931 mono_metadata_encode_value (20, b
, &b
);
1932 values
[MONO_FILE_HASH_VALUE
] = mono_image_add_stream_data (&assembly
->blob
, blob_size
, b
-blob_size
);
1933 mono_image_add_stream_data (&assembly
->blob
, (char*)hash
, 20);
1935 idx
= table
->next_idx
++;
1937 idx
= MONO_IMPLEMENTATION_FILE
| (idx
<< MONO_IMPLEMENTATION_BITS
);
1943 data
= mono_array_addr_internal (rsrc
->data
, char, 0);
1944 len
= mono_array_length_internal (rsrc
->data
);
1950 sizebuf
[0] = offset
; sizebuf
[1] = offset
>> 8;
1951 sizebuf
[2] = offset
>> 16; sizebuf
[3] = offset
>> 24;
1952 rsrc
->offset
= mono_image_add_stream_data (&assembly
->resources
, sizebuf
, 4);
1953 mono_image_add_stream_data (&assembly
->resources
, data
, len
);
1957 * The entry should be emitted into the MANIFESTRESOURCE table of
1958 * the main module, but that needs to reference the FILE table
1959 * which isn't emitted yet.
1966 return assembly_add_resource_manifest (mb
, assembly
, rsrc
, idx
, error
);
1970 set_version_from_string (MonoString
*version
, guint32
*values
, MonoError
*error
)
1972 gchar
*ver
, *p
, *str
;
1977 values
[MONO_ASSEMBLY_MAJOR_VERSION
] = 0;
1978 values
[MONO_ASSEMBLY_MINOR_VERSION
] = 0;
1979 values
[MONO_ASSEMBLY_REV_NUMBER
] = 0;
1980 values
[MONO_ASSEMBLY_BUILD_NUMBER
] = 0;
1983 ver
= str
= mono_string_to_utf8_checked_internal (version
, error
);
1984 return_val_if_nok (error
, FALSE
);
1985 for (i
= 0; i
< 4; ++i
) {
1986 values
[MONO_ASSEMBLY_MAJOR_VERSION
+ i
] = strtol (ver
, &p
, 10);
1992 /* handle Revision and Build */
2003 load_public_key (MonoArray
*pkey
, MonoDynamicImage
*assembly
) {
2007 char *b
= blob_size
;
2012 len
= mono_array_length_internal (pkey
);
2013 mono_metadata_encode_value (len
, b
, &b
);
2014 token
= mono_image_add_stream_data (&assembly
->blob
, blob_size
, b
- blob_size
);
2015 mono_image_add_stream_data (&assembly
->blob
, mono_array_addr_internal (pkey
, char, 0), len
);
2017 assembly
->public_key
= (guint8
*)g_malloc (len
);
2018 memcpy (assembly
->public_key
, mono_array_addr_internal (pkey
, char, 0), len
);
2019 assembly
->public_key_len
= len
;
2021 /* Special case: check for ECMA key (16 bytes) */
2022 if ((len
== MONO_ECMA_KEY_LENGTH
) && mono_is_ecma_key (mono_array_addr_internal (pkey
, char, 0), len
)) {
2023 /* In this case we must reserve 128 bytes (1024 bits) for the signature */
2024 assembly
->strong_name_size
= MONO_DEFAULT_PUBLIC_KEY_LENGTH
;
2025 } else if (len
>= MONO_PUBLIC_KEY_HEADER_LENGTH
+ MONO_MINIMUM_PUBLIC_KEY_LENGTH
) {
2026 /* minimum key size (in 2.0) is 384 bits */
2027 assembly
->strong_name_size
= len
- MONO_PUBLIC_KEY_HEADER_LENGTH
;
2029 /* FIXME - verifier */
2030 g_warning ("Invalid public key length: %d bits (total: %d)", (int)MONO_PUBLIC_KEY_BIT_SIZE (len
), (int)len
);
2031 assembly
->strong_name_size
= MONO_DEFAULT_PUBLIC_KEY_LENGTH
; /* to be safe */
2033 assembly
->strong_name
= (char *)g_malloc0 (assembly
->strong_name_size
);
2039 mono_image_emit_manifest (MonoReflectionModuleBuilder
*moduleb
, MonoError
*error
)
2041 MonoDynamicTable
*table
;
2042 MonoDynamicImage
*assembly
;
2043 MonoReflectionAssemblyBuilder
*assemblyb
;
2047 guint32 module_index
;
2051 assemblyb
= moduleb
->assemblyb
;
2052 assembly
= moduleb
->dynamic_image
;
2053 domain
= mono_object_domain (assemblyb
);
2055 /* Emit ASSEMBLY table */
2056 table
= &assembly
->tables
[MONO_TABLE_ASSEMBLY
];
2057 alloc_table (table
, 1);
2058 values
= table
->values
+ MONO_ASSEMBLY_SIZE
;
2059 values
[MONO_ASSEMBLY_HASH_ALG
] = assemblyb
->algid
? assemblyb
->algid
: ASSEMBLY_HASH_SHA1
;
2060 values
[MONO_ASSEMBLY_NAME
] = string_heap_insert_mstring (&assembly
->sheap
, assemblyb
->name
, error
);
2061 return_val_if_nok (error
, FALSE
);
2062 if (assemblyb
->culture
) {
2063 values
[MONO_ASSEMBLY_CULTURE
] = string_heap_insert_mstring (&assembly
->sheap
, assemblyb
->culture
, error
);
2064 return_val_if_nok (error
, FALSE
);
2066 values
[MONO_ASSEMBLY_CULTURE
] = string_heap_insert (&assembly
->sheap
, "");
2068 values
[MONO_ASSEMBLY_PUBLIC_KEY
] = load_public_key (assemblyb
->public_key
, assembly
);
2069 values
[MONO_ASSEMBLY_FLAGS
] = assemblyb
->flags
;
2070 if (!set_version_from_string (assemblyb
->version
, values
, error
))
2073 /* Emit FILE + EXPORTED_TYPE table */
2075 for (i
= 0; i
< mono_array_length_internal (assemblyb
->modules
); ++i
) {
2077 MonoReflectionModuleBuilder
*file_module
=
2078 mono_array_get_internal (assemblyb
->modules
, MonoReflectionModuleBuilder
*, i
);
2079 if (file_module
!= moduleb
) {
2080 if (!mono_image_fill_file_table (domain
, (MonoReflectionModule
*)file_module
, assembly
, error
))
2083 if (file_module
->types
) {
2084 for (j
= 0; j
< file_module
->num_types
; ++j
) {
2085 MonoReflectionTypeBuilder
*tb
= mono_array_get_internal (file_module
->types
, MonoReflectionTypeBuilder
*, j
);
2086 mono_image_fill_export_table (domain
, tb
, module_index
, 0, assembly
, error
);
2087 return_val_if_nok (error
, FALSE
);
2092 if (assemblyb
->loaded_modules
) {
2093 for (i
= 0; i
< mono_array_length_internal (assemblyb
->loaded_modules
); ++i
) {
2094 MonoReflectionModule
*file_module
=
2095 mono_array_get_internal (assemblyb
->loaded_modules
, MonoReflectionModule
*, i
);
2096 if (!mono_image_fill_file_table (domain
, file_module
, assembly
, error
))
2099 mono_image_fill_export_table_from_module (domain
, file_module
, module_index
, assembly
);
2102 if (assemblyb
->type_forwarders
)
2103 mono_image_fill_export_table_from_type_forwarders (assemblyb
, assembly
);
2105 /* Emit MANIFESTRESOURCE table */
2107 for (i
= 0; i
< mono_array_length_internal (assemblyb
->modules
); ++i
) {
2109 MonoReflectionModuleBuilder
*file_module
=
2110 mono_array_get_internal (assemblyb
->modules
, MonoReflectionModuleBuilder
*, i
);
2111 /* The table for the main module is emitted later */
2112 if (file_module
!= moduleb
) {
2114 if (file_module
->resources
) {
2115 int len
= mono_array_length_internal (file_module
->resources
);
2116 for (j
= 0; j
< len
; ++j
) {
2117 MonoReflectionResource
* res
= (MonoReflectionResource
*)mono_array_addr_internal (file_module
->resources
, MonoReflectionResource
, j
);
2118 if (!assembly_add_resource_manifest (file_module
, assembly
, res
, MONO_IMPLEMENTATION_FILE
| (module_index
<< MONO_IMPLEMENTATION_BITS
), error
))
2127 #ifndef DISABLE_REFLECTION_EMIT_SAVE
2130 * Insert into the metadata tables all the info about the TypeBuilder tb.
2131 * Data in the tables is inserted in a predefined order, since some tables need to be sorted.
2134 mono_image_get_type_info (MonoDomain
*domain
, MonoReflectionTypeBuilder
*tb
, MonoDynamicImage
*assembly
, MonoError
*error
)
2136 MonoDynamicTable
*table
;
2138 int i
, is_object
= 0, is_system
= 0;
2143 table
= &assembly
->tables
[MONO_TABLE_TYPEDEF
];
2144 values
= table
->values
+ tb
->table_idx
* MONO_TYPEDEF_SIZE
;
2145 values
[MONO_TYPEDEF_FLAGS
] = tb
->attrs
;
2146 n
= mono_string_to_utf8_checked_internal (tb
->name
, error
);
2147 return_val_if_nok (error
, FALSE
);
2148 if (strcmp (n
, "Object") == 0)
2150 values
[MONO_TYPEDEF_NAME
] = string_heap_insert (&assembly
->sheap
, n
);
2152 n
= mono_string_to_utf8_checked_internal (tb
->nspace
, error
);
2153 return_val_if_nok (error
, FALSE
);
2154 if (strcmp (n
, "System") == 0)
2156 values
[MONO_TYPEDEF_NAMESPACE
] = string_heap_insert (&assembly
->sheap
, n
);
2158 if (tb
->parent
&& !(is_system
&& is_object
) &&
2159 !(tb
->attrs
& TYPE_ATTRIBUTE_INTERFACE
)) { /* interfaces don't have a parent */
2160 MonoType
*parent_type
= mono_reflection_type_get_handle ((MonoReflectionType
*)tb
->parent
, error
);
2161 return_val_if_nok (error
, FALSE
);
2162 values
[MONO_TYPEDEF_EXTENDS
] = mono_image_typedef_or_ref (assembly
, parent_type
);
2164 values
[MONO_TYPEDEF_EXTENDS
] = 0;
2166 values
[MONO_TYPEDEF_FIELD_LIST
] = assembly
->tables
[MONO_TABLE_FIELD
].next_idx
;
2167 values
[MONO_TYPEDEF_METHOD_LIST
] = assembly
->tables
[MONO_TABLE_METHOD
].next_idx
;
2170 * if we have explicitlayout or sequentiallayouts, output data in the
2171 * ClassLayout table.
2173 if (((tb
->attrs
& TYPE_ATTRIBUTE_LAYOUT_MASK
) != TYPE_ATTRIBUTE_AUTO_LAYOUT
) &&
2174 ((tb
->class_size
> 0) || (tb
->packing_size
> 0))) {
2175 table
= &assembly
->tables
[MONO_TABLE_CLASSLAYOUT
];
2177 alloc_table (table
, table
->rows
);
2178 values
= table
->values
+ table
->rows
* MONO_CLASS_LAYOUT_SIZE
;
2179 values
[MONO_CLASS_LAYOUT_PARENT
] = tb
->table_idx
;
2180 values
[MONO_CLASS_LAYOUT_CLASS_SIZE
] = tb
->class_size
;
2181 values
[MONO_CLASS_LAYOUT_PACKING_SIZE
] = tb
->packing_size
;
2184 /* handle interfaces */
2185 if (tb
->interfaces
) {
2186 table
= &assembly
->tables
[MONO_TABLE_INTERFACEIMPL
];
2188 table
->rows
+= mono_array_length_internal (tb
->interfaces
);
2189 alloc_table (table
, table
->rows
);
2190 values
= table
->values
+ (i
+ 1) * MONO_INTERFACEIMPL_SIZE
;
2191 for (i
= 0; i
< mono_array_length_internal (tb
->interfaces
); ++i
) {
2192 MonoReflectionType
* iface
= (MonoReflectionType
*) mono_array_get_internal (tb
->interfaces
, gpointer
, i
);
2193 MonoType
*iface_type
= mono_reflection_type_get_handle (iface
, error
);
2194 return_val_if_nok (error
, FALSE
);
2195 values
[MONO_INTERFACEIMPL_CLASS
] = tb
->table_idx
;
2196 values
[MONO_INTERFACEIMPL_INTERFACE
] = mono_image_typedef_or_ref (assembly
, iface_type
);
2197 values
+= MONO_INTERFACEIMPL_SIZE
;
2203 table
= &assembly
->tables
[MONO_TABLE_FIELD
];
2204 table
->rows
+= tb
->num_fields
;
2205 alloc_table (table
, table
->rows
);
2206 for (i
= 0; i
< tb
->num_fields
; ++i
) {
2207 mono_image_get_field_info (
2208 mono_array_get_internal (tb
->fields
, MonoReflectionFieldBuilder
*, i
), assembly
, error
);
2209 return_val_if_nok (error
, FALSE
);
2213 /* handle constructors */
2215 table
= &assembly
->tables
[MONO_TABLE_METHOD
];
2216 table
->rows
+= mono_array_length_internal (tb
->ctors
);
2217 alloc_table (table
, table
->rows
);
2218 for (i
= 0; i
< mono_array_length_internal (tb
->ctors
); ++i
) {
2219 if (!mono_image_get_ctor_info (domain
,
2220 mono_array_get_internal (tb
->ctors
, MonoReflectionCtorBuilder
*, i
),
2226 /* handle methods */
2228 table
= &assembly
->tables
[MONO_TABLE_METHOD
];
2229 table
->rows
+= tb
->num_methods
;
2230 alloc_table (table
, table
->rows
);
2231 for (i
= 0; i
< tb
->num_methods
; ++i
) {
2232 if (!mono_image_get_method_info (
2233 mono_array_get_internal (tb
->methods
, MonoReflectionMethodBuilder
*, i
), assembly
, error
))
2238 /* Do the same with properties etc.. */
2239 if (tb
->events
&& mono_array_length_internal (tb
->events
)) {
2240 table
= &assembly
->tables
[MONO_TABLE_EVENT
];
2241 table
->rows
+= mono_array_length_internal (tb
->events
);
2242 alloc_table (table
, table
->rows
);
2243 table
= &assembly
->tables
[MONO_TABLE_EVENTMAP
];
2245 alloc_table (table
, table
->rows
);
2246 values
= table
->values
+ table
->rows
* MONO_EVENT_MAP_SIZE
;
2247 values
[MONO_EVENT_MAP_PARENT
] = tb
->table_idx
;
2248 values
[MONO_EVENT_MAP_EVENTLIST
] = assembly
->tables
[MONO_TABLE_EVENT
].next_idx
;
2249 for (i
= 0; i
< mono_array_length_internal (tb
->events
); ++i
) {
2250 mono_image_get_event_info (
2251 mono_array_get_internal (tb
->events
, MonoReflectionEventBuilder
*, i
), assembly
, error
);
2252 return_val_if_nok (error
, FALSE
);
2255 if (tb
->properties
&& mono_array_length_internal (tb
->properties
)) {
2256 table
= &assembly
->tables
[MONO_TABLE_PROPERTY
];
2257 table
->rows
+= mono_array_length_internal (tb
->properties
);
2258 alloc_table (table
, table
->rows
);
2259 table
= &assembly
->tables
[MONO_TABLE_PROPERTYMAP
];
2261 alloc_table (table
, table
->rows
);
2262 values
= table
->values
+ table
->rows
* MONO_PROPERTY_MAP_SIZE
;
2263 values
[MONO_PROPERTY_MAP_PARENT
] = tb
->table_idx
;
2264 values
[MONO_PROPERTY_MAP_PROPERTY_LIST
] = assembly
->tables
[MONO_TABLE_PROPERTY
].next_idx
;
2265 for (i
= 0; i
< mono_array_length_internal (tb
->properties
); ++i
) {
2266 mono_image_get_property_info (
2267 mono_array_get_internal (tb
->properties
, MonoReflectionPropertyBuilder
*, i
), assembly
, error
);
2268 return_val_if_nok (error
, FALSE
);
2272 /* handle generic parameters */
2273 if (tb
->generic_params
) {
2274 table
= &assembly
->tables
[MONO_TABLE_GENERICPARAM
];
2275 table
->rows
+= mono_array_length_internal (tb
->generic_params
);
2276 alloc_table (table
, table
->rows
);
2277 for (i
= 0; i
< mono_array_length_internal (tb
->generic_params
); ++i
) {
2278 guint32 owner
= MONO_TYPEORMETHOD_TYPE
| (tb
->table_idx
<< MONO_TYPEORMETHOD_BITS
);
2280 mono_image_get_generic_param_info (
2281 mono_array_get_internal (tb
->generic_params
, MonoReflectionGenericParam
*, i
), owner
, assembly
);
2285 mono_image_add_decl_security (assembly
,
2286 mono_metadata_make_token (MONO_TABLE_TYPEDEF
, tb
->table_idx
), tb
->permissions
);
2289 MonoDynamicTable
*ntable
;
2291 ntable
= &assembly
->tables
[MONO_TABLE_NESTEDCLASS
];
2292 ntable
->rows
+= mono_array_length_internal (tb
->subtypes
);
2293 alloc_table (ntable
, ntable
->rows
);
2294 values
= ntable
->values
+ ntable
->next_idx
* MONO_NESTED_CLASS_SIZE
;
2296 for (i
= 0; i
< mono_array_length_internal (tb
->subtypes
); ++i
) {
2297 MonoReflectionTypeBuilder
*subtype
= mono_array_get_internal (tb
->subtypes
, MonoReflectionTypeBuilder
*, i
);
2299 values
[MONO_NESTED_CLASS_NESTED
] = subtype
->table_idx
;
2300 values
[MONO_NESTED_CLASS_ENCLOSING
] = tb
->table_idx
;
2301 /*g_print ("nesting %s (%d) in %s (%d) (rows %d/%d)\n",
2302 mono_string_to_utf8 (subtype->name), subtype->table_idx,
2303 mono_string_to_utf8 (tb->name), tb->table_idx,
2304 ntable->next_idx, ntable->rows);*/
2305 values
+= MONO_NESTED_CLASS_SIZE
;
2315 * mono_image_build_metadata() will fill the info in all the needed metadata tables
2316 * for the modulebuilder @moduleb.
2317 * At the end of the process, method and field tokens are fixed up and the
2318 * on-disk compressed metadata representation is created.
2319 * Return TRUE on success, or FALSE on failure and sets @error
2322 mono_image_build_metadata (MonoReflectionModuleBuilder
*moduleb
, MonoError
*error
)
2324 MonoDynamicTable
*table
;
2325 MonoDynamicImage
*assembly
;
2326 MonoReflectionAssemblyBuilder
*assemblyb
;
2334 assemblyb
= moduleb
->assemblyb
;
2335 assembly
= moduleb
->dynamic_image
;
2336 domain
= mono_object_domain (assemblyb
);
2338 if (assembly
->text_rva
)
2341 assembly
->text_rva
= START_TEXT_RVA
;
2343 if (moduleb
->is_main
) {
2344 mono_image_emit_manifest (moduleb
, error
);
2345 return_val_if_nok (error
, FALSE
);
2348 table
= &assembly
->tables
[MONO_TABLE_TYPEDEF
];
2349 table
->rows
= 1; /* .<Module> */
2351 alloc_table (table
, table
->rows
);
2353 * Set the first entry.
2355 values
= table
->values
+ table
->columns
;
2356 values
[MONO_TYPEDEF_FLAGS
] = 0;
2357 values
[MONO_TYPEDEF_NAME
] = string_heap_insert (&assembly
->sheap
, "<Module>") ;
2358 values
[MONO_TYPEDEF_NAMESPACE
] = string_heap_insert (&assembly
->sheap
, "") ;
2359 values
[MONO_TYPEDEF_EXTENDS
] = 0;
2360 values
[MONO_TYPEDEF_FIELD_LIST
] = 1;
2361 values
[MONO_TYPEDEF_METHOD_LIST
] = 1;
2364 * handle global methods
2365 * FIXME: test what to do when global methods are defined in multiple modules.
2367 if (moduleb
->global_methods
) {
2368 table
= &assembly
->tables
[MONO_TABLE_METHOD
];
2369 table
->rows
+= mono_array_length_internal (moduleb
->global_methods
);
2370 alloc_table (table
, table
->rows
);
2371 for (i
= 0; i
< mono_array_length_internal (moduleb
->global_methods
); ++i
) {
2372 if (!mono_image_get_method_info (
2373 mono_array_get_internal (moduleb
->global_methods
, MonoReflectionMethodBuilder
*, i
), assembly
, error
))
2377 if (moduleb
->global_fields
) {
2378 table
= &assembly
->tables
[MONO_TABLE_FIELD
];
2379 table
->rows
+= mono_array_length_internal (moduleb
->global_fields
);
2380 alloc_table (table
, table
->rows
);
2381 for (i
= 0; i
< mono_array_length_internal (moduleb
->global_fields
); ++i
) {
2382 mono_image_get_field_info (
2383 mono_array_get_internal (moduleb
->global_fields
, MonoReflectionFieldBuilder
*, i
), assembly
,
2385 goto_if_nok (error
, leave
);
2389 table
= &assembly
->tables
[MONO_TABLE_MODULE
];
2390 alloc_table (table
, 1);
2391 mono_image_fill_module_table (domain
, moduleb
, assembly
, error
);
2392 goto_if_nok (error
, leave
);
2394 /* Collect all types into a list sorted by their table_idx */
2395 mono_ptr_array_init (types
, moduleb
->num_types
, MONO_ROOT_SOURCE_REFLECTION
, NULL
, "Reflection Dynamic Image Type List");
2398 for (i
= 0; i
< moduleb
->num_types
; ++i
) {
2399 MonoReflectionTypeBuilder
*type
= mono_array_get_internal (moduleb
->types
, MonoReflectionTypeBuilder
*, i
);
2400 collect_types (&types
, type
);
2403 mono_ptr_array_sort (types
, (int (*)(const void *, const void *))compare_types_by_table_idx
);
2404 table
= &assembly
->tables
[MONO_TABLE_TYPEDEF
];
2405 table
->rows
+= mono_ptr_array_size (types
);
2406 alloc_table (table
, table
->rows
);
2409 * Emit type names + namespaces at one place inside the string heap,
2410 * so load_class_names () needs to touch fewer pages.
2412 for (i
= 0; i
< mono_ptr_array_size (types
); ++i
) {
2413 MonoReflectionTypeBuilder
*tb
= (MonoReflectionTypeBuilder
*)mono_ptr_array_get (types
, i
);
2414 string_heap_insert_mstring (&assembly
->sheap
, tb
->nspace
, error
);
2415 goto_if_nok (error
, leave_types
);
2417 for (i
= 0; i
< mono_ptr_array_size (types
); ++i
) {
2418 MonoReflectionTypeBuilder
*tb
= (MonoReflectionTypeBuilder
*)mono_ptr_array_get (types
, i
);
2419 string_heap_insert_mstring (&assembly
->sheap
, tb
->name
, error
);
2420 goto_if_nok (error
, leave_types
);
2423 for (i
= 0; i
< mono_ptr_array_size (types
); ++i
) {
2424 MonoReflectionTypeBuilder
*type
= (MonoReflectionTypeBuilder
*)mono_ptr_array_get (types
, i
);
2425 if (!mono_image_get_type_info (domain
, type
, assembly
, error
))
2430 * table->rows is already set above and in mono_image_fill_module_table.
2432 /* add all the custom attributes at the end, once all the indexes are stable */
2433 if (!mono_image_add_cattrs (assembly
, 1, MONO_CUSTOM_ATTR_ASSEMBLY
, assemblyb
->cattrs
, error
))
2436 /* CAS assembly permissions */
2437 if (assemblyb
->permissions_minimum
)
2438 mono_image_add_decl_security (assembly
, mono_metadata_make_token (MONO_TABLE_ASSEMBLY
, 1), assemblyb
->permissions_minimum
);
2439 if (assemblyb
->permissions_optional
)
2440 mono_image_add_decl_security (assembly
, mono_metadata_make_token (MONO_TABLE_ASSEMBLY
, 1), assemblyb
->permissions_optional
);
2441 if (assemblyb
->permissions_refused
)
2442 mono_image_add_decl_security (assembly
, mono_metadata_make_token (MONO_TABLE_ASSEMBLY
, 1), assemblyb
->permissions_refused
);
2444 if (!module_add_cattrs (assembly
, moduleb
, error
))
2448 mono_g_hash_table_foreach (assembly
->token_fixups
, (GHFunc
)fixup_method
, assembly
);
2450 /* Create the MethodImpl table. We do this after emitting all methods so we already know
2451 * the final tokens and don't need another fixup pass. */
2453 if (moduleb
->global_methods
) {
2454 for (i
= 0; i
< mono_array_length_internal (moduleb
->global_methods
); ++i
) {
2455 MonoReflectionMethodBuilder
*mb
= mono_array_get_internal (
2456 moduleb
->global_methods
, MonoReflectionMethodBuilder
*, i
);
2457 if (!mono_image_add_methodimpl (assembly
, mb
, error
))
2462 for (i
= 0; i
< mono_ptr_array_size (types
); ++i
) {
2463 MonoReflectionTypeBuilder
*type
= (MonoReflectionTypeBuilder
*)mono_ptr_array_get (types
, i
);
2464 if (type
->methods
) {
2465 for (j
= 0; j
< type
->num_methods
; ++j
) {
2466 MonoReflectionMethodBuilder
*mb
= mono_array_get_internal (
2467 type
->methods
, MonoReflectionMethodBuilder
*, j
);
2469 if (!mono_image_add_methodimpl (assembly
, mb
, error
))
2475 fixup_cattrs (assembly
);
2478 mono_ptr_array_destroy (types
);
2481 return mono_error_ok (error
);
2484 #else /* DISABLE_REFLECTION_EMIT_SAVE */
2487 mono_image_build_metadata (MonoReflectionModuleBuilder
*moduleb
, MonoError
*error
)
2489 g_error ("This mono runtime was configured with --enable-minimal=reflection_emit_save, so saving of dynamic assemblies is not supported.");
2492 #endif /* DISABLE_REFLECTION_EMIT_SAVE */
2494 #ifndef DISABLE_REFLECTION_EMIT_SAVE
2497 calc_section_size (MonoDynamicImage
*assembly
)
2501 /* alignment constraints */
2502 mono_image_add_stream_zero (&assembly
->code
, 4 - (assembly
->code
.index
% 4));
2503 g_assert ((assembly
->code
.index
% 4) == 0);
2504 assembly
->meta_size
+= 3;
2505 assembly
->meta_size
&= ~3;
2506 mono_image_add_stream_zero (&assembly
->resources
, 4 - (assembly
->resources
.index
% 4));
2507 g_assert ((assembly
->resources
.index
% 4) == 0);
2509 assembly
->sections
[MONO_SECTION_TEXT
].size
= assembly
->meta_size
+ assembly
->code
.index
+ assembly
->resources
.index
+ assembly
->strong_name_size
;
2510 assembly
->sections
[MONO_SECTION_TEXT
].attrs
= SECT_FLAGS_HAS_CODE
| SECT_FLAGS_MEM_EXECUTE
| SECT_FLAGS_MEM_READ
;
2513 if (assembly
->win32_res
) {
2514 guint32 res_size
= (assembly
->win32_res_size
+ 3) & ~3;
2516 assembly
->sections
[MONO_SECTION_RSRC
].size
= res_size
;
2517 assembly
->sections
[MONO_SECTION_RSRC
].attrs
= SECT_FLAGS_HAS_INITIALIZED_DATA
| SECT_FLAGS_MEM_READ
;
2521 assembly
->sections
[MONO_SECTION_RELOC
].size
= 12;
2522 assembly
->sections
[MONO_SECTION_RELOC
].attrs
= SECT_FLAGS_MEM_READ
| SECT_FLAGS_MEM_DISCARDABLE
| SECT_FLAGS_HAS_INITIALIZED_DATA
;
2532 MonoReflectionWin32Resource
*win32_res
; /* Only for leaf nodes */
2536 resource_tree_compare_by_id (gconstpointer a
, gconstpointer b
)
2538 ResTreeNode
*t1
= (ResTreeNode
*)a
;
2539 ResTreeNode
*t2
= (ResTreeNode
*)b
;
2541 return t1
->id
- t2
->id
;
2545 * resource_tree_create:
2547 * Organize the resources into a resource tree.
2549 static ResTreeNode
*
2550 resource_tree_create (MonoArray
*win32_resources
)
2552 ResTreeNode
*tree
, *res_node
, *type_node
, *lang_node
;
2556 tree
= g_new0 (ResTreeNode
, 1);
2558 for (i
= 0; i
< mono_array_length_internal (win32_resources
); ++i
) {
2559 MonoReflectionWin32Resource
*win32_res
=
2560 (MonoReflectionWin32Resource
*)mono_array_addr_internal (win32_resources
, MonoReflectionWin32Resource
, i
);
2564 /* FIXME: BUG: this stores managed references in unmanaged memory */
2565 lang_node
= g_new0 (ResTreeNode
, 1);
2566 lang_node
->id
= win32_res
->lang_id
;
2567 lang_node
->win32_res
= win32_res
;
2569 /* Create type node if neccesary */
2571 for (l
= tree
->children
; l
; l
= l
->next
)
2572 if (((ResTreeNode
*)(l
->data
))->id
== win32_res
->res_type
) {
2573 type_node
= (ResTreeNode
*)l
->data
;
2578 type_node
= g_new0 (ResTreeNode
, 1);
2579 type_node
->id
= win32_res
->res_type
;
2582 * The resource types have to be sorted otherwise
2583 * Windows Explorer can't display the version information.
2585 tree
->children
= g_slist_insert_sorted (tree
->children
,
2586 type_node
, resource_tree_compare_by_id
);
2589 /* Create res node if neccesary */
2591 for (l
= type_node
->children
; l
; l
= l
->next
)
2592 if (((ResTreeNode
*)(l
->data
))->id
== win32_res
->res_id
) {
2593 res_node
= (ResTreeNode
*)l
->data
;
2598 res_node
= g_new0 (ResTreeNode
, 1);
2599 res_node
->id
= win32_res
->res_id
;
2600 type_node
->children
= g_slist_append (type_node
->children
, res_node
);
2603 res_node
->children
= g_slist_append (res_node
->children
, lang_node
);
2610 * resource_tree_encode:
2612 * Encode the resource tree into the format used in the PE file.
2615 resource_tree_encode (ResTreeNode
*node
, char *begin
, char *p
, char **endbuf
)
2618 MonoPEResourceDir dir
;
2619 MonoPEResourceDirEntry dir_entry
;
2620 MonoPEResourceDataEntry data_entry
;
2622 guint32 res_id_entries
;
2625 * For the format of the resource directory, see the article
2626 * "An In-Depth Look into the Win32 Portable Executable File Format" by
2630 memset (&dir
, 0, sizeof (dir
));
2631 memset (&dir_entry
, 0, sizeof (dir_entry
));
2632 memset (&data_entry
, 0, sizeof (data_entry
));
2634 g_assert (sizeof (dir
) == 16);
2635 g_assert (sizeof (dir_entry
) == 8);
2636 g_assert (sizeof (data_entry
) == 16);
2638 node
->offset
= p
- begin
;
2640 /* IMAGE_RESOURCE_DIRECTORY */
2641 res_id_entries
= g_slist_length (node
->children
);
2642 dir
.res_id_entries
= GUINT16_TO_LE (res_id_entries
);
2644 memcpy (p
, &dir
, sizeof (dir
));
2647 /* Reserve space for entries */
2649 p
+= sizeof (dir_entry
) * res_id_entries
;
2651 /* Write children */
2652 for (l
= node
->children
; l
; l
= l
->next
) {
2653 ResTreeNode
*child
= (ResTreeNode
*)l
->data
;
2655 if (child
->win32_res
) {
2658 child
->offset
= p
- begin
;
2660 /* IMAGE_RESOURCE_DATA_ENTRY */
2661 data_entry
.rde_data_offset
= GUINT32_TO_LE (p
- begin
+ sizeof (data_entry
));
2662 size
= mono_array_length_internal (child
->win32_res
->res_data
);
2663 data_entry
.rde_size
= GUINT32_TO_LE (size
);
2665 memcpy (p
, &data_entry
, sizeof (data_entry
));
2666 p
+= sizeof (data_entry
);
2668 memcpy (p
, mono_array_addr_internal (child
->win32_res
->res_data
, char, 0), size
);
2671 resource_tree_encode (child
, begin
, p
, &p
);
2675 /* IMAGE_RESOURCE_ENTRY */
2676 for (l
= node
->children
; l
; l
= l
->next
) {
2677 ResTreeNode
*child
= (ResTreeNode
*)l
->data
;
2679 MONO_PE_RES_DIR_ENTRY_SET_NAME (dir_entry
, FALSE
, child
->id
);
2680 MONO_PE_RES_DIR_ENTRY_SET_DIR (dir_entry
, !child
->win32_res
, child
->offset
);
2682 memcpy (entries
, &dir_entry
, sizeof (dir_entry
));
2683 entries
+= sizeof (dir_entry
);
2690 resource_tree_free (ResTreeNode
* node
)
2693 for (list
= node
->children
; list
; list
= list
->next
)
2694 resource_tree_free ((ResTreeNode
*)list
->data
);
2695 g_slist_free(node
->children
);
2700 assembly_add_win32_resources (MonoDynamicImage
*assembly
, MonoReflectionAssemblyBuilder
*assemblyb
)
2705 MonoReflectionWin32Resource
*win32_res
;
2708 if (!assemblyb
->win32_resources
)
2712 * Resources are stored in a three level tree inside the PE file.
2713 * - level one contains a node for each type of resource
2714 * - level two contains a node for each resource
2715 * - level three contains a node for each instance of a resource for a
2716 * specific language.
2719 tree
= resource_tree_create (assemblyb
->win32_resources
);
2721 /* Estimate the size of the encoded tree */
2723 for (i
= 0; i
< mono_array_length_internal (assemblyb
->win32_resources
); ++i
) {
2724 win32_res
= (MonoReflectionWin32Resource
*)mono_array_addr_internal (assemblyb
->win32_resources
, MonoReflectionWin32Resource
, i
);
2725 size
+= mono_array_length_internal (win32_res
->res_data
);
2727 /* Directory structure */
2728 size
+= mono_array_length_internal (assemblyb
->win32_resources
) * 256;
2729 p
= buf
= (char *)g_malloc (size
);
2731 resource_tree_encode (tree
, p
, p
, &p
);
2733 g_assert (p
- buf
<= size
);
2735 assembly
->win32_res
= (char *)g_malloc (p
- buf
);
2736 assembly
->win32_res_size
= p
- buf
;
2737 memcpy (assembly
->win32_res
, buf
, p
- buf
);
2740 resource_tree_free (tree
);
2744 fixup_resource_directory (char *res_section
, char *p
, guint32 rva
)
2746 MonoPEResourceDir
*dir
= (MonoPEResourceDir
*)p
;
2749 p
+= sizeof (MonoPEResourceDir
);
2750 for (i
= 0; i
< GUINT16_FROM_LE (dir
->res_named_entries
) + GUINT16_FROM_LE (dir
->res_id_entries
); ++i
) {
2751 MonoPEResourceDirEntry
*dir_entry
= (MonoPEResourceDirEntry
*)p
;
2752 char *child
= res_section
+ MONO_PE_RES_DIR_ENTRY_DIR_OFFSET (*dir_entry
);
2753 if (MONO_PE_RES_DIR_ENTRY_IS_DIR (*dir_entry
)) {
2754 fixup_resource_directory (res_section
, child
, rva
);
2756 MonoPEResourceDataEntry
*data_entry
= (MonoPEResourceDataEntry
*)child
;
2757 data_entry
->rde_data_offset
= GUINT32_TO_LE (GUINT32_FROM_LE (data_entry
->rde_data_offset
) + rva
);
2760 p
+= sizeof (MonoPEResourceDirEntry
);
2765 checked_write_file (HANDLE f
, gconstpointer buffer
, guint32 numbytes
)
2768 gint32 win32error
= 0;
2769 if (!mono_w32file_write (f
, buffer
, numbytes
, &dummy
, &win32error
))
2770 g_error ("mono_w32file_write returned %d\n", win32error
);
2774 * mono_image_create_pefile:
2775 * @mb: a module builder object
2777 * This function creates the PE-COFF header, the image sections, the CLI header * etc. all the data is written in
2778 * assembly->pefile where it can be easily retrieved later in chunks.
2781 mono_image_create_pefile (MonoReflectionModuleBuilder
*mb
, HANDLE file
, MonoError
*error
)
2783 MonoMSDOSHeader
*msdos
;
2784 MonoDotNetHeader
*header
;
2785 MonoSectionTable
*section
;
2786 MonoCLIHeader
*cli_header
;
2787 guint32 size
, image_size
, virtual_base
, text_offset
;
2788 guint32 header_start
, section_start
, file_offset
, virtual_offset
;
2789 MonoDynamicImage
*assembly
;
2790 MonoReflectionAssemblyBuilder
*assemblyb
;
2791 MonoDynamicStream pefile_stream
= {0};
2792 MonoDynamicStream
*pefile
= &pefile_stream
;
2794 guint32
*rva
, value
;
2796 static const unsigned char msheader
[] = {
2797 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
2798 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2799 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2800 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
2801 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68,
2802 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f,
2803 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,
2804 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
2809 assemblyb
= mb
->assemblyb
;
2811 mono_reflection_dynimage_basic_init (assemblyb
);
2812 assembly
= mb
->dynamic_image
;
2814 assembly
->pe_kind
= assemblyb
->pe_kind
;
2815 assembly
->machine
= assemblyb
->machine
;
2816 ((MonoDynamicImage
*)assemblyb
->dynamic_assembly
->assembly
.image
)->pe_kind
= assemblyb
->pe_kind
;
2817 ((MonoDynamicImage
*)assemblyb
->dynamic_assembly
->assembly
.image
)->machine
= assemblyb
->machine
;
2819 if (!mono_image_build_metadata (mb
, error
))
2823 if (mb
->is_main
&& assemblyb
->resources
) {
2824 int len
= mono_array_length_internal (assemblyb
->resources
);
2825 for (i
= 0; i
< len
; ++i
) {
2826 if (!assembly_add_resource (mb
, assembly
, (MonoReflectionResource
*)mono_array_addr_internal (assemblyb
->resources
, MonoReflectionResource
, i
), error
))
2831 if (mb
->resources
) {
2832 int len
= mono_array_length_internal (mb
->resources
);
2833 for (i
= 0; i
< len
; ++i
) {
2834 if (!assembly_add_resource (mb
, assembly
, (MonoReflectionResource
*)mono_array_addr_internal (mb
->resources
, MonoReflectionResource
, i
), error
))
2839 if (!build_compressed_metadata (assembly
, error
))
2843 assembly_add_win32_resources (assembly
, assemblyb
);
2845 nsections
= calc_section_size (assembly
);
2847 /* The DOS header and stub */
2848 g_assert (sizeof (MonoMSDOSHeader
) == sizeof (msheader
));
2849 mono_image_add_stream_data (pefile
, (char*)msheader
, sizeof (msheader
));
2851 /* the dotnet header */
2852 header_start
= mono_image_add_stream_zero (pefile
, sizeof (MonoDotNetHeader
));
2854 /* the section tables */
2855 section_start
= mono_image_add_stream_zero (pefile
, sizeof (MonoSectionTable
) * nsections
);
2857 file_offset
= section_start
+ sizeof (MonoSectionTable
) * nsections
;
2858 virtual_offset
= VIRT_ALIGN
;
2861 for (i
= 0; i
< MONO_SECTION_MAX
; ++i
) {
2862 if (!assembly
->sections
[i
].size
)
2865 file_offset
+= FILE_ALIGN
- 1;
2866 file_offset
&= ~(FILE_ALIGN
- 1);
2867 virtual_offset
+= VIRT_ALIGN
- 1;
2868 virtual_offset
&= ~(VIRT_ALIGN
- 1);
2870 assembly
->sections
[i
].offset
= file_offset
;
2871 assembly
->sections
[i
].rva
= virtual_offset
;
2873 file_offset
+= assembly
->sections
[i
].size
;
2874 virtual_offset
+= assembly
->sections
[i
].size
;
2875 image_size
+= (assembly
->sections
[i
].size
+ VIRT_ALIGN
- 1) & ~(VIRT_ALIGN
- 1);
2878 file_offset
+= FILE_ALIGN
- 1;
2879 file_offset
&= ~(FILE_ALIGN
- 1);
2881 image_size
+= section_start
+ sizeof (MonoSectionTable
) * nsections
;
2883 /* back-patch info */
2884 msdos
= (MonoMSDOSHeader
*)pefile
->data
;
2885 msdos
->pe_offset
= GUINT32_FROM_LE (sizeof (MonoMSDOSHeader
));
2887 header
= (MonoDotNetHeader
*)(pefile
->data
+ header_start
);
2888 header
->pesig
[0] = 'P';
2889 header
->pesig
[1] = 'E';
2891 header
->coff
.coff_machine
= GUINT16_FROM_LE (assemblyb
->machine
);
2892 header
->coff
.coff_sections
= GUINT16_FROM_LE (nsections
);
2893 header
->coff
.coff_time
= GUINT32_FROM_LE (time (NULL
));
2894 header
->coff
.coff_opt_header_size
= GUINT16_FROM_LE (sizeof (MonoDotNetHeader
) - sizeof (MonoCOFFHeader
) - 4);
2895 if (assemblyb
->pekind
== 1) {
2897 header
->coff
.coff_attributes
= GUINT16_FROM_LE (0x210e);
2900 header
->coff
.coff_attributes
= GUINT16_FROM_LE (0x010e);
2903 virtual_base
= 0x400000; /* FIXME: 0x10000000 if a DLL */
2905 header
->pe
.pe_magic
= GUINT16_FROM_LE (0x10B);
2906 header
->pe
.pe_major
= 6;
2907 header
->pe
.pe_minor
= 0;
2908 size
= assembly
->sections
[MONO_SECTION_TEXT
].size
;
2909 size
+= FILE_ALIGN
- 1;
2910 size
&= ~(FILE_ALIGN
- 1);
2911 header
->pe
.pe_code_size
= GUINT32_FROM_LE(size
);
2912 size
= assembly
->sections
[MONO_SECTION_RSRC
].size
;
2913 size
+= FILE_ALIGN
- 1;
2914 size
&= ~(FILE_ALIGN
- 1);
2915 header
->pe
.pe_data_size
= GUINT32_FROM_LE(size
);
2916 g_assert (START_TEXT_RVA
== assembly
->sections
[MONO_SECTION_TEXT
].rva
);
2917 header
->pe
.pe_rva_code_base
= GUINT32_FROM_LE (assembly
->sections
[MONO_SECTION_TEXT
].rva
);
2918 header
->pe
.pe_rva_data_base
= GUINT32_FROM_LE (assembly
->sections
[MONO_SECTION_RSRC
].rva
);
2919 /* pe_rva_entry_point always at the beginning of the text section */
2920 header
->pe
.pe_rva_entry_point
= GUINT32_FROM_LE (assembly
->sections
[MONO_SECTION_TEXT
].rva
);
2922 header
->nt
.pe_image_base
= GUINT32_FROM_LE (virtual_base
);
2923 header
->nt
.pe_section_align
= GUINT32_FROM_LE (VIRT_ALIGN
);
2924 header
->nt
.pe_file_alignment
= GUINT32_FROM_LE (FILE_ALIGN
);
2925 header
->nt
.pe_os_major
= GUINT16_FROM_LE (4);
2926 header
->nt
.pe_os_minor
= GUINT16_FROM_LE (0);
2927 header
->nt
.pe_subsys_major
= GUINT16_FROM_LE (4);
2928 size
= section_start
;
2929 size
+= FILE_ALIGN
- 1;
2930 size
&= ~(FILE_ALIGN
- 1);
2931 header
->nt
.pe_header_size
= GUINT32_FROM_LE (size
);
2933 size
+= VIRT_ALIGN
- 1;
2934 size
&= ~(VIRT_ALIGN
- 1);
2935 header
->nt
.pe_image_size
= GUINT32_FROM_LE (size
);
2938 // Translate the PEFileKind value to the value expected by the Windows loader
2944 // PEFileKinds.Dll == 1
2945 // PEFileKinds.ConsoleApplication == 2
2946 // PEFileKinds.WindowApplication == 3
2949 // IMAGE_SUBSYSTEM_WINDOWS_GUI 2 // Image runs in the Windows GUI subsystem.
2950 // IMAGE_SUBSYSTEM_WINDOWS_CUI 3 // Image runs in the Windows character subsystem.
2952 if (assemblyb
->pekind
== 3)
2957 header
->nt
.pe_subsys_required
= GUINT16_FROM_LE (kind
);
2959 header
->nt
.pe_stack_reserve
= GUINT32_FROM_LE (0x00100000);
2960 header
->nt
.pe_stack_commit
= GUINT32_FROM_LE (0x00001000);
2961 header
->nt
.pe_heap_reserve
= GUINT32_FROM_LE (0x00100000);
2962 header
->nt
.pe_heap_commit
= GUINT32_FROM_LE (0x00001000);
2963 header
->nt
.pe_loader_flags
= GUINT32_FROM_LE (0);
2964 header
->nt
.pe_data_dir_count
= GUINT32_FROM_LE (16);
2966 /* fill data directory entries */
2968 header
->datadir
.pe_resource_table
.size
= GUINT32_FROM_LE (assembly
->sections
[MONO_SECTION_RSRC
].size
);
2969 header
->datadir
.pe_resource_table
.rva
= GUINT32_FROM_LE (assembly
->sections
[MONO_SECTION_RSRC
].rva
);
2971 header
->datadir
.pe_reloc_table
.size
= GUINT32_FROM_LE (assembly
->sections
[MONO_SECTION_RELOC
].size
);
2972 header
->datadir
.pe_reloc_table
.rva
= GUINT32_FROM_LE (assembly
->sections
[MONO_SECTION_RELOC
].rva
);
2974 header
->datadir
.pe_cli_header
.size
= GUINT32_FROM_LE (72);
2975 header
->datadir
.pe_cli_header
.rva
= GUINT32_FROM_LE (assembly
->text_rva
+ assembly
->cli_header_offset
);
2976 header
->datadir
.pe_iat
.size
= GUINT32_FROM_LE (8);
2977 header
->datadir
.pe_iat
.rva
= GUINT32_FROM_LE (assembly
->text_rva
+ assembly
->iat_offset
);
2978 /* patch entrypoint name */
2979 if (assemblyb
->pekind
== 1)
2980 memcpy (assembly
->code
.data
+ assembly
->imp_names_offset
+ 2, "_CorDllMain", 12);
2982 memcpy (assembly
->code
.data
+ assembly
->imp_names_offset
+ 2, "_CorExeMain", 12);
2983 /* patch imported function RVA name */
2984 rva
= (guint32
*)(assembly
->code
.data
+ assembly
->iat_offset
);
2985 *rva
= GUINT32_FROM_LE (assembly
->text_rva
+ assembly
->imp_names_offset
);
2987 /* the import table */
2988 header
->datadir
.pe_import_table
.size
= GUINT32_FROM_LE (79); /* FIXME: magic number? */
2989 header
->datadir
.pe_import_table
.rva
= GUINT32_FROM_LE (assembly
->text_rva
+ assembly
->idt_offset
);
2990 /* patch imported dll RVA name and other entries in the dir */
2991 rva
= (guint32
*)(assembly
->code
.data
+ assembly
->idt_offset
+ G_STRUCT_OFFSET (MonoIDT
, name_rva
));
2992 *rva
= GUINT32_FROM_LE (assembly
->text_rva
+ assembly
->imp_names_offset
+ 14); /* 14 is hint+strlen+1 of func name */
2993 rva
= (guint32
*)(assembly
->code
.data
+ assembly
->idt_offset
+ G_STRUCT_OFFSET (MonoIDT
, import_address_table_rva
));
2994 *rva
= GUINT32_FROM_LE (assembly
->text_rva
+ assembly
->iat_offset
);
2995 rva
= (guint32
*)(assembly
->code
.data
+ assembly
->idt_offset
+ G_STRUCT_OFFSET (MonoIDT
, import_lookup_table
));
2996 *rva
= GUINT32_FROM_LE (assembly
->text_rva
+ assembly
->ilt_offset
);
2998 p
= (guchar
*)(assembly
->code
.data
+ assembly
->ilt_offset
);
2999 value
= (assembly
->text_rva
+ assembly
->imp_names_offset
);
3000 *p
++ = (value
) & 0xff;
3001 *p
++ = (value
>> 8) & (0xff);
3002 *p
++ = (value
>> 16) & (0xff);
3003 *p
++ = (value
>> 24) & (0xff);
3005 /* the CLI header info */
3006 cli_header
= (MonoCLIHeader
*)(assembly
->code
.data
+ assembly
->cli_header_offset
);
3007 cli_header
->ch_size
= GUINT32_FROM_LE (72);
3008 cli_header
->ch_runtime_major
= GUINT16_FROM_LE (2);
3009 cli_header
->ch_runtime_minor
= GUINT16_FROM_LE (5);
3010 cli_header
->ch_flags
= GUINT32_FROM_LE (assemblyb
->pe_kind
);
3011 if (assemblyb
->entry_point
) {
3012 guint32 table_idx
= 0;
3013 if (!strcmp (m_class_get_name (mono_object_class (&assemblyb
->entry_point
->object
)), "MethodBuilder")) {
3014 MonoReflectionMethodBuilder
*methodb
= (MonoReflectionMethodBuilder
*)assemblyb
->entry_point
;
3015 table_idx
= methodb
->table_idx
;
3017 table_idx
= GPOINTER_TO_UINT (g_hash_table_lookup (assembly
->method_to_table_idx
, assemblyb
->entry_point
->method
));
3019 cli_header
->ch_entry_point
= GUINT32_FROM_LE (table_idx
| MONO_TOKEN_METHOD_DEF
);
3021 cli_header
->ch_entry_point
= GUINT32_FROM_LE (0);
3023 /* The embedded managed resources */
3024 text_offset
= assembly
->text_rva
+ assembly
->code
.index
;
3025 cli_header
->ch_resources
.rva
= GUINT32_FROM_LE (text_offset
);
3026 cli_header
->ch_resources
.size
= GUINT32_FROM_LE (assembly
->resources
.index
);
3027 text_offset
+= assembly
->resources
.index
;
3028 cli_header
->ch_metadata
.rva
= GUINT32_FROM_LE (text_offset
);
3029 cli_header
->ch_metadata
.size
= GUINT32_FROM_LE (assembly
->meta_size
);
3030 text_offset
+= assembly
->meta_size
;
3031 if (assembly
->strong_name_size
) {
3032 cli_header
->ch_strong_name
.rva
= GUINT32_FROM_LE (text_offset
);
3033 cli_header
->ch_strong_name
.size
= GUINT32_FROM_LE (assembly
->strong_name_size
);
3034 text_offset
+= assembly
->strong_name_size
;
3037 /* write the section tables and section content */
3038 section
= (MonoSectionTable
*)(pefile
->data
+ section_start
);
3039 for (i
= 0; i
< MONO_SECTION_MAX
; ++i
) {
3040 static const char section_names
[][7] = {
3041 ".text", ".rsrc", ".reloc"
3043 if (!assembly
->sections
[i
].size
)
3045 strcpy (section
->st_name
, section_names
[i
]);
3046 /*g_print ("output section %s (%d), size: %d\n", section->st_name, i, assembly->sections [i].size);*/
3047 section
->st_virtual_address
= GUINT32_FROM_LE (assembly
->sections
[i
].rva
);
3048 section
->st_virtual_size
= GUINT32_FROM_LE (assembly
->sections
[i
].size
);
3049 section
->st_raw_data_size
= GUINT32_FROM_LE (GUINT32_TO_LE (section
->st_virtual_size
) + (FILE_ALIGN
- 1));
3050 section
->st_raw_data_size
&= GUINT32_FROM_LE (~(FILE_ALIGN
- 1));
3051 section
->st_raw_data_ptr
= GUINT32_FROM_LE (assembly
->sections
[i
].offset
);
3052 section
->st_flags
= GUINT32_FROM_LE (assembly
->sections
[i
].attrs
);
3056 checked_write_file (file
, pefile
->data
, pefile
->index
);
3058 mono_dynamic_stream_reset (pefile
);
3060 for (i
= 0; i
< MONO_SECTION_MAX
; ++i
) {
3061 if (!assembly
->sections
[i
].size
)
3064 if (mono_w32file_seek (file
, assembly
->sections
[i
].offset
, NULL
, FILE_BEGIN
) == INVALID_SET_FILE_POINTER
)
3065 g_error ("mono_w32file_seek returned %d\n", mono_w32error_get_last ());
3068 case MONO_SECTION_TEXT
:
3069 /* patch entry point */
3070 p
= (guchar
*)(assembly
->code
.data
+ 2);
3071 value
= (virtual_base
+ assembly
->text_rva
+ assembly
->iat_offset
);
3072 *p
++ = (value
) & 0xff;
3073 *p
++ = (value
>> 8) & 0xff;
3074 *p
++ = (value
>> 16) & 0xff;
3075 *p
++ = (value
>> 24) & 0xff;
3077 checked_write_file (file
, assembly
->code
.data
, assembly
->code
.index
);
3078 checked_write_file (file
, assembly
->resources
.data
, assembly
->resources
.index
);
3079 checked_write_file (file
, assembly
->image
.raw_metadata
, assembly
->meta_size
);
3080 checked_write_file (file
, assembly
->strong_name
, assembly
->strong_name_size
);
3083 g_free (assembly
->image
.raw_metadata
);
3085 case MONO_SECTION_RELOC
: {
3089 guint16 type_and_offset
;
3093 g_assert (sizeof (reloc
) == 12);
3095 reloc
.page_rva
= GUINT32_FROM_LE (assembly
->text_rva
);
3096 reloc
.block_size
= GUINT32_FROM_LE (12);
3099 * the entrypoint is always at the start of the text section
3100 * 3 is IMAGE_REL_BASED_HIGHLOW
3101 * 2 is patch_size_rva - text_rva
3103 reloc
.type_and_offset
= GUINT16_FROM_LE ((3 << 12) + (2));
3106 checked_write_file (file
, &reloc
, sizeof (reloc
));
3110 case MONO_SECTION_RSRC
:
3111 if (assembly
->win32_res
) {
3113 /* Fixup the offsets in the IMAGE_RESOURCE_DATA_ENTRY structures */
3114 fixup_resource_directory (assembly
->win32_res
, assembly
->win32_res
, assembly
->sections
[i
].rva
);
3115 checked_write_file (file
, assembly
->win32_res
, assembly
->win32_res_size
);
3119 g_assert_not_reached ();
3123 /* check that the file is properly padded */
3124 if (mono_w32file_seek (file
, file_offset
, NULL
, FILE_BEGIN
) == INVALID_SET_FILE_POINTER
)
3125 g_error ("mono_w32file_seek returned %d\n", mono_w32error_get_last ());
3126 if (! mono_w32file_truncate (file
))
3127 g_error ("mono_w32file_truncate returned %d\n", mono_w32error_get_last ());
3129 mono_dynamic_stream_reset (&assembly
->code
);
3130 mono_dynamic_stream_reset (&assembly
->us
);
3131 mono_dynamic_stream_reset (&assembly
->blob
);
3132 mono_dynamic_stream_reset (&assembly
->guid
);
3133 mono_dynamic_stream_reset (&assembly
->sheap
);
3135 g_hash_table_foreach (assembly
->blob_cache
, (GHFunc
)g_free
, NULL
);
3136 g_hash_table_destroy (assembly
->blob_cache
);
3137 assembly
->blob_cache
= NULL
;
3142 #else /* DISABLE_REFLECTION_EMIT_SAVE */
3145 mono_image_create_pefile (MonoReflectionModuleBuilder
*mb
, HANDLE file
, MonoError
*error
)
3147 g_assert_not_reached ();
3150 #endif /* DISABLE_REFLECTION_EMIT_SAVE */