[sre-save] Handle ConstructorBuilder custom attribute constructors.
[mono-project.git] / mono / metadata / sre-save.c
blobf430028e861594daad59c28c417cdc6ecc937005
1 /*
2 * sre-save.c: Routine for saving an image to a file.
3 *
4 *
5 * Author:
6 * Paolo Molaro (lupus@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
10 * Copyright 2011 Rodrigo Kumpera
11 * Copyright 2016 Microsoft
13 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
16 #include <config.h>
17 #include <glib.h>
19 #include "mono/metadata/dynamic-image-internals.h"
20 #include "mono/metadata/dynamic-stream-internals.h"
21 #include "mono/metadata/mono-ptr-array.h"
22 #include "mono/metadata/object-internals.h"
23 #include "mono/metadata/sre-internals.h"
24 #include "mono/metadata/security-manager.h"
25 #include "mono/metadata/tabledefs.h"
26 #include "mono/metadata/tokentype.h"
27 #include "mono/metadata/w32file.h"
28 #include "mono/metadata/w32error.h"
30 #include "mono/utils/checked-build.h"
31 #include "mono/utils/mono-digest.h"
32 #include "mono/utils/mono-error-internals.h"
33 #include "mono/utils/w32api.h"
35 #define TEXT_OFFSET 512
36 #define CLI_H_SIZE 136
37 #define FILE_ALIGN 512
38 #define VIRT_ALIGN 8192
39 #define START_TEXT_RVA 0x00002000
41 static void mono_image_get_generic_param_info (MonoReflectionGenericParam *gparam, guint32 owner, MonoDynamicImage *assembly);
43 static void
44 alloc_table (MonoDynamicTable *table, guint nrows)
46 mono_dynimage_alloc_table (table, nrows);
49 static guint32
50 string_heap_insert (MonoDynamicStream *sh, const char *str)
52 return mono_dynstream_insert_string (sh, str);
55 static guint32
56 string_heap_insert_mstring (MonoDynamicStream *sh, MonoString *str, MonoError *error)
58 return mono_dynstream_insert_mstring (sh, str, error);
61 static guint32
62 mono_image_add_stream_data (MonoDynamicStream *stream, const char *data, guint32 len)
64 return mono_dynstream_add_data (stream, data, len);
67 static guint32
68 mono_image_add_stream_zero (MonoDynamicStream *stream, guint32 len)
70 return mono_dynstream_add_zero (stream, len);
73 static void
74 stream_data_align (MonoDynamicStream *stream)
76 mono_dynstream_data_align (stream);
79 static guint32
80 mono_image_typedef_or_ref (MonoDynamicImage *assembly, MonoType *type)
82 return mono_dynimage_encode_typedef_or_ref_full (assembly, type, TRUE);
85 static guint32
86 find_index_in_table (MonoDynamicImage *assembly, int table_idx, int col, guint32 token)
88 MONO_REQ_GC_NEUTRAL_MODE;
90 int i;
91 MonoDynamicTable *table;
92 guint32 *values;
94 table = &assembly->tables [table_idx];
96 g_assert (col < table->columns);
98 values = table->values + table->columns;
99 for (i = 1; i <= table->rows; ++i) {
100 if (values [col] == token)
101 return i;
102 values += table->columns;
104 return 0;
108 * Copy len * nelem bytes from val to dest, swapping bytes to LE if necessary.
109 * dest may be misaligned.
111 static void
112 swap_with_size (char *dest, const char* val, int len, int nelem) {
113 MONO_REQ_GC_NEUTRAL_MODE;
114 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
115 int elem;
117 for (elem = 0; elem < nelem; ++elem) {
118 switch (len) {
119 case 1:
120 *dest = *val;
121 break;
122 case 2:
123 dest [0] = val [1];
124 dest [1] = val [0];
125 break;
126 case 4:
127 dest [0] = val [3];
128 dest [1] = val [2];
129 dest [2] = val [1];
130 dest [3] = val [0];
131 break;
132 case 8:
133 dest [0] = val [7];
134 dest [1] = val [6];
135 dest [2] = val [5];
136 dest [3] = val [4];
137 dest [4] = val [3];
138 dest [5] = val [2];
139 dest [6] = val [1];
140 dest [7] = val [0];
141 break;
142 default:
143 g_assert_not_reached ();
145 dest += len;
146 val += len;
148 #else
149 memcpy (dest, val, len * nelem);
150 #endif
153 static guint32
154 add_mono_string_to_blob_cached (MonoDynamicImage *assembly, MonoString *str)
156 MONO_REQ_GC_UNSAFE_MODE;
158 char blob_size [64];
159 char *b = blob_size;
160 guint32 idx = 0, len;
162 len = str->length * 2;
163 mono_metadata_encode_value (len, b, &b);
164 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
166 char *swapped = g_malloc (2 * mono_string_length (str));
167 const char *p = (const char*)mono_string_chars (str);
169 swap_with_size (swapped, p, 2, mono_string_length (str));
170 idx = mono_dynamic_image_add_to_blob_cached (assembly, blob_size, b-blob_size, swapped, len);
171 g_free (swapped);
173 #else
174 idx = mono_dynamic_image_add_to_blob_cached (assembly, blob_size, b-blob_size, (char*)mono_string_chars (str), len);
175 #endif
176 return idx;
179 static guint32
180 image_create_token_raw (MonoDynamicImage *assembly, MonoObject* obj_raw, gboolean create_methodspec, gboolean register_token, MonoError *error)
182 HANDLE_FUNCTION_ENTER (); /* FIXME callers of image_create_token_raw should use handles */
183 mono_error_init (error);
184 MONO_HANDLE_DCL (MonoObject, obj);
185 guint32 result = mono_image_create_token (assembly, obj, create_methodspec, register_token, error);
186 HANDLE_FUNCTION_RETURN_VAL (result);
191 * idx is the table index of the object
192 * type is one of MONO_CUSTOM_ATTR_*
194 static gboolean
195 mono_image_add_cattrs (MonoDynamicImage *assembly, guint32 idx, guint32 type, MonoArray *cattrs, MonoError *error)
197 MONO_REQ_GC_UNSAFE_MODE;
199 MonoDynamicTable *table;
200 MonoReflectionCustomAttr *cattr;
201 guint32 *values;
202 guint32 count, i, token;
203 char blob_size [6];
204 char *p = blob_size;
206 mono_error_init (error);
208 /* it is legal to pass a NULL cattrs: we avoid to use the if in a lot of places */
209 if (!cattrs)
210 return TRUE;
211 count = mono_array_length (cattrs);
212 table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
213 table->rows += count;
214 alloc_table (table, table->rows);
215 values = table->values + table->next_idx * MONO_CUSTOM_ATTR_SIZE;
216 idx <<= MONO_CUSTOM_ATTR_BITS;
217 idx |= type;
218 for (i = 0; i < count; ++i) {
219 cattr = (MonoReflectionCustomAttr*)mono_array_get (cattrs, gpointer, i);
220 values [MONO_CUSTOM_ATTR_PARENT] = idx;
221 g_assert (cattr->ctor != NULL);
222 if (mono_is_sre_ctor_builder (mono_object_class (cattr->ctor))) {
223 MonoReflectionCtorBuilder *ctor = (MonoReflectionCtorBuilder*)cattr->ctor;
224 MonoMethod *method = ctor->mhandle;
225 if (method->klass->image == &assembly->image)
226 token = MONO_TOKEN_METHOD_DEF | ((MonoReflectionCtorBuilder*)cattr->ctor)->table_idx;
227 else
228 token = mono_image_get_methodref_token (assembly, method, FALSE);
229 } else {
230 token = image_create_token_raw (assembly, (MonoObject*)cattr->ctor, FALSE, FALSE, error); /* FIXME use handles */
231 if (!mono_error_ok (error)) goto fail;
233 type = mono_metadata_token_index (token);
234 type <<= MONO_CUSTOM_ATTR_TYPE_BITS;
235 switch (mono_metadata_token_table (token)) {
236 case MONO_TABLE_METHOD:
237 type |= MONO_CUSTOM_ATTR_TYPE_METHODDEF;
239 * fixup_cattrs () needs to fix this up. We can't use image->tokens, since it contains the old token for the
240 * method, not the one returned by mono_image_create_token ().
242 mono_g_hash_table_insert (assembly->remapped_tokens, GUINT_TO_POINTER (token), cattr->ctor);
243 break;
244 case MONO_TABLE_MEMBERREF:
245 type |= MONO_CUSTOM_ATTR_TYPE_MEMBERREF;
246 break;
247 default:
248 g_warning ("got wrong token in custom attr");
249 continue;
251 values [MONO_CUSTOM_ATTR_TYPE] = type;
252 p = blob_size;
253 mono_metadata_encode_value (mono_array_length (cattr->data), p, &p);
254 values [MONO_CUSTOM_ATTR_VALUE] = mono_dynamic_image_add_to_blob_cached (assembly, blob_size, p - blob_size,
255 mono_array_addr (cattr->data, char, 0), mono_array_length (cattr->data));
256 values += MONO_CUSTOM_ATTR_SIZE;
257 ++table->next_idx;
260 return TRUE;
262 fail:
263 return FALSE;
266 static void
267 mono_image_add_decl_security (MonoDynamicImage *assembly, guint32 parent_token, MonoArray *permissions)
269 MONO_REQ_GC_UNSAFE_MODE;
271 MonoDynamicTable *table;
272 guint32 *values;
273 guint32 count, i, idx;
274 MonoReflectionPermissionSet *perm;
276 if (!permissions)
277 return;
279 count = mono_array_length (permissions);
280 table = &assembly->tables [MONO_TABLE_DECLSECURITY];
281 table->rows += count;
282 alloc_table (table, table->rows);
284 for (i = 0; i < mono_array_length (permissions); ++i) {
285 perm = (MonoReflectionPermissionSet*)mono_array_addr (permissions, MonoReflectionPermissionSet, i);
287 values = table->values + table->next_idx * MONO_DECL_SECURITY_SIZE;
289 idx = mono_metadata_token_index (parent_token);
290 idx <<= MONO_HAS_DECL_SECURITY_BITS;
291 switch (mono_metadata_token_table (parent_token)) {
292 case MONO_TABLE_TYPEDEF:
293 idx |= MONO_HAS_DECL_SECURITY_TYPEDEF;
294 break;
295 case MONO_TABLE_METHOD:
296 idx |= MONO_HAS_DECL_SECURITY_METHODDEF;
297 break;
298 case MONO_TABLE_ASSEMBLY:
299 idx |= MONO_HAS_DECL_SECURITY_ASSEMBLY;
300 break;
301 default:
302 g_assert_not_reached ();
305 values [MONO_DECL_SECURITY_ACTION] = perm->action;
306 values [MONO_DECL_SECURITY_PARENT] = idx;
307 values [MONO_DECL_SECURITY_PERMISSIONSET] = add_mono_string_to_blob_cached (assembly, perm->pset);
309 ++table->next_idx;
314 * method_encode_code:
316 * @assembly the assembly
317 * @mb the managed MethodBuilder
318 * @error set on error
320 * Note that the return value is not sensible if @error is set.
322 static guint32
323 method_encode_code (MonoDynamicImage *assembly, ReflectionMethodBuilder *mb, MonoError *error)
325 MONO_REQ_GC_UNSAFE_MODE;
327 char flags = 0;
328 guint32 idx;
329 guint32 code_size;
330 gint32 max_stack, i;
331 gint32 num_locals = 0;
332 gint32 num_exception = 0;
333 gint maybe_small;
334 guint32 fat_flags;
335 char fat_header [12];
336 guint32 int_value;
337 guint16 short_value;
338 guint32 local_sig = 0;
339 guint32 header_size = 12;
340 MonoArray *code;
342 mono_error_init (error);
344 if ((mb->attrs & (METHOD_ATTRIBUTE_PINVOKE_IMPL | METHOD_ATTRIBUTE_ABSTRACT)) ||
345 (mb->iattrs & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)))
346 return 0;
348 /*if (mb->name)
349 g_print ("Encode method %s\n", mono_string_to_utf8 (mb->name));*/
350 if (mb->ilgen) {
351 code = mb->ilgen->code;
352 code_size = mb->ilgen->code_len;
353 max_stack = mb->ilgen->max_stack;
354 num_locals = mb->ilgen->locals ? mono_array_length (mb->ilgen->locals) : 0;
355 if (mb->ilgen->ex_handlers)
356 num_exception = mono_reflection_method_count_clauses (mb->ilgen);
357 } else {
358 code = mb->code;
359 if (code == NULL){
360 MonoError inner_error;
361 char *name = mono_string_to_utf8_checked (mb->name, &inner_error);
362 if (!is_ok (&inner_error)) {
363 name = g_strdup ("");
364 mono_error_cleanup (&inner_error);
366 char *str = g_strdup_printf ("Method %s does not have any IL associated", name);
367 mono_error_set_argument (error, NULL, "a method does not have any IL associated");
368 g_free (str);
369 g_free (name);
370 return 0;
373 code_size = mono_array_length (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);
381 if (maybe_small) {
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 */
386 } else {
387 goto fat_header;
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 (assembly->token_fixups, mb->ilgen, GUINT_TO_POINTER (idx + 1));
393 mono_image_add_stream_data (&assembly->code, mono_array_addr (code, char, 0), code_size);
394 return assembly->text_rva + idx;
396 fat_header:
397 if (num_locals) {
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)
405 fat_flags = 0x03;
406 if (num_exception)
407 fat_flags |= METHOD_HEADER_MORE_SECTS;
408 if (mb->init_locals)
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 (assembly->token_fixups, mb->ilgen, GUINT_TO_POINTER (idx + 12));
423 mono_image_add_stream_data (&assembly->code, mono_array_addr (code, char, 0), code_size);
424 if (num_exception) {
425 unsigned char sheader [4];
426 MonoILExceptionInfo * ex_info;
427 MonoILExceptionBlock * ex_block;
428 int j;
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 */
440 /* reverse order */
441 for (i = mono_array_length (mb->ilgen->ex_handlers) - 1; i >= 0; --i) {
442 ex_info = (MonoILExceptionInfo *)mono_array_addr (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 (ex_info->handlers); ++j) {
446 guint32 val;
447 ex_block = (MonoILExceptionBlock*)mono_array_addr (ex_info->handlers, MonoILExceptionBlock, j);
448 /* the flags */
449 val = GUINT32_TO_LE (ex_block->type);
450 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
451 /* try offset */
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);
457 else
458 val = GUINT32_TO_LE (ex_info->len);
459 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
460 /* handler offset */
461 val = GUINT32_TO_LE (ex_block->start);
462 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
463 /* handler len */
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));
472 } else {
473 if (ex_block->type == MONO_EXCEPTION_CLAUSE_FILTER)
474 val = ex_block->filter_offset;
475 else
476 val = 0;
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);*/
483 } else {
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.
495 static gboolean
496 mono_image_basic_method (ReflectionMethodBuilder *mb, MonoDynamicImage *assembly, MonoError *error)
498 MONO_REQ_GC_UNSAFE_MODE;
500 MonoDynamicTable *table;
501 guint32 *values;
502 guint i, count;
504 mono_error_init (error);
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);
526 if (mb->pinfo) {
527 MonoDynamicTable *mtable;
528 guint32 *mvalues;
530 mtable = &assembly->tables [MONO_TABLE_FIELDMARSHAL];
531 mvalues = mtable->values + mtable->next_idx * MONO_FIELD_MARSHAL_SIZE;
533 count = 0;
534 for (i = 0; i < mono_array_length (mb->pinfo); ++i) {
535 if (mono_array_get (mb->pinfo, gpointer, i))
536 count++;
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 (mb->pinfo); ++i) {
542 MonoReflectionParamBuilder *pb;
543 if ((pb = mono_array_get (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);
549 } else {
550 values [MONO_PARAM_NAME] = 0;
552 values += MONO_PARAM_SIZE;
553 if (pb->marshal_info) {
554 mtable->rows++;
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 guint32 field_type = 0;
564 mtable = &assembly->tables [MONO_TABLE_CONSTANT];
565 mtable->rows ++;
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;
577 return TRUE;
580 static gboolean
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;
587 guint32 *values;
588 guint32 tok;
589 MonoReflectionMethod *m;
590 int i;
592 mono_error_init (error);
594 if (!mb->override_methods)
595 return TRUE;
597 for (i = 0; i < mono_array_length (mb->override_methods); ++i) {
598 m = mono_array_get (mb->override_methods, MonoReflectionMethod*, i);
600 table = &assembly->tables [MONO_TABLE_METHODIMPL];
601 table->rows ++;
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;
613 break;
614 case MONO_TABLE_METHOD:
615 tok = (mono_metadata_token_index (tok) << MONO_METHODDEFORREF_BITS ) | MONO_METHODDEFORREF_METHODDEF;
616 break;
617 default:
618 g_assert_not_reached ();
620 values [MONO_METHODIMPL_DECLARATION] = tok;
623 return TRUE;
626 #ifndef DISABLE_REFLECTION_EMIT
627 static gboolean
628 mono_image_get_method_info (MonoReflectionMethodBuilder *mb, MonoDynamicImage *assembly, MonoError *error)
630 MONO_REQ_GC_UNSAFE_MODE;
632 MonoDynamicTable *table;
633 guint32 *values;
634 ReflectionMethodBuilder rmb;
635 int i;
637 mono_error_init (error);
639 if (!mono_reflection_methodbuilder_from_method_builder (&rmb, mb, error) ||
640 !mono_image_basic_method (&rmb, assembly, error))
641 return FALSE;
643 mb->table_idx = *rmb.table_idx;
645 if (mb->dll) { /* It's a P/Invoke method */
646 guint32 moduleref;
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];
651 table->rows ++;
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 */
657 if (mb->dllentry) {
658 values [MONO_IMPLMAP_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->dllentry, error);
659 return_val_if_nok (error, FALSE);
660 } else {
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];
668 table->rows ++;
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 (mb->generic_params);
678 alloc_table (table, table->rows);
679 for (i = 0; i < mono_array_length (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 (mb->generic_params, gpointer, i), owner, assembly);
687 return TRUE;
690 static gboolean
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))
698 return FALSE;
700 if (!mono_image_basic_method (&rmb, assembly, error))
701 return FALSE;
703 mb->table_idx = *rmb.table_idx;
705 return TRUE;
707 #endif
709 static void
710 mono_image_get_field_info (MonoReflectionFieldBuilder *fb, MonoDynamicImage *assembly, MonoError *error)
712 MONO_REQ_GC_UNSAFE_MODE;
714 mono_error_init (error);
716 MonoDynamicTable *table;
717 guint32 *values;
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 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];
734 table->rows ++;
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];
743 table->rows ++;
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) {
752 guint32 rva_idx;
753 table = &assembly->tables [MONO_TABLE_FIELDRVA];
754 table->rows ++;
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.
761 if (fb->rva_data) {
762 if (mono_array_length (fb->rva_data) >= 10)
763 stream_data_align (&assembly->code);
764 rva_idx = mono_image_add_stream_data (&assembly->code, mono_array_addr (fb->rva_data, char, 0), mono_array_length (fb->rva_data));
765 } else
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];
771 table->rows ++;
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);
780 static void
781 mono_image_get_property_info (MonoReflectionPropertyBuilder *pb, MonoDynamicImage *assembly, MonoError *error)
783 MONO_REQ_GC_UNSAFE_MODE;
785 mono_error_init (error);
787 MonoDynamicTable *table;
788 guint32 *values;
789 guint num_methods = 0;
790 guint32 semaidx;
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)
797 * METHODSEMANTICS
798 * CONSTANT
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];
835 table->rows ++;
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;
845 static void
846 mono_image_get_event_info (MonoReflectionEventBuilder *eb, MonoDynamicImage *assembly, MonoError *error)
848 MONO_REQ_GC_UNSAFE_MODE;
850 MonoDynamicTable *table;
851 guint32 *values;
852 guint num_methods = 0;
853 guint32 semaidx;
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)
860 * METHODSEMANTICS
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;
906 static void
907 encode_constraints (MonoReflectionGenericParam *gparam, guint32 owner, MonoDynamicImage *assembly, MonoError *error)
909 MONO_REQ_GC_UNSAFE_MODE;
911 mono_error_init (error);
913 MonoDynamicTable *table;
914 guint32 num_constraints, i;
915 guint32 *values;
916 guint32 table_idx;
918 table = &assembly->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
919 num_constraints = gparam->iface_constraints ?
920 mono_array_length (gparam->iface_constraints) : 0;
921 table->rows += num_constraints;
922 if (gparam->base_type)
923 table->rows++;
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 (
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);
951 static void
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, "reflection generic parameter");
969 entry->gparam = gparam;
971 g_ptr_array_add (assembly->gen_params, entry);
974 static gboolean
975 write_generic_param_entry (MonoDynamicImage *assembly, GenericParamTableEntry *entry, MonoError *error)
977 MONO_REQ_GC_UNSAFE_MODE;
979 MonoDynamicTable *table;
980 MonoGenericParam *param;
981 guint32 *values;
982 guint32 table_idx;
984 mono_error_init (error);
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_info (param)->name);
1000 if (!mono_image_add_cattrs (assembly, table_idx, MONO_CUSTOM_ATTR_GENERICPAR, entry->gparam->cattrs, error))
1001 return FALSE;
1003 encode_constraints (entry->gparam, table_idx, assembly, error);
1004 return_val_if_nok (error, FALSE);
1006 return TRUE;
1009 static void
1010 collect_types (MonoPtrArray *types, MonoReflectionTypeBuilder *type)
1012 int i;
1014 mono_ptr_array_append (*types, type);
1016 if (!type->subtypes)
1017 return;
1019 for (i = 0; i < mono_array_length (type->subtypes); ++i) {
1020 MonoReflectionTypeBuilder *subtype = mono_array_get (type->subtypes, MonoReflectionTypeBuilder*, i);
1021 collect_types (types, subtype);
1025 static gint
1026 compare_types_by_table_idx (MonoReflectionTypeBuilder **type1, MonoReflectionTypeBuilder **type2)
1028 if ((*type1)->table_idx < (*type2)->table_idx)
1029 return -1;
1030 else
1031 if ((*type1)->table_idx > (*type2)->table_idx)
1032 return 1;
1033 else
1034 return 0;
1037 static gboolean
1038 params_add_cattrs (MonoDynamicImage *assembly, MonoArray *pinfo, MonoError *error) {
1039 int i;
1041 mono_error_init (error);
1042 if (!pinfo)
1043 return TRUE;
1044 for (i = 0; i < mono_array_length (pinfo); ++i) {
1045 MonoReflectionParamBuilder *pb;
1046 pb = mono_array_get (pinfo, MonoReflectionParamBuilder *, i);
1047 if (!pb)
1048 continue;
1049 if (!mono_image_add_cattrs (assembly, pb->table_idx, MONO_CUSTOM_ATTR_PARAMDEF, pb->cattrs, error))
1050 return FALSE;
1053 return TRUE;
1056 static gboolean
1057 type_add_cattrs (MonoDynamicImage *assembly, MonoReflectionTypeBuilder *tb, MonoError *error) {
1058 int i;
1060 mono_error_init (error);
1062 if (!mono_image_add_cattrs (assembly, tb->table_idx, MONO_CUSTOM_ATTR_TYPEDEF, tb->cattrs, error))
1063 return FALSE;
1064 if (tb->fields) {
1065 for (i = 0; i < tb->num_fields; ++i) {
1066 MonoReflectionFieldBuilder* fb;
1067 fb = mono_array_get (tb->fields, MonoReflectionFieldBuilder*, i);
1068 if (!mono_image_add_cattrs (assembly, fb->table_idx, MONO_CUSTOM_ATTR_FIELDDEF, fb->cattrs, error))
1069 return FALSE;
1072 if (tb->events) {
1073 for (i = 0; i < mono_array_length (tb->events); ++i) {
1074 MonoReflectionEventBuilder* eb;
1075 eb = mono_array_get (tb->events, MonoReflectionEventBuilder*, i);
1076 if (!mono_image_add_cattrs (assembly, eb->table_idx, MONO_CUSTOM_ATTR_EVENT, eb->cattrs, error))
1077 return FALSE;
1080 if (tb->properties) {
1081 for (i = 0; i < mono_array_length (tb->properties); ++i) {
1082 MonoReflectionPropertyBuilder* pb;
1083 pb = mono_array_get (tb->properties, MonoReflectionPropertyBuilder*, i);
1084 if (!mono_image_add_cattrs (assembly, pb->table_idx, MONO_CUSTOM_ATTR_PROPERTY, pb->cattrs, error))
1085 return FALSE;
1088 if (tb->ctors) {
1089 for (i = 0; i < mono_array_length (tb->ctors); ++i) {
1090 MonoReflectionCtorBuilder* cb;
1091 cb = mono_array_get (tb->ctors, MonoReflectionCtorBuilder*, i);
1092 if (!mono_image_add_cattrs (assembly, cb->table_idx, MONO_CUSTOM_ATTR_METHODDEF, cb->cattrs, error) ||
1093 !params_add_cattrs (assembly, cb->pinfo, error))
1094 return FALSE;
1098 if (tb->methods) {
1099 for (i = 0; i < tb->num_methods; ++i) {
1100 MonoReflectionMethodBuilder* mb;
1101 mb = mono_array_get (tb->methods, MonoReflectionMethodBuilder*, i);
1102 if (!mono_image_add_cattrs (assembly, mb->table_idx, MONO_CUSTOM_ATTR_METHODDEF, mb->cattrs, error) ||
1103 !params_add_cattrs (assembly, mb->pinfo, error))
1104 return FALSE;
1108 if (tb->subtypes) {
1109 for (i = 0; i < mono_array_length (tb->subtypes); ++i) {
1110 if (!type_add_cattrs (assembly, mono_array_get (tb->subtypes, MonoReflectionTypeBuilder*, i), error))
1111 return FALSE;
1115 return TRUE;
1118 static gboolean
1119 module_add_cattrs (MonoDynamicImage *assembly, MonoReflectionModuleBuilder *moduleb, MonoError *error)
1121 int i;
1123 mono_error_init (error);
1125 if (!mono_image_add_cattrs (assembly, moduleb->table_idx, MONO_CUSTOM_ATTR_MODULE, moduleb->cattrs, error))
1126 return FALSE;
1128 if (moduleb->global_methods) {
1129 for (i = 0; i < mono_array_length (moduleb->global_methods); ++i) {
1130 MonoReflectionMethodBuilder* mb = mono_array_get (moduleb->global_methods, MonoReflectionMethodBuilder*, i);
1131 if (!mono_image_add_cattrs (assembly, mb->table_idx, MONO_CUSTOM_ATTR_METHODDEF, mb->cattrs, error) ||
1132 !params_add_cattrs (assembly, mb->pinfo, error))
1133 return FALSE;
1137 if (moduleb->global_fields) {
1138 for (i = 0; i < mono_array_length (moduleb->global_fields); ++i) {
1139 MonoReflectionFieldBuilder *fb = mono_array_get (moduleb->global_fields, MonoReflectionFieldBuilder*, i);
1140 if (!mono_image_add_cattrs (assembly, fb->table_idx, MONO_CUSTOM_ATTR_FIELDDEF, fb->cattrs, error))
1141 return FALSE;
1145 if (moduleb->types) {
1146 for (i = 0; i < moduleb->num_types; ++i) {
1147 if (!type_add_cattrs (assembly, mono_array_get (moduleb->types, MonoReflectionTypeBuilder*, i), error))
1148 return FALSE;
1152 return TRUE;
1155 static gboolean
1156 mono_image_fill_file_table (MonoDomain *domain, MonoReflectionModule *module, MonoDynamicImage *assembly, MonoError *error)
1158 MonoDynamicTable *table;
1159 guint32 *values;
1160 char blob_size [6];
1161 guchar hash [20];
1162 char *b = blob_size;
1163 char *dir, *path;
1165 mono_error_init (error);
1167 table = &assembly->tables [MONO_TABLE_FILE];
1168 table->rows++;
1169 alloc_table (table, table->rows);
1170 values = table->values + table->next_idx * MONO_FILE_SIZE;
1171 values [MONO_FILE_FLAGS] = FILE_CONTAINS_METADATA;
1172 values [MONO_FILE_NAME] = string_heap_insert (&assembly->sheap, module->image->module_name);
1173 if (image_is_dynamic (module->image)) {
1174 /* This depends on the fact that the main module is emitted last */
1175 dir = mono_string_to_utf8_checked (((MonoReflectionModuleBuilder*)module)->assemblyb->dir, error);
1176 return_val_if_nok (error, FALSE);
1177 path = g_strdup_printf ("%s%c%s", dir, G_DIR_SEPARATOR, module->image->module_name);
1178 } else {
1179 dir = NULL;
1180 path = g_strdup (module->image->name);
1182 mono_sha1_get_digest_from_file (path, hash);
1183 g_free (dir);
1184 g_free (path);
1185 mono_metadata_encode_value (20, b, &b);
1186 values [MONO_FILE_HASH_VALUE] = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
1187 mono_image_add_stream_data (&assembly->blob, (char*)hash, 20);
1188 table->next_idx ++;
1189 return TRUE;
1192 static void
1193 mono_image_fill_module_table (MonoDomain *domain, MonoReflectionModuleBuilder *mb, MonoDynamicImage *assembly, MonoError *error)
1195 MonoDynamicTable *table;
1196 int i;
1198 mono_error_init (error);
1200 table = &assembly->tables [MONO_TABLE_MODULE];
1201 mb->table_idx = table->next_idx ++;
1202 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->module.name, error);
1203 return_if_nok (error);
1204 i = mono_image_add_stream_data (&assembly->guid, mono_array_addr (mb->guid, char, 0), 16);
1205 i /= 16;
1206 ++i;
1207 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_GENERATION] = 0;
1208 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_MVID] = i;
1209 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_ENC] = 0;
1210 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_ENCBASE] = 0;
1213 static guint32
1214 mono_image_fill_export_table_from_class (MonoDomain *domain, MonoClass *klass,
1215 guint32 module_index, guint32 parent_index, MonoDynamicImage *assembly)
1217 MonoDynamicTable *table;
1218 guint32 *values;
1219 guint32 visib, res;
1221 visib = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_VISIBILITY_MASK;
1222 if (! ((visib & TYPE_ATTRIBUTE_PUBLIC) || (visib & TYPE_ATTRIBUTE_NESTED_PUBLIC)))
1223 return 0;
1225 table = &assembly->tables [MONO_TABLE_EXPORTEDTYPE];
1226 table->rows++;
1227 alloc_table (table, table->rows);
1228 values = table->values + table->next_idx * MONO_EXP_TYPE_SIZE;
1230 values [MONO_EXP_TYPE_FLAGS] = mono_class_get_flags (klass);
1231 values [MONO_EXP_TYPE_TYPEDEF] = klass->type_token;
1232 if (klass->nested_in)
1233 values [MONO_EXP_TYPE_IMPLEMENTATION] = (parent_index << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_EXP_TYPE;
1234 else
1235 values [MONO_EXP_TYPE_IMPLEMENTATION] = (module_index << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_FILE;
1236 values [MONO_EXP_TYPE_NAME] = string_heap_insert (&assembly->sheap, klass->name);
1237 values [MONO_EXP_TYPE_NAMESPACE] = string_heap_insert (&assembly->sheap, klass->name_space);
1239 res = table->next_idx;
1241 table->next_idx ++;
1243 /* Emit nested types */
1244 GList *nested_classes = mono_class_get_nested_classes_property (klass);
1245 GList *tmp;
1246 for (tmp = nested_classes; tmp; tmp = tmp->next)
1247 mono_image_fill_export_table_from_class (domain, (MonoClass *)tmp->data, module_index, table->next_idx - 1, assembly);
1249 return res;
1252 static void
1253 mono_image_fill_export_table (MonoDomain *domain, MonoReflectionTypeBuilder *tb,
1254 guint32 module_index, guint32 parent_index, MonoDynamicImage *assembly,
1255 MonoError *error)
1257 MonoClass *klass;
1258 guint32 idx, i;
1260 mono_error_init (error);
1262 MonoType *t = mono_reflection_type_get_handle ((MonoReflectionType*)tb, error);
1263 return_if_nok (error);
1265 klass = mono_class_from_mono_type (t);
1267 klass->type_token = mono_metadata_make_token (MONO_TABLE_TYPEDEF, tb->table_idx);
1269 idx = mono_image_fill_export_table_from_class (domain, klass, module_index,
1270 parent_index, assembly);
1273 * Emit nested types
1274 * We need to do this ourselves since klass->nested_classes is not set up.
1276 if (tb->subtypes) {
1277 for (i = 0; i < mono_array_length (tb->subtypes); ++i) {
1278 mono_image_fill_export_table (domain, mono_array_get (tb->subtypes, MonoReflectionTypeBuilder*, i), module_index, idx, assembly, error);
1279 return_if_nok (error);
1284 static void
1285 mono_image_fill_export_table_from_module (MonoDomain *domain, MonoReflectionModule *module,
1286 guint32 module_index, MonoDynamicImage *assembly)
1288 MonoImage *image = module->image;
1289 MonoTableInfo *t;
1290 guint32 i;
1292 t = &image->tables [MONO_TABLE_TYPEDEF];
1294 for (i = 0; i < t->rows; ++i) {
1295 MonoError error;
1296 MonoClass *klass = mono_class_get_checked (image, mono_metadata_make_token (MONO_TABLE_TYPEDEF, i + 1), &error);
1297 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
1299 if (mono_class_is_public (klass))
1300 mono_image_fill_export_table_from_class (domain, klass, module_index, 0, assembly);
1304 static void
1305 add_exported_type (MonoReflectionAssemblyBuilder *assemblyb, MonoDynamicImage *assembly, MonoClass *klass, guint32 parent_index)
1307 MonoDynamicTable *table;
1308 guint32 *values;
1309 guint32 scope, scope_idx, impl, current_idx;
1310 gboolean forwarder = TRUE;
1311 gpointer iter = NULL;
1312 MonoClass *nested;
1314 if (klass->nested_in) {
1315 impl = (parent_index << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_EXP_TYPE;
1316 forwarder = FALSE;
1317 } else {
1318 scope = mono_reflection_resolution_scope_from_image (assembly, klass->image);
1319 g_assert ((scope & MONO_RESOLUTION_SCOPE_MASK) == MONO_RESOLUTION_SCOPE_ASSEMBLYREF);
1320 scope_idx = scope >> MONO_RESOLUTION_SCOPE_BITS;
1321 impl = (scope_idx << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_ASSEMBLYREF;
1324 table = &assembly->tables [MONO_TABLE_EXPORTEDTYPE];
1326 table->rows++;
1327 alloc_table (table, table->rows);
1328 current_idx = table->next_idx;
1329 values = table->values + current_idx * MONO_EXP_TYPE_SIZE;
1331 values [MONO_EXP_TYPE_FLAGS] = forwarder ? TYPE_ATTRIBUTE_FORWARDER : 0;
1332 values [MONO_EXP_TYPE_TYPEDEF] = 0;
1333 values [MONO_EXP_TYPE_IMPLEMENTATION] = impl;
1334 values [MONO_EXP_TYPE_NAME] = string_heap_insert (&assembly->sheap, klass->name);
1335 values [MONO_EXP_TYPE_NAMESPACE] = string_heap_insert (&assembly->sheap, klass->name_space);
1337 table->next_idx++;
1339 while ((nested = mono_class_get_nested_types (klass, &iter)))
1340 add_exported_type (assemblyb, assembly, nested, current_idx);
1343 static void
1344 mono_image_fill_export_table_from_type_forwarders (MonoReflectionAssemblyBuilder *assemblyb, MonoDynamicImage *assembly)
1346 MonoError error;
1347 MonoClass *klass;
1348 int i;
1350 if (!assemblyb->type_forwarders)
1351 return;
1353 for (i = 0; i < mono_array_length (assemblyb->type_forwarders); ++i) {
1354 MonoReflectionType *t = mono_array_get (assemblyb->type_forwarders, MonoReflectionType *, i);
1355 MonoType *type;
1356 if (!t)
1357 continue;
1359 type = mono_reflection_type_get_handle (t, &error);
1360 mono_error_assert_ok (&error);
1361 g_assert (type);
1363 klass = mono_class_from_mono_type (type);
1365 add_exported_type (assemblyb, assembly, klass, 0);
1369 #define align_pointer(base,p)\
1370 do {\
1371 guint32 __diff = (unsigned char*)(p)-(unsigned char*)(base);\
1372 if (__diff & 3)\
1373 (p) += 4 - (__diff & 3);\
1374 } while (0)
1376 static int
1377 compare_constants (const void *a, const void *b)
1379 const guint32 *a_values = (const guint32 *)a;
1380 const guint32 *b_values = (const guint32 *)b;
1381 return a_values [MONO_CONSTANT_PARENT] - b_values [MONO_CONSTANT_PARENT];
1384 static int
1385 compare_semantics (const void *a, const void *b)
1387 const guint32 *a_values = (const guint32 *)a;
1388 const guint32 *b_values = (const guint32 *)b;
1389 int assoc = a_values [MONO_METHOD_SEMA_ASSOCIATION] - b_values [MONO_METHOD_SEMA_ASSOCIATION];
1390 if (assoc)
1391 return assoc;
1392 return a_values [MONO_METHOD_SEMA_SEMANTICS] - b_values [MONO_METHOD_SEMA_SEMANTICS];
1395 static int
1396 compare_custom_attrs (const void *a, const void *b)
1398 const guint32 *a_values = (const guint32 *)a;
1399 const guint32 *b_values = (const guint32 *)b;
1401 return a_values [MONO_CUSTOM_ATTR_PARENT] - b_values [MONO_CUSTOM_ATTR_PARENT];
1404 static int
1405 compare_field_marshal (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_FIELD_MARSHAL_PARENT] - b_values [MONO_FIELD_MARSHAL_PARENT];
1413 static int
1414 compare_nested (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_NESTED_CLASS_NESTED] - b_values [MONO_NESTED_CLASS_NESTED];
1422 static int
1423 compare_genericparam (const void *a, const void *b)
1425 MonoError error;
1426 const GenericParamTableEntry **a_entry = (const GenericParamTableEntry **) a;
1427 const GenericParamTableEntry **b_entry = (const GenericParamTableEntry **) b;
1429 if ((*b_entry)->owner == (*a_entry)->owner) {
1430 MonoType *a_type = mono_reflection_type_get_handle ((MonoReflectionType*)(*a_entry)->gparam, &error);
1431 mono_error_assert_ok (&error);
1432 MonoType *b_type = mono_reflection_type_get_handle ((MonoReflectionType*)(*b_entry)->gparam, &error);
1433 mono_error_assert_ok (&error);
1434 return
1435 mono_type_get_generic_param_num (a_type) -
1436 mono_type_get_generic_param_num (b_type);
1437 } else
1438 return (*a_entry)->owner - (*b_entry)->owner;
1441 static int
1442 compare_declsecurity_attrs (const void *a, const void *b)
1444 const guint32 *a_values = (const guint32 *)a;
1445 const guint32 *b_values = (const guint32 *)b;
1447 return a_values [MONO_DECL_SECURITY_PARENT] - b_values [MONO_DECL_SECURITY_PARENT];
1450 static int
1451 compare_interface_impl (const void *a, const void *b)
1453 const guint32 *a_values = (const guint32 *)a;
1454 const guint32 *b_values = (const guint32 *)b;
1456 int klass = a_values [MONO_INTERFACEIMPL_CLASS] - b_values [MONO_INTERFACEIMPL_CLASS];
1457 if (klass)
1458 return klass;
1460 return a_values [MONO_INTERFACEIMPL_INTERFACE] - b_values [MONO_INTERFACEIMPL_INTERFACE];
1463 struct StreamDesc {
1464 const char *name;
1465 MonoDynamicStream *stream;
1469 * build_compressed_metadata() fills in the blob of data that represents the
1470 * raw metadata as it will be saved in the PE file. The five streams are output
1471 * and the metadata tables are comnpressed from the guint32 array representation,
1472 * to the compressed on-disk format.
1474 static gboolean
1475 build_compressed_metadata (MonoDynamicImage *assembly, MonoError *error)
1477 MonoDynamicTable *table;
1478 int i;
1479 guint64 valid_mask = 0;
1480 guint64 sorted_mask;
1481 guint32 heapt_size = 0;
1482 guint32 meta_size = 256; /* allow for header and other stuff */
1483 guint32 table_offset;
1484 guint32 ntables = 0;
1485 guint64 *int64val;
1486 guint32 *int32val;
1487 guint16 *int16val;
1488 MonoImage *meta;
1489 unsigned char *p;
1490 struct StreamDesc stream_desc [5];
1492 mono_error_init (error);
1494 qsort (assembly->gen_params->pdata, assembly->gen_params->len, sizeof (gpointer), compare_genericparam);
1495 for (i = 0; i < assembly->gen_params->len; i++) {
1496 GenericParamTableEntry *entry = (GenericParamTableEntry *)g_ptr_array_index (assembly->gen_params, i);
1497 if (!write_generic_param_entry (assembly, entry, error))
1498 return FALSE;
1501 stream_desc [0].name = "#~";
1502 stream_desc [0].stream = &assembly->tstream;
1503 stream_desc [1].name = "#Strings";
1504 stream_desc [1].stream = &assembly->sheap;
1505 stream_desc [2].name = "#US";
1506 stream_desc [2].stream = &assembly->us;
1507 stream_desc [3].name = "#Blob";
1508 stream_desc [3].stream = &assembly->blob;
1509 stream_desc [4].name = "#GUID";
1510 stream_desc [4].stream = &assembly->guid;
1512 /* tables that are sorted */
1513 sorted_mask = ((guint64)1 << MONO_TABLE_CONSTANT) | ((guint64)1 << MONO_TABLE_FIELDMARSHAL)
1514 | ((guint64)1 << MONO_TABLE_METHODSEMANTICS) | ((guint64)1 << MONO_TABLE_CLASSLAYOUT)
1515 | ((guint64)1 << MONO_TABLE_FIELDLAYOUT) | ((guint64)1 << MONO_TABLE_FIELDRVA)
1516 | ((guint64)1 << MONO_TABLE_IMPLMAP) | ((guint64)1 << MONO_TABLE_NESTEDCLASS)
1517 | ((guint64)1 << MONO_TABLE_METHODIMPL) | ((guint64)1 << MONO_TABLE_CUSTOMATTRIBUTE)
1518 | ((guint64)1 << MONO_TABLE_DECLSECURITY) | ((guint64)1 << MONO_TABLE_GENERICPARAM)
1519 | ((guint64)1 << MONO_TABLE_INTERFACEIMPL);
1521 /* Compute table sizes */
1522 /* the MonoImage has already been created in mono_reflection_dynimage_basic_init() */
1523 meta = &assembly->image;
1525 /* sizes should be multiple of 4 */
1526 mono_dynstream_data_align (&assembly->blob);
1527 mono_dynstream_data_align (&assembly->guid);
1528 mono_dynstream_data_align (&assembly->sheap);
1529 mono_dynstream_data_align (&assembly->us);
1531 /* Setup the info used by compute_sizes () */
1532 meta->idx_blob_wide = assembly->blob.index >= 65536 ? 1 : 0;
1533 meta->idx_guid_wide = assembly->guid.index >= 65536 ? 1 : 0;
1534 meta->idx_string_wide = assembly->sheap.index >= 65536 ? 1 : 0;
1536 meta_size += assembly->blob.index;
1537 meta_size += assembly->guid.index;
1538 meta_size += assembly->sheap.index;
1539 meta_size += assembly->us.index;
1541 for (i=0; i < MONO_TABLE_NUM; ++i)
1542 meta->tables [i].rows = assembly->tables [i].rows;
1544 for (i = 0; i < MONO_TABLE_NUM; i++){
1545 if (meta->tables [i].rows == 0)
1546 continue;
1547 valid_mask |= (guint64)1 << i;
1548 ntables ++;
1549 meta->tables [i].row_size = mono_metadata_compute_size (
1550 meta, i, &meta->tables [i].size_bitfield);
1551 heapt_size += meta->tables [i].row_size * meta->tables [i].rows;
1553 heapt_size += 24; /* #~ header size */
1554 heapt_size += ntables * 4;
1555 /* make multiple of 4 */
1556 heapt_size += 3;
1557 heapt_size &= ~3;
1558 meta_size += heapt_size;
1559 meta->raw_metadata = (char *)g_malloc0 (meta_size);
1560 p = (unsigned char*)meta->raw_metadata;
1561 /* the metadata signature */
1562 *p++ = 'B'; *p++ = 'S'; *p++ = 'J'; *p++ = 'B';
1563 /* version numbers and 4 bytes reserved */
1564 int16val = (guint16*)p;
1565 *int16val++ = GUINT16_TO_LE (meta->md_version_major);
1566 *int16val = GUINT16_TO_LE (meta->md_version_minor);
1567 p += 8;
1568 /* version string */
1569 int32val = (guint32*)p;
1570 *int32val = GUINT32_TO_LE ((strlen (meta->version) + 3) & (~3)); /* needs to be multiple of 4 */
1571 p += 4;
1572 memcpy (p, meta->version, strlen (meta->version));
1573 p += GUINT32_FROM_LE (*int32val);
1574 align_pointer (meta->raw_metadata, p);
1575 int16val = (guint16*)p;
1576 *int16val++ = GUINT16_TO_LE (0); /* flags must be 0 */
1577 *int16val = GUINT16_TO_LE (5); /* number of streams */
1578 p += 4;
1581 * write the stream info.
1583 table_offset = (p - (unsigned char*)meta->raw_metadata) + 5 * 8 + 40; /* room needed for stream headers */
1584 table_offset += 3; table_offset &= ~3;
1586 assembly->tstream.index = heapt_size;
1587 for (i = 0; i < 5; ++i) {
1588 int32val = (guint32*)p;
1589 stream_desc [i].stream->offset = table_offset;
1590 *int32val++ = GUINT32_TO_LE (table_offset);
1591 *int32val = GUINT32_TO_LE (stream_desc [i].stream->index);
1592 table_offset += GUINT32_FROM_LE (*int32val);
1593 table_offset += 3; table_offset &= ~3;
1594 p += 8;
1595 strcpy ((char*)p, stream_desc [i].name);
1596 p += strlen (stream_desc [i].name) + 1;
1597 align_pointer (meta->raw_metadata, p);
1600 * now copy the data, the table stream header and contents goes first.
1602 g_assert ((p - (unsigned char*)meta->raw_metadata) < assembly->tstream.offset);
1603 p = (guchar*)meta->raw_metadata + assembly->tstream.offset;
1604 int32val = (guint32*)p;
1605 *int32val = GUINT32_TO_LE (0); /* reserved */
1606 p += 4;
1608 *p++ = 2; /* version */
1609 *p++ = 0;
1611 if (meta->idx_string_wide)
1612 *p |= 0x01;
1613 if (meta->idx_guid_wide)
1614 *p |= 0x02;
1615 if (meta->idx_blob_wide)
1616 *p |= 0x04;
1617 ++p;
1618 *p++ = 1; /* reserved */
1619 int64val = (guint64*)p;
1620 *int64val++ = GUINT64_TO_LE (valid_mask);
1621 *int64val++ = GUINT64_TO_LE (valid_mask & sorted_mask); /* bitvector of sorted tables */
1622 p += 16;
1623 int32val = (guint32*)p;
1624 for (i = 0; i < MONO_TABLE_NUM; i++){
1625 if (meta->tables [i].rows == 0)
1626 continue;
1627 *int32val++ = GUINT32_TO_LE (meta->tables [i].rows);
1629 p = (unsigned char*)int32val;
1631 /* sort the tables that still need sorting */
1632 table = &assembly->tables [MONO_TABLE_CONSTANT];
1633 if (table->rows)
1634 qsort (table->values + MONO_CONSTANT_SIZE, table->rows, sizeof (guint32) * MONO_CONSTANT_SIZE, compare_constants);
1635 table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
1636 if (table->rows)
1637 qsort (table->values + MONO_METHOD_SEMA_SIZE, table->rows, sizeof (guint32) * MONO_METHOD_SEMA_SIZE, compare_semantics);
1638 table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1639 if (table->rows)
1640 qsort (table->values + MONO_CUSTOM_ATTR_SIZE, table->rows, sizeof (guint32) * MONO_CUSTOM_ATTR_SIZE, compare_custom_attrs);
1641 table = &assembly->tables [MONO_TABLE_FIELDMARSHAL];
1642 if (table->rows)
1643 qsort (table->values + MONO_FIELD_MARSHAL_SIZE, table->rows, sizeof (guint32) * MONO_FIELD_MARSHAL_SIZE, compare_field_marshal);
1644 table = &assembly->tables [MONO_TABLE_NESTEDCLASS];
1645 if (table->rows)
1646 qsort (table->values + MONO_NESTED_CLASS_SIZE, table->rows, sizeof (guint32) * MONO_NESTED_CLASS_SIZE, compare_nested);
1647 /* Section 21.11 DeclSecurity in Partition II doesn't specify this to be sorted by MS implementation requires it */
1648 table = &assembly->tables [MONO_TABLE_DECLSECURITY];
1649 if (table->rows)
1650 qsort (table->values + MONO_DECL_SECURITY_SIZE, table->rows, sizeof (guint32) * MONO_DECL_SECURITY_SIZE, compare_declsecurity_attrs);
1651 table = &assembly->tables [MONO_TABLE_INTERFACEIMPL];
1652 if (table->rows)
1653 qsort (table->values + MONO_INTERFACEIMPL_SIZE, table->rows, sizeof (guint32) * MONO_INTERFACEIMPL_SIZE, compare_interface_impl);
1655 /* compress the tables */
1656 for (i = 0; i < MONO_TABLE_NUM; i++){
1657 int row, col;
1658 guint32 *values;
1659 guint32 bitfield = meta->tables [i].size_bitfield;
1660 if (!meta->tables [i].rows)
1661 continue;
1662 if (assembly->tables [i].columns != mono_metadata_table_count (bitfield))
1663 g_error ("col count mismatch in %d: %d %d", i, assembly->tables [i].columns, mono_metadata_table_count (bitfield));
1664 meta->tables [i].base = (char*)p;
1665 for (row = 1; row <= meta->tables [i].rows; ++row) {
1666 values = assembly->tables [i].values + row * assembly->tables [i].columns;
1667 for (col = 0; col < assembly->tables [i].columns; ++col) {
1668 switch (mono_metadata_table_size (bitfield, col)) {
1669 case 1:
1670 *p++ = values [col];
1671 break;
1672 case 2:
1673 *p++ = values [col] & 0xff;
1674 *p++ = (values [col] >> 8) & 0xff;
1675 break;
1676 case 4:
1677 *p++ = values [col] & 0xff;
1678 *p++ = (values [col] >> 8) & 0xff;
1679 *p++ = (values [col] >> 16) & 0xff;
1680 *p++ = (values [col] >> 24) & 0xff;
1681 break;
1682 default:
1683 g_assert_not_reached ();
1687 g_assert ((p - (const unsigned char*)meta->tables [i].base) == (meta->tables [i].rows * meta->tables [i].row_size));
1690 g_assert (assembly->guid.offset + assembly->guid.index < meta_size);
1691 memcpy (meta->raw_metadata + assembly->sheap.offset, assembly->sheap.data, assembly->sheap.index);
1692 memcpy (meta->raw_metadata + assembly->us.offset, assembly->us.data, assembly->us.index);
1693 memcpy (meta->raw_metadata + assembly->blob.offset, assembly->blob.data, assembly->blob.index);
1694 memcpy (meta->raw_metadata + assembly->guid.offset, assembly->guid.data, assembly->guid.index);
1696 assembly->meta_size = assembly->guid.offset + assembly->guid.index;
1698 return TRUE;
1702 * Some tables in metadata need to be sorted according to some criteria, but
1703 * when methods and fields are first created with reflection, they may be assigned a token
1704 * that doesn't correspond to the final token they will get assigned after the sorting.
1705 * ILGenerator.cs keeps a fixup table that maps the position of tokens in the IL code stream
1706 * with the reflection objects that represent them. Once all the tables are set up, the
1707 * reflection objects will contains the correct table index. fixup_method() will fixup the
1708 * tokens for the method with ILGenerator @ilgen.
1710 static void
1711 fixup_method (MonoReflectionILGen *ilgen, gpointer value, MonoDynamicImage *assembly)
1713 guint32 code_idx = GPOINTER_TO_UINT (value);
1714 MonoReflectionILTokenInfo *iltoken;
1715 MonoReflectionTypeBuilder *tb;
1716 MonoReflectionArrayMethod *am;
1717 guint32 i, idx = 0;
1718 unsigned char *target;
1720 for (i = 0; i < ilgen->num_token_fixups; ++i) {
1721 iltoken = (MonoReflectionILTokenInfo *)mono_array_addr_with_size (ilgen->token_fixups, sizeof (MonoReflectionILTokenInfo), i);
1722 target = (guchar*)assembly->code.data + code_idx + iltoken->code_pos;
1723 switch (target [3]) {
1724 case MONO_TABLE_FIELD:
1725 if (!strcmp (iltoken->member->vtable->klass->name, "FieldBuilder")) {
1726 g_assert_not_reached ();
1727 } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoField")) {
1728 MonoClassField *f = ((MonoReflectionField*)iltoken->member)->field;
1729 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->field_to_table_idx, f));
1730 } else {
1731 g_assert_not_reached ();
1733 break;
1734 case MONO_TABLE_METHOD:
1735 if (!strcmp (iltoken->member->vtable->klass->name, "MethodBuilder")) {
1736 g_assert_not_reached ();
1737 } else if (!strcmp (iltoken->member->vtable->klass->name, "ConstructorBuilder")) {
1738 g_assert_not_reached ();
1739 } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoMethod") ||
1740 !strcmp (iltoken->member->vtable->klass->name, "MonoCMethod")) {
1741 MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
1742 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, m));
1743 } else {
1744 g_assert_not_reached ();
1746 break;
1747 case MONO_TABLE_TYPEDEF:
1748 if (!strcmp (iltoken->member->vtable->klass->name, "TypeBuilder")) {
1749 g_assert_not_reached ();
1750 } else if (!strcmp (iltoken->member->vtable->klass->name, "RuntimeType")) {
1751 MonoClass *k = mono_class_from_mono_type (((MonoReflectionType*)iltoken->member)->type);
1752 MonoObject *obj = mono_class_get_ref_info_raw (k); /* FIXME use handles */
1753 g_assert (obj);
1754 g_assert (!strcmp (mono_object_class (obj)->name, "TypeBuilder"));
1755 tb = (MonoReflectionTypeBuilder*)obj;
1756 idx = tb->table_idx;
1757 } else {
1758 g_assert_not_reached ();
1760 break;
1761 case MONO_TABLE_MEMBERREF:
1762 if (!strcmp (iltoken->member->vtable->klass->name, "MonoArrayMethod")) {
1763 am = (MonoReflectionArrayMethod*)iltoken->member;
1764 idx = am->table_idx;
1765 } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoMethod") ||
1766 !strcmp (iltoken->member->vtable->klass->name, "MonoCMethod")) {
1767 MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
1768 g_assert (mono_class_is_ginst (m->klass) || mono_class_is_gtd (m->klass));
1769 continue;
1770 } else if (!strcmp (iltoken->member->vtable->klass->name, "FieldBuilder")) {
1771 g_assert_not_reached ();
1772 continue;
1773 } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoField")) {
1774 continue;
1775 } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodBuilder") ||
1776 !strcmp (iltoken->member->vtable->klass->name, "ConstructorBuilder")) {
1777 g_assert_not_reached ();
1778 continue;
1779 } else if (!strcmp (iltoken->member->vtable->klass->name, "FieldOnTypeBuilderInst")) {
1780 g_assert_not_reached ();
1781 continue;
1782 } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodOnTypeBuilderInst")) {
1783 g_assert_not_reached ();
1784 continue;
1785 } else if (!strcmp (iltoken->member->vtable->klass->name, "ConstructorOnTypeBuilderInst")) {
1786 g_assert_not_reached ();
1787 continue;
1788 } else {
1789 g_assert_not_reached ();
1791 break;
1792 case MONO_TABLE_METHODSPEC:
1793 if (!strcmp (iltoken->member->vtable->klass->name, "MonoMethod")) {
1794 MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
1795 g_assert (mono_method_signature (m)->generic_param_count);
1796 continue;
1797 } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodBuilder")) {
1798 g_assert_not_reached ();
1799 continue;
1800 } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodOnTypeBuilderInst")) {
1801 g_assert_not_reached ();
1802 continue;
1803 } else {
1804 g_assert_not_reached ();
1806 break;
1807 case MONO_TABLE_TYPESPEC:
1808 if (!strcmp (iltoken->member->vtable->klass->name, "RuntimeType")) {
1809 continue;
1810 } else {
1811 g_assert_not_reached ();
1813 break;
1814 default:
1815 g_error ("got unexpected table 0x%02x in fixup", target [3]);
1817 target [0] = idx & 0xff;
1818 target [1] = (idx >> 8) & 0xff;
1819 target [2] = (idx >> 16) & 0xff;
1824 * fixup_cattrs:
1826 * The CUSTOM_ATTRIBUTE table might contain METHODDEF tokens whose final
1827 * value is not known when the table is emitted.
1829 static void
1830 fixup_cattrs (MonoDynamicImage *assembly)
1832 MonoDynamicTable *table;
1833 guint32 *values;
1834 guint32 type, i, idx, token;
1835 MonoObject *ctor;
1837 table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1839 for (i = 0; i < table->rows; ++i) {
1840 values = table->values + ((i + 1) * MONO_CUSTOM_ATTR_SIZE);
1842 type = values [MONO_CUSTOM_ATTR_TYPE];
1843 if ((type & MONO_CUSTOM_ATTR_TYPE_MASK) == MONO_CUSTOM_ATTR_TYPE_METHODDEF) {
1844 idx = type >> MONO_CUSTOM_ATTR_TYPE_BITS;
1845 token = mono_metadata_make_token (MONO_TABLE_METHOD, idx);
1846 ctor = (MonoObject *)mono_g_hash_table_lookup (assembly->remapped_tokens, GUINT_TO_POINTER (token));
1847 g_assert (ctor);
1849 if (!strcmp (ctor->vtable->klass->name, "MonoCMethod")) {
1850 MonoMethod *m = ((MonoReflectionMethod*)ctor)->method;
1851 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, m));
1852 values [MONO_CUSTOM_ATTR_TYPE] = (idx << MONO_CUSTOM_ATTR_TYPE_BITS) | MONO_CUSTOM_ATTR_TYPE_METHODDEF;
1853 } else if (!strcmp (ctor->vtable->klass->name, "ConstructorBuilder")) {
1854 MonoMethod *m = ((MonoReflectionCtorBuilder*)ctor)->mhandle;
1855 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, m));
1856 values [MONO_CUSTOM_ATTR_TYPE] = (idx << MONO_CUSTOM_ATTR_TYPE_BITS) | MONO_CUSTOM_ATTR_TYPE_METHODDEF;
1862 static gboolean
1863 assembly_add_resource_manifest (MonoReflectionModuleBuilder *mb, MonoDynamicImage *assembly, MonoReflectionResource *rsrc, guint32 implementation, MonoError *error)
1865 MonoDynamicTable *table;
1866 guint32 *values;
1868 mono_error_init (error);
1870 table = &assembly->tables [MONO_TABLE_MANIFESTRESOURCE];
1871 table->rows++;
1872 alloc_table (table, table->rows);
1873 values = table->values + table->next_idx * MONO_MANIFEST_SIZE;
1874 values [MONO_MANIFEST_OFFSET] = rsrc->offset;
1875 values [MONO_MANIFEST_FLAGS] = rsrc->attrs;
1876 values [MONO_MANIFEST_NAME] = string_heap_insert_mstring (&assembly->sheap, rsrc->name, error);
1877 return_val_if_nok (error, FALSE);
1878 values [MONO_MANIFEST_IMPLEMENTATION] = implementation;
1879 table->next_idx++;
1880 return TRUE;
1883 static gboolean
1884 assembly_add_resource (MonoReflectionModuleBuilder *mb, MonoDynamicImage *assembly, MonoReflectionResource *rsrc, MonoError *error)
1886 MonoDynamicTable *table;
1887 guint32 *values;
1888 char blob_size [6];
1889 guchar hash [20];
1890 char *b = blob_size;
1891 char *name, *sname;
1892 guint32 idx, offset;
1894 mono_error_init (error);
1896 if (rsrc->filename) {
1897 name = mono_string_to_utf8_checked (rsrc->filename, error);
1898 return_val_if_nok (error, FALSE);
1899 sname = g_path_get_basename (name);
1901 table = &assembly->tables [MONO_TABLE_FILE];
1902 table->rows++;
1903 alloc_table (table, table->rows);
1904 values = table->values + table->next_idx * MONO_FILE_SIZE;
1905 values [MONO_FILE_FLAGS] = FILE_CONTAINS_NO_METADATA;
1906 values [MONO_FILE_NAME] = string_heap_insert (&assembly->sheap, sname);
1907 g_free (sname);
1909 mono_sha1_get_digest_from_file (name, hash);
1910 mono_metadata_encode_value (20, b, &b);
1911 values [MONO_FILE_HASH_VALUE] = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
1912 mono_image_add_stream_data (&assembly->blob, (char*)hash, 20);
1913 g_free (name);
1914 idx = table->next_idx++;
1915 rsrc->offset = 0;
1916 idx = MONO_IMPLEMENTATION_FILE | (idx << MONO_IMPLEMENTATION_BITS);
1917 } else {
1918 char sizebuf [4];
1919 char *data;
1920 guint len;
1921 if (rsrc->data) {
1922 data = mono_array_addr (rsrc->data, char, 0);
1923 len = mono_array_length (rsrc->data);
1924 } else {
1925 data = NULL;
1926 len = 0;
1928 offset = len;
1929 sizebuf [0] = offset; sizebuf [1] = offset >> 8;
1930 sizebuf [2] = offset >> 16; sizebuf [3] = offset >> 24;
1931 rsrc->offset = mono_image_add_stream_data (&assembly->resources, sizebuf, 4);
1932 mono_image_add_stream_data (&assembly->resources, data, len);
1934 if (!mb->is_main)
1936 * The entry should be emitted into the MANIFESTRESOURCE table of
1937 * the main module, but that needs to reference the FILE table
1938 * which isn't emitted yet.
1940 return TRUE;
1941 else
1942 idx = 0;
1945 return assembly_add_resource_manifest (mb, assembly, rsrc, idx, error);
1948 static gboolean
1949 set_version_from_string (MonoString *version, guint32 *values, MonoError *error)
1951 gchar *ver, *p, *str;
1952 guint32 i;
1954 mono_error_init (error);
1956 values [MONO_ASSEMBLY_MAJOR_VERSION] = 0;
1957 values [MONO_ASSEMBLY_MINOR_VERSION] = 0;
1958 values [MONO_ASSEMBLY_REV_NUMBER] = 0;
1959 values [MONO_ASSEMBLY_BUILD_NUMBER] = 0;
1960 if (!version)
1961 return TRUE;
1962 ver = str = mono_string_to_utf8_checked (version, error);
1963 return_val_if_nok (error, FALSE);
1964 for (i = 0; i < 4; ++i) {
1965 values [MONO_ASSEMBLY_MAJOR_VERSION + i] = strtol (ver, &p, 10);
1966 switch (*p) {
1967 case '.':
1968 p++;
1969 break;
1970 case '*':
1971 /* handle Revision and Build */
1972 p++;
1973 break;
1975 ver = p;
1977 g_free (str);
1978 return TRUE;
1981 static guint32
1982 load_public_key (MonoArray *pkey, MonoDynamicImage *assembly) {
1983 gsize len;
1984 guint32 token = 0;
1985 char blob_size [6];
1986 char *b = blob_size;
1988 if (!pkey)
1989 return token;
1991 len = mono_array_length (pkey);
1992 mono_metadata_encode_value (len, b, &b);
1993 token = mono_image_add_stream_data (&assembly->blob, blob_size, b - blob_size);
1994 mono_image_add_stream_data (&assembly->blob, mono_array_addr (pkey, char, 0), len);
1996 assembly->public_key = (guint8 *)g_malloc (len);
1997 memcpy (assembly->public_key, mono_array_addr (pkey, char, 0), len);
1998 assembly->public_key_len = len;
2000 /* Special case: check for ECMA key (16 bytes) */
2001 if ((len == MONO_ECMA_KEY_LENGTH) && mono_is_ecma_key (mono_array_addr (pkey, char, 0), len)) {
2002 /* In this case we must reserve 128 bytes (1024 bits) for the signature */
2003 assembly->strong_name_size = MONO_DEFAULT_PUBLIC_KEY_LENGTH;
2004 } else if (len >= MONO_PUBLIC_KEY_HEADER_LENGTH + MONO_MINIMUM_PUBLIC_KEY_LENGTH) {
2005 /* minimum key size (in 2.0) is 384 bits */
2006 assembly->strong_name_size = len - MONO_PUBLIC_KEY_HEADER_LENGTH;
2007 } else {
2008 /* FIXME - verifier */
2009 g_warning ("Invalid public key length: %d bits (total: %d)", (int)MONO_PUBLIC_KEY_BIT_SIZE (len), (int)len);
2010 assembly->strong_name_size = MONO_DEFAULT_PUBLIC_KEY_LENGTH; /* to be safe */
2012 assembly->strong_name = (char *)g_malloc0 (assembly->strong_name_size);
2014 return token;
2017 static gboolean
2018 mono_image_emit_manifest (MonoReflectionModuleBuilder *moduleb, MonoError *error)
2020 MonoDynamicTable *table;
2021 MonoDynamicImage *assembly;
2022 MonoReflectionAssemblyBuilder *assemblyb;
2023 MonoDomain *domain;
2024 guint32 *values;
2025 int i;
2026 guint32 module_index;
2028 mono_error_init (error);
2030 assemblyb = moduleb->assemblyb;
2031 assembly = moduleb->dynamic_image;
2032 domain = mono_object_domain (assemblyb);
2034 /* Emit ASSEMBLY table */
2035 table = &assembly->tables [MONO_TABLE_ASSEMBLY];
2036 alloc_table (table, 1);
2037 values = table->values + MONO_ASSEMBLY_SIZE;
2038 values [MONO_ASSEMBLY_HASH_ALG] = assemblyb->algid? assemblyb->algid: ASSEMBLY_HASH_SHA1;
2039 values [MONO_ASSEMBLY_NAME] = string_heap_insert_mstring (&assembly->sheap, assemblyb->name, error);
2040 return_val_if_nok (error, FALSE);
2041 if (assemblyb->culture) {
2042 values [MONO_ASSEMBLY_CULTURE] = string_heap_insert_mstring (&assembly->sheap, assemblyb->culture, error);
2043 return_val_if_nok (error, FALSE);
2044 } else {
2045 values [MONO_ASSEMBLY_CULTURE] = string_heap_insert (&assembly->sheap, "");
2047 values [MONO_ASSEMBLY_PUBLIC_KEY] = load_public_key (assemblyb->public_key, assembly);
2048 values [MONO_ASSEMBLY_FLAGS] = assemblyb->flags;
2049 if (!set_version_from_string (assemblyb->version, values, error))
2050 return FALSE;
2052 /* Emit FILE + EXPORTED_TYPE table */
2053 module_index = 0;
2054 for (i = 0; i < mono_array_length (assemblyb->modules); ++i) {
2055 int j;
2056 MonoReflectionModuleBuilder *file_module =
2057 mono_array_get (assemblyb->modules, MonoReflectionModuleBuilder*, i);
2058 if (file_module != moduleb) {
2059 if (!mono_image_fill_file_table (domain, (MonoReflectionModule*)file_module, assembly, error))
2060 return FALSE;
2061 module_index ++;
2062 if (file_module->types) {
2063 for (j = 0; j < file_module->num_types; ++j) {
2064 MonoReflectionTypeBuilder *tb = mono_array_get (file_module->types, MonoReflectionTypeBuilder*, j);
2065 mono_image_fill_export_table (domain, tb, module_index, 0, assembly, error);
2066 return_val_if_nok (error, FALSE);
2071 if (assemblyb->loaded_modules) {
2072 for (i = 0; i < mono_array_length (assemblyb->loaded_modules); ++i) {
2073 MonoReflectionModule *file_module =
2074 mono_array_get (assemblyb->loaded_modules, MonoReflectionModule*, i);
2075 if (!mono_image_fill_file_table (domain, file_module, assembly, error))
2076 return FALSE;
2077 module_index ++;
2078 mono_image_fill_export_table_from_module (domain, file_module, module_index, assembly);
2081 if (assemblyb->type_forwarders)
2082 mono_image_fill_export_table_from_type_forwarders (assemblyb, assembly);
2084 /* Emit MANIFESTRESOURCE table */
2085 module_index = 0;
2086 for (i = 0; i < mono_array_length (assemblyb->modules); ++i) {
2087 int j;
2088 MonoReflectionModuleBuilder *file_module =
2089 mono_array_get (assemblyb->modules, MonoReflectionModuleBuilder*, i);
2090 /* The table for the main module is emitted later */
2091 if (file_module != moduleb) {
2092 module_index ++;
2093 if (file_module->resources) {
2094 int len = mono_array_length (file_module->resources);
2095 for (j = 0; j < len; ++j) {
2096 MonoReflectionResource* res = (MonoReflectionResource*)mono_array_addr (file_module->resources, MonoReflectionResource, j);
2097 if (!assembly_add_resource_manifest (file_module, assembly, res, MONO_IMPLEMENTATION_FILE | (module_index << MONO_IMPLEMENTATION_BITS), error))
2098 return FALSE;
2103 return TRUE;
2106 #ifndef DISABLE_REFLECTION_EMIT_SAVE
2109 * Insert into the metadata tables all the info about the TypeBuilder tb.
2110 * Data in the tables is inserted in a predefined order, since some tables need to be sorted.
2112 static gboolean
2113 mono_image_get_type_info (MonoDomain *domain, MonoReflectionTypeBuilder *tb, MonoDynamicImage *assembly, MonoError *error)
2115 MonoDynamicTable *table;
2116 guint *values;
2117 int i, is_object = 0, is_system = 0;
2118 char *n;
2120 mono_error_init (error);
2122 table = &assembly->tables [MONO_TABLE_TYPEDEF];
2123 values = table->values + tb->table_idx * MONO_TYPEDEF_SIZE;
2124 values [MONO_TYPEDEF_FLAGS] = tb->attrs;
2125 n = mono_string_to_utf8_checked (tb->name, error);
2126 return_val_if_nok (error, FALSE);
2127 if (strcmp (n, "Object") == 0)
2128 is_object++;
2129 values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, n);
2130 g_free (n);
2131 n = mono_string_to_utf8_checked (tb->nspace, error);
2132 return_val_if_nok (error, FALSE);
2133 if (strcmp (n, "System") == 0)
2134 is_system++;
2135 values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, n);
2136 g_free (n);
2137 if (tb->parent && !(is_system && is_object) &&
2138 !(tb->attrs & TYPE_ATTRIBUTE_INTERFACE)) { /* interfaces don't have a parent */
2139 MonoType *parent_type = mono_reflection_type_get_handle ((MonoReflectionType*)tb->parent, error);
2140 return_val_if_nok (error, FALSE);
2141 values [MONO_TYPEDEF_EXTENDS] = mono_image_typedef_or_ref (assembly, parent_type);
2142 } else {
2143 values [MONO_TYPEDEF_EXTENDS] = 0;
2145 values [MONO_TYPEDEF_FIELD_LIST] = assembly->tables [MONO_TABLE_FIELD].next_idx;
2146 values [MONO_TYPEDEF_METHOD_LIST] = assembly->tables [MONO_TABLE_METHOD].next_idx;
2149 * if we have explicitlayout or sequentiallayouts, output data in the
2150 * ClassLayout table.
2152 if (((tb->attrs & TYPE_ATTRIBUTE_LAYOUT_MASK) != TYPE_ATTRIBUTE_AUTO_LAYOUT) &&
2153 ((tb->class_size > 0) || (tb->packing_size > 0))) {
2154 table = &assembly->tables [MONO_TABLE_CLASSLAYOUT];
2155 table->rows++;
2156 alloc_table (table, table->rows);
2157 values = table->values + table->rows * MONO_CLASS_LAYOUT_SIZE;
2158 values [MONO_CLASS_LAYOUT_PARENT] = tb->table_idx;
2159 values [MONO_CLASS_LAYOUT_CLASS_SIZE] = tb->class_size;
2160 values [MONO_CLASS_LAYOUT_PACKING_SIZE] = tb->packing_size;
2163 /* handle interfaces */
2164 if (tb->interfaces) {
2165 table = &assembly->tables [MONO_TABLE_INTERFACEIMPL];
2166 i = table->rows;
2167 table->rows += mono_array_length (tb->interfaces);
2168 alloc_table (table, table->rows);
2169 values = table->values + (i + 1) * MONO_INTERFACEIMPL_SIZE;
2170 for (i = 0; i < mono_array_length (tb->interfaces); ++i) {
2171 MonoReflectionType* iface = (MonoReflectionType*) mono_array_get (tb->interfaces, gpointer, i);
2172 MonoType *iface_type = mono_reflection_type_get_handle (iface, error);
2173 return_val_if_nok (error, FALSE);
2174 values [MONO_INTERFACEIMPL_CLASS] = tb->table_idx;
2175 values [MONO_INTERFACEIMPL_INTERFACE] = mono_image_typedef_or_ref (assembly, iface_type);
2176 values += MONO_INTERFACEIMPL_SIZE;
2180 /* handle fields */
2181 if (tb->fields) {
2182 table = &assembly->tables [MONO_TABLE_FIELD];
2183 table->rows += tb->num_fields;
2184 alloc_table (table, table->rows);
2185 for (i = 0; i < tb->num_fields; ++i) {
2186 mono_image_get_field_info (
2187 mono_array_get (tb->fields, MonoReflectionFieldBuilder*, i), assembly, error);
2188 return_val_if_nok (error, FALSE);
2192 /* handle constructors */
2193 if (tb->ctors) {
2194 table = &assembly->tables [MONO_TABLE_METHOD];
2195 table->rows += mono_array_length (tb->ctors);
2196 alloc_table (table, table->rows);
2197 for (i = 0; i < mono_array_length (tb->ctors); ++i) {
2198 if (!mono_image_get_ctor_info (domain,
2199 mono_array_get (tb->ctors, MonoReflectionCtorBuilder*, i),
2200 assembly, error))
2201 return FALSE;
2205 /* handle methods */
2206 if (tb->methods) {
2207 table = &assembly->tables [MONO_TABLE_METHOD];
2208 table->rows += tb->num_methods;
2209 alloc_table (table, table->rows);
2210 for (i = 0; i < tb->num_methods; ++i) {
2211 if (!mono_image_get_method_info (
2212 mono_array_get (tb->methods, MonoReflectionMethodBuilder*, i), assembly, error))
2213 return FALSE;
2217 /* Do the same with properties etc.. */
2218 if (tb->events && mono_array_length (tb->events)) {
2219 table = &assembly->tables [MONO_TABLE_EVENT];
2220 table->rows += mono_array_length (tb->events);
2221 alloc_table (table, table->rows);
2222 table = &assembly->tables [MONO_TABLE_EVENTMAP];
2223 table->rows ++;
2224 alloc_table (table, table->rows);
2225 values = table->values + table->rows * MONO_EVENT_MAP_SIZE;
2226 values [MONO_EVENT_MAP_PARENT] = tb->table_idx;
2227 values [MONO_EVENT_MAP_EVENTLIST] = assembly->tables [MONO_TABLE_EVENT].next_idx;
2228 for (i = 0; i < mono_array_length (tb->events); ++i) {
2229 mono_image_get_event_info (
2230 mono_array_get (tb->events, MonoReflectionEventBuilder*, i), assembly, error);
2231 return_val_if_nok (error, FALSE);
2234 if (tb->properties && mono_array_length (tb->properties)) {
2235 table = &assembly->tables [MONO_TABLE_PROPERTY];
2236 table->rows += mono_array_length (tb->properties);
2237 alloc_table (table, table->rows);
2238 table = &assembly->tables [MONO_TABLE_PROPERTYMAP];
2239 table->rows ++;
2240 alloc_table (table, table->rows);
2241 values = table->values + table->rows * MONO_PROPERTY_MAP_SIZE;
2242 values [MONO_PROPERTY_MAP_PARENT] = tb->table_idx;
2243 values [MONO_PROPERTY_MAP_PROPERTY_LIST] = assembly->tables [MONO_TABLE_PROPERTY].next_idx;
2244 for (i = 0; i < mono_array_length (tb->properties); ++i) {
2245 mono_image_get_property_info (
2246 mono_array_get (tb->properties, MonoReflectionPropertyBuilder*, i), assembly, error);
2247 return_val_if_nok (error, FALSE);
2251 /* handle generic parameters */
2252 if (tb->generic_params) {
2253 table = &assembly->tables [MONO_TABLE_GENERICPARAM];
2254 table->rows += mono_array_length (tb->generic_params);
2255 alloc_table (table, table->rows);
2256 for (i = 0; i < mono_array_length (tb->generic_params); ++i) {
2257 guint32 owner = MONO_TYPEORMETHOD_TYPE | (tb->table_idx << MONO_TYPEORMETHOD_BITS);
2259 mono_image_get_generic_param_info (
2260 mono_array_get (tb->generic_params, MonoReflectionGenericParam*, i), owner, assembly);
2264 mono_image_add_decl_security (assembly,
2265 mono_metadata_make_token (MONO_TABLE_TYPEDEF, tb->table_idx), tb->permissions);
2267 if (tb->subtypes) {
2268 MonoDynamicTable *ntable;
2270 ntable = &assembly->tables [MONO_TABLE_NESTEDCLASS];
2271 ntable->rows += mono_array_length (tb->subtypes);
2272 alloc_table (ntable, ntable->rows);
2273 values = ntable->values + ntable->next_idx * MONO_NESTED_CLASS_SIZE;
2275 for (i = 0; i < mono_array_length (tb->subtypes); ++i) {
2276 MonoReflectionTypeBuilder *subtype = mono_array_get (tb->subtypes, MonoReflectionTypeBuilder*, i);
2278 values [MONO_NESTED_CLASS_NESTED] = subtype->table_idx;
2279 values [MONO_NESTED_CLASS_ENCLOSING] = tb->table_idx;
2280 /*g_print ("nesting %s (%d) in %s (%d) (rows %d/%d)\n",
2281 mono_string_to_utf8 (subtype->name), subtype->table_idx,
2282 mono_string_to_utf8 (tb->name), tb->table_idx,
2283 ntable->next_idx, ntable->rows);*/
2284 values += MONO_NESTED_CLASS_SIZE;
2285 ntable->next_idx++;
2289 return TRUE;
2294 * mono_image_build_metadata() will fill the info in all the needed metadata tables
2295 * for the modulebuilder @moduleb.
2296 * At the end of the process, method and field tokens are fixed up and the
2297 * on-disk compressed metadata representation is created.
2298 * Return TRUE on success, or FALSE on failure and sets @error
2300 gboolean
2301 mono_image_build_metadata (MonoReflectionModuleBuilder *moduleb, MonoError *error)
2303 MonoDynamicTable *table;
2304 MonoDynamicImage *assembly;
2305 MonoReflectionAssemblyBuilder *assemblyb;
2306 MonoDomain *domain;
2307 MonoPtrArray types;
2308 guint32 *values;
2309 int i, j;
2311 mono_error_init (error);
2313 assemblyb = moduleb->assemblyb;
2314 assembly = moduleb->dynamic_image;
2315 domain = mono_object_domain (assemblyb);
2317 if (assembly->text_rva)
2318 return TRUE;
2320 assembly->text_rva = START_TEXT_RVA;
2322 if (moduleb->is_main) {
2323 mono_image_emit_manifest (moduleb, error);
2324 return_val_if_nok (error, FALSE);
2327 table = &assembly->tables [MONO_TABLE_TYPEDEF];
2328 table->rows = 1; /* .<Module> */
2329 table->next_idx++;
2330 alloc_table (table, table->rows);
2332 * Set the first entry.
2334 values = table->values + table->columns;
2335 values [MONO_TYPEDEF_FLAGS] = 0;
2336 values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, "<Module>") ;
2337 values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, "") ;
2338 values [MONO_TYPEDEF_EXTENDS] = 0;
2339 values [MONO_TYPEDEF_FIELD_LIST] = 1;
2340 values [MONO_TYPEDEF_METHOD_LIST] = 1;
2343 * handle global methods
2344 * FIXME: test what to do when global methods are defined in multiple modules.
2346 if (moduleb->global_methods) {
2347 table = &assembly->tables [MONO_TABLE_METHOD];
2348 table->rows += mono_array_length (moduleb->global_methods);
2349 alloc_table (table, table->rows);
2350 for (i = 0; i < mono_array_length (moduleb->global_methods); ++i) {
2351 if (!mono_image_get_method_info (
2352 mono_array_get (moduleb->global_methods, MonoReflectionMethodBuilder*, i), assembly, error))
2353 goto leave;
2356 if (moduleb->global_fields) {
2357 table = &assembly->tables [MONO_TABLE_FIELD];
2358 table->rows += mono_array_length (moduleb->global_fields);
2359 alloc_table (table, table->rows);
2360 for (i = 0; i < mono_array_length (moduleb->global_fields); ++i) {
2361 mono_image_get_field_info (
2362 mono_array_get (moduleb->global_fields, MonoReflectionFieldBuilder*, i), assembly,
2363 error);
2364 if (!is_ok (error))
2365 goto leave;
2369 table = &assembly->tables [MONO_TABLE_MODULE];
2370 alloc_table (table, 1);
2371 mono_image_fill_module_table (domain, moduleb, assembly, error);
2372 if (!is_ok (error))
2373 goto leave;
2375 /* Collect all types into a list sorted by their table_idx */
2376 mono_ptr_array_init (types, moduleb->num_types, MONO_ROOT_SOURCE_REFLECTION, "dynamic module types list");
2378 if (moduleb->types)
2379 for (i = 0; i < moduleb->num_types; ++i) {
2380 MonoReflectionTypeBuilder *type = mono_array_get (moduleb->types, MonoReflectionTypeBuilder*, i);
2381 collect_types (&types, type);
2384 mono_ptr_array_sort (types, (int (*)(const void *, const void *))compare_types_by_table_idx);
2385 table = &assembly->tables [MONO_TABLE_TYPEDEF];
2386 table->rows += mono_ptr_array_size (types);
2387 alloc_table (table, table->rows);
2390 * Emit type names + namespaces at one place inside the string heap,
2391 * so load_class_names () needs to touch fewer pages.
2393 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2394 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2395 string_heap_insert_mstring (&assembly->sheap, tb->nspace, error);
2396 if (!is_ok (error))
2397 goto leave_types;
2399 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2400 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2401 string_heap_insert_mstring (&assembly->sheap, tb->name, error);
2402 if (!is_ok (error))
2403 goto leave_types;
2406 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2407 MonoReflectionTypeBuilder *type = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2408 if (!mono_image_get_type_info (domain, type, assembly, error))
2409 goto leave_types;
2413 * table->rows is already set above and in mono_image_fill_module_table.
2415 /* add all the custom attributes at the end, once all the indexes are stable */
2416 if (!mono_image_add_cattrs (assembly, 1, MONO_CUSTOM_ATTR_ASSEMBLY, assemblyb->cattrs, error))
2417 goto leave_types;
2419 /* CAS assembly permissions */
2420 if (assemblyb->permissions_minimum)
2421 mono_image_add_decl_security (assembly, mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1), assemblyb->permissions_minimum);
2422 if (assemblyb->permissions_optional)
2423 mono_image_add_decl_security (assembly, mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1), assemblyb->permissions_optional);
2424 if (assemblyb->permissions_refused)
2425 mono_image_add_decl_security (assembly, mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1), assemblyb->permissions_refused);
2427 if (!module_add_cattrs (assembly, moduleb, error))
2428 goto leave_types;
2430 /* fixup tokens */
2431 mono_g_hash_table_foreach (assembly->token_fixups, (GHFunc)fixup_method, assembly);
2433 /* Create the MethodImpl table. We do this after emitting all methods so we already know
2434 * the final tokens and don't need another fixup pass. */
2436 if (moduleb->global_methods) {
2437 for (i = 0; i < mono_array_length (moduleb->global_methods); ++i) {
2438 MonoReflectionMethodBuilder *mb = mono_array_get (
2439 moduleb->global_methods, MonoReflectionMethodBuilder*, i);
2440 if (!mono_image_add_methodimpl (assembly, mb, error))
2441 goto leave_types;
2445 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2446 MonoReflectionTypeBuilder *type = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2447 if (type->methods) {
2448 for (j = 0; j < type->num_methods; ++j) {
2449 MonoReflectionMethodBuilder *mb = mono_array_get (
2450 type->methods, MonoReflectionMethodBuilder*, j);
2452 if (!mono_image_add_methodimpl (assembly, mb, error))
2453 goto leave_types;
2458 fixup_cattrs (assembly);
2460 leave_types:
2461 mono_ptr_array_destroy (types);
2462 leave:
2464 return mono_error_ok (error);
2467 #else /* DISABLE_REFLECTION_EMIT_SAVE */
2469 gboolean
2470 mono_image_build_metadata (MonoReflectionModuleBuilder *moduleb, MonoError *error)
2472 g_error ("This mono runtime was configured with --enable-minimal=reflection_emit_save, so saving of dynamic assemblies is not supported.");
2475 #endif /* DISABLE_REFLECTION_EMIT_SAVE */
2477 #ifndef DISABLE_REFLECTION_EMIT_SAVE
2479 static int
2480 calc_section_size (MonoDynamicImage *assembly)
2482 int nsections = 0;
2484 /* alignment constraints */
2485 mono_image_add_stream_zero (&assembly->code, 4 - (assembly->code.index % 4));
2486 g_assert ((assembly->code.index % 4) == 0);
2487 assembly->meta_size += 3;
2488 assembly->meta_size &= ~3;
2489 mono_image_add_stream_zero (&assembly->resources, 4 - (assembly->resources.index % 4));
2490 g_assert ((assembly->resources.index % 4) == 0);
2492 assembly->sections [MONO_SECTION_TEXT].size = assembly->meta_size + assembly->code.index + assembly->resources.index + assembly->strong_name_size;
2493 assembly->sections [MONO_SECTION_TEXT].attrs = SECT_FLAGS_HAS_CODE | SECT_FLAGS_MEM_EXECUTE | SECT_FLAGS_MEM_READ;
2494 nsections++;
2496 if (assembly->win32_res) {
2497 guint32 res_size = (assembly->win32_res_size + 3) & ~3;
2499 assembly->sections [MONO_SECTION_RSRC].size = res_size;
2500 assembly->sections [MONO_SECTION_RSRC].attrs = SECT_FLAGS_HAS_INITIALIZED_DATA | SECT_FLAGS_MEM_READ;
2501 nsections++;
2504 assembly->sections [MONO_SECTION_RELOC].size = 12;
2505 assembly->sections [MONO_SECTION_RELOC].attrs = SECT_FLAGS_MEM_READ | SECT_FLAGS_MEM_DISCARDABLE | SECT_FLAGS_HAS_INITIALIZED_DATA;
2506 nsections++;
2508 return nsections;
2511 typedef struct {
2512 guint32 id;
2513 guint32 offset;
2514 GSList *children;
2515 MonoReflectionWin32Resource *win32_res; /* Only for leaf nodes */
2516 } ResTreeNode;
2518 static int
2519 resource_tree_compare_by_id (gconstpointer a, gconstpointer b)
2521 ResTreeNode *t1 = (ResTreeNode*)a;
2522 ResTreeNode *t2 = (ResTreeNode*)b;
2524 return t1->id - t2->id;
2528 * resource_tree_create:
2530 * Organize the resources into a resource tree.
2532 static ResTreeNode *
2533 resource_tree_create (MonoArray *win32_resources)
2535 ResTreeNode *tree, *res_node, *type_node, *lang_node;
2536 GSList *l;
2537 int i;
2539 tree = g_new0 (ResTreeNode, 1);
2541 for (i = 0; i < mono_array_length (win32_resources); ++i) {
2542 MonoReflectionWin32Resource *win32_res =
2543 (MonoReflectionWin32Resource*)mono_array_addr (win32_resources, MonoReflectionWin32Resource, i);
2545 /* Create node */
2547 /* FIXME: BUG: this stores managed references in unmanaged memory */
2548 lang_node = g_new0 (ResTreeNode, 1);
2549 lang_node->id = win32_res->lang_id;
2550 lang_node->win32_res = win32_res;
2552 /* Create type node if neccesary */
2553 type_node = NULL;
2554 for (l = tree->children; l; l = l->next)
2555 if (((ResTreeNode*)(l->data))->id == win32_res->res_type) {
2556 type_node = (ResTreeNode*)l->data;
2557 break;
2560 if (!type_node) {
2561 type_node = g_new0 (ResTreeNode, 1);
2562 type_node->id = win32_res->res_type;
2565 * The resource types have to be sorted otherwise
2566 * Windows Explorer can't display the version information.
2568 tree->children = g_slist_insert_sorted (tree->children,
2569 type_node, resource_tree_compare_by_id);
2572 /* Create res node if neccesary */
2573 res_node = NULL;
2574 for (l = type_node->children; l; l = l->next)
2575 if (((ResTreeNode*)(l->data))->id == win32_res->res_id) {
2576 res_node = (ResTreeNode*)l->data;
2577 break;
2580 if (!res_node) {
2581 res_node = g_new0 (ResTreeNode, 1);
2582 res_node->id = win32_res->res_id;
2583 type_node->children = g_slist_append (type_node->children, res_node);
2586 res_node->children = g_slist_append (res_node->children, lang_node);
2589 return tree;
2593 * resource_tree_encode:
2595 * Encode the resource tree into the format used in the PE file.
2597 static void
2598 resource_tree_encode (ResTreeNode *node, char *begin, char *p, char **endbuf)
2600 char *entries;
2601 MonoPEResourceDir dir;
2602 MonoPEResourceDirEntry dir_entry;
2603 MonoPEResourceDataEntry data_entry;
2604 GSList *l;
2605 guint32 res_id_entries;
2608 * For the format of the resource directory, see the article
2609 * "An In-Depth Look into the Win32 Portable Executable File Format" by
2610 * Matt Pietrek
2613 memset (&dir, 0, sizeof (dir));
2614 memset (&dir_entry, 0, sizeof (dir_entry));
2615 memset (&data_entry, 0, sizeof (data_entry));
2617 g_assert (sizeof (dir) == 16);
2618 g_assert (sizeof (dir_entry) == 8);
2619 g_assert (sizeof (data_entry) == 16);
2621 node->offset = p - begin;
2623 /* IMAGE_RESOURCE_DIRECTORY */
2624 res_id_entries = g_slist_length (node->children);
2625 dir.res_id_entries = GUINT16_TO_LE (res_id_entries);
2627 memcpy (p, &dir, sizeof (dir));
2628 p += sizeof (dir);
2630 /* Reserve space for entries */
2631 entries = p;
2632 p += sizeof (dir_entry) * res_id_entries;
2634 /* Write children */
2635 for (l = node->children; l; l = l->next) {
2636 ResTreeNode *child = (ResTreeNode*)l->data;
2638 if (child->win32_res) {
2639 guint32 size;
2641 child->offset = p - begin;
2643 /* IMAGE_RESOURCE_DATA_ENTRY */
2644 data_entry.rde_data_offset = GUINT32_TO_LE (p - begin + sizeof (data_entry));
2645 size = mono_array_length (child->win32_res->res_data);
2646 data_entry.rde_size = GUINT32_TO_LE (size);
2648 memcpy (p, &data_entry, sizeof (data_entry));
2649 p += sizeof (data_entry);
2651 memcpy (p, mono_array_addr (child->win32_res->res_data, char, 0), size);
2652 p += size;
2653 } else {
2654 resource_tree_encode (child, begin, p, &p);
2658 /* IMAGE_RESOURCE_ENTRY */
2659 for (l = node->children; l; l = l->next) {
2660 ResTreeNode *child = (ResTreeNode*)l->data;
2662 MONO_PE_RES_DIR_ENTRY_SET_NAME (dir_entry, FALSE, child->id);
2663 MONO_PE_RES_DIR_ENTRY_SET_DIR (dir_entry, !child->win32_res, child->offset);
2665 memcpy (entries, &dir_entry, sizeof (dir_entry));
2666 entries += sizeof (dir_entry);
2669 *endbuf = p;
2672 static void
2673 resource_tree_free (ResTreeNode * node)
2675 GSList * list;
2676 for (list = node->children; list; list = list->next)
2677 resource_tree_free ((ResTreeNode*)list->data);
2678 g_slist_free(node->children);
2679 g_free (node);
2682 static void
2683 assembly_add_win32_resources (MonoDynamicImage *assembly, MonoReflectionAssemblyBuilder *assemblyb)
2685 char *buf;
2686 char *p;
2687 guint32 size, i;
2688 MonoReflectionWin32Resource *win32_res;
2689 ResTreeNode *tree;
2691 if (!assemblyb->win32_resources)
2692 return;
2695 * Resources are stored in a three level tree inside the PE file.
2696 * - level one contains a node for each type of resource
2697 * - level two contains a node for each resource
2698 * - level three contains a node for each instance of a resource for a
2699 * specific language.
2702 tree = resource_tree_create (assemblyb->win32_resources);
2704 /* Estimate the size of the encoded tree */
2705 size = 0;
2706 for (i = 0; i < mono_array_length (assemblyb->win32_resources); ++i) {
2707 win32_res = (MonoReflectionWin32Resource*)mono_array_addr (assemblyb->win32_resources, MonoReflectionWin32Resource, i);
2708 size += mono_array_length (win32_res->res_data);
2710 /* Directory structure */
2711 size += mono_array_length (assemblyb->win32_resources) * 256;
2712 p = buf = (char *)g_malloc (size);
2714 resource_tree_encode (tree, p, p, &p);
2716 g_assert (p - buf <= size);
2718 assembly->win32_res = (char *)g_malloc (p - buf);
2719 assembly->win32_res_size = p - buf;
2720 memcpy (assembly->win32_res, buf, p - buf);
2722 g_free (buf);
2723 resource_tree_free (tree);
2726 static void
2727 fixup_resource_directory (char *res_section, char *p, guint32 rva)
2729 MonoPEResourceDir *dir = (MonoPEResourceDir*)p;
2730 int i;
2732 p += sizeof (MonoPEResourceDir);
2733 for (i = 0; i < GUINT16_FROM_LE (dir->res_named_entries) + GUINT16_FROM_LE (dir->res_id_entries); ++i) {
2734 MonoPEResourceDirEntry *dir_entry = (MonoPEResourceDirEntry*)p;
2735 char *child = res_section + MONO_PE_RES_DIR_ENTRY_DIR_OFFSET (*dir_entry);
2736 if (MONO_PE_RES_DIR_ENTRY_IS_DIR (*dir_entry)) {
2737 fixup_resource_directory (res_section, child, rva);
2738 } else {
2739 MonoPEResourceDataEntry *data_entry = (MonoPEResourceDataEntry*)child;
2740 data_entry->rde_data_offset = GUINT32_TO_LE (GUINT32_FROM_LE (data_entry->rde_data_offset) + rva);
2743 p += sizeof (MonoPEResourceDirEntry);
2747 static void
2748 checked_write_file (HANDLE f, gconstpointer buffer, guint32 numbytes)
2750 guint32 dummy;
2751 if (!mono_w32file_write (f, buffer, numbytes, &dummy))
2752 g_error ("mono_w32file_write returned %d\n", mono_w32error_get_last ());
2756 * mono_image_create_pefile:
2757 * @mb: a module builder object
2759 * This function creates the PE-COFF header, the image sections, the CLI header * etc. all the data is written in
2760 * assembly->pefile where it can be easily retrieved later in chunks.
2762 gboolean
2763 mono_image_create_pefile (MonoReflectionModuleBuilder *mb, HANDLE file, MonoError *error)
2765 MonoMSDOSHeader *msdos;
2766 MonoDotNetHeader *header;
2767 MonoSectionTable *section;
2768 MonoCLIHeader *cli_header;
2769 guint32 size, image_size, virtual_base, text_offset;
2770 guint32 header_start, section_start, file_offset, virtual_offset;
2771 MonoDynamicImage *assembly;
2772 MonoReflectionAssemblyBuilder *assemblyb;
2773 MonoDynamicStream pefile_stream = {0};
2774 MonoDynamicStream *pefile = &pefile_stream;
2775 int i, nsections;
2776 guint32 *rva, value;
2777 guchar *p;
2778 static const unsigned char msheader[] = {
2779 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
2780 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2781 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2782 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
2783 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68,
2784 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f,
2785 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,
2786 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
2789 mono_error_init (error);
2791 assemblyb = mb->assemblyb;
2793 mono_reflection_dynimage_basic_init (assemblyb);
2794 assembly = mb->dynamic_image;
2796 assembly->pe_kind = assemblyb->pe_kind;
2797 assembly->machine = assemblyb->machine;
2798 ((MonoDynamicImage*)assemblyb->dynamic_assembly->assembly.image)->pe_kind = assemblyb->pe_kind;
2799 ((MonoDynamicImage*)assemblyb->dynamic_assembly->assembly.image)->machine = assemblyb->machine;
2801 if (!mono_image_build_metadata (mb, error))
2802 return FALSE;
2805 if (mb->is_main && assemblyb->resources) {
2806 int len = mono_array_length (assemblyb->resources);
2807 for (i = 0; i < len; ++i) {
2808 if (!assembly_add_resource (mb, assembly, (MonoReflectionResource*)mono_array_addr (assemblyb->resources, MonoReflectionResource, i), error))
2809 return FALSE;
2813 if (mb->resources) {
2814 int len = mono_array_length (mb->resources);
2815 for (i = 0; i < len; ++i) {
2816 if (!assembly_add_resource (mb, assembly, (MonoReflectionResource*)mono_array_addr (mb->resources, MonoReflectionResource, i), error))
2817 return FALSE;
2821 if (!build_compressed_metadata (assembly, error))
2822 return FALSE;
2824 if (mb->is_main)
2825 assembly_add_win32_resources (assembly, assemblyb);
2827 nsections = calc_section_size (assembly);
2829 /* The DOS header and stub */
2830 g_assert (sizeof (MonoMSDOSHeader) == sizeof (msheader));
2831 mono_image_add_stream_data (pefile, (char*)msheader, sizeof (msheader));
2833 /* the dotnet header */
2834 header_start = mono_image_add_stream_zero (pefile, sizeof (MonoDotNetHeader));
2836 /* the section tables */
2837 section_start = mono_image_add_stream_zero (pefile, sizeof (MonoSectionTable) * nsections);
2839 file_offset = section_start + sizeof (MonoSectionTable) * nsections;
2840 virtual_offset = VIRT_ALIGN;
2841 image_size = 0;
2843 for (i = 0; i < MONO_SECTION_MAX; ++i) {
2844 if (!assembly->sections [i].size)
2845 continue;
2846 /* align offsets */
2847 file_offset += FILE_ALIGN - 1;
2848 file_offset &= ~(FILE_ALIGN - 1);
2849 virtual_offset += VIRT_ALIGN - 1;
2850 virtual_offset &= ~(VIRT_ALIGN - 1);
2852 assembly->sections [i].offset = file_offset;
2853 assembly->sections [i].rva = virtual_offset;
2855 file_offset += assembly->sections [i].size;
2856 virtual_offset += assembly->sections [i].size;
2857 image_size += (assembly->sections [i].size + VIRT_ALIGN - 1) & ~(VIRT_ALIGN - 1);
2860 file_offset += FILE_ALIGN - 1;
2861 file_offset &= ~(FILE_ALIGN - 1);
2863 image_size += section_start + sizeof (MonoSectionTable) * nsections;
2865 /* back-patch info */
2866 msdos = (MonoMSDOSHeader*)pefile->data;
2867 msdos->pe_offset = GUINT32_FROM_LE (sizeof (MonoMSDOSHeader));
2869 header = (MonoDotNetHeader*)(pefile->data + header_start);
2870 header->pesig [0] = 'P';
2871 header->pesig [1] = 'E';
2873 header->coff.coff_machine = GUINT16_FROM_LE (assemblyb->machine);
2874 header->coff.coff_sections = GUINT16_FROM_LE (nsections);
2875 header->coff.coff_time = GUINT32_FROM_LE (time (NULL));
2876 header->coff.coff_opt_header_size = GUINT16_FROM_LE (sizeof (MonoDotNetHeader) - sizeof (MonoCOFFHeader) - 4);
2877 if (assemblyb->pekind == 1) {
2878 /* it's a dll */
2879 header->coff.coff_attributes = GUINT16_FROM_LE (0x210e);
2880 } else {
2881 /* it's an exe */
2882 header->coff.coff_attributes = GUINT16_FROM_LE (0x010e);
2885 virtual_base = 0x400000; /* FIXME: 0x10000000 if a DLL */
2887 header->pe.pe_magic = GUINT16_FROM_LE (0x10B);
2888 header->pe.pe_major = 6;
2889 header->pe.pe_minor = 0;
2890 size = assembly->sections [MONO_SECTION_TEXT].size;
2891 size += FILE_ALIGN - 1;
2892 size &= ~(FILE_ALIGN - 1);
2893 header->pe.pe_code_size = GUINT32_FROM_LE(size);
2894 size = assembly->sections [MONO_SECTION_RSRC].size;
2895 size += FILE_ALIGN - 1;
2896 size &= ~(FILE_ALIGN - 1);
2897 header->pe.pe_data_size = GUINT32_FROM_LE(size);
2898 g_assert (START_TEXT_RVA == assembly->sections [MONO_SECTION_TEXT].rva);
2899 header->pe.pe_rva_code_base = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_TEXT].rva);
2900 header->pe.pe_rva_data_base = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].rva);
2901 /* pe_rva_entry_point always at the beginning of the text section */
2902 header->pe.pe_rva_entry_point = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_TEXT].rva);
2904 header->nt.pe_image_base = GUINT32_FROM_LE (virtual_base);
2905 header->nt.pe_section_align = GUINT32_FROM_LE (VIRT_ALIGN);
2906 header->nt.pe_file_alignment = GUINT32_FROM_LE (FILE_ALIGN);
2907 header->nt.pe_os_major = GUINT16_FROM_LE (4);
2908 header->nt.pe_os_minor = GUINT16_FROM_LE (0);
2909 header->nt.pe_subsys_major = GUINT16_FROM_LE (4);
2910 size = section_start;
2911 size += FILE_ALIGN - 1;
2912 size &= ~(FILE_ALIGN - 1);
2913 header->nt.pe_header_size = GUINT32_FROM_LE (size);
2914 size = image_size;
2915 size += VIRT_ALIGN - 1;
2916 size &= ~(VIRT_ALIGN - 1);
2917 header->nt.pe_image_size = GUINT32_FROM_LE (size);
2920 // Translate the PEFileKind value to the value expected by the Windows loader
2923 short kind;
2926 // PEFileKinds.Dll == 1
2927 // PEFileKinds.ConsoleApplication == 2
2928 // PEFileKinds.WindowApplication == 3
2930 // need to get:
2931 // IMAGE_SUBSYSTEM_WINDOWS_GUI 2 // Image runs in the Windows GUI subsystem.
2932 // IMAGE_SUBSYSTEM_WINDOWS_CUI 3 // Image runs in the Windows character subsystem.
2934 if (assemblyb->pekind == 3)
2935 kind = 2;
2936 else
2937 kind = 3;
2939 header->nt.pe_subsys_required = GUINT16_FROM_LE (kind);
2941 header->nt.pe_stack_reserve = GUINT32_FROM_LE (0x00100000);
2942 header->nt.pe_stack_commit = GUINT32_FROM_LE (0x00001000);
2943 header->nt.pe_heap_reserve = GUINT32_FROM_LE (0x00100000);
2944 header->nt.pe_heap_commit = GUINT32_FROM_LE (0x00001000);
2945 header->nt.pe_loader_flags = GUINT32_FROM_LE (0);
2946 header->nt.pe_data_dir_count = GUINT32_FROM_LE (16);
2948 /* fill data directory entries */
2950 header->datadir.pe_resource_table.size = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].size);
2951 header->datadir.pe_resource_table.rva = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].rva);
2953 header->datadir.pe_reloc_table.size = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RELOC].size);
2954 header->datadir.pe_reloc_table.rva = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RELOC].rva);
2956 header->datadir.pe_cli_header.size = GUINT32_FROM_LE (72);
2957 header->datadir.pe_cli_header.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->cli_header_offset);
2958 header->datadir.pe_iat.size = GUINT32_FROM_LE (8);
2959 header->datadir.pe_iat.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->iat_offset);
2960 /* patch entrypoint name */
2961 if (assemblyb->pekind == 1)
2962 memcpy (assembly->code.data + assembly->imp_names_offset + 2, "_CorDllMain", 12);
2963 else
2964 memcpy (assembly->code.data + assembly->imp_names_offset + 2, "_CorExeMain", 12);
2965 /* patch imported function RVA name */
2966 rva = (guint32*)(assembly->code.data + assembly->iat_offset);
2967 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->imp_names_offset);
2969 /* the import table */
2970 header->datadir.pe_import_table.size = GUINT32_FROM_LE (79); /* FIXME: magic number? */
2971 header->datadir.pe_import_table.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->idt_offset);
2972 /* patch imported dll RVA name and other entries in the dir */
2973 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, name_rva));
2974 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->imp_names_offset + 14); /* 14 is hint+strlen+1 of func name */
2975 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, import_address_table_rva));
2976 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->iat_offset);
2977 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, import_lookup_table));
2978 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->ilt_offset);
2980 p = (guchar*)(assembly->code.data + assembly->ilt_offset);
2981 value = (assembly->text_rva + assembly->imp_names_offset);
2982 *p++ = (value) & 0xff;
2983 *p++ = (value >> 8) & (0xff);
2984 *p++ = (value >> 16) & (0xff);
2985 *p++ = (value >> 24) & (0xff);
2987 /* the CLI header info */
2988 cli_header = (MonoCLIHeader*)(assembly->code.data + assembly->cli_header_offset);
2989 cli_header->ch_size = GUINT32_FROM_LE (72);
2990 cli_header->ch_runtime_major = GUINT16_FROM_LE (2);
2991 cli_header->ch_runtime_minor = GUINT16_FROM_LE (5);
2992 cli_header->ch_flags = GUINT32_FROM_LE (assemblyb->pe_kind);
2993 if (assemblyb->entry_point) {
2994 guint32 table_idx = 0;
2995 if (!strcmp (assemblyb->entry_point->object.vtable->klass->name, "MethodBuilder")) {
2996 MonoReflectionMethodBuilder *methodb = (MonoReflectionMethodBuilder*)assemblyb->entry_point;
2997 table_idx = methodb->table_idx;
2998 } else {
2999 table_idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, assemblyb->entry_point->method));
3001 cli_header->ch_entry_point = GUINT32_FROM_LE (table_idx | MONO_TOKEN_METHOD_DEF);
3002 } else {
3003 cli_header->ch_entry_point = GUINT32_FROM_LE (0);
3005 /* The embedded managed resources */
3006 text_offset = assembly->text_rva + assembly->code.index;
3007 cli_header->ch_resources.rva = GUINT32_FROM_LE (text_offset);
3008 cli_header->ch_resources.size = GUINT32_FROM_LE (assembly->resources.index);
3009 text_offset += assembly->resources.index;
3010 cli_header->ch_metadata.rva = GUINT32_FROM_LE (text_offset);
3011 cli_header->ch_metadata.size = GUINT32_FROM_LE (assembly->meta_size);
3012 text_offset += assembly->meta_size;
3013 if (assembly->strong_name_size) {
3014 cli_header->ch_strong_name.rva = GUINT32_FROM_LE (text_offset);
3015 cli_header->ch_strong_name.size = GUINT32_FROM_LE (assembly->strong_name_size);
3016 text_offset += assembly->strong_name_size;
3019 /* write the section tables and section content */
3020 section = (MonoSectionTable*)(pefile->data + section_start);
3021 for (i = 0; i < MONO_SECTION_MAX; ++i) {
3022 static const char section_names [][7] = {
3023 ".text", ".rsrc", ".reloc"
3025 if (!assembly->sections [i].size)
3026 continue;
3027 strcpy (section->st_name, section_names [i]);
3028 /*g_print ("output section %s (%d), size: %d\n", section->st_name, i, assembly->sections [i].size);*/
3029 section->st_virtual_address = GUINT32_FROM_LE (assembly->sections [i].rva);
3030 section->st_virtual_size = GUINT32_FROM_LE (assembly->sections [i].size);
3031 section->st_raw_data_size = GUINT32_FROM_LE (GUINT32_TO_LE (section->st_virtual_size) + (FILE_ALIGN - 1));
3032 section->st_raw_data_size &= GUINT32_FROM_LE (~(FILE_ALIGN - 1));
3033 section->st_raw_data_ptr = GUINT32_FROM_LE (assembly->sections [i].offset);
3034 section->st_flags = GUINT32_FROM_LE (assembly->sections [i].attrs);
3035 section ++;
3038 checked_write_file (file, pefile->data, pefile->index);
3040 mono_dynamic_stream_reset (pefile);
3042 for (i = 0; i < MONO_SECTION_MAX; ++i) {
3043 if (!assembly->sections [i].size)
3044 continue;
3046 if (mono_w32file_seek (file, assembly->sections [i].offset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
3047 g_error ("mono_w32file_seek returned %d\n", mono_w32error_get_last ());
3049 switch (i) {
3050 case MONO_SECTION_TEXT:
3051 /* patch entry point */
3052 p = (guchar*)(assembly->code.data + 2);
3053 value = (virtual_base + assembly->text_rva + assembly->iat_offset);
3054 *p++ = (value) & 0xff;
3055 *p++ = (value >> 8) & 0xff;
3056 *p++ = (value >> 16) & 0xff;
3057 *p++ = (value >> 24) & 0xff;
3059 checked_write_file (file, assembly->code.data, assembly->code.index);
3060 checked_write_file (file, assembly->resources.data, assembly->resources.index);
3061 checked_write_file (file, assembly->image.raw_metadata, assembly->meta_size);
3062 checked_write_file (file, assembly->strong_name, assembly->strong_name_size);
3065 g_free (assembly->image.raw_metadata);
3066 break;
3067 case MONO_SECTION_RELOC: {
3068 struct {
3069 guint32 page_rva;
3070 guint32 block_size;
3071 guint16 type_and_offset;
3072 guint16 term;
3073 } reloc;
3075 g_assert (sizeof (reloc) == 12);
3077 reloc.page_rva = GUINT32_FROM_LE (assembly->text_rva);
3078 reloc.block_size = GUINT32_FROM_LE (12);
3081 * the entrypoint is always at the start of the text section
3082 * 3 is IMAGE_REL_BASED_HIGHLOW
3083 * 2 is patch_size_rva - text_rva
3085 reloc.type_and_offset = GUINT16_FROM_LE ((3 << 12) + (2));
3086 reloc.term = 0;
3088 checked_write_file (file, &reloc, sizeof (reloc));
3090 break;
3092 case MONO_SECTION_RSRC:
3093 if (assembly->win32_res) {
3095 /* Fixup the offsets in the IMAGE_RESOURCE_DATA_ENTRY structures */
3096 fixup_resource_directory (assembly->win32_res, assembly->win32_res, assembly->sections [i].rva);
3097 checked_write_file (file, assembly->win32_res, assembly->win32_res_size);
3099 break;
3100 default:
3101 g_assert_not_reached ();
3105 /* check that the file is properly padded */
3106 if (mono_w32file_seek (file, file_offset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
3107 g_error ("mono_w32file_seek returned %d\n", mono_w32error_get_last ());
3108 if (! mono_w32file_truncate (file))
3109 g_error ("mono_w32file_truncate returned %d\n", mono_w32error_get_last ());
3111 mono_dynamic_stream_reset (&assembly->code);
3112 mono_dynamic_stream_reset (&assembly->us);
3113 mono_dynamic_stream_reset (&assembly->blob);
3114 mono_dynamic_stream_reset (&assembly->guid);
3115 mono_dynamic_stream_reset (&assembly->sheap);
3117 g_hash_table_foreach (assembly->blob_cache, (GHFunc)g_free, NULL);
3118 g_hash_table_destroy (assembly->blob_cache);
3119 assembly->blob_cache = NULL;
3121 return TRUE;
3124 #else /* DISABLE_REFLECTION_EMIT_SAVE */
3126 gboolean
3127 mono_image_create_pefile (MonoReflectionModuleBuilder *mb, HANDLE file, MonoError *error)
3129 g_assert_not_reached ();
3132 #endif /* DISABLE_REFLECTION_EMIT_SAVE */