[coop] Transition various public APIs into an external/internal form to avoid unneces...
[mono-project.git] / mono / metadata / sre-save.c
bloba4787ee7961f01eb5c109094c930b920211e05ef
1 /**
2 * \file
3 * Routine for saving an image to a file.
4 *
5 *
6 * Author:
7 * Paolo Molaro (lupus@ximian.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2011 Rodrigo Kumpera
12 * Copyright 2016 Microsoft
14 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
17 #include <config.h>
18 #include <glib.h>
20 #include "mono/metadata/dynamic-image-internals.h"
21 #include "mono/metadata/dynamic-stream-internals.h"
22 #include "mono/metadata/mono-ptr-array.h"
23 #include "mono/metadata/mono-hash-internals.h"
24 #include "mono/metadata/object-internals.h"
25 #include "mono/metadata/sre-internals.h"
26 #include "mono/metadata/security-manager.h"
27 #include "mono/metadata/tabledefs.h"
28 #include "mono/metadata/tokentype.h"
29 #include "mono/metadata/w32file.h"
30 #include "mono/metadata/w32error.h"
32 #include "mono/utils/checked-build.h"
33 #include "mono/utils/mono-digest.h"
34 #include "mono/utils/mono-error-internals.h"
35 #include "mono/utils/w32api.h"
37 #define TEXT_OFFSET 512
38 #define CLI_H_SIZE 136
39 #define FILE_ALIGN 512
40 #define VIRT_ALIGN 8192
41 #define START_TEXT_RVA 0x00002000
43 static void mono_image_get_generic_param_info (MonoReflectionGenericParam *gparam, guint32 owner, MonoDynamicImage *assembly);
45 static void
46 alloc_table (MonoDynamicTable *table, guint nrows)
48 mono_dynimage_alloc_table (table, nrows);
51 static guint32
52 string_heap_insert (MonoDynamicStream *sh, const char *str)
54 return mono_dynstream_insert_string (sh, str);
57 static guint32
58 string_heap_insert_mstring (MonoDynamicStream *sh, MonoString *str, MonoError *error)
60 return mono_dynstream_insert_mstring (sh, str, error);
63 static guint32
64 mono_image_add_stream_data (MonoDynamicStream *stream, const char *data, guint32 len)
66 return mono_dynstream_add_data (stream, data, len);
69 static guint32
70 mono_image_add_stream_zero (MonoDynamicStream *stream, guint32 len)
72 return mono_dynstream_add_zero (stream, len);
75 static void
76 stream_data_align (MonoDynamicStream *stream)
78 mono_dynstream_data_align (stream);
81 static guint32
82 mono_image_typedef_or_ref (MonoDynamicImage *assembly, MonoType *type)
84 return mono_dynimage_encode_typedef_or_ref_full (assembly, type, TRUE);
87 static guint32
88 find_index_in_table (MonoDynamicImage *assembly, int table_idx, int col, guint32 token)
90 MONO_REQ_GC_NEUTRAL_MODE;
92 int i;
93 MonoDynamicTable *table;
94 guint32 *values;
96 table = &assembly->tables [table_idx];
98 g_assert (col < table->columns);
100 values = table->values + table->columns;
101 for (i = 1; i <= table->rows; ++i) {
102 if (values [col] == token)
103 return i;
104 values += table->columns;
106 return 0;
110 * Copy len * nelem bytes from val to dest, swapping bytes to LE if necessary.
111 * dest may be misaligned.
113 static void
114 swap_with_size (char *dest, const char* val, int len, int nelem) {
115 MONO_REQ_GC_NEUTRAL_MODE;
116 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
117 int elem;
119 for (elem = 0; elem < nelem; ++elem) {
120 switch (len) {
121 case 1:
122 *dest = *val;
123 break;
124 case 2:
125 dest [0] = val [1];
126 dest [1] = val [0];
127 break;
128 case 4:
129 dest [0] = val [3];
130 dest [1] = val [2];
131 dest [2] = val [1];
132 dest [3] = val [0];
133 break;
134 case 8:
135 dest [0] = val [7];
136 dest [1] = val [6];
137 dest [2] = val [5];
138 dest [3] = val [4];
139 dest [4] = val [3];
140 dest [5] = val [2];
141 dest [6] = val [1];
142 dest [7] = val [0];
143 break;
144 default:
145 g_assert_not_reached ();
147 dest += len;
148 val += len;
150 #else
151 memcpy (dest, val, len * nelem);
152 #endif
155 static guint32
156 add_mono_string_to_blob_cached (MonoDynamicImage *assembly, MonoString *str)
158 MONO_REQ_GC_UNSAFE_MODE;
160 char blob_size [64];
161 char *b = blob_size;
162 guint32 idx = 0, len;
164 len = str->length * 2;
165 mono_metadata_encode_value (len, b, &b);
166 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
168 char *swapped = g_malloc (2 * mono_string_length_internal (str));
169 const char *p = (const char*)mono_string_chars_internal (str);
171 swap_with_size (swapped, p, 2, mono_string_length_internal (str));
172 idx = mono_dynamic_image_add_to_blob_cached (assembly, blob_size, b-blob_size, swapped, len);
173 g_free (swapped);
175 #else
176 idx = mono_dynamic_image_add_to_blob_cached (assembly, blob_size, b-blob_size, mono_string_chars_internal (str), len);
177 #endif
178 return idx;
181 static guint32
182 image_create_token_raw (MonoDynamicImage *assembly, MonoObject* obj_raw, gboolean create_methodspec, gboolean register_token, MonoError *error)
184 HANDLE_FUNCTION_ENTER (); /* FIXME callers of image_create_token_raw should use handles */
185 error_init (error);
186 MONO_HANDLE_DCL (MonoObject, obj);
187 guint32 result = mono_image_create_token (assembly, obj, create_methodspec, register_token, error);
188 HANDLE_FUNCTION_RETURN_VAL (result);
193 * idx is the table index of the object
194 * type is one of MONO_CUSTOM_ATTR_*
196 static gboolean
197 mono_image_add_cattrs (MonoDynamicImage *assembly, guint32 idx, guint32 type, MonoArray *cattrs, MonoError *error)
199 MONO_REQ_GC_UNSAFE_MODE;
201 MonoDynamicTable *table;
202 MonoReflectionCustomAttr *cattr;
203 guint32 *values;
204 guint32 count, i, token;
205 char blob_size [6];
206 char *p = blob_size;
208 error_init (error);
210 /* it is legal to pass a NULL cattrs: we avoid to use the if in a lot of places */
211 if (!cattrs)
212 return TRUE;
213 count = mono_array_length_internal (cattrs);
214 table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
215 table->rows += count;
216 alloc_table (table, table->rows);
217 values = table->values + table->next_idx * MONO_CUSTOM_ATTR_SIZE;
218 idx <<= MONO_CUSTOM_ATTR_BITS;
219 idx |= type;
220 for (i = 0; i < count; ++i) {
221 cattr = (MonoReflectionCustomAttr*)mono_array_get_internal (cattrs, gpointer, i);
222 values [MONO_CUSTOM_ATTR_PARENT] = idx;
223 g_assert (cattr->ctor != NULL);
224 if (mono_is_sre_ctor_builder (mono_object_class (cattr->ctor))) {
225 MonoReflectionCtorBuilder *ctor = (MonoReflectionCtorBuilder*)cattr->ctor;
226 MonoMethod *method = ctor->mhandle;
227 if (m_class_get_image (method->klass) == &assembly->image)
228 token = MONO_TOKEN_METHOD_DEF | ((MonoReflectionCtorBuilder*)cattr->ctor)->table_idx;
229 else
230 token = mono_image_get_methodref_token (assembly, method, FALSE);
231 } else {
232 token = image_create_token_raw (assembly, (MonoObject*)cattr->ctor, FALSE, FALSE, error); /* FIXME use handles */
233 if (!mono_error_ok (error)) goto fail;
235 type = mono_metadata_token_index (token);
236 type <<= MONO_CUSTOM_ATTR_TYPE_BITS;
237 switch (mono_metadata_token_table (token)) {
238 case MONO_TABLE_METHOD:
239 type |= MONO_CUSTOM_ATTR_TYPE_METHODDEF;
241 * fixup_cattrs () needs to fix this up. We can't use image->tokens, since it contains the old token for the
242 * method, not the one returned by mono_image_create_token ().
244 mono_g_hash_table_insert_internal (assembly->remapped_tokens, GUINT_TO_POINTER (token), cattr->ctor);
245 break;
246 case MONO_TABLE_MEMBERREF:
247 type |= MONO_CUSTOM_ATTR_TYPE_MEMBERREF;
248 break;
249 default:
250 g_warning ("got wrong token in custom attr");
251 continue;
253 values [MONO_CUSTOM_ATTR_TYPE] = type;
254 p = blob_size;
255 mono_metadata_encode_value (mono_array_length_internal (cattr->data), p, &p);
256 values [MONO_CUSTOM_ATTR_VALUE] = mono_dynamic_image_add_to_blob_cached (assembly, blob_size, p - blob_size,
257 mono_array_addr_internal (cattr->data, char, 0), mono_array_length_internal (cattr->data));
258 values += MONO_CUSTOM_ATTR_SIZE;
259 ++table->next_idx;
262 return TRUE;
264 fail:
265 return FALSE;
268 static void
269 mono_image_add_decl_security (MonoDynamicImage *assembly, guint32 parent_token, MonoArray *permissions)
271 MONO_REQ_GC_UNSAFE_MODE;
273 MonoDynamicTable *table;
274 guint32 *values;
275 guint32 count, i, idx;
276 MonoReflectionPermissionSet *perm;
278 if (!permissions)
279 return;
281 count = mono_array_length_internal (permissions);
282 table = &assembly->tables [MONO_TABLE_DECLSECURITY];
283 table->rows += count;
284 alloc_table (table, table->rows);
286 for (i = 0; i < mono_array_length_internal (permissions); ++i) {
287 perm = (MonoReflectionPermissionSet*)mono_array_addr_internal (permissions, MonoReflectionPermissionSet, i);
289 values = table->values + table->next_idx * MONO_DECL_SECURITY_SIZE;
291 idx = mono_metadata_token_index (parent_token);
292 idx <<= MONO_HAS_DECL_SECURITY_BITS;
293 switch (mono_metadata_token_table (parent_token)) {
294 case MONO_TABLE_TYPEDEF:
295 idx |= MONO_HAS_DECL_SECURITY_TYPEDEF;
296 break;
297 case MONO_TABLE_METHOD:
298 idx |= MONO_HAS_DECL_SECURITY_METHODDEF;
299 break;
300 case MONO_TABLE_ASSEMBLY:
301 idx |= MONO_HAS_DECL_SECURITY_ASSEMBLY;
302 break;
303 default:
304 g_assert_not_reached ();
307 values [MONO_DECL_SECURITY_ACTION] = perm->action;
308 values [MONO_DECL_SECURITY_PARENT] = idx;
309 values [MONO_DECL_SECURITY_PERMISSIONSET] = add_mono_string_to_blob_cached (assembly, perm->pset);
311 ++table->next_idx;
316 * method_encode_code:
318 * @assembly the assembly
319 * @mb the managed MethodBuilder
320 * @error set on error
322 * Note that the return value is not sensible if @error is set.
324 static guint32
325 method_encode_code (MonoDynamicImage *assembly, ReflectionMethodBuilder *mb, MonoError *error)
327 MONO_REQ_GC_UNSAFE_MODE;
329 char flags = 0;
330 guint32 idx;
331 guint32 code_size;
332 gint32 max_stack, i;
333 gint32 num_locals = 0;
334 gint32 num_exception = 0;
335 gint maybe_small;
336 guint32 fat_flags;
337 char fat_header [12];
338 guint32 int_value;
339 guint16 short_value;
340 guint32 local_sig = 0;
341 guint32 header_size = 12;
342 MonoArray *code;
344 error_init (error);
346 if ((mb->attrs & (METHOD_ATTRIBUTE_PINVOKE_IMPL | METHOD_ATTRIBUTE_ABSTRACT)) ||
347 (mb->iattrs & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)))
348 return 0;
350 /*if (mb->name)
351 g_print ("Encode method %s\n", mono_string_to_utf8 (mb->name));*/
352 if (mb->ilgen) {
353 code = mb->ilgen->code;
354 code_size = mb->ilgen->code_len;
355 max_stack = mb->ilgen->max_stack;
356 num_locals = mb->ilgen->locals ? mono_array_length_internal (mb->ilgen->locals) : 0;
357 if (mb->ilgen->ex_handlers)
358 num_exception = mono_reflection_method_count_clauses (mb->ilgen);
359 } else {
360 code = mb->code;
361 if (code == NULL) {
362 ERROR_DECL (inner_error);
363 char *name = mono_string_to_utf8_checked_internal (mb->name, inner_error);
364 if (!is_ok (inner_error))
365 mono_error_set_argument (error, NULL, "a method does not have any IL associated");
366 else
367 mono_error_set_argument_format (error, NULL, "Method %s does not have any IL associated", name);
368 mono_error_cleanup (inner_error);
369 g_free (name);
370 return 0;
373 code_size = mono_array_length_internal (code);
374 max_stack = 8; /* we probably need to run a verifier on the code... */
377 stream_data_align (&assembly->code);
379 /* check for exceptions, maxstack, locals */
380 maybe_small = (max_stack <= 8) && (!num_locals) && (!num_exception);
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_internal (assembly->token_fixups, mb->ilgen, GUINT_TO_POINTER (idx + 1));
393 mono_image_add_stream_data (&assembly->code, mono_array_addr_internal (code, char, 0), code_size);
394 return assembly->text_rva + idx;
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_internal (assembly->token_fixups, mb->ilgen, GUINT_TO_POINTER (idx + 12));
423 mono_image_add_stream_data (&assembly->code, mono_array_addr_internal (code, char, 0), code_size);
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_internal (mb->ilgen->ex_handlers) - 1; i >= 0; --i) {
442 ex_info = (MonoILExceptionInfo *)mono_array_addr_internal (mb->ilgen->ex_handlers, MonoILExceptionInfo, i);
443 if (ex_info->handlers) {
444 int finally_start = ex_info->start + ex_info->len;
445 for (j = 0; j < mono_array_length_internal (ex_info->handlers); ++j) {
446 guint32 val;
447 ex_block = (MonoILExceptionBlock*)mono_array_addr_internal (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 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_internal (mb->pinfo); ++i) {
535 if (mono_array_get_internal (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_internal (mb->pinfo); ++i) {
542 MonoReflectionParamBuilder *pb;
543 if ((pb = mono_array_get_internal (mb->pinfo, MonoReflectionParamBuilder*, i))) {
544 values [MONO_PARAM_FLAGS] = pb->attrs;
545 values [MONO_PARAM_SEQUENCE] = i;
546 if (pb->name != NULL) {
547 values [MONO_PARAM_NAME] = string_heap_insert_mstring (&assembly->sheap, pb->name, error);
548 return_val_if_nok (error, FALSE);
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 MonoTypeEnum field_type = (MonoTypeEnum)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 error_init (error);
594 if (!mb->override_methods)
595 return TRUE;
597 for (i = 0; i < mono_array_length_internal (mb->override_methods); ++i) {
598 m = mono_array_get_internal (mb->override_methods, MonoReflectionMethod*, i);
600 table = &assembly->tables [MONO_TABLE_METHODIMPL];
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 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_internal (mb->generic_params);
678 alloc_table (table, table->rows);
679 for (i = 0; i < mono_array_length_internal (mb->generic_params); ++i) {
680 guint32 owner = MONO_TYPEORMETHOD_METHOD | (mb->table_idx << MONO_TYPEORMETHOD_BITS);
682 mono_image_get_generic_param_info (
683 (MonoReflectionGenericParam *)mono_array_get_internal (mb->generic_params, gpointer, i), owner, assembly);
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 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 guint32 fb_table_idx = table->next_idx ++;
724 g_hash_table_insert (assembly->field_to_table_idx, fb->handle, GUINT_TO_POINTER (fb_table_idx));
725 values = table->values + fb_table_idx * MONO_FIELD_SIZE;
726 values [MONO_FIELD_NAME] = string_heap_insert_mstring (&assembly->sheap, fb->name, error);
727 return_if_nok (error);
728 values [MONO_FIELD_FLAGS] = fb->attrs;
729 values [MONO_FIELD_SIGNATURE] = mono_dynimage_encode_field_signature (assembly, fb, error);
730 return_if_nok (error);
732 if (fb->offset != -1) {
733 table = &assembly->tables [MONO_TABLE_FIELDLAYOUT];
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_internal (fb->rva_data) >= 10)
763 stream_data_align (&assembly->code);
764 rva_idx = mono_image_add_stream_data (&assembly->code, mono_array_addr_internal (fb->rva_data, char, 0), mono_array_length_internal (fb->rva_data));
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 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 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_internal (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_internal (
938 gparam->iface_constraints, gpointer, i);
940 table_idx = table->next_idx ++;
941 values = table->values + table_idx * MONO_GENPARCONSTRAINT_SIZE;
943 MonoType *constraint_type = mono_reflection_type_get_handle (constraint, error);
944 return_if_nok (error);
946 values [MONO_GENPARCONSTRAINT_GENERICPAR] = owner;
947 values [MONO_GENPARCONSTRAINT_CONSTRAINT] = mono_image_typedef_or_ref (assembly, constraint_type);
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, NULL, "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 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_name (param));
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_internal (type->subtypes); ++i) {
1020 MonoReflectionTypeBuilder *subtype = mono_array_get_internal (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 error_init (error);
1042 if (!pinfo)
1043 return TRUE;
1044 for (i = 0; i < mono_array_length_internal (pinfo); ++i) {
1045 MonoReflectionParamBuilder *pb;
1046 pb = mono_array_get_internal (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 guint32
1057 field_builder_table_index (MonoDynamicImage* assembly, MonoReflectionFieldBuilder *fb)
1059 return GPOINTER_TO_UINT (g_hash_table_lookup (assembly->field_to_table_idx, fb->handle));
1062 static gboolean
1063 type_add_cattrs (MonoDynamicImage *assembly, MonoReflectionTypeBuilder *tb, MonoError *error) {
1064 int i;
1066 error_init (error);
1068 if (!mono_image_add_cattrs (assembly, tb->table_idx, MONO_CUSTOM_ATTR_TYPEDEF, tb->cattrs, error))
1069 return FALSE;
1070 if (tb->fields) {
1071 for (i = 0; i < tb->num_fields; ++i) {
1072 MonoReflectionFieldBuilder* fb;
1073 fb = mono_array_get_internal (tb->fields, MonoReflectionFieldBuilder*, i);
1074 if (!mono_image_add_cattrs (assembly, field_builder_table_index (assembly, fb), MONO_CUSTOM_ATTR_FIELDDEF, fb->cattrs, error))
1075 return FALSE;
1078 if (tb->events) {
1079 for (i = 0; i < mono_array_length_internal (tb->events); ++i) {
1080 MonoReflectionEventBuilder* eb;
1081 eb = mono_array_get_internal (tb->events, MonoReflectionEventBuilder*, i);
1082 if (!mono_image_add_cattrs (assembly, eb->table_idx, MONO_CUSTOM_ATTR_EVENT, eb->cattrs, error))
1083 return FALSE;
1086 if (tb->properties) {
1087 for (i = 0; i < mono_array_length_internal (tb->properties); ++i) {
1088 MonoReflectionPropertyBuilder* pb;
1089 pb = mono_array_get_internal (tb->properties, MonoReflectionPropertyBuilder*, i);
1090 if (!mono_image_add_cattrs (assembly, pb->table_idx, MONO_CUSTOM_ATTR_PROPERTY, pb->cattrs, error))
1091 return FALSE;
1094 if (tb->ctors) {
1095 for (i = 0; i < mono_array_length_internal (tb->ctors); ++i) {
1096 MonoReflectionCtorBuilder* cb;
1097 cb = mono_array_get_internal (tb->ctors, MonoReflectionCtorBuilder*, i);
1098 if (!mono_image_add_cattrs (assembly, cb->table_idx, MONO_CUSTOM_ATTR_METHODDEF, cb->cattrs, error) ||
1099 !params_add_cattrs (assembly, cb->pinfo, error))
1100 return FALSE;
1104 if (tb->methods) {
1105 for (i = 0; i < tb->num_methods; ++i) {
1106 MonoReflectionMethodBuilder* mb;
1107 mb = mono_array_get_internal (tb->methods, MonoReflectionMethodBuilder*, i);
1108 if (!mono_image_add_cattrs (assembly, mb->table_idx, MONO_CUSTOM_ATTR_METHODDEF, mb->cattrs, error) ||
1109 !params_add_cattrs (assembly, mb->pinfo, error))
1110 return FALSE;
1114 if (tb->subtypes) {
1115 for (i = 0; i < mono_array_length_internal (tb->subtypes); ++i) {
1116 if (!type_add_cattrs (assembly, mono_array_get_internal (tb->subtypes, MonoReflectionTypeBuilder*, i), error))
1117 return FALSE;
1121 return TRUE;
1124 static gboolean
1125 module_add_cattrs (MonoDynamicImage *assembly, MonoReflectionModuleBuilder *moduleb, MonoError *error)
1127 int i;
1129 error_init (error);
1131 if (!mono_image_add_cattrs (assembly, moduleb->table_idx, MONO_CUSTOM_ATTR_MODULE, moduleb->cattrs, error))
1132 return FALSE;
1134 if (moduleb->global_methods) {
1135 for (i = 0; i < mono_array_length_internal (moduleb->global_methods); ++i) {
1136 MonoReflectionMethodBuilder* mb = mono_array_get_internal (moduleb->global_methods, MonoReflectionMethodBuilder*, i);
1137 if (!mono_image_add_cattrs (assembly, mb->table_idx, MONO_CUSTOM_ATTR_METHODDEF, mb->cattrs, error) ||
1138 !params_add_cattrs (assembly, mb->pinfo, error))
1139 return FALSE;
1143 if (moduleb->global_fields) {
1144 for (i = 0; i < mono_array_length_internal (moduleb->global_fields); ++i) {
1145 MonoReflectionFieldBuilder *fb = mono_array_get_internal (moduleb->global_fields, MonoReflectionFieldBuilder*, i);
1146 if (!mono_image_add_cattrs (assembly, field_builder_table_index (assembly, fb), MONO_CUSTOM_ATTR_FIELDDEF, fb->cattrs, error))
1147 return FALSE;
1151 if (moduleb->types) {
1152 for (i = 0; i < moduleb->num_types; ++i) {
1153 if (!type_add_cattrs (assembly, mono_array_get_internal (moduleb->types, MonoReflectionTypeBuilder*, i), error))
1154 return FALSE;
1158 return TRUE;
1161 static gboolean
1162 mono_image_fill_file_table (MonoDomain *domain, MonoReflectionModule *module, MonoDynamicImage *assembly, MonoError *error)
1164 MonoDynamicTable *table;
1165 guint32 *values;
1166 char blob_size [6];
1167 guchar hash [20];
1168 char *b = blob_size;
1169 char *dir, *path;
1171 error_init (error);
1173 table = &assembly->tables [MONO_TABLE_FILE];
1174 table->rows++;
1175 alloc_table (table, table->rows);
1176 values = table->values + table->next_idx * MONO_FILE_SIZE;
1177 values [MONO_FILE_FLAGS] = FILE_CONTAINS_METADATA;
1178 values [MONO_FILE_NAME] = string_heap_insert (&assembly->sheap, module->image->module_name);
1179 if (image_is_dynamic (module->image)) {
1180 /* This depends on the fact that the main module is emitted last */
1181 dir = mono_string_to_utf8_checked_internal (((MonoReflectionModuleBuilder*)module)->assemblyb->dir, error);
1182 return_val_if_nok (error, FALSE);
1183 path = g_strdup_printf ("%s%c%s", dir, G_DIR_SEPARATOR, module->image->module_name);
1184 } else {
1185 dir = NULL;
1186 path = g_strdup (module->image->name);
1188 mono_sha1_get_digest_from_file (path, hash);
1189 g_free (dir);
1190 g_free (path);
1191 mono_metadata_encode_value (20, b, &b);
1192 values [MONO_FILE_HASH_VALUE] = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
1193 mono_image_add_stream_data (&assembly->blob, (char*)hash, 20);
1194 table->next_idx ++;
1195 return TRUE;
1198 static void
1199 mono_image_fill_module_table (MonoDomain *domain, MonoReflectionModuleBuilder *mb, MonoDynamicImage *assembly, MonoError *error)
1201 MonoDynamicTable *table;
1202 int i;
1204 error_init (error);
1206 table = &assembly->tables [MONO_TABLE_MODULE];
1207 mb->table_idx = table->next_idx ++;
1208 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->module.name, error);
1209 return_if_nok (error);
1210 i = mono_image_add_stream_data (&assembly->guid, mono_array_addr_internal (mb->guid, char, 0), 16);
1211 i /= 16;
1212 ++i;
1213 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_GENERATION] = 0;
1214 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_MVID] = i;
1215 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_ENC] = 0;
1216 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_ENCBASE] = 0;
1219 static guint32
1220 mono_image_fill_export_table_from_class (MonoDomain *domain, MonoClass *klass,
1221 guint32 module_index, guint32 parent_index, MonoDynamicImage *assembly)
1223 MonoDynamicTable *table;
1224 guint32 *values;
1225 guint32 visib, res;
1227 visib = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_VISIBILITY_MASK;
1228 if (! ((visib & TYPE_ATTRIBUTE_PUBLIC) || (visib & TYPE_ATTRIBUTE_NESTED_PUBLIC)))
1229 return 0;
1231 table = &assembly->tables [MONO_TABLE_EXPORTEDTYPE];
1232 table->rows++;
1233 alloc_table (table, table->rows);
1234 values = table->values + table->next_idx * MONO_EXP_TYPE_SIZE;
1236 values [MONO_EXP_TYPE_FLAGS] = mono_class_get_flags (klass);
1237 values [MONO_EXP_TYPE_TYPEDEF] = m_class_get_type_token (klass);
1238 if (m_class_get_nested_in (klass))
1239 values [MONO_EXP_TYPE_IMPLEMENTATION] = (parent_index << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_EXP_TYPE;
1240 else
1241 values [MONO_EXP_TYPE_IMPLEMENTATION] = (module_index << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_FILE;
1242 values [MONO_EXP_TYPE_NAME] = string_heap_insert (&assembly->sheap, m_class_get_name (klass));
1243 values [MONO_EXP_TYPE_NAMESPACE] = string_heap_insert (&assembly->sheap, m_class_get_name_space (klass));
1245 res = table->next_idx;
1247 table->next_idx ++;
1249 /* Emit nested types */
1250 GList *nested_classes = mono_class_get_nested_classes_property (klass);
1251 GList *tmp;
1252 for (tmp = nested_classes; tmp; tmp = tmp->next)
1253 mono_image_fill_export_table_from_class (domain, (MonoClass *)tmp->data, module_index, table->next_idx - 1, assembly);
1255 return res;
1258 static void
1259 mono_image_fill_export_table (MonoDomain *domain, MonoReflectionTypeBuilder *tb,
1260 guint32 module_index, guint32 parent_index, MonoDynamicImage *assembly,
1261 MonoError *error)
1263 MonoClass *klass;
1264 guint32 idx, i;
1266 error_init (error);
1268 MonoType *t = mono_reflection_type_get_handle ((MonoReflectionType*)tb, error);
1269 return_if_nok (error);
1271 klass = mono_class_from_mono_type_internal (t);
1273 guint32 tb_token = mono_metadata_make_token (MONO_TABLE_TYPEDEF, tb->table_idx);
1274 if (m_class_get_type_token (klass) != tb_token) {
1275 g_error ("TypeBuilder token %08x does not match klass token %08x", tb_token, m_class_get_type_token (klass));
1278 idx = mono_image_fill_export_table_from_class (domain, klass, module_index,
1279 parent_index, assembly);
1282 * Emit nested types
1283 * We need to do this ourselves since klass->nested_classes is not set up.
1285 if (tb->subtypes) {
1286 for (i = 0; i < mono_array_length_internal (tb->subtypes); ++i) {
1287 mono_image_fill_export_table (domain, mono_array_get_internal (tb->subtypes, MonoReflectionTypeBuilder*, i), module_index, idx, assembly, error);
1288 return_if_nok (error);
1293 static void
1294 mono_image_fill_export_table_from_module (MonoDomain *domain, MonoReflectionModule *module,
1295 guint32 module_index, MonoDynamicImage *assembly)
1297 MonoImage *image = module->image;
1298 MonoTableInfo *t;
1299 guint32 i;
1301 t = &image->tables [MONO_TABLE_TYPEDEF];
1303 for (i = 0; i < t->rows; ++i) {
1304 ERROR_DECL (error);
1305 MonoClass *klass = mono_class_get_checked (image, mono_metadata_make_token (MONO_TABLE_TYPEDEF, i + 1), error);
1306 g_assert (mono_error_ok (error)); /* FIXME don't swallow the error */
1308 if (mono_class_is_public (klass))
1309 mono_image_fill_export_table_from_class (domain, klass, module_index, 0, assembly);
1313 static void
1314 add_exported_type (MonoReflectionAssemblyBuilder *assemblyb, MonoDynamicImage *assembly, MonoClass *klass, guint32 parent_index)
1316 MonoDynamicTable *table;
1317 guint32 *values;
1318 guint32 scope, scope_idx, impl, current_idx;
1319 gboolean forwarder = TRUE;
1320 gpointer iter = NULL;
1321 MonoClass *nested;
1323 if (m_class_get_nested_in (klass)) {
1324 impl = (parent_index << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_EXP_TYPE;
1325 forwarder = FALSE;
1326 } else {
1327 scope = mono_reflection_resolution_scope_from_image (assembly, m_class_get_image (klass));
1328 g_assert ((scope & MONO_RESOLUTION_SCOPE_MASK) == MONO_RESOLUTION_SCOPE_ASSEMBLYREF);
1329 scope_idx = scope >> MONO_RESOLUTION_SCOPE_BITS;
1330 impl = (scope_idx << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_ASSEMBLYREF;
1333 table = &assembly->tables [MONO_TABLE_EXPORTEDTYPE];
1335 table->rows++;
1336 alloc_table (table, table->rows);
1337 current_idx = table->next_idx;
1338 values = table->values + current_idx * MONO_EXP_TYPE_SIZE;
1340 values [MONO_EXP_TYPE_FLAGS] = forwarder ? TYPE_ATTRIBUTE_FORWARDER : 0;
1341 values [MONO_EXP_TYPE_TYPEDEF] = 0;
1342 values [MONO_EXP_TYPE_IMPLEMENTATION] = impl;
1343 values [MONO_EXP_TYPE_NAME] = string_heap_insert (&assembly->sheap, m_class_get_name (klass));
1344 values [MONO_EXP_TYPE_NAMESPACE] = string_heap_insert (&assembly->sheap, m_class_get_name_space (klass));
1346 table->next_idx++;
1348 while ((nested = mono_class_get_nested_types (klass, &iter)))
1349 add_exported_type (assemblyb, assembly, nested, current_idx);
1352 static void
1353 mono_image_fill_export_table_from_type_forwarders (MonoReflectionAssemblyBuilder *assemblyb, MonoDynamicImage *assembly)
1355 ERROR_DECL (error);
1356 MonoClass *klass;
1357 int i;
1359 if (!assemblyb->type_forwarders)
1360 return;
1362 for (i = 0; i < mono_array_length_internal (assemblyb->type_forwarders); ++i) {
1363 MonoReflectionType *t = mono_array_get_internal (assemblyb->type_forwarders, MonoReflectionType *, i);
1364 MonoType *type;
1365 if (!t)
1366 continue;
1368 type = mono_reflection_type_get_handle (t, error);
1369 mono_error_assert_ok (error);
1370 g_assert (type);
1372 klass = mono_class_from_mono_type_internal (type);
1374 add_exported_type (assemblyb, assembly, klass, 0);
1378 #define align_pointer(base,p)\
1379 do {\
1380 guint32 __diff = (unsigned char*)(p)-(unsigned char*)(base);\
1381 if (__diff & 3)\
1382 (p) += 4 - (__diff & 3);\
1383 } while (0)
1385 static int
1386 compare_constants (const void *a, const void *b)
1388 const guint32 *a_values = (const guint32 *)a;
1389 const guint32 *b_values = (const guint32 *)b;
1390 return a_values [MONO_CONSTANT_PARENT] - b_values [MONO_CONSTANT_PARENT];
1393 static int
1394 compare_semantics (const void *a, const void *b)
1396 const guint32 *a_values = (const guint32 *)a;
1397 const guint32 *b_values = (const guint32 *)b;
1398 int assoc = a_values [MONO_METHOD_SEMA_ASSOCIATION] - b_values [MONO_METHOD_SEMA_ASSOCIATION];
1399 if (assoc)
1400 return assoc;
1401 return a_values [MONO_METHOD_SEMA_SEMANTICS] - b_values [MONO_METHOD_SEMA_SEMANTICS];
1404 static int
1405 compare_custom_attrs (const void *a, const void *b)
1407 const guint32 *a_values = (const guint32 *)a;
1408 const guint32 *b_values = (const guint32 *)b;
1410 return a_values [MONO_CUSTOM_ATTR_PARENT] - b_values [MONO_CUSTOM_ATTR_PARENT];
1413 static int
1414 compare_field_marshal (const void *a, const void *b)
1416 const guint32 *a_values = (const guint32 *)a;
1417 const guint32 *b_values = (const guint32 *)b;
1419 return a_values [MONO_FIELD_MARSHAL_PARENT] - b_values [MONO_FIELD_MARSHAL_PARENT];
1422 static int
1423 compare_nested (const void *a, const void *b)
1425 const guint32 *a_values = (const guint32 *)a;
1426 const guint32 *b_values = (const guint32 *)b;
1428 return a_values [MONO_NESTED_CLASS_NESTED] - b_values [MONO_NESTED_CLASS_NESTED];
1431 static int
1432 compare_genericparam (const void *a, const void *b)
1434 ERROR_DECL (error);
1435 const GenericParamTableEntry **a_entry = (const GenericParamTableEntry **) a;
1436 const GenericParamTableEntry **b_entry = (const GenericParamTableEntry **) b;
1438 if ((*b_entry)->owner == (*a_entry)->owner) {
1439 MonoType *a_type = mono_reflection_type_get_handle ((MonoReflectionType*)(*a_entry)->gparam, error);
1440 mono_error_assert_ok (error);
1441 MonoType *b_type = mono_reflection_type_get_handle ((MonoReflectionType*)(*b_entry)->gparam, error);
1442 mono_error_assert_ok (error);
1443 return
1444 mono_type_get_generic_param_num (a_type) -
1445 mono_type_get_generic_param_num (b_type);
1446 } else
1447 return (*a_entry)->owner - (*b_entry)->owner;
1450 static int
1451 compare_declsecurity_attrs (const void *a, const void *b)
1453 const guint32 *a_values = (const guint32 *)a;
1454 const guint32 *b_values = (const guint32 *)b;
1456 return a_values [MONO_DECL_SECURITY_PARENT] - b_values [MONO_DECL_SECURITY_PARENT];
1459 static int
1460 compare_interface_impl (const void *a, const void *b)
1462 const guint32 *a_values = (const guint32 *)a;
1463 const guint32 *b_values = (const guint32 *)b;
1465 int klass = a_values [MONO_INTERFACEIMPL_CLASS] - b_values [MONO_INTERFACEIMPL_CLASS];
1466 if (klass)
1467 return klass;
1469 return a_values [MONO_INTERFACEIMPL_INTERFACE] - b_values [MONO_INTERFACEIMPL_INTERFACE];
1472 struct StreamDesc {
1473 const char *name;
1474 MonoDynamicStream *stream;
1478 * build_compressed_metadata() fills in the blob of data that represents the
1479 * raw metadata as it will be saved in the PE file. The five streams are output
1480 * and the metadata tables are comnpressed from the guint32 array representation,
1481 * to the compressed on-disk format.
1483 static gboolean
1484 build_compressed_metadata (MonoDynamicImage *assembly, MonoError *error)
1486 MonoDynamicTable *table;
1487 int i;
1488 guint64 valid_mask = 0;
1489 guint64 sorted_mask;
1490 guint32 heapt_size = 0;
1491 guint32 meta_size = 256; /* allow for header and other stuff */
1492 guint32 table_offset;
1493 guint32 ntables = 0;
1494 guint64 *int64val;
1495 guint32 *int32val;
1496 guint16 *int16val;
1497 MonoImage *meta;
1498 unsigned char *p;
1499 struct StreamDesc stream_desc [5];
1501 error_init (error);
1503 qsort (assembly->gen_params->pdata, assembly->gen_params->len, sizeof (gpointer), compare_genericparam);
1504 for (i = 0; i < assembly->gen_params->len; i++) {
1505 GenericParamTableEntry *entry = (GenericParamTableEntry *)g_ptr_array_index (assembly->gen_params, i);
1506 if (!write_generic_param_entry (assembly, entry, error))
1507 return FALSE;
1510 stream_desc [0].name = "#~";
1511 stream_desc [0].stream = &assembly->tstream;
1512 stream_desc [1].name = "#Strings";
1513 stream_desc [1].stream = &assembly->sheap;
1514 stream_desc [2].name = "#US";
1515 stream_desc [2].stream = &assembly->us;
1516 stream_desc [3].name = "#Blob";
1517 stream_desc [3].stream = &assembly->blob;
1518 stream_desc [4].name = "#GUID";
1519 stream_desc [4].stream = &assembly->guid;
1521 /* tables that are sorted */
1522 sorted_mask = ((guint64)1 << MONO_TABLE_CONSTANT) | ((guint64)1 << MONO_TABLE_FIELDMARSHAL)
1523 | ((guint64)1 << MONO_TABLE_METHODSEMANTICS) | ((guint64)1 << MONO_TABLE_CLASSLAYOUT)
1524 | ((guint64)1 << MONO_TABLE_FIELDLAYOUT) | ((guint64)1 << MONO_TABLE_FIELDRVA)
1525 | ((guint64)1 << MONO_TABLE_IMPLMAP) | ((guint64)1 << MONO_TABLE_NESTEDCLASS)
1526 | ((guint64)1 << MONO_TABLE_METHODIMPL) | ((guint64)1 << MONO_TABLE_CUSTOMATTRIBUTE)
1527 | ((guint64)1 << MONO_TABLE_DECLSECURITY) | ((guint64)1 << MONO_TABLE_GENERICPARAM)
1528 | ((guint64)1 << MONO_TABLE_INTERFACEIMPL);
1530 /* Compute table sizes */
1531 /* the MonoImage has already been created in mono_reflection_dynimage_basic_init() */
1532 meta = &assembly->image;
1534 /* sizes should be multiple of 4 */
1535 mono_dynstream_data_align (&assembly->blob);
1536 mono_dynstream_data_align (&assembly->guid);
1537 mono_dynstream_data_align (&assembly->sheap);
1538 mono_dynstream_data_align (&assembly->us);
1540 /* Setup the info used by compute_sizes () */
1541 meta->idx_blob_wide = assembly->blob.index >= 65536 ? 1 : 0;
1542 meta->idx_guid_wide = assembly->guid.index >= 65536 ? 1 : 0;
1543 meta->idx_string_wide = assembly->sheap.index >= 65536 ? 1 : 0;
1545 meta_size += assembly->blob.index;
1546 meta_size += assembly->guid.index;
1547 meta_size += assembly->sheap.index;
1548 meta_size += assembly->us.index;
1550 for (i=0; i < MONO_TABLE_NUM; ++i)
1551 meta->tables [i].rows = assembly->tables [i].rows;
1553 for (i = 0; i < MONO_TABLE_NUM; i++){
1554 if (meta->tables [i].rows == 0)
1555 continue;
1556 valid_mask |= (guint64)1 << i;
1557 ntables ++;
1558 meta->tables [i].row_size = mono_metadata_compute_size (
1559 meta, i, &meta->tables [i].size_bitfield);
1560 heapt_size += meta->tables [i].row_size * meta->tables [i].rows;
1562 heapt_size += 24; /* #~ header size */
1563 heapt_size += ntables * 4;
1564 /* make multiple of 4 */
1565 heapt_size += 3;
1566 heapt_size &= ~3;
1567 meta_size += heapt_size;
1568 meta->raw_metadata = (char *)g_malloc0 (meta_size);
1569 p = (unsigned char*)meta->raw_metadata;
1570 /* the metadata signature */
1571 *p++ = 'B'; *p++ = 'S'; *p++ = 'J'; *p++ = 'B';
1572 /* version numbers and 4 bytes reserved */
1573 int16val = (guint16*)p;
1574 *int16val++ = GUINT16_TO_LE (meta->md_version_major);
1575 *int16val = GUINT16_TO_LE (meta->md_version_minor);
1576 p += 8;
1577 /* version string */
1578 int32val = (guint32*)p;
1579 *int32val = GUINT32_TO_LE ((strlen (meta->version) + 3) & (~3)); /* needs to be multiple of 4 */
1580 p += 4;
1581 memcpy (p, meta->version, strlen (meta->version));
1582 p += GUINT32_FROM_LE (*int32val);
1583 align_pointer (meta->raw_metadata, p);
1584 int16val = (guint16*)p;
1585 *int16val++ = GUINT16_TO_LE (0); /* flags must be 0 */
1586 *int16val = GUINT16_TO_LE (5); /* number of streams */
1587 p += 4;
1590 * write the stream info.
1592 table_offset = (p - (unsigned char*)meta->raw_metadata) + 5 * 8 + 40; /* room needed for stream headers */
1593 table_offset += 3; table_offset &= ~3;
1595 assembly->tstream.index = heapt_size;
1596 for (i = 0; i < 5; ++i) {
1597 int32val = (guint32*)p;
1598 stream_desc [i].stream->offset = table_offset;
1599 *int32val++ = GUINT32_TO_LE (table_offset);
1600 *int32val = GUINT32_TO_LE (stream_desc [i].stream->index);
1601 table_offset += GUINT32_FROM_LE (*int32val);
1602 table_offset += 3; table_offset &= ~3;
1603 p += 8;
1604 strcpy ((char*)p, stream_desc [i].name);
1605 p += strlen (stream_desc [i].name) + 1;
1606 align_pointer (meta->raw_metadata, p);
1609 * now copy the data, the table stream header and contents goes first.
1611 g_assert ((p - (unsigned char*)meta->raw_metadata) < assembly->tstream.offset);
1612 p = (guchar*)meta->raw_metadata + assembly->tstream.offset;
1613 int32val = (guint32*)p;
1614 *int32val = GUINT32_TO_LE (0); /* reserved */
1615 p += 4;
1617 *p++ = 2; /* version */
1618 *p++ = 0;
1620 if (meta->idx_string_wide)
1621 *p |= 0x01;
1622 if (meta->idx_guid_wide)
1623 *p |= 0x02;
1624 if (meta->idx_blob_wide)
1625 *p |= 0x04;
1626 ++p;
1627 *p++ = 1; /* reserved */
1628 int64val = (guint64*)p;
1629 *int64val++ = GUINT64_TO_LE (valid_mask);
1630 *int64val++ = GUINT64_TO_LE (valid_mask & sorted_mask); /* bitvector of sorted tables */
1631 p += 16;
1632 int32val = (guint32*)p;
1633 for (i = 0; i < MONO_TABLE_NUM; i++){
1634 if (meta->tables [i].rows == 0)
1635 continue;
1636 *int32val++ = GUINT32_TO_LE (meta->tables [i].rows);
1638 p = (unsigned char*)int32val;
1640 /* sort the tables that still need sorting */
1641 table = &assembly->tables [MONO_TABLE_CONSTANT];
1642 if (table->rows)
1643 qsort (table->values + MONO_CONSTANT_SIZE, table->rows, sizeof (guint32) * MONO_CONSTANT_SIZE, compare_constants);
1644 table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
1645 if (table->rows)
1646 qsort (table->values + MONO_METHOD_SEMA_SIZE, table->rows, sizeof (guint32) * MONO_METHOD_SEMA_SIZE, compare_semantics);
1647 table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1648 if (table->rows)
1649 qsort (table->values + MONO_CUSTOM_ATTR_SIZE, table->rows, sizeof (guint32) * MONO_CUSTOM_ATTR_SIZE, compare_custom_attrs);
1650 table = &assembly->tables [MONO_TABLE_FIELDMARSHAL];
1651 if (table->rows)
1652 qsort (table->values + MONO_FIELD_MARSHAL_SIZE, table->rows, sizeof (guint32) * MONO_FIELD_MARSHAL_SIZE, compare_field_marshal);
1653 table = &assembly->tables [MONO_TABLE_NESTEDCLASS];
1654 if (table->rows)
1655 qsort (table->values + MONO_NESTED_CLASS_SIZE, table->rows, sizeof (guint32) * MONO_NESTED_CLASS_SIZE, compare_nested);
1656 /* Section 21.11 DeclSecurity in Partition II doesn't specify this to be sorted by MS implementation requires it */
1657 table = &assembly->tables [MONO_TABLE_DECLSECURITY];
1658 if (table->rows)
1659 qsort (table->values + MONO_DECL_SECURITY_SIZE, table->rows, sizeof (guint32) * MONO_DECL_SECURITY_SIZE, compare_declsecurity_attrs);
1660 table = &assembly->tables [MONO_TABLE_INTERFACEIMPL];
1661 if (table->rows)
1662 qsort (table->values + MONO_INTERFACEIMPL_SIZE, table->rows, sizeof (guint32) * MONO_INTERFACEIMPL_SIZE, compare_interface_impl);
1664 /* compress the tables */
1665 for (i = 0; i < MONO_TABLE_NUM; i++){
1666 int row, col;
1667 guint32 *values;
1668 guint32 bitfield = meta->tables [i].size_bitfield;
1669 if (!meta->tables [i].rows)
1670 continue;
1671 if (assembly->tables [i].columns != mono_metadata_table_count (bitfield))
1672 g_error ("col count mismatch in %d: %d %d", i, assembly->tables [i].columns, mono_metadata_table_count (bitfield));
1673 meta->tables [i].base = (char*)p;
1674 for (row = 1; row <= meta->tables [i].rows; ++row) {
1675 values = assembly->tables [i].values + row * assembly->tables [i].columns;
1676 for (col = 0; col < assembly->tables [i].columns; ++col) {
1677 switch (mono_metadata_table_size (bitfield, col)) {
1678 case 1:
1679 *p++ = values [col];
1680 break;
1681 case 2:
1682 *p++ = values [col] & 0xff;
1683 *p++ = (values [col] >> 8) & 0xff;
1684 break;
1685 case 4:
1686 *p++ = values [col] & 0xff;
1687 *p++ = (values [col] >> 8) & 0xff;
1688 *p++ = (values [col] >> 16) & 0xff;
1689 *p++ = (values [col] >> 24) & 0xff;
1690 break;
1691 default:
1692 g_assert_not_reached ();
1696 g_assert ((p - (const unsigned char*)meta->tables [i].base) == (meta->tables [i].rows * meta->tables [i].row_size));
1699 g_assert (assembly->guid.offset + assembly->guid.index < meta_size);
1700 memcpy (meta->raw_metadata + assembly->sheap.offset, assembly->sheap.data, assembly->sheap.index);
1701 memcpy (meta->raw_metadata + assembly->us.offset, assembly->us.data, assembly->us.index);
1702 memcpy (meta->raw_metadata + assembly->blob.offset, assembly->blob.data, assembly->blob.index);
1703 memcpy (meta->raw_metadata + assembly->guid.offset, assembly->guid.data, assembly->guid.index);
1705 assembly->meta_size = assembly->guid.offset + assembly->guid.index;
1707 return TRUE;
1711 * Some tables in metadata need to be sorted according to some criteria, but
1712 * when methods and fields are first created with reflection, they may be assigned a token
1713 * that doesn't correspond to the final token they will get assigned after the sorting.
1714 * ILGenerator.cs keeps a fixup table that maps the position of tokens in the IL code stream
1715 * with the reflection objects that represent them. Once all the tables are set up, the
1716 * reflection objects will contains the correct table index. fixup_method() will fixup the
1717 * tokens for the method with ILGenerator @ilgen.
1719 static void
1720 fixup_method (MonoReflectionILGen *ilgen, gpointer value, MonoDynamicImage *assembly)
1722 guint32 code_idx = GPOINTER_TO_UINT (value);
1723 MonoReflectionILTokenInfo *iltoken;
1724 MonoReflectionTypeBuilder *tb;
1725 MonoReflectionArrayMethod *am;
1726 guint32 i, idx = 0;
1727 unsigned char *target;
1729 for (i = 0; i < ilgen->num_token_fixups; ++i) {
1730 iltoken = (MonoReflectionILTokenInfo *)mono_array_addr_with_size_internal (ilgen->token_fixups, sizeof (MonoReflectionILTokenInfo), i);
1731 target = (guchar*)assembly->code.data + code_idx + iltoken->code_pos;
1732 MonoClass *iltoken_member_class = mono_object_class (iltoken->member);
1733 const char *iltoken_member_class_name = m_class_get_name (iltoken_member_class);
1734 switch (target [3]) {
1735 case MONO_TABLE_FIELD:
1736 if (!strcmp (iltoken_member_class_name, "FieldBuilder")) {
1737 g_assert_not_reached ();
1738 } else if (!strcmp (iltoken_member_class_name, "RuntimeFieldInfo")) {
1739 MonoClassField *f = ((MonoReflectionField*)iltoken->member)->field;
1740 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->field_to_table_idx, f));
1741 } else {
1742 g_assert_not_reached ();
1744 break;
1745 case MONO_TABLE_METHOD:
1746 if (!strcmp (iltoken_member_class_name, "MethodBuilder")) {
1747 g_assert_not_reached ();
1748 } else if (!strcmp (iltoken_member_class_name, "ConstructorBuilder")) {
1749 g_assert_not_reached ();
1750 } else if (!strcmp (iltoken_member_class_name, "RuntimeMethodInfo") ||
1751 !strcmp (iltoken_member_class_name, "RuntimeConstructorInfo")) {
1752 MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
1753 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, m));
1754 } else {
1755 g_assert_not_reached ();
1757 break;
1758 case MONO_TABLE_TYPEDEF:
1759 if (!strcmp (iltoken_member_class_name, "TypeBuilder")) {
1760 g_assert_not_reached ();
1761 } else if (!strcmp (iltoken_member_class_name, "RuntimeType")) {
1762 MonoClass *k = mono_class_from_mono_type_internal (((MonoReflectionType*)iltoken->member)->type);
1763 MonoObject *obj = &mono_class_get_ref_info_raw (k)->type.object; /* FIXME use handles */
1764 g_assert (obj);
1765 g_assert (!strcmp (m_class_get_name (mono_object_class (obj)), "TypeBuilder"));
1766 tb = (MonoReflectionTypeBuilder*)obj;
1767 idx = tb->table_idx;
1768 } else {
1769 g_assert_not_reached ();
1771 break;
1772 case MONO_TABLE_TYPEREF:
1773 g_assert (!strcmp (iltoken_member_class_name, "RuntimeType"));
1774 MonoClass *k;
1775 k = mono_class_from_mono_type_internal (((MonoReflectionType*)iltoken->member)->type);
1776 MonoObject *obj;
1777 obj = &mono_class_get_ref_info_raw (k)->type.object; /* FIXME use handles */
1778 g_assert (obj);
1779 g_assert (!strcmp (m_class_get_name (mono_object_class (obj)), "TypeBuilder"));
1780 g_assert (((MonoReflectionTypeBuilder*)obj)->module->dynamic_image != assembly);
1781 continue;
1782 case MONO_TABLE_MEMBERREF:
1783 if (!strcmp (iltoken_member_class_name, "MonoArrayMethod")) {
1784 am = (MonoReflectionArrayMethod*)iltoken->member;
1785 idx = am->table_idx;
1786 } else if (!strcmp (iltoken_member_class_name, "RuntimeMethodInfo") ||
1787 !strcmp (iltoken_member_class_name, "RuntimeConstructorInfo")) {
1788 MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
1789 g_assert (mono_class_is_ginst (m->klass) || mono_class_is_gtd (m->klass));
1790 continue;
1791 } else if (!strcmp (iltoken_member_class_name, "FieldBuilder")) {
1792 g_assert_not_reached ();
1793 continue;
1794 } else if (!strcmp (iltoken_member_class_name, "RuntimeFieldInfo")) {
1795 continue;
1796 } else if (!strcmp (iltoken_member_class_name, "MethodBuilder") ||
1797 !strcmp (iltoken_member_class_name, "ConstructorBuilder")) {
1798 g_assert_not_reached ();
1799 continue;
1800 } else if (!strcmp (iltoken_member_class_name, "FieldOnTypeBuilderInst")) {
1801 g_assert_not_reached ();
1802 continue;
1803 } else if (!strcmp (iltoken_member_class_name, "MethodOnTypeBuilderInst")) {
1804 g_assert_not_reached ();
1805 continue;
1806 } else if (!strcmp (iltoken_member_class_name, "ConstructorOnTypeBuilderInst")) {
1807 g_assert_not_reached ();
1808 continue;
1809 } else {
1810 g_assert_not_reached ();
1812 break;
1813 case MONO_TABLE_METHODSPEC:
1814 if (!strcmp (iltoken_member_class_name, "RuntimeMethodInfo")) {
1815 MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
1816 g_assert (mono_method_signature_internal (m)->generic_param_count);
1817 continue;
1818 } else if (!strcmp (iltoken_member_class_name, "MethodBuilder")) {
1819 g_assert_not_reached ();
1820 continue;
1821 } else if (!strcmp (iltoken_member_class_name, "MethodOnTypeBuilderInst")) {
1822 g_assert_not_reached ();
1823 continue;
1824 } else {
1825 g_assert_not_reached ();
1827 break;
1828 case MONO_TABLE_TYPESPEC:
1829 if (!strcmp (iltoken_member_class_name, "RuntimeType")) {
1830 continue;
1831 } else {
1832 g_assert_not_reached ();
1834 break;
1835 default:
1836 g_error ("got unexpected table 0x%02x in fixup", target [3]);
1838 target [0] = idx & 0xff;
1839 target [1] = (idx >> 8) & 0xff;
1840 target [2] = (idx >> 16) & 0xff;
1845 * fixup_cattrs:
1847 * The CUSTOM_ATTRIBUTE table might contain METHODDEF tokens whose final
1848 * value is not known when the table is emitted.
1850 static void
1851 fixup_cattrs (MonoDynamicImage *assembly)
1853 MonoDynamicTable *table;
1854 guint32 *values;
1855 guint32 type, i, idx, token;
1856 MonoObject *ctor;
1858 table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1860 for (i = 0; i < table->rows; ++i) {
1861 values = table->values + ((i + 1) * MONO_CUSTOM_ATTR_SIZE);
1863 type = values [MONO_CUSTOM_ATTR_TYPE];
1864 if ((type & MONO_CUSTOM_ATTR_TYPE_MASK) == MONO_CUSTOM_ATTR_TYPE_METHODDEF) {
1865 idx = type >> MONO_CUSTOM_ATTR_TYPE_BITS;
1866 token = mono_metadata_make_token (MONO_TABLE_METHOD, idx);
1867 ctor = (MonoObject *)mono_g_hash_table_lookup (assembly->remapped_tokens, GUINT_TO_POINTER (token));
1868 g_assert (ctor);
1870 if (!strcmp (m_class_get_name (mono_object_class (ctor)), "RuntimeConstructorInfo")) {
1871 MonoMethod *m = ((MonoReflectionMethod*)ctor)->method;
1872 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, m));
1873 values [MONO_CUSTOM_ATTR_TYPE] = (idx << MONO_CUSTOM_ATTR_TYPE_BITS) | MONO_CUSTOM_ATTR_TYPE_METHODDEF;
1874 } else if (!strcmp (m_class_get_name (mono_object_class (ctor)), "ConstructorBuilder")) {
1875 MonoMethod *m = ((MonoReflectionCtorBuilder*)ctor)->mhandle;
1876 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, m));
1877 values [MONO_CUSTOM_ATTR_TYPE] = (idx << MONO_CUSTOM_ATTR_TYPE_BITS) | MONO_CUSTOM_ATTR_TYPE_METHODDEF;
1883 static gboolean
1884 assembly_add_resource_manifest (MonoReflectionModuleBuilder *mb, MonoDynamicImage *assembly, MonoReflectionResource *rsrc, guint32 implementation, MonoError *error)
1886 MonoDynamicTable *table;
1887 guint32 *values;
1889 error_init (error);
1891 table = &assembly->tables [MONO_TABLE_MANIFESTRESOURCE];
1892 table->rows++;
1893 alloc_table (table, table->rows);
1894 values = table->values + table->next_idx * MONO_MANIFEST_SIZE;
1895 values [MONO_MANIFEST_OFFSET] = rsrc->offset;
1896 values [MONO_MANIFEST_FLAGS] = rsrc->attrs;
1897 values [MONO_MANIFEST_NAME] = string_heap_insert_mstring (&assembly->sheap, rsrc->name, error);
1898 return_val_if_nok (error, FALSE);
1899 values [MONO_MANIFEST_IMPLEMENTATION] = implementation;
1900 table->next_idx++;
1901 return TRUE;
1904 static gboolean
1905 assembly_add_resource (MonoReflectionModuleBuilder *mb, MonoDynamicImage *assembly, MonoReflectionResource *rsrc, MonoError *error)
1907 MonoDynamicTable *table;
1908 guint32 *values;
1909 char blob_size [6];
1910 guchar hash [20];
1911 char *b = blob_size;
1912 char *name, *sname;
1913 guint32 idx, offset;
1915 error_init (error);
1917 if (rsrc->filename) {
1918 name = mono_string_to_utf8_checked_internal (rsrc->filename, error);
1919 return_val_if_nok (error, FALSE);
1920 sname = g_path_get_basename (name);
1922 table = &assembly->tables [MONO_TABLE_FILE];
1923 table->rows++;
1924 alloc_table (table, table->rows);
1925 values = table->values + table->next_idx * MONO_FILE_SIZE;
1926 values [MONO_FILE_FLAGS] = FILE_CONTAINS_NO_METADATA;
1927 values [MONO_FILE_NAME] = string_heap_insert (&assembly->sheap, sname);
1928 g_free (sname);
1930 mono_sha1_get_digest_from_file (name, hash);
1931 mono_metadata_encode_value (20, b, &b);
1932 values [MONO_FILE_HASH_VALUE] = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
1933 mono_image_add_stream_data (&assembly->blob, (char*)hash, 20);
1934 g_free (name);
1935 idx = table->next_idx++;
1936 rsrc->offset = 0;
1937 idx = MONO_IMPLEMENTATION_FILE | (idx << MONO_IMPLEMENTATION_BITS);
1938 } else {
1939 char sizebuf [4];
1940 char *data;
1941 guint len;
1942 if (rsrc->data) {
1943 data = mono_array_addr_internal (rsrc->data, char, 0);
1944 len = mono_array_length_internal (rsrc->data);
1945 } else {
1946 data = NULL;
1947 len = 0;
1949 offset = len;
1950 sizebuf [0] = offset; sizebuf [1] = offset >> 8;
1951 sizebuf [2] = offset >> 16; sizebuf [3] = offset >> 24;
1952 rsrc->offset = mono_image_add_stream_data (&assembly->resources, sizebuf, 4);
1953 mono_image_add_stream_data (&assembly->resources, data, len);
1955 if (!mb->is_main)
1957 * The entry should be emitted into the MANIFESTRESOURCE table of
1958 * the main module, but that needs to reference the FILE table
1959 * which isn't emitted yet.
1961 return TRUE;
1962 else
1963 idx = 0;
1966 return assembly_add_resource_manifest (mb, assembly, rsrc, idx, error);
1969 static gboolean
1970 set_version_from_string (MonoString *version, guint32 *values, MonoError *error)
1972 gchar *ver, *p, *str;
1973 guint32 i;
1975 error_init (error);
1977 values [MONO_ASSEMBLY_MAJOR_VERSION] = 0;
1978 values [MONO_ASSEMBLY_MINOR_VERSION] = 0;
1979 values [MONO_ASSEMBLY_REV_NUMBER] = 0;
1980 values [MONO_ASSEMBLY_BUILD_NUMBER] = 0;
1981 if (!version)
1982 return TRUE;
1983 ver = str = mono_string_to_utf8_checked_internal (version, error);
1984 return_val_if_nok (error, FALSE);
1985 for (i = 0; i < 4; ++i) {
1986 values [MONO_ASSEMBLY_MAJOR_VERSION + i] = strtol (ver, &p, 10);
1987 switch (*p) {
1988 case '.':
1989 p++;
1990 break;
1991 case '*':
1992 /* handle Revision and Build */
1993 p++;
1994 break;
1996 ver = p;
1998 g_free (str);
1999 return TRUE;
2002 static guint32
2003 load_public_key (MonoArray *pkey, MonoDynamicImage *assembly) {
2004 gsize len;
2005 guint32 token = 0;
2006 char blob_size [6];
2007 char *b = blob_size;
2009 if (!pkey)
2010 return token;
2012 len = mono_array_length_internal (pkey);
2013 mono_metadata_encode_value (len, b, &b);
2014 token = mono_image_add_stream_data (&assembly->blob, blob_size, b - blob_size);
2015 mono_image_add_stream_data (&assembly->blob, mono_array_addr_internal (pkey, char, 0), len);
2017 assembly->public_key = (guint8 *)g_malloc (len);
2018 memcpy (assembly->public_key, mono_array_addr_internal (pkey, char, 0), len);
2019 assembly->public_key_len = len;
2021 /* Special case: check for ECMA key (16 bytes) */
2022 if ((len == MONO_ECMA_KEY_LENGTH) && mono_is_ecma_key (mono_array_addr_internal (pkey, char, 0), len)) {
2023 /* In this case we must reserve 128 bytes (1024 bits) for the signature */
2024 assembly->strong_name_size = MONO_DEFAULT_PUBLIC_KEY_LENGTH;
2025 } else if (len >= MONO_PUBLIC_KEY_HEADER_LENGTH + MONO_MINIMUM_PUBLIC_KEY_LENGTH) {
2026 /* minimum key size (in 2.0) is 384 bits */
2027 assembly->strong_name_size = len - MONO_PUBLIC_KEY_HEADER_LENGTH;
2028 } else {
2029 /* FIXME - verifier */
2030 g_warning ("Invalid public key length: %d bits (total: %d)", (int)MONO_PUBLIC_KEY_BIT_SIZE (len), (int)len);
2031 assembly->strong_name_size = MONO_DEFAULT_PUBLIC_KEY_LENGTH; /* to be safe */
2033 assembly->strong_name = (char *)g_malloc0 (assembly->strong_name_size);
2035 return token;
2038 static gboolean
2039 mono_image_emit_manifest (MonoReflectionModuleBuilder *moduleb, MonoError *error)
2041 MonoDynamicTable *table;
2042 MonoDynamicImage *assembly;
2043 MonoReflectionAssemblyBuilder *assemblyb;
2044 MonoDomain *domain;
2045 guint32 *values;
2046 int i;
2047 guint32 module_index;
2049 error_init (error);
2051 assemblyb = moduleb->assemblyb;
2052 assembly = moduleb->dynamic_image;
2053 domain = mono_object_domain (assemblyb);
2055 /* Emit ASSEMBLY table */
2056 table = &assembly->tables [MONO_TABLE_ASSEMBLY];
2057 alloc_table (table, 1);
2058 values = table->values + MONO_ASSEMBLY_SIZE;
2059 values [MONO_ASSEMBLY_HASH_ALG] = assemblyb->algid? assemblyb->algid: ASSEMBLY_HASH_SHA1;
2060 values [MONO_ASSEMBLY_NAME] = string_heap_insert_mstring (&assembly->sheap, assemblyb->name, error);
2061 return_val_if_nok (error, FALSE);
2062 if (assemblyb->culture) {
2063 values [MONO_ASSEMBLY_CULTURE] = string_heap_insert_mstring (&assembly->sheap, assemblyb->culture, error);
2064 return_val_if_nok (error, FALSE);
2065 } else {
2066 values [MONO_ASSEMBLY_CULTURE] = string_heap_insert (&assembly->sheap, "");
2068 values [MONO_ASSEMBLY_PUBLIC_KEY] = load_public_key (assemblyb->public_key, assembly);
2069 values [MONO_ASSEMBLY_FLAGS] = assemblyb->flags;
2070 if (!set_version_from_string (assemblyb->version, values, error))
2071 return FALSE;
2073 /* Emit FILE + EXPORTED_TYPE table */
2074 module_index = 0;
2075 for (i = 0; i < mono_array_length_internal (assemblyb->modules); ++i) {
2076 int j;
2077 MonoReflectionModuleBuilder *file_module =
2078 mono_array_get_internal (assemblyb->modules, MonoReflectionModuleBuilder*, i);
2079 if (file_module != moduleb) {
2080 if (!mono_image_fill_file_table (domain, (MonoReflectionModule*)file_module, assembly, error))
2081 return FALSE;
2082 module_index ++;
2083 if (file_module->types) {
2084 for (j = 0; j < file_module->num_types; ++j) {
2085 MonoReflectionTypeBuilder *tb = mono_array_get_internal (file_module->types, MonoReflectionTypeBuilder*, j);
2086 mono_image_fill_export_table (domain, tb, module_index, 0, assembly, error);
2087 return_val_if_nok (error, FALSE);
2092 if (assemblyb->loaded_modules) {
2093 for (i = 0; i < mono_array_length_internal (assemblyb->loaded_modules); ++i) {
2094 MonoReflectionModule *file_module =
2095 mono_array_get_internal (assemblyb->loaded_modules, MonoReflectionModule*, i);
2096 if (!mono_image_fill_file_table (domain, file_module, assembly, error))
2097 return FALSE;
2098 module_index ++;
2099 mono_image_fill_export_table_from_module (domain, file_module, module_index, assembly);
2102 if (assemblyb->type_forwarders)
2103 mono_image_fill_export_table_from_type_forwarders (assemblyb, assembly);
2105 /* Emit MANIFESTRESOURCE table */
2106 module_index = 0;
2107 for (i = 0; i < mono_array_length_internal (assemblyb->modules); ++i) {
2108 int j;
2109 MonoReflectionModuleBuilder *file_module =
2110 mono_array_get_internal (assemblyb->modules, MonoReflectionModuleBuilder*, i);
2111 /* The table for the main module is emitted later */
2112 if (file_module != moduleb) {
2113 module_index ++;
2114 if (file_module->resources) {
2115 int len = mono_array_length_internal (file_module->resources);
2116 for (j = 0; j < len; ++j) {
2117 MonoReflectionResource* res = (MonoReflectionResource*)mono_array_addr_internal (file_module->resources, MonoReflectionResource, j);
2118 if (!assembly_add_resource_manifest (file_module, assembly, res, MONO_IMPLEMENTATION_FILE | (module_index << MONO_IMPLEMENTATION_BITS), error))
2119 return FALSE;
2124 return TRUE;
2127 #ifndef DISABLE_REFLECTION_EMIT_SAVE
2130 * Insert into the metadata tables all the info about the TypeBuilder tb.
2131 * Data in the tables is inserted in a predefined order, since some tables need to be sorted.
2133 static gboolean
2134 mono_image_get_type_info (MonoDomain *domain, MonoReflectionTypeBuilder *tb, MonoDynamicImage *assembly, MonoError *error)
2136 MonoDynamicTable *table;
2137 guint *values;
2138 int i, is_object = 0, is_system = 0;
2139 char *n;
2141 error_init (error);
2143 table = &assembly->tables [MONO_TABLE_TYPEDEF];
2144 values = table->values + tb->table_idx * MONO_TYPEDEF_SIZE;
2145 values [MONO_TYPEDEF_FLAGS] = tb->attrs;
2146 n = mono_string_to_utf8_checked_internal (tb->name, error);
2147 return_val_if_nok (error, FALSE);
2148 if (strcmp (n, "Object") == 0)
2149 is_object++;
2150 values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, n);
2151 g_free (n);
2152 n = mono_string_to_utf8_checked_internal (tb->nspace, error);
2153 return_val_if_nok (error, FALSE);
2154 if (strcmp (n, "System") == 0)
2155 is_system++;
2156 values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, n);
2157 g_free (n);
2158 if (tb->parent && !(is_system && is_object) &&
2159 !(tb->attrs & TYPE_ATTRIBUTE_INTERFACE)) { /* interfaces don't have a parent */
2160 MonoType *parent_type = mono_reflection_type_get_handle ((MonoReflectionType*)tb->parent, error);
2161 return_val_if_nok (error, FALSE);
2162 values [MONO_TYPEDEF_EXTENDS] = mono_image_typedef_or_ref (assembly, parent_type);
2163 } else {
2164 values [MONO_TYPEDEF_EXTENDS] = 0;
2166 values [MONO_TYPEDEF_FIELD_LIST] = assembly->tables [MONO_TABLE_FIELD].next_idx;
2167 values [MONO_TYPEDEF_METHOD_LIST] = assembly->tables [MONO_TABLE_METHOD].next_idx;
2170 * if we have explicitlayout or sequentiallayouts, output data in the
2171 * ClassLayout table.
2173 if (((tb->attrs & TYPE_ATTRIBUTE_LAYOUT_MASK) != TYPE_ATTRIBUTE_AUTO_LAYOUT) &&
2174 ((tb->class_size > 0) || (tb->packing_size > 0))) {
2175 table = &assembly->tables [MONO_TABLE_CLASSLAYOUT];
2176 table->rows++;
2177 alloc_table (table, table->rows);
2178 values = table->values + table->rows * MONO_CLASS_LAYOUT_SIZE;
2179 values [MONO_CLASS_LAYOUT_PARENT] = tb->table_idx;
2180 values [MONO_CLASS_LAYOUT_CLASS_SIZE] = tb->class_size;
2181 values [MONO_CLASS_LAYOUT_PACKING_SIZE] = tb->packing_size;
2184 /* handle interfaces */
2185 if (tb->interfaces) {
2186 table = &assembly->tables [MONO_TABLE_INTERFACEIMPL];
2187 i = table->rows;
2188 table->rows += mono_array_length_internal (tb->interfaces);
2189 alloc_table (table, table->rows);
2190 values = table->values + (i + 1) * MONO_INTERFACEIMPL_SIZE;
2191 for (i = 0; i < mono_array_length_internal (tb->interfaces); ++i) {
2192 MonoReflectionType* iface = (MonoReflectionType*) mono_array_get_internal (tb->interfaces, gpointer, i);
2193 MonoType *iface_type = mono_reflection_type_get_handle (iface, error);
2194 return_val_if_nok (error, FALSE);
2195 values [MONO_INTERFACEIMPL_CLASS] = tb->table_idx;
2196 values [MONO_INTERFACEIMPL_INTERFACE] = mono_image_typedef_or_ref (assembly, iface_type);
2197 values += MONO_INTERFACEIMPL_SIZE;
2201 /* handle fields */
2202 if (tb->fields) {
2203 table = &assembly->tables [MONO_TABLE_FIELD];
2204 table->rows += tb->num_fields;
2205 alloc_table (table, table->rows);
2206 for (i = 0; i < tb->num_fields; ++i) {
2207 mono_image_get_field_info (
2208 mono_array_get_internal (tb->fields, MonoReflectionFieldBuilder*, i), assembly, error);
2209 return_val_if_nok (error, FALSE);
2213 /* handle constructors */
2214 if (tb->ctors) {
2215 table = &assembly->tables [MONO_TABLE_METHOD];
2216 table->rows += mono_array_length_internal (tb->ctors);
2217 alloc_table (table, table->rows);
2218 for (i = 0; i < mono_array_length_internal (tb->ctors); ++i) {
2219 if (!mono_image_get_ctor_info (domain,
2220 mono_array_get_internal (tb->ctors, MonoReflectionCtorBuilder*, i),
2221 assembly, error))
2222 return FALSE;
2226 /* handle methods */
2227 if (tb->methods) {
2228 table = &assembly->tables [MONO_TABLE_METHOD];
2229 table->rows += tb->num_methods;
2230 alloc_table (table, table->rows);
2231 for (i = 0; i < tb->num_methods; ++i) {
2232 if (!mono_image_get_method_info (
2233 mono_array_get_internal (tb->methods, MonoReflectionMethodBuilder*, i), assembly, error))
2234 return FALSE;
2238 /* Do the same with properties etc.. */
2239 if (tb->events && mono_array_length_internal (tb->events)) {
2240 table = &assembly->tables [MONO_TABLE_EVENT];
2241 table->rows += mono_array_length_internal (tb->events);
2242 alloc_table (table, table->rows);
2243 table = &assembly->tables [MONO_TABLE_EVENTMAP];
2244 table->rows ++;
2245 alloc_table (table, table->rows);
2246 values = table->values + table->rows * MONO_EVENT_MAP_SIZE;
2247 values [MONO_EVENT_MAP_PARENT] = tb->table_idx;
2248 values [MONO_EVENT_MAP_EVENTLIST] = assembly->tables [MONO_TABLE_EVENT].next_idx;
2249 for (i = 0; i < mono_array_length_internal (tb->events); ++i) {
2250 mono_image_get_event_info (
2251 mono_array_get_internal (tb->events, MonoReflectionEventBuilder*, i), assembly, error);
2252 return_val_if_nok (error, FALSE);
2255 if (tb->properties && mono_array_length_internal (tb->properties)) {
2256 table = &assembly->tables [MONO_TABLE_PROPERTY];
2257 table->rows += mono_array_length_internal (tb->properties);
2258 alloc_table (table, table->rows);
2259 table = &assembly->tables [MONO_TABLE_PROPERTYMAP];
2260 table->rows ++;
2261 alloc_table (table, table->rows);
2262 values = table->values + table->rows * MONO_PROPERTY_MAP_SIZE;
2263 values [MONO_PROPERTY_MAP_PARENT] = tb->table_idx;
2264 values [MONO_PROPERTY_MAP_PROPERTY_LIST] = assembly->tables [MONO_TABLE_PROPERTY].next_idx;
2265 for (i = 0; i < mono_array_length_internal (tb->properties); ++i) {
2266 mono_image_get_property_info (
2267 mono_array_get_internal (tb->properties, MonoReflectionPropertyBuilder*, i), assembly, error);
2268 return_val_if_nok (error, FALSE);
2272 /* handle generic parameters */
2273 if (tb->generic_params) {
2274 table = &assembly->tables [MONO_TABLE_GENERICPARAM];
2275 table->rows += mono_array_length_internal (tb->generic_params);
2276 alloc_table (table, table->rows);
2277 for (i = 0; i < mono_array_length_internal (tb->generic_params); ++i) {
2278 guint32 owner = MONO_TYPEORMETHOD_TYPE | (tb->table_idx << MONO_TYPEORMETHOD_BITS);
2280 mono_image_get_generic_param_info (
2281 mono_array_get_internal (tb->generic_params, MonoReflectionGenericParam*, i), owner, assembly);
2285 mono_image_add_decl_security (assembly,
2286 mono_metadata_make_token (MONO_TABLE_TYPEDEF, tb->table_idx), tb->permissions);
2288 if (tb->subtypes) {
2289 MonoDynamicTable *ntable;
2291 ntable = &assembly->tables [MONO_TABLE_NESTEDCLASS];
2292 ntable->rows += mono_array_length_internal (tb->subtypes);
2293 alloc_table (ntable, ntable->rows);
2294 values = ntable->values + ntable->next_idx * MONO_NESTED_CLASS_SIZE;
2296 for (i = 0; i < mono_array_length_internal (tb->subtypes); ++i) {
2297 MonoReflectionTypeBuilder *subtype = mono_array_get_internal (tb->subtypes, MonoReflectionTypeBuilder*, i);
2299 values [MONO_NESTED_CLASS_NESTED] = subtype->table_idx;
2300 values [MONO_NESTED_CLASS_ENCLOSING] = tb->table_idx;
2301 /*g_print ("nesting %s (%d) in %s (%d) (rows %d/%d)\n",
2302 mono_string_to_utf8 (subtype->name), subtype->table_idx,
2303 mono_string_to_utf8 (tb->name), tb->table_idx,
2304 ntable->next_idx, ntable->rows);*/
2305 values += MONO_NESTED_CLASS_SIZE;
2306 ntable->next_idx++;
2310 return TRUE;
2315 * mono_image_build_metadata() will fill the info in all the needed metadata tables
2316 * for the modulebuilder @moduleb.
2317 * At the end of the process, method and field tokens are fixed up and the
2318 * on-disk compressed metadata representation is created.
2319 * Return TRUE on success, or FALSE on failure and sets @error
2321 gboolean
2322 mono_image_build_metadata (MonoReflectionModuleBuilder *moduleb, MonoError *error)
2324 MonoDynamicTable *table;
2325 MonoDynamicImage *assembly;
2326 MonoReflectionAssemblyBuilder *assemblyb;
2327 MonoDomain *domain;
2328 MonoPtrArray types;
2329 guint32 *values;
2330 int i, j;
2332 error_init (error);
2334 assemblyb = moduleb->assemblyb;
2335 assembly = moduleb->dynamic_image;
2336 domain = mono_object_domain (assemblyb);
2338 if (assembly->text_rva)
2339 return TRUE;
2341 assembly->text_rva = START_TEXT_RVA;
2343 if (moduleb->is_main) {
2344 mono_image_emit_manifest (moduleb, error);
2345 return_val_if_nok (error, FALSE);
2348 table = &assembly->tables [MONO_TABLE_TYPEDEF];
2349 table->rows = 1; /* .<Module> */
2350 table->next_idx++;
2351 alloc_table (table, table->rows);
2353 * Set the first entry.
2355 values = table->values + table->columns;
2356 values [MONO_TYPEDEF_FLAGS] = 0;
2357 values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, "<Module>") ;
2358 values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, "") ;
2359 values [MONO_TYPEDEF_EXTENDS] = 0;
2360 values [MONO_TYPEDEF_FIELD_LIST] = 1;
2361 values [MONO_TYPEDEF_METHOD_LIST] = 1;
2364 * handle global methods
2365 * FIXME: test what to do when global methods are defined in multiple modules.
2367 if (moduleb->global_methods) {
2368 table = &assembly->tables [MONO_TABLE_METHOD];
2369 table->rows += mono_array_length_internal (moduleb->global_methods);
2370 alloc_table (table, table->rows);
2371 for (i = 0; i < mono_array_length_internal (moduleb->global_methods); ++i) {
2372 if (!mono_image_get_method_info (
2373 mono_array_get_internal (moduleb->global_methods, MonoReflectionMethodBuilder*, i), assembly, error))
2374 goto leave;
2377 if (moduleb->global_fields) {
2378 table = &assembly->tables [MONO_TABLE_FIELD];
2379 table->rows += mono_array_length_internal (moduleb->global_fields);
2380 alloc_table (table, table->rows);
2381 for (i = 0; i < mono_array_length_internal (moduleb->global_fields); ++i) {
2382 mono_image_get_field_info (
2383 mono_array_get_internal (moduleb->global_fields, MonoReflectionFieldBuilder*, i), assembly,
2384 error);
2385 goto_if_nok (error, leave);
2389 table = &assembly->tables [MONO_TABLE_MODULE];
2390 alloc_table (table, 1);
2391 mono_image_fill_module_table (domain, moduleb, assembly, error);
2392 goto_if_nok (error, leave);
2394 /* Collect all types into a list sorted by their table_idx */
2395 mono_ptr_array_init (types, moduleb->num_types, MONO_ROOT_SOURCE_REFLECTION, NULL, "Reflection Dynamic Image Type List");
2397 if (moduleb->types)
2398 for (i = 0; i < moduleb->num_types; ++i) {
2399 MonoReflectionTypeBuilder *type = mono_array_get_internal (moduleb->types, MonoReflectionTypeBuilder*, i);
2400 collect_types (&types, type);
2403 mono_ptr_array_sort (types, (int (*)(const void *, const void *))compare_types_by_table_idx);
2404 table = &assembly->tables [MONO_TABLE_TYPEDEF];
2405 table->rows += mono_ptr_array_size (types);
2406 alloc_table (table, table->rows);
2409 * Emit type names + namespaces at one place inside the string heap,
2410 * so load_class_names () needs to touch fewer pages.
2412 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2413 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2414 string_heap_insert_mstring (&assembly->sheap, tb->nspace, error);
2415 goto_if_nok (error, leave_types);
2417 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2418 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2419 string_heap_insert_mstring (&assembly->sheap, tb->name, error);
2420 goto_if_nok (error, leave_types);
2423 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2424 MonoReflectionTypeBuilder *type = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2425 if (!mono_image_get_type_info (domain, type, assembly, error))
2426 goto leave_types;
2430 * table->rows is already set above and in mono_image_fill_module_table.
2432 /* add all the custom attributes at the end, once all the indexes are stable */
2433 if (!mono_image_add_cattrs (assembly, 1, MONO_CUSTOM_ATTR_ASSEMBLY, assemblyb->cattrs, error))
2434 goto leave_types;
2436 /* CAS assembly permissions */
2437 if (assemblyb->permissions_minimum)
2438 mono_image_add_decl_security (assembly, mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1), assemblyb->permissions_minimum);
2439 if (assemblyb->permissions_optional)
2440 mono_image_add_decl_security (assembly, mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1), assemblyb->permissions_optional);
2441 if (assemblyb->permissions_refused)
2442 mono_image_add_decl_security (assembly, mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1), assemblyb->permissions_refused);
2444 if (!module_add_cattrs (assembly, moduleb, error))
2445 goto leave_types;
2447 /* fixup tokens */
2448 mono_g_hash_table_foreach (assembly->token_fixups, (GHFunc)fixup_method, assembly);
2450 /* Create the MethodImpl table. We do this after emitting all methods so we already know
2451 * the final tokens and don't need another fixup pass. */
2453 if (moduleb->global_methods) {
2454 for (i = 0; i < mono_array_length_internal (moduleb->global_methods); ++i) {
2455 MonoReflectionMethodBuilder *mb = mono_array_get_internal (
2456 moduleb->global_methods, MonoReflectionMethodBuilder*, i);
2457 if (!mono_image_add_methodimpl (assembly, mb, error))
2458 goto leave_types;
2462 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2463 MonoReflectionTypeBuilder *type = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2464 if (type->methods) {
2465 for (j = 0; j < type->num_methods; ++j) {
2466 MonoReflectionMethodBuilder *mb = mono_array_get_internal (
2467 type->methods, MonoReflectionMethodBuilder*, j);
2469 if (!mono_image_add_methodimpl (assembly, mb, error))
2470 goto leave_types;
2475 fixup_cattrs (assembly);
2477 leave_types:
2478 mono_ptr_array_destroy (types);
2479 leave:
2481 return mono_error_ok (error);
2484 #else /* DISABLE_REFLECTION_EMIT_SAVE */
2486 gboolean
2487 mono_image_build_metadata (MonoReflectionModuleBuilder *moduleb, MonoError *error)
2489 g_error ("This mono runtime was configured with --enable-minimal=reflection_emit_save, so saving of dynamic assemblies is not supported.");
2492 #endif /* DISABLE_REFLECTION_EMIT_SAVE */
2494 #ifndef DISABLE_REFLECTION_EMIT_SAVE
2496 static int
2497 calc_section_size (MonoDynamicImage *assembly)
2499 int nsections = 0;
2501 /* alignment constraints */
2502 mono_image_add_stream_zero (&assembly->code, 4 - (assembly->code.index % 4));
2503 g_assert ((assembly->code.index % 4) == 0);
2504 assembly->meta_size += 3;
2505 assembly->meta_size &= ~3;
2506 mono_image_add_stream_zero (&assembly->resources, 4 - (assembly->resources.index % 4));
2507 g_assert ((assembly->resources.index % 4) == 0);
2509 assembly->sections [MONO_SECTION_TEXT].size = assembly->meta_size + assembly->code.index + assembly->resources.index + assembly->strong_name_size;
2510 assembly->sections [MONO_SECTION_TEXT].attrs = SECT_FLAGS_HAS_CODE | SECT_FLAGS_MEM_EXECUTE | SECT_FLAGS_MEM_READ;
2511 nsections++;
2513 if (assembly->win32_res) {
2514 guint32 res_size = (assembly->win32_res_size + 3) & ~3;
2516 assembly->sections [MONO_SECTION_RSRC].size = res_size;
2517 assembly->sections [MONO_SECTION_RSRC].attrs = SECT_FLAGS_HAS_INITIALIZED_DATA | SECT_FLAGS_MEM_READ;
2518 nsections++;
2521 assembly->sections [MONO_SECTION_RELOC].size = 12;
2522 assembly->sections [MONO_SECTION_RELOC].attrs = SECT_FLAGS_MEM_READ | SECT_FLAGS_MEM_DISCARDABLE | SECT_FLAGS_HAS_INITIALIZED_DATA;
2523 nsections++;
2525 return nsections;
2528 typedef struct {
2529 guint32 id;
2530 guint32 offset;
2531 GSList *children;
2532 MonoReflectionWin32Resource *win32_res; /* Only for leaf nodes */
2533 } ResTreeNode;
2535 static int
2536 resource_tree_compare_by_id (gconstpointer a, gconstpointer b)
2538 ResTreeNode *t1 = (ResTreeNode*)a;
2539 ResTreeNode *t2 = (ResTreeNode*)b;
2541 return t1->id - t2->id;
2545 * resource_tree_create:
2547 * Organize the resources into a resource tree.
2549 static ResTreeNode *
2550 resource_tree_create (MonoArray *win32_resources)
2552 ResTreeNode *tree, *res_node, *type_node, *lang_node;
2553 GSList *l;
2554 int i;
2556 tree = g_new0 (ResTreeNode, 1);
2558 for (i = 0; i < mono_array_length_internal (win32_resources); ++i) {
2559 MonoReflectionWin32Resource *win32_res =
2560 (MonoReflectionWin32Resource*)mono_array_addr_internal (win32_resources, MonoReflectionWin32Resource, i);
2562 /* Create node */
2564 /* FIXME: BUG: this stores managed references in unmanaged memory */
2565 lang_node = g_new0 (ResTreeNode, 1);
2566 lang_node->id = win32_res->lang_id;
2567 lang_node->win32_res = win32_res;
2569 /* Create type node if neccesary */
2570 type_node = NULL;
2571 for (l = tree->children; l; l = l->next)
2572 if (((ResTreeNode*)(l->data))->id == win32_res->res_type) {
2573 type_node = (ResTreeNode*)l->data;
2574 break;
2577 if (!type_node) {
2578 type_node = g_new0 (ResTreeNode, 1);
2579 type_node->id = win32_res->res_type;
2582 * The resource types have to be sorted otherwise
2583 * Windows Explorer can't display the version information.
2585 tree->children = g_slist_insert_sorted (tree->children,
2586 type_node, resource_tree_compare_by_id);
2589 /* Create res node if neccesary */
2590 res_node = NULL;
2591 for (l = type_node->children; l; l = l->next)
2592 if (((ResTreeNode*)(l->data))->id == win32_res->res_id) {
2593 res_node = (ResTreeNode*)l->data;
2594 break;
2597 if (!res_node) {
2598 res_node = g_new0 (ResTreeNode, 1);
2599 res_node->id = win32_res->res_id;
2600 type_node->children = g_slist_append (type_node->children, res_node);
2603 res_node->children = g_slist_append (res_node->children, lang_node);
2606 return tree;
2610 * resource_tree_encode:
2612 * Encode the resource tree into the format used in the PE file.
2614 static void
2615 resource_tree_encode (ResTreeNode *node, char *begin, char *p, char **endbuf)
2617 char *entries;
2618 MonoPEResourceDir dir;
2619 MonoPEResourceDirEntry dir_entry;
2620 MonoPEResourceDataEntry data_entry;
2621 GSList *l;
2622 guint32 res_id_entries;
2625 * For the format of the resource directory, see the article
2626 * "An In-Depth Look into the Win32 Portable Executable File Format" by
2627 * Matt Pietrek
2630 memset (&dir, 0, sizeof (dir));
2631 memset (&dir_entry, 0, sizeof (dir_entry));
2632 memset (&data_entry, 0, sizeof (data_entry));
2634 g_assert (sizeof (dir) == 16);
2635 g_assert (sizeof (dir_entry) == 8);
2636 g_assert (sizeof (data_entry) == 16);
2638 node->offset = p - begin;
2640 /* IMAGE_RESOURCE_DIRECTORY */
2641 res_id_entries = g_slist_length (node->children);
2642 dir.res_id_entries = GUINT16_TO_LE (res_id_entries);
2644 memcpy (p, &dir, sizeof (dir));
2645 p += sizeof (dir);
2647 /* Reserve space for entries */
2648 entries = p;
2649 p += sizeof (dir_entry) * res_id_entries;
2651 /* Write children */
2652 for (l = node->children; l; l = l->next) {
2653 ResTreeNode *child = (ResTreeNode*)l->data;
2655 if (child->win32_res) {
2656 guint32 size;
2658 child->offset = p - begin;
2660 /* IMAGE_RESOURCE_DATA_ENTRY */
2661 data_entry.rde_data_offset = GUINT32_TO_LE (p - begin + sizeof (data_entry));
2662 size = mono_array_length_internal (child->win32_res->res_data);
2663 data_entry.rde_size = GUINT32_TO_LE (size);
2665 memcpy (p, &data_entry, sizeof (data_entry));
2666 p += sizeof (data_entry);
2668 memcpy (p, mono_array_addr_internal (child->win32_res->res_data, char, 0), size);
2669 p += size;
2670 } else {
2671 resource_tree_encode (child, begin, p, &p);
2675 /* IMAGE_RESOURCE_ENTRY */
2676 for (l = node->children; l; l = l->next) {
2677 ResTreeNode *child = (ResTreeNode*)l->data;
2679 MONO_PE_RES_DIR_ENTRY_SET_NAME (dir_entry, FALSE, child->id);
2680 MONO_PE_RES_DIR_ENTRY_SET_DIR (dir_entry, !child->win32_res, child->offset);
2682 memcpy (entries, &dir_entry, sizeof (dir_entry));
2683 entries += sizeof (dir_entry);
2686 *endbuf = p;
2689 static void
2690 resource_tree_free (ResTreeNode * node)
2692 GSList * list;
2693 for (list = node->children; list; list = list->next)
2694 resource_tree_free ((ResTreeNode*)list->data);
2695 g_slist_free(node->children);
2696 g_free (node);
2699 static void
2700 assembly_add_win32_resources (MonoDynamicImage *assembly, MonoReflectionAssemblyBuilder *assemblyb)
2702 char *buf;
2703 char *p;
2704 guint32 size, i;
2705 MonoReflectionWin32Resource *win32_res;
2706 ResTreeNode *tree;
2708 if (!assemblyb->win32_resources)
2709 return;
2712 * Resources are stored in a three level tree inside the PE file.
2713 * - level one contains a node for each type of resource
2714 * - level two contains a node for each resource
2715 * - level three contains a node for each instance of a resource for a
2716 * specific language.
2719 tree = resource_tree_create (assemblyb->win32_resources);
2721 /* Estimate the size of the encoded tree */
2722 size = 0;
2723 for (i = 0; i < mono_array_length_internal (assemblyb->win32_resources); ++i) {
2724 win32_res = (MonoReflectionWin32Resource*)mono_array_addr_internal (assemblyb->win32_resources, MonoReflectionWin32Resource, i);
2725 size += mono_array_length_internal (win32_res->res_data);
2727 /* Directory structure */
2728 size += mono_array_length_internal (assemblyb->win32_resources) * 256;
2729 p = buf = (char *)g_malloc (size);
2731 resource_tree_encode (tree, p, p, &p);
2733 g_assert (p - buf <= size);
2735 assembly->win32_res = (char *)g_malloc (p - buf);
2736 assembly->win32_res_size = p - buf;
2737 memcpy (assembly->win32_res, buf, p - buf);
2739 g_free (buf);
2740 resource_tree_free (tree);
2743 static void
2744 fixup_resource_directory (char *res_section, char *p, guint32 rva)
2746 MonoPEResourceDir *dir = (MonoPEResourceDir*)p;
2747 int i;
2749 p += sizeof (MonoPEResourceDir);
2750 for (i = 0; i < GUINT16_FROM_LE (dir->res_named_entries) + GUINT16_FROM_LE (dir->res_id_entries); ++i) {
2751 MonoPEResourceDirEntry *dir_entry = (MonoPEResourceDirEntry*)p;
2752 char *child = res_section + MONO_PE_RES_DIR_ENTRY_DIR_OFFSET (*dir_entry);
2753 if (MONO_PE_RES_DIR_ENTRY_IS_DIR (*dir_entry)) {
2754 fixup_resource_directory (res_section, child, rva);
2755 } else {
2756 MonoPEResourceDataEntry *data_entry = (MonoPEResourceDataEntry*)child;
2757 data_entry->rde_data_offset = GUINT32_TO_LE (GUINT32_FROM_LE (data_entry->rde_data_offset) + rva);
2760 p += sizeof (MonoPEResourceDirEntry);
2764 static void
2765 checked_write_file (HANDLE f, gconstpointer buffer, guint32 numbytes)
2767 guint32 dummy;
2768 gint32 win32error = 0;
2769 if (!mono_w32file_write (f, buffer, numbytes, &dummy, &win32error))
2770 g_error ("mono_w32file_write returned %d\n", win32error);
2774 * mono_image_create_pefile:
2775 * @mb: a module builder object
2777 * This function creates the PE-COFF header, the image sections, the CLI header * etc. all the data is written in
2778 * assembly->pefile where it can be easily retrieved later in chunks.
2780 gboolean
2781 mono_image_create_pefile (MonoReflectionModuleBuilder *mb, HANDLE file, MonoError *error)
2783 MonoMSDOSHeader *msdos;
2784 MonoDotNetHeader *header;
2785 MonoSectionTable *section;
2786 MonoCLIHeader *cli_header;
2787 guint32 size, image_size, virtual_base, text_offset;
2788 guint32 header_start, section_start, file_offset, virtual_offset;
2789 MonoDynamicImage *assembly;
2790 MonoReflectionAssemblyBuilder *assemblyb;
2791 MonoDynamicStream pefile_stream = {0};
2792 MonoDynamicStream *pefile = &pefile_stream;
2793 int i, nsections;
2794 guint32 *rva, value;
2795 guchar *p;
2796 static const unsigned char msheader[] = {
2797 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
2798 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2799 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2800 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
2801 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68,
2802 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f,
2803 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,
2804 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
2807 error_init (error);
2809 assemblyb = mb->assemblyb;
2811 mono_reflection_dynimage_basic_init (assemblyb);
2812 assembly = mb->dynamic_image;
2814 assembly->pe_kind = assemblyb->pe_kind;
2815 assembly->machine = assemblyb->machine;
2816 ((MonoDynamicImage*)assemblyb->dynamic_assembly->assembly.image)->pe_kind = assemblyb->pe_kind;
2817 ((MonoDynamicImage*)assemblyb->dynamic_assembly->assembly.image)->machine = assemblyb->machine;
2819 if (!mono_image_build_metadata (mb, error))
2820 return FALSE;
2823 if (mb->is_main && assemblyb->resources) {
2824 int len = mono_array_length_internal (assemblyb->resources);
2825 for (i = 0; i < len; ++i) {
2826 if (!assembly_add_resource (mb, assembly, (MonoReflectionResource*)mono_array_addr_internal (assemblyb->resources, MonoReflectionResource, i), error))
2827 return FALSE;
2831 if (mb->resources) {
2832 int len = mono_array_length_internal (mb->resources);
2833 for (i = 0; i < len; ++i) {
2834 if (!assembly_add_resource (mb, assembly, (MonoReflectionResource*)mono_array_addr_internal (mb->resources, MonoReflectionResource, i), error))
2835 return FALSE;
2839 if (!build_compressed_metadata (assembly, error))
2840 return FALSE;
2842 if (mb->is_main)
2843 assembly_add_win32_resources (assembly, assemblyb);
2845 nsections = calc_section_size (assembly);
2847 /* The DOS header and stub */
2848 g_assert (sizeof (MonoMSDOSHeader) == sizeof (msheader));
2849 mono_image_add_stream_data (pefile, (char*)msheader, sizeof (msheader));
2851 /* the dotnet header */
2852 header_start = mono_image_add_stream_zero (pefile, sizeof (MonoDotNetHeader));
2854 /* the section tables */
2855 section_start = mono_image_add_stream_zero (pefile, sizeof (MonoSectionTable) * nsections);
2857 file_offset = section_start + sizeof (MonoSectionTable) * nsections;
2858 virtual_offset = VIRT_ALIGN;
2859 image_size = 0;
2861 for (i = 0; i < MONO_SECTION_MAX; ++i) {
2862 if (!assembly->sections [i].size)
2863 continue;
2864 /* align offsets */
2865 file_offset += FILE_ALIGN - 1;
2866 file_offset &= ~(FILE_ALIGN - 1);
2867 virtual_offset += VIRT_ALIGN - 1;
2868 virtual_offset &= ~(VIRT_ALIGN - 1);
2870 assembly->sections [i].offset = file_offset;
2871 assembly->sections [i].rva = virtual_offset;
2873 file_offset += assembly->sections [i].size;
2874 virtual_offset += assembly->sections [i].size;
2875 image_size += (assembly->sections [i].size + VIRT_ALIGN - 1) & ~(VIRT_ALIGN - 1);
2878 file_offset += FILE_ALIGN - 1;
2879 file_offset &= ~(FILE_ALIGN - 1);
2881 image_size += section_start + sizeof (MonoSectionTable) * nsections;
2883 /* back-patch info */
2884 msdos = (MonoMSDOSHeader*)pefile->data;
2885 msdos->pe_offset = GUINT32_FROM_LE (sizeof (MonoMSDOSHeader));
2887 header = (MonoDotNetHeader*)(pefile->data + header_start);
2888 header->pesig [0] = 'P';
2889 header->pesig [1] = 'E';
2891 header->coff.coff_machine = GUINT16_FROM_LE (assemblyb->machine);
2892 header->coff.coff_sections = GUINT16_FROM_LE (nsections);
2893 header->coff.coff_time = GUINT32_FROM_LE (time (NULL));
2894 header->coff.coff_opt_header_size = GUINT16_FROM_LE (sizeof (MonoDotNetHeader) - sizeof (MonoCOFFHeader) - 4);
2895 if (assemblyb->pekind == 1) {
2896 /* it's a dll */
2897 header->coff.coff_attributes = GUINT16_FROM_LE (0x210e);
2898 } else {
2899 /* it's an exe */
2900 header->coff.coff_attributes = GUINT16_FROM_LE (0x010e);
2903 virtual_base = 0x400000; /* FIXME: 0x10000000 if a DLL */
2905 header->pe.pe_magic = GUINT16_FROM_LE (0x10B);
2906 header->pe.pe_major = 6;
2907 header->pe.pe_minor = 0;
2908 size = assembly->sections [MONO_SECTION_TEXT].size;
2909 size += FILE_ALIGN - 1;
2910 size &= ~(FILE_ALIGN - 1);
2911 header->pe.pe_code_size = GUINT32_FROM_LE(size);
2912 size = assembly->sections [MONO_SECTION_RSRC].size;
2913 size += FILE_ALIGN - 1;
2914 size &= ~(FILE_ALIGN - 1);
2915 header->pe.pe_data_size = GUINT32_FROM_LE(size);
2916 g_assert (START_TEXT_RVA == assembly->sections [MONO_SECTION_TEXT].rva);
2917 header->pe.pe_rva_code_base = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_TEXT].rva);
2918 header->pe.pe_rva_data_base = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].rva);
2919 /* pe_rva_entry_point always at the beginning of the text section */
2920 header->pe.pe_rva_entry_point = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_TEXT].rva);
2922 header->nt.pe_image_base = GUINT32_FROM_LE (virtual_base);
2923 header->nt.pe_section_align = GUINT32_FROM_LE (VIRT_ALIGN);
2924 header->nt.pe_file_alignment = GUINT32_FROM_LE (FILE_ALIGN);
2925 header->nt.pe_os_major = GUINT16_FROM_LE (4);
2926 header->nt.pe_os_minor = GUINT16_FROM_LE (0);
2927 header->nt.pe_subsys_major = GUINT16_FROM_LE (4);
2928 size = section_start;
2929 size += FILE_ALIGN - 1;
2930 size &= ~(FILE_ALIGN - 1);
2931 header->nt.pe_header_size = GUINT32_FROM_LE (size);
2932 size = image_size;
2933 size += VIRT_ALIGN - 1;
2934 size &= ~(VIRT_ALIGN - 1);
2935 header->nt.pe_image_size = GUINT32_FROM_LE (size);
2938 // Translate the PEFileKind value to the value expected by the Windows loader
2941 short kind;
2944 // PEFileKinds.Dll == 1
2945 // PEFileKinds.ConsoleApplication == 2
2946 // PEFileKinds.WindowApplication == 3
2948 // need to get:
2949 // IMAGE_SUBSYSTEM_WINDOWS_GUI 2 // Image runs in the Windows GUI subsystem.
2950 // IMAGE_SUBSYSTEM_WINDOWS_CUI 3 // Image runs in the Windows character subsystem.
2952 if (assemblyb->pekind == 3)
2953 kind = 2;
2954 else
2955 kind = 3;
2957 header->nt.pe_subsys_required = GUINT16_FROM_LE (kind);
2959 header->nt.pe_stack_reserve = GUINT32_FROM_LE (0x00100000);
2960 header->nt.pe_stack_commit = GUINT32_FROM_LE (0x00001000);
2961 header->nt.pe_heap_reserve = GUINT32_FROM_LE (0x00100000);
2962 header->nt.pe_heap_commit = GUINT32_FROM_LE (0x00001000);
2963 header->nt.pe_loader_flags = GUINT32_FROM_LE (0);
2964 header->nt.pe_data_dir_count = GUINT32_FROM_LE (16);
2966 /* fill data directory entries */
2968 header->datadir.pe_resource_table.size = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].size);
2969 header->datadir.pe_resource_table.rva = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].rva);
2971 header->datadir.pe_reloc_table.size = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RELOC].size);
2972 header->datadir.pe_reloc_table.rva = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RELOC].rva);
2974 header->datadir.pe_cli_header.size = GUINT32_FROM_LE (72);
2975 header->datadir.pe_cli_header.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->cli_header_offset);
2976 header->datadir.pe_iat.size = GUINT32_FROM_LE (8);
2977 header->datadir.pe_iat.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->iat_offset);
2978 /* patch entrypoint name */
2979 if (assemblyb->pekind == 1)
2980 memcpy (assembly->code.data + assembly->imp_names_offset + 2, "_CorDllMain", 12);
2981 else
2982 memcpy (assembly->code.data + assembly->imp_names_offset + 2, "_CorExeMain", 12);
2983 /* patch imported function RVA name */
2984 rva = (guint32*)(assembly->code.data + assembly->iat_offset);
2985 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->imp_names_offset);
2987 /* the import table */
2988 header->datadir.pe_import_table.size = GUINT32_FROM_LE (79); /* FIXME: magic number? */
2989 header->datadir.pe_import_table.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->idt_offset);
2990 /* patch imported dll RVA name and other entries in the dir */
2991 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, name_rva));
2992 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->imp_names_offset + 14); /* 14 is hint+strlen+1 of func name */
2993 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, import_address_table_rva));
2994 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->iat_offset);
2995 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, import_lookup_table));
2996 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->ilt_offset);
2998 p = (guchar*)(assembly->code.data + assembly->ilt_offset);
2999 value = (assembly->text_rva + assembly->imp_names_offset);
3000 *p++ = (value) & 0xff;
3001 *p++ = (value >> 8) & (0xff);
3002 *p++ = (value >> 16) & (0xff);
3003 *p++ = (value >> 24) & (0xff);
3005 /* the CLI header info */
3006 cli_header = (MonoCLIHeader*)(assembly->code.data + assembly->cli_header_offset);
3007 cli_header->ch_size = GUINT32_FROM_LE (72);
3008 cli_header->ch_runtime_major = GUINT16_FROM_LE (2);
3009 cli_header->ch_runtime_minor = GUINT16_FROM_LE (5);
3010 cli_header->ch_flags = GUINT32_FROM_LE (assemblyb->pe_kind);
3011 if (assemblyb->entry_point) {
3012 guint32 table_idx = 0;
3013 if (!strcmp (m_class_get_name (mono_object_class (&assemblyb->entry_point->object)), "MethodBuilder")) {
3014 MonoReflectionMethodBuilder *methodb = (MonoReflectionMethodBuilder*)assemblyb->entry_point;
3015 table_idx = methodb->table_idx;
3016 } else {
3017 table_idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, assemblyb->entry_point->method));
3019 cli_header->ch_entry_point = GUINT32_FROM_LE (table_idx | MONO_TOKEN_METHOD_DEF);
3020 } else {
3021 cli_header->ch_entry_point = GUINT32_FROM_LE (0);
3023 /* The embedded managed resources */
3024 text_offset = assembly->text_rva + assembly->code.index;
3025 cli_header->ch_resources.rva = GUINT32_FROM_LE (text_offset);
3026 cli_header->ch_resources.size = GUINT32_FROM_LE (assembly->resources.index);
3027 text_offset += assembly->resources.index;
3028 cli_header->ch_metadata.rva = GUINT32_FROM_LE (text_offset);
3029 cli_header->ch_metadata.size = GUINT32_FROM_LE (assembly->meta_size);
3030 text_offset += assembly->meta_size;
3031 if (assembly->strong_name_size) {
3032 cli_header->ch_strong_name.rva = GUINT32_FROM_LE (text_offset);
3033 cli_header->ch_strong_name.size = GUINT32_FROM_LE (assembly->strong_name_size);
3034 text_offset += assembly->strong_name_size;
3037 /* write the section tables and section content */
3038 section = (MonoSectionTable*)(pefile->data + section_start);
3039 for (i = 0; i < MONO_SECTION_MAX; ++i) {
3040 static const char section_names [][7] = {
3041 ".text", ".rsrc", ".reloc"
3043 if (!assembly->sections [i].size)
3044 continue;
3045 strcpy (section->st_name, section_names [i]);
3046 /*g_print ("output section %s (%d), size: %d\n", section->st_name, i, assembly->sections [i].size);*/
3047 section->st_virtual_address = GUINT32_FROM_LE (assembly->sections [i].rva);
3048 section->st_virtual_size = GUINT32_FROM_LE (assembly->sections [i].size);
3049 section->st_raw_data_size = GUINT32_FROM_LE (GUINT32_TO_LE (section->st_virtual_size) + (FILE_ALIGN - 1));
3050 section->st_raw_data_size &= GUINT32_FROM_LE (~(FILE_ALIGN - 1));
3051 section->st_raw_data_ptr = GUINT32_FROM_LE (assembly->sections [i].offset);
3052 section->st_flags = GUINT32_FROM_LE (assembly->sections [i].attrs);
3053 section ++;
3056 checked_write_file (file, pefile->data, pefile->index);
3058 mono_dynamic_stream_reset (pefile);
3060 for (i = 0; i < MONO_SECTION_MAX; ++i) {
3061 if (!assembly->sections [i].size)
3062 continue;
3064 if (mono_w32file_seek (file, assembly->sections [i].offset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
3065 g_error ("mono_w32file_seek returned %d\n", mono_w32error_get_last ());
3067 switch (i) {
3068 case MONO_SECTION_TEXT:
3069 /* patch entry point */
3070 p = (guchar*)(assembly->code.data + 2);
3071 value = (virtual_base + assembly->text_rva + assembly->iat_offset);
3072 *p++ = (value) & 0xff;
3073 *p++ = (value >> 8) & 0xff;
3074 *p++ = (value >> 16) & 0xff;
3075 *p++ = (value >> 24) & 0xff;
3077 checked_write_file (file, assembly->code.data, assembly->code.index);
3078 checked_write_file (file, assembly->resources.data, assembly->resources.index);
3079 checked_write_file (file, assembly->image.raw_metadata, assembly->meta_size);
3080 checked_write_file (file, assembly->strong_name, assembly->strong_name_size);
3083 g_free (assembly->image.raw_metadata);
3084 break;
3085 case MONO_SECTION_RELOC: {
3086 struct {
3087 guint32 page_rva;
3088 guint32 block_size;
3089 guint16 type_and_offset;
3090 guint16 term;
3091 } reloc;
3093 g_assert (sizeof (reloc) == 12);
3095 reloc.page_rva = GUINT32_FROM_LE (assembly->text_rva);
3096 reloc.block_size = GUINT32_FROM_LE (12);
3099 * the entrypoint is always at the start of the text section
3100 * 3 is IMAGE_REL_BASED_HIGHLOW
3101 * 2 is patch_size_rva - text_rva
3103 reloc.type_and_offset = GUINT16_FROM_LE ((3 << 12) + (2));
3104 reloc.term = 0;
3106 checked_write_file (file, &reloc, sizeof (reloc));
3108 break;
3110 case MONO_SECTION_RSRC:
3111 if (assembly->win32_res) {
3113 /* Fixup the offsets in the IMAGE_RESOURCE_DATA_ENTRY structures */
3114 fixup_resource_directory (assembly->win32_res, assembly->win32_res, assembly->sections [i].rva);
3115 checked_write_file (file, assembly->win32_res, assembly->win32_res_size);
3117 break;
3118 default:
3119 g_assert_not_reached ();
3123 /* check that the file is properly padded */
3124 if (mono_w32file_seek (file, file_offset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
3125 g_error ("mono_w32file_seek returned %d\n", mono_w32error_get_last ());
3126 if (! mono_w32file_truncate (file))
3127 g_error ("mono_w32file_truncate returned %d\n", mono_w32error_get_last ());
3129 mono_dynamic_stream_reset (&assembly->code);
3130 mono_dynamic_stream_reset (&assembly->us);
3131 mono_dynamic_stream_reset (&assembly->blob);
3132 mono_dynamic_stream_reset (&assembly->guid);
3133 mono_dynamic_stream_reset (&assembly->sheap);
3135 g_hash_table_foreach (assembly->blob_cache, (GHFunc)g_free, NULL);
3136 g_hash_table_destroy (assembly->blob_cache);
3137 assembly->blob_cache = NULL;
3139 return TRUE;
3142 #else /* DISABLE_REFLECTION_EMIT_SAVE */
3144 gboolean
3145 mono_image_create_pefile (MonoReflectionModuleBuilder *mb, HANDLE file, MonoError *error)
3147 g_assert_not_reached ();
3150 #endif /* DISABLE_REFLECTION_EMIT_SAVE */