[LoongArch64] Part-5:add loongarch support in some files for LoongArch64. (#21769)
[mono-project.git] / mono / metadata / sre-save.c
blobe61514de08e7a46c11d7a16dbdaed477511a438e
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;
109 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
111 * Copy len * nelem bytes from val to dest, swapping bytes to LE if necessary.
112 * dest may be misaligned.
114 static void
115 swap_with_size (char *dest, const char* val, int len, int nelem) {
116 MONO_REQ_GC_NEUTRAL_MODE;
117 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
118 int elem;
120 for (elem = 0; elem < nelem; ++elem) {
121 switch (len) {
122 case 1:
123 *dest = *val;
124 break;
125 case 2:
126 dest [0] = val [1];
127 dest [1] = val [0];
128 break;
129 case 4:
130 dest [0] = val [3];
131 dest [1] = val [2];
132 dest [2] = val [1];
133 dest [3] = val [0];
134 break;
135 case 8:
136 dest [0] = val [7];
137 dest [1] = val [6];
138 dest [2] = val [5];
139 dest [3] = val [4];
140 dest [4] = val [3];
141 dest [5] = val [2];
142 dest [6] = val [1];
143 dest [7] = val [0];
144 break;
145 default:
146 g_assert_not_reached ();
148 dest += len;
149 val += len;
151 #else
152 memcpy (dest, val, len * nelem);
153 #endif
155 #endif
157 static guint32
158 add_mono_string_to_blob_cached (MonoDynamicImage *assembly, MonoString *str)
160 MONO_REQ_GC_UNSAFE_MODE;
162 char blob_size [64];
163 char *b = blob_size;
164 guint32 idx = 0, len;
166 len = str->length * 2;
167 mono_metadata_encode_value (len, b, &b);
168 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
170 char *swapped = g_malloc (2 * mono_string_length_internal (str));
171 const char *p = (const char*)mono_string_chars_internal (str);
173 swap_with_size (swapped, p, 2, mono_string_length_internal (str));
174 idx = mono_dynamic_image_add_to_blob_cached (assembly, blob_size, b-blob_size, swapped, len);
175 g_free (swapped);
177 #else
178 idx = mono_dynamic_image_add_to_blob_cached (assembly, blob_size, b-blob_size, mono_string_chars_internal (str), len);
179 #endif
180 return idx;
183 static guint32
184 image_create_token_raw (MonoDynamicImage *assembly, MonoObject* obj_raw, gboolean create_methodspec, gboolean register_token, MonoError *error)
186 HANDLE_FUNCTION_ENTER (); /* FIXME callers of image_create_token_raw should use handles */
187 error_init (error);
188 MONO_HANDLE_DCL (MonoObject, obj);
189 guint32 const result = mono_image_create_token (assembly, obj, create_methodspec, register_token, error);
190 HANDLE_FUNCTION_RETURN_VAL (result);
195 * idx is the table index of the object
196 * type is one of MONO_CUSTOM_ATTR_*
198 static gboolean
199 mono_image_add_cattrs (MonoDynamicImage *assembly, guint32 idx, guint32 type, MonoArray *cattrs, MonoError *error)
201 MONO_REQ_GC_UNSAFE_MODE;
203 MonoDynamicTable *table;
204 MonoReflectionCustomAttr *cattr;
205 guint32 *values;
206 guint32 count, i, token;
207 char blob_size [6];
208 char *p = blob_size;
210 error_init (error);
212 /* it is legal to pass a NULL cattrs: we avoid to use the if in a lot of places */
213 if (!cattrs)
214 return TRUE;
215 count = mono_array_length_internal (cattrs);
216 table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
217 table->rows += count;
218 alloc_table (table, table->rows);
219 values = table->values + table->next_idx * MONO_CUSTOM_ATTR_SIZE;
220 idx <<= MONO_CUSTOM_ATTR_BITS;
221 idx |= type;
222 for (i = 0; i < count; ++i) {
223 cattr = (MonoReflectionCustomAttr*)mono_array_get_internal (cattrs, gpointer, i);
224 values [MONO_CUSTOM_ATTR_PARENT] = idx;
225 g_assert (cattr->ctor != NULL);
226 if (mono_is_sre_ctor_builder (mono_object_class (cattr->ctor))) {
227 MonoReflectionCtorBuilder *ctor = (MonoReflectionCtorBuilder*)cattr->ctor;
228 MonoMethod *method = ctor->mhandle;
229 if (m_class_get_image (method->klass) == &assembly->image)
230 token = MONO_TOKEN_METHOD_DEF | ((MonoReflectionCtorBuilder*)cattr->ctor)->table_idx;
231 else
232 token = mono_image_get_methodref_token (assembly, method, FALSE);
233 } else {
234 token = image_create_token_raw (assembly, (MonoObject*)cattr->ctor, FALSE, FALSE, error); /* FIXME use handles */
235 if (!is_ok (error)) goto fail;
237 type = mono_metadata_token_index (token);
238 type <<= MONO_CUSTOM_ATTR_TYPE_BITS;
239 switch (mono_metadata_token_table (token)) {
240 case MONO_TABLE_METHOD:
241 type |= MONO_CUSTOM_ATTR_TYPE_METHODDEF;
243 * fixup_cattrs () needs to fix this up. We can't use image->tokens, since it contains the old token for the
244 * method, not the one returned by mono_image_create_token ().
246 mono_g_hash_table_insert_internal (assembly->remapped_tokens, GUINT_TO_POINTER (token), cattr->ctor);
247 break;
248 case MONO_TABLE_MEMBERREF:
249 type |= MONO_CUSTOM_ATTR_TYPE_MEMBERREF;
250 break;
251 default:
252 g_warning ("got wrong token in custom attr");
253 continue;
255 values [MONO_CUSTOM_ATTR_TYPE] = type;
256 p = blob_size;
257 mono_metadata_encode_value (mono_array_length_internal (cattr->data), p, &p);
258 values [MONO_CUSTOM_ATTR_VALUE] = mono_dynamic_image_add_to_blob_cached (assembly, blob_size, p - blob_size,
259 mono_array_addr_internal (cattr->data, char, 0), mono_array_length_internal (cattr->data));
260 values += MONO_CUSTOM_ATTR_SIZE;
261 ++table->next_idx;
264 return TRUE;
266 fail:
267 return FALSE;
270 static void
271 mono_image_add_decl_security (MonoDynamicImage *assembly, guint32 parent_token, MonoArray *permissions)
273 MONO_REQ_GC_UNSAFE_MODE;
275 MonoDynamicTable *table;
276 guint32 *values;
277 guint32 count, i, idx;
278 MonoReflectionPermissionSet *perm;
280 if (!permissions)
281 return;
283 count = mono_array_length_internal (permissions);
284 table = &assembly->tables [MONO_TABLE_DECLSECURITY];
285 table->rows += count;
286 alloc_table (table, table->rows);
288 for (i = 0; i < mono_array_length_internal (permissions); ++i) {
289 perm = (MonoReflectionPermissionSet*)mono_array_addr_internal (permissions, MonoReflectionPermissionSet, i);
291 values = table->values + table->next_idx * MONO_DECL_SECURITY_SIZE;
293 idx = mono_metadata_token_index (parent_token);
294 idx <<= MONO_HAS_DECL_SECURITY_BITS;
295 switch (mono_metadata_token_table (parent_token)) {
296 case MONO_TABLE_TYPEDEF:
297 idx |= MONO_HAS_DECL_SECURITY_TYPEDEF;
298 break;
299 case MONO_TABLE_METHOD:
300 idx |= MONO_HAS_DECL_SECURITY_METHODDEF;
301 break;
302 case MONO_TABLE_ASSEMBLY:
303 idx |= MONO_HAS_DECL_SECURITY_ASSEMBLY;
304 break;
305 default:
306 g_assert_not_reached ();
309 values [MONO_DECL_SECURITY_ACTION] = perm->action;
310 values [MONO_DECL_SECURITY_PARENT] = idx;
311 values [MONO_DECL_SECURITY_PERMISSIONSET] = add_mono_string_to_blob_cached (assembly, perm->pset);
313 ++table->next_idx;
318 * method_encode_code:
320 * @assembly the assembly
321 * @mb the managed MethodBuilder
322 * @error set on error
324 * Note that the return value is not sensible if @error is set.
326 static guint32
327 method_encode_code (MonoDynamicImage *assembly, ReflectionMethodBuilder *mb, MonoError *error)
329 MONO_REQ_GC_UNSAFE_MODE;
331 char flags = 0;
332 guint32 idx;
333 guint32 code_size;
334 gint32 max_stack, i;
335 gint32 num_locals = 0;
336 gint32 num_exception = 0;
337 gint maybe_small;
338 guint32 fat_flags;
339 char fat_header [12];
340 guint32 int_value;
341 guint16 short_value;
342 guint32 local_sig = 0;
343 guint32 header_size = 12;
344 MonoArray *code;
346 error_init (error);
348 if ((mb->attrs & (METHOD_ATTRIBUTE_PINVOKE_IMPL | METHOD_ATTRIBUTE_ABSTRACT)) ||
349 (mb->iattrs & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)))
350 return 0;
352 /*if (mb->name)
353 g_print ("Encode method %s\n", mono_string_to_utf8 (mb->name));*/
354 if (mb->ilgen) {
355 code = mb->ilgen->code;
356 code_size = mb->ilgen->code_len;
357 max_stack = mb->ilgen->max_stack;
358 num_locals = mb->ilgen->locals ? mono_array_length_internal (mb->ilgen->locals) : 0;
359 if (mb->ilgen->ex_handlers)
360 num_exception = mono_reflection_method_count_clauses (mb->ilgen);
361 } else {
362 code = mb->code;
363 if (code == NULL) {
364 ERROR_DECL (inner_error);
365 char *name = mono_string_to_utf8_checked_internal (mb->name, inner_error);
366 if (!is_ok (inner_error))
367 mono_error_set_argument (error, NULL, "a method does not have any IL associated");
368 else
369 mono_error_set_argument_format (error, NULL, "Method %s does not have any IL associated", name);
370 mono_error_cleanup (inner_error);
371 g_free (name);
372 return 0;
375 code_size = mono_array_length_internal (code);
376 max_stack = 8; /* we probably need to run a verifier on the code... */
379 stream_data_align (&assembly->code);
381 /* check for exceptions, maxstack, locals */
382 maybe_small = (max_stack <= 8) && (!num_locals) && (!num_exception);
383 if (maybe_small) {
384 if (code_size < 64 && !(code_size & 1)) {
385 flags = (code_size << 2) | 0x2;
386 } else if (code_size < 32 && (code_size & 1)) {
387 flags = (code_size << 2) | 0x6; /* LAMESPEC: see metadata.c */
388 } else {
389 goto fat_header;
391 idx = mono_image_add_stream_data (&assembly->code, &flags, 1);
392 /* add to the fixup todo list */
393 if (mb->ilgen && mb->ilgen->num_token_fixups)
394 mono_g_hash_table_insert_internal (assembly->token_fixups, mb->ilgen, GUINT_TO_POINTER (idx + 1));
395 mono_image_add_stream_data (&assembly->code, mono_array_addr_internal (code, char, 0), code_size);
396 return assembly->text_rva + idx;
398 fat_header:
399 if (num_locals) {
400 local_sig = MONO_TOKEN_SIGNATURE | mono_dynimage_encode_locals (assembly, mb->ilgen, error);
401 return_val_if_nok (error, 0);
404 * FIXME: need to set also the header size in fat_flags.
405 * (and more sects and init locals flags)
407 fat_flags = 0x03;
408 if (num_exception)
409 fat_flags |= METHOD_HEADER_MORE_SECTS;
410 if (mb->init_locals)
411 fat_flags |= METHOD_HEADER_INIT_LOCALS;
412 fat_header [0] = fat_flags;
413 fat_header [1] = (header_size / 4 ) << 4;
414 short_value = GUINT16_TO_LE (max_stack);
415 memcpy (fat_header + 2, &short_value, 2);
416 int_value = GUINT32_TO_LE (code_size);
417 memcpy (fat_header + 4, &int_value, 4);
418 int_value = GUINT32_TO_LE (local_sig);
419 memcpy (fat_header + 8, &int_value, 4);
420 idx = mono_image_add_stream_data (&assembly->code, fat_header, 12);
421 /* add to the fixup todo list */
422 if (mb->ilgen && mb->ilgen->num_token_fixups)
423 mono_g_hash_table_insert_internal (assembly->token_fixups, mb->ilgen, GUINT_TO_POINTER (idx + 12));
425 mono_image_add_stream_data (&assembly->code, mono_array_addr_internal (code, char, 0), code_size);
426 if (num_exception) {
427 unsigned char sheader [4];
428 MonoILExceptionInfo * ex_info;
429 MonoILExceptionBlock * ex_block;
430 int j;
432 stream_data_align (&assembly->code);
433 /* always use fat format for now */
434 sheader [0] = METHOD_HEADER_SECTION_FAT_FORMAT | METHOD_HEADER_SECTION_EHTABLE;
435 num_exception *= 6 * sizeof (guint32);
436 num_exception += 4; /* include the size of the header */
437 sheader [1] = num_exception & 0xff;
438 sheader [2] = (num_exception >> 8) & 0xff;
439 sheader [3] = (num_exception >> 16) & 0xff;
440 mono_image_add_stream_data (&assembly->code, (char*)sheader, 4);
441 /* fat header, so we are already aligned */
442 /* reverse order */
443 for (i = mono_array_length_internal (mb->ilgen->ex_handlers) - 1; i >= 0; --i) {
444 ex_info = (MonoILExceptionInfo *)mono_array_addr_internal (mb->ilgen->ex_handlers, MonoILExceptionInfo, i);
445 if (ex_info->handlers) {
446 int finally_start = ex_info->start + ex_info->len;
447 for (j = 0; j < mono_array_length_internal (ex_info->handlers); ++j) {
448 guint32 val;
449 ex_block = (MonoILExceptionBlock*)mono_array_addr_internal (ex_info->handlers, MonoILExceptionBlock, j);
450 /* the flags */
451 val = GUINT32_TO_LE (ex_block->type);
452 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
453 /* try offset */
454 val = GUINT32_TO_LE (ex_info->start);
455 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
456 /* need fault, too, probably */
457 if (ex_block->type == MONO_EXCEPTION_CLAUSE_FINALLY)
458 val = GUINT32_TO_LE (finally_start - ex_info->start);
459 else
460 val = GUINT32_TO_LE (ex_info->len);
461 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
462 /* handler offset */
463 val = GUINT32_TO_LE (ex_block->start);
464 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
465 /* handler len */
466 val = GUINT32_TO_LE (ex_block->len);
467 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
468 finally_start = ex_block->start + ex_block->len;
469 if (ex_block->extype) {
470 MonoType *extype = mono_reflection_type_get_handle ((MonoReflectionType*)ex_block->extype, error);
471 return_val_if_nok (error, 0);
473 val = mono_metadata_token_from_dor (mono_image_typedef_or_ref (assembly, extype));
474 } else {
475 if (ex_block->type == MONO_EXCEPTION_CLAUSE_FILTER)
476 val = ex_block->filter_offset;
477 else
478 val = 0;
480 val = GUINT32_TO_LE (val);
481 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
482 /*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",
483 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);*/
485 } else {
486 g_error ("No clauses for ex info block %d", i);
490 return assembly->text_rva + idx;
494 * Fill in the MethodDef and ParamDef tables for a method.
495 * This is used for both normal methods and constructors.
497 static gboolean
498 mono_image_basic_method (ReflectionMethodBuilder *mb, MonoDynamicImage *assembly, MonoError *error)
500 MONO_REQ_GC_UNSAFE_MODE;
502 MonoDynamicTable *table;
503 guint32 *values;
504 guint i, count;
506 error_init (error);
508 /* room in this table is already allocated */
509 table = &assembly->tables [MONO_TABLE_METHOD];
510 *mb->table_idx = table->next_idx ++;
511 g_hash_table_insert (assembly->method_to_table_idx, mb->mhandle, GUINT_TO_POINTER ((*mb->table_idx)));
512 values = table->values + *mb->table_idx * MONO_METHOD_SIZE;
513 values [MONO_METHOD_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->name, error);
514 return_val_if_nok (error, FALSE);
515 values [MONO_METHOD_FLAGS] = mb->attrs;
516 values [MONO_METHOD_IMPLFLAGS] = mb->iattrs;
517 values [MONO_METHOD_SIGNATURE] = mono_dynimage_encode_method_builder_signature (assembly, mb, error);
518 return_val_if_nok (error, FALSE);
519 values [MONO_METHOD_RVA] = method_encode_code (assembly, mb, error);
520 return_val_if_nok (error, FALSE);
522 table = &assembly->tables [MONO_TABLE_PARAM];
523 values [MONO_METHOD_PARAMLIST] = table->next_idx;
525 mono_image_add_decl_security (assembly,
526 mono_metadata_make_token (MONO_TABLE_METHOD, *mb->table_idx), mb->permissions);
528 if (mb->pinfo) {
529 MonoDynamicTable *mtable;
530 guint32 *mvalues;
532 mtable = &assembly->tables [MONO_TABLE_FIELDMARSHAL];
533 mvalues = mtable->values + mtable->next_idx * MONO_FIELD_MARSHAL_SIZE;
535 count = 0;
536 for (i = 0; i < mono_array_length_internal (mb->pinfo); ++i) {
537 if (mono_array_get_internal (mb->pinfo, gpointer, i))
538 count++;
540 table->rows += count;
541 alloc_table (table, table->rows);
542 values = table->values + table->next_idx * MONO_PARAM_SIZE;
543 for (i = 0; i < mono_array_length_internal (mb->pinfo); ++i) {
544 MonoReflectionParamBuilder *pb;
545 if ((pb = mono_array_get_internal (mb->pinfo, MonoReflectionParamBuilder*, i))) {
546 values [MONO_PARAM_FLAGS] = pb->attrs;
547 values [MONO_PARAM_SEQUENCE] = i;
548 if (pb->name != NULL) {
549 values [MONO_PARAM_NAME] = string_heap_insert_mstring (&assembly->sheap, pb->name, error);
550 return_val_if_nok (error, FALSE);
551 } else {
552 values [MONO_PARAM_NAME] = 0;
554 values += MONO_PARAM_SIZE;
555 if (pb->marshal_info) {
556 mtable->rows++;
557 alloc_table (mtable, mtable->rows);
558 mvalues = mtable->values + mtable->rows * MONO_FIELD_MARSHAL_SIZE;
559 mvalues [MONO_FIELD_MARSHAL_PARENT] = (table->next_idx << MONO_HAS_FIELD_MARSHAL_BITS) | MONO_HAS_FIELD_MARSHAL_PARAMDEF;
560 mvalues [MONO_FIELD_MARSHAL_NATIVE_TYPE] = mono_dynimage_save_encode_marshal_blob (assembly, pb->marshal_info, error);
561 return_val_if_nok (error, FALSE);
563 pb->table_idx = table->next_idx++;
564 if (pb->attrs & PARAM_ATTRIBUTE_HAS_DEFAULT) {
565 MonoTypeEnum field_type = (MonoTypeEnum)0;
566 mtable = &assembly->tables [MONO_TABLE_CONSTANT];
567 mtable->rows ++;
568 alloc_table (mtable, mtable->rows);
569 mvalues = mtable->values + mtable->rows * MONO_CONSTANT_SIZE;
570 mvalues [MONO_CONSTANT_PARENT] = MONO_HASCONSTANT_PARAM | (pb->table_idx << MONO_HASCONSTANT_BITS);
571 mvalues [MONO_CONSTANT_VALUE] = mono_dynimage_encode_constant (assembly, pb->def_value, &field_type);
572 mvalues [MONO_CONSTANT_TYPE] = field_type;
573 mvalues [MONO_CONSTANT_PADDING] = 0;
579 return TRUE;
582 static gboolean
583 mono_image_add_methodimpl (MonoDynamicImage *assembly, MonoReflectionMethodBuilder *mb, MonoError *error)
585 MONO_REQ_GC_UNSAFE_MODE;
587 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mb->type;
588 MonoDynamicTable *table;
589 guint32 *values;
590 guint32 tok;
591 MonoReflectionMethod *m;
592 int i;
594 error_init (error);
596 if (!mb->override_methods)
597 return TRUE;
599 for (i = 0; i < mono_array_length_internal (mb->override_methods); ++i) {
600 m = mono_array_get_internal (mb->override_methods, MonoReflectionMethod*, i);
602 table = &assembly->tables [MONO_TABLE_METHODIMPL];
603 table->rows ++;
604 alloc_table (table, table->rows);
605 values = table->values + table->rows * MONO_METHODIMPL_SIZE;
606 values [MONO_METHODIMPL_CLASS] = tb->table_idx;
607 values [MONO_METHODIMPL_BODY] = MONO_METHODDEFORREF_METHODDEF | (mb->table_idx << MONO_METHODDEFORREF_BITS);
609 tok = image_create_token_raw (assembly, (MonoObject*)m, FALSE, FALSE, error); /* FIXME use handles */
610 return_val_if_nok (error, FALSE);
612 switch (mono_metadata_token_table (tok)) {
613 case MONO_TABLE_MEMBERREF:
614 tok = (mono_metadata_token_index (tok) << MONO_METHODDEFORREF_BITS ) | MONO_METHODDEFORREF_METHODREF;
615 break;
616 case MONO_TABLE_METHOD:
617 tok = (mono_metadata_token_index (tok) << MONO_METHODDEFORREF_BITS ) | MONO_METHODDEFORREF_METHODDEF;
618 break;
619 default:
620 g_assert_not_reached ();
622 values [MONO_METHODIMPL_DECLARATION] = tok;
625 return TRUE;
628 #ifndef DISABLE_REFLECTION_EMIT
629 static gboolean
630 mono_image_get_method_info (MonoReflectionMethodBuilder *mb, MonoDynamicImage *assembly, MonoError *error)
632 MONO_REQ_GC_UNSAFE_MODE;
633 /* We need to clear handles for rmb fields created in mono_reflection_methodbuilder_from_method_builder */
634 HANDLE_FUNCTION_ENTER ();
636 MonoDynamicTable *table;
637 guint32 *values;
638 ReflectionMethodBuilder rmb;
639 int i;
640 gboolean ret = TRUE;
642 error_init (error);
644 if (!mono_reflection_methodbuilder_from_method_builder (&rmb, mb, error) ||
645 !mono_image_basic_method (&rmb, assembly, error)) {
646 ret = FALSE;
647 goto exit;
650 mb->table_idx = *rmb.table_idx;
652 if (mb->dll) { /* It's a P/Invoke method */
653 guint32 moduleref;
654 /* map CharSet values to on-disk values */
655 int ncharset = (mb->charset ? (mb->charset - 1) * 2 : 0);
656 int extra_flags = mb->extra_flags;
657 table = &assembly->tables [MONO_TABLE_IMPLMAP];
658 table->rows ++;
659 alloc_table (table, table->rows);
660 values = table->values + table->rows * MONO_IMPLMAP_SIZE;
662 values [MONO_IMPLMAP_FLAGS] = (mb->native_cc << 8) | ncharset | extra_flags;
663 values [MONO_IMPLMAP_MEMBER] = (mb->table_idx << 1) | 1; /* memberforwarded: method */
664 if (mb->dllentry) {
665 values [MONO_IMPLMAP_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->dllentry, error);
666 return_val_if_nok (error, FALSE);
667 } else {
668 values [MONO_IMPLMAP_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->name, error);
669 return_val_if_nok (error, FALSE);
671 moduleref = string_heap_insert_mstring (&assembly->sheap, mb->dll, error);
672 return_val_if_nok (error, FALSE);
673 if (!(values [MONO_IMPLMAP_SCOPE] = find_index_in_table (assembly, MONO_TABLE_MODULEREF, MONO_MODULEREF_NAME, moduleref))) {
674 table = &assembly->tables [MONO_TABLE_MODULEREF];
675 table->rows ++;
676 alloc_table (table, table->rows);
677 table->values [table->rows * MONO_MODULEREF_SIZE + MONO_MODULEREF_NAME] = moduleref;
678 values [MONO_IMPLMAP_SCOPE] = table->rows;
682 if (mb->generic_params) {
683 table = &assembly->tables [MONO_TABLE_GENERICPARAM];
684 table->rows += mono_array_length_internal (mb->generic_params);
685 alloc_table (table, table->rows);
686 for (i = 0; i < mono_array_length_internal (mb->generic_params); ++i) {
687 guint32 owner = MONO_TYPEORMETHOD_METHOD | (mb->table_idx << MONO_TYPEORMETHOD_BITS);
689 mono_image_get_generic_param_info (
690 (MonoReflectionGenericParam *)mono_array_get_internal (mb->generic_params, gpointer, i), owner, assembly);
693 exit:
694 HANDLE_FUNCTION_RETURN_VAL (ret);
697 static gboolean
698 mono_image_get_ctor_info (MonoDomain *domain, MonoReflectionCtorBuilder *mb, MonoDynamicImage *assembly, MonoError *error)
700 /* We need to clear handles for rmb fields created in mono_reflection_methodbuilder_from_ctor_builder */
701 HANDLE_FUNCTION_ENTER ();
702 MONO_REQ_GC_UNSAFE_MODE;
704 gboolean ret = TRUE;
705 ReflectionMethodBuilder rmb;
707 if (!mono_reflection_methodbuilder_from_ctor_builder (&rmb, mb, error)) {
708 ret = FALSE;
709 goto exit;
712 if (!mono_image_basic_method (&rmb, assembly, error)) {
713 ret = FALSE;
714 goto exit;
717 mb->table_idx = *rmb.table_idx;
718 exit:
719 HANDLE_FUNCTION_RETURN_VAL (ret);
721 #endif
723 static void
724 mono_image_get_field_info (MonoReflectionFieldBuilder *fb, MonoDynamicImage *assembly, MonoError *error)
726 MONO_REQ_GC_UNSAFE_MODE;
728 error_init (error);
730 MonoDynamicTable *table;
731 guint32 *values;
733 /* maybe this fixup should be done in the C# code */
734 if (fb->attrs & FIELD_ATTRIBUTE_LITERAL)
735 fb->attrs |= FIELD_ATTRIBUTE_HAS_DEFAULT;
736 table = &assembly->tables [MONO_TABLE_FIELD];
737 guint32 fb_table_idx = table->next_idx ++;
738 g_hash_table_insert (assembly->field_to_table_idx, fb->handle, GUINT_TO_POINTER (fb_table_idx));
739 values = table->values + fb_table_idx * MONO_FIELD_SIZE;
740 values [MONO_FIELD_NAME] = string_heap_insert_mstring (&assembly->sheap, fb->name, error);
741 return_if_nok (error);
742 values [MONO_FIELD_FLAGS] = fb->attrs;
743 values [MONO_FIELD_SIGNATURE] = mono_dynimage_encode_field_signature (assembly, fb, error);
744 return_if_nok (error);
746 if (fb->offset != -1) {
747 table = &assembly->tables [MONO_TABLE_FIELDLAYOUT];
748 table->rows ++;
749 alloc_table (table, table->rows);
750 values = table->values + table->rows * MONO_FIELD_LAYOUT_SIZE;
751 values [MONO_FIELD_LAYOUT_FIELD] = fb_table_idx;
752 values [MONO_FIELD_LAYOUT_OFFSET] = fb->offset;
754 if (fb->attrs & FIELD_ATTRIBUTE_LITERAL) {
755 MonoTypeEnum field_type = (MonoTypeEnum)0;
756 table = &assembly->tables [MONO_TABLE_CONSTANT];
757 table->rows ++;
758 alloc_table (table, table->rows);
759 values = table->values + table->rows * MONO_CONSTANT_SIZE;
760 values [MONO_CONSTANT_PARENT] = MONO_HASCONSTANT_FIEDDEF | (fb_table_idx << MONO_HASCONSTANT_BITS);
761 values [MONO_CONSTANT_VALUE] = mono_dynimage_encode_constant (assembly, fb->def_value, &field_type);
762 values [MONO_CONSTANT_TYPE] = field_type;
763 values [MONO_CONSTANT_PADDING] = 0;
765 if (fb->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA) {
766 guint32 rva_idx;
767 table = &assembly->tables [MONO_TABLE_FIELDRVA];
768 table->rows ++;
769 alloc_table (table, table->rows);
770 values = table->values + table->rows * MONO_FIELD_RVA_SIZE;
771 values [MONO_FIELD_RVA_FIELD] = fb_table_idx;
773 * We store it in the code section because it's simpler for now.
775 if (fb->rva_data) {
776 if (mono_array_length_internal (fb->rva_data) >= 10)
777 stream_data_align (&assembly->code);
778 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));
779 } else
780 rva_idx = mono_image_add_stream_zero (&assembly->code, mono_class_value_size (fb->handle->parent, NULL));
781 values [MONO_FIELD_RVA_RVA] = rva_idx + assembly->text_rva;
783 if (fb->marshal_info) {
784 table = &assembly->tables [MONO_TABLE_FIELDMARSHAL];
785 table->rows ++;
786 alloc_table (table, table->rows);
787 values = table->values + table->rows * MONO_FIELD_MARSHAL_SIZE;
788 values [MONO_FIELD_MARSHAL_PARENT] = (fb_table_idx << MONO_HAS_FIELD_MARSHAL_BITS) | MONO_HAS_FIELD_MARSHAL_FIELDSREF;
789 values [MONO_FIELD_MARSHAL_NATIVE_TYPE] = mono_dynimage_save_encode_marshal_blob (assembly, fb->marshal_info, error);
790 return_if_nok (error);
794 static void
795 mono_image_get_property_info (MonoReflectionPropertyBuilder *pb, MonoDynamicImage *assembly, MonoError *error)
797 MONO_REQ_GC_UNSAFE_MODE;
799 error_init (error);
801 MonoDynamicTable *table;
802 guint32 *values;
803 guint num_methods = 0;
804 guint32 semaidx;
807 * we need to set things in the following tables:
808 * PROPERTYMAP (info already filled in _get_type_info ())
809 * PROPERTY (rows already preallocated in _get_type_info ())
810 * METHOD (method info already done with the generic method code)
811 * METHODSEMANTICS
812 * CONSTANT
814 table = &assembly->tables [MONO_TABLE_PROPERTY];
815 pb->table_idx = table->next_idx ++;
816 values = table->values + pb->table_idx * MONO_PROPERTY_SIZE;
817 values [MONO_PROPERTY_NAME] = string_heap_insert_mstring (&assembly->sheap, pb->name, error);
818 return_if_nok (error);
819 values [MONO_PROPERTY_FLAGS] = pb->attrs;
820 values [MONO_PROPERTY_TYPE] = mono_dynimage_save_encode_property_signature (assembly, pb, error);
821 return_if_nok (error);
824 /* FIXME: we still don't handle 'other' methods */
825 if (pb->get_method) num_methods ++;
826 if (pb->set_method) num_methods ++;
828 table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
829 table->rows += num_methods;
830 alloc_table (table, table->rows);
832 if (pb->get_method) {
833 semaidx = table->next_idx ++;
834 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
835 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_GETTER;
836 values [MONO_METHOD_SEMA_METHOD] = pb->get_method->table_idx;
837 values [MONO_METHOD_SEMA_ASSOCIATION] = (pb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_PROPERTY;
839 if (pb->set_method) {
840 semaidx = table->next_idx ++;
841 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
842 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_SETTER;
843 values [MONO_METHOD_SEMA_METHOD] = pb->set_method->table_idx;
844 values [MONO_METHOD_SEMA_ASSOCIATION] = (pb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_PROPERTY;
846 if (pb->attrs & PROPERTY_ATTRIBUTE_HAS_DEFAULT) {
847 MonoTypeEnum field_type = (MonoTypeEnum)0;
848 table = &assembly->tables [MONO_TABLE_CONSTANT];
849 table->rows ++;
850 alloc_table (table, table->rows);
851 values = table->values + table->rows * MONO_CONSTANT_SIZE;
852 values [MONO_CONSTANT_PARENT] = MONO_HASCONSTANT_PROPERTY | (pb->table_idx << MONO_HASCONSTANT_BITS);
853 values [MONO_CONSTANT_VALUE] = mono_dynimage_encode_constant (assembly, pb->def_value, &field_type);
854 values [MONO_CONSTANT_TYPE] = field_type;
855 values [MONO_CONSTANT_PADDING] = 0;
859 static void
860 mono_image_get_event_info (MonoReflectionEventBuilder *eb, MonoDynamicImage *assembly, MonoError *error)
862 MONO_REQ_GC_UNSAFE_MODE;
864 MonoDynamicTable *table;
865 guint32 *values;
866 guint num_methods = 0;
867 guint32 semaidx;
870 * we need to set things in the following tables:
871 * EVENTMAP (info already filled in _get_type_info ())
872 * EVENT (rows already preallocated in _get_type_info ())
873 * METHOD (method info already done with the generic method code)
874 * METHODSEMANTICS
876 table = &assembly->tables [MONO_TABLE_EVENT];
877 eb->table_idx = table->next_idx ++;
878 values = table->values + eb->table_idx * MONO_EVENT_SIZE;
879 values [MONO_EVENT_NAME] = string_heap_insert_mstring (&assembly->sheap, eb->name, error);
880 return_if_nok (error);
881 values [MONO_EVENT_FLAGS] = eb->attrs;
882 MonoType *ebtype = mono_reflection_type_get_handle (eb->type, error);
883 return_if_nok (error);
884 values [MONO_EVENT_TYPE] = mono_image_typedef_or_ref (assembly, ebtype);
887 * FIXME: we still don't handle 'other' methods
889 if (eb->add_method) num_methods ++;
890 if (eb->remove_method) num_methods ++;
891 if (eb->raise_method) num_methods ++;
893 table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
894 table->rows += num_methods;
895 alloc_table (table, table->rows);
897 if (eb->add_method) {
898 semaidx = table->next_idx ++;
899 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
900 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_ADD_ON;
901 values [MONO_METHOD_SEMA_METHOD] = eb->add_method->table_idx;
902 values [MONO_METHOD_SEMA_ASSOCIATION] = (eb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_EVENT;
904 if (eb->remove_method) {
905 semaidx = table->next_idx ++;
906 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
907 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_REMOVE_ON;
908 values [MONO_METHOD_SEMA_METHOD] = eb->remove_method->table_idx;
909 values [MONO_METHOD_SEMA_ASSOCIATION] = (eb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_EVENT;
911 if (eb->raise_method) {
912 semaidx = table->next_idx ++;
913 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
914 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_FIRE;
915 values [MONO_METHOD_SEMA_METHOD] = eb->raise_method->table_idx;
916 values [MONO_METHOD_SEMA_ASSOCIATION] = (eb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_EVENT;
920 static void
921 encode_constraints (MonoReflectionGenericParam *gparam, guint32 owner, MonoDynamicImage *assembly, MonoError *error)
923 MONO_REQ_GC_UNSAFE_MODE;
925 error_init (error);
927 MonoDynamicTable *table;
928 guint32 num_constraints, i;
929 guint32 *values;
930 guint32 table_idx;
932 table = &assembly->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
933 num_constraints = gparam->iface_constraints ?
934 mono_array_length_internal (gparam->iface_constraints) : 0;
935 table->rows += num_constraints;
936 if (gparam->base_type)
937 table->rows++;
938 alloc_table (table, table->rows);
940 if (gparam->base_type) {
941 table_idx = table->next_idx ++;
942 values = table->values + table_idx * MONO_GENPARCONSTRAINT_SIZE;
944 MonoType *gpbasetype = mono_reflection_type_get_handle (gparam->base_type, error);
945 return_if_nok (error);
946 values [MONO_GENPARCONSTRAINT_GENERICPAR] = owner;
947 values [MONO_GENPARCONSTRAINT_CONSTRAINT] = mono_image_typedef_or_ref (assembly, gpbasetype);
950 for (i = 0; i < num_constraints; i++) {
951 MonoReflectionType *constraint = (MonoReflectionType *)mono_array_get_internal (
952 gparam->iface_constraints, gpointer, i);
954 table_idx = table->next_idx ++;
955 values = table->values + table_idx * MONO_GENPARCONSTRAINT_SIZE;
957 MonoType *constraint_type = mono_reflection_type_get_handle (constraint, error);
958 return_if_nok (error);
960 values [MONO_GENPARCONSTRAINT_GENERICPAR] = owner;
961 values [MONO_GENPARCONSTRAINT_CONSTRAINT] = mono_image_typedef_or_ref (assembly, constraint_type);
965 static void
966 mono_image_get_generic_param_info (MonoReflectionGenericParam *gparam, guint32 owner, MonoDynamicImage *assembly)
968 MONO_REQ_GC_UNSAFE_MODE;
970 GenericParamTableEntry *entry;
973 * The GenericParam table must be sorted according to the `owner' field.
974 * We need to do this sorting prior to writing the GenericParamConstraint
975 * table, since we have to use the final GenericParam table indices there
976 * and they must also be sorted.
979 entry = g_new0 (GenericParamTableEntry, 1);
980 entry->owner = owner;
981 /* FIXME: track where gen_params should be freed and remove the GC root as well */
982 MONO_GC_REGISTER_ROOT_IF_MOVING (entry->gparam, MONO_ROOT_SOURCE_REFLECTION, NULL, "Reflection Generic Parameter");
983 entry->gparam = gparam;
985 g_ptr_array_add (assembly->gen_params, entry);
988 static gboolean
989 write_generic_param_entry (MonoDynamicImage *assembly, GenericParamTableEntry *entry, MonoError *error)
991 MONO_REQ_GC_UNSAFE_MODE;
993 MonoDynamicTable *table;
994 MonoGenericParam *param;
995 guint32 *values;
996 guint32 table_idx;
998 error_init (error);
1000 table = &assembly->tables [MONO_TABLE_GENERICPARAM];
1001 table_idx = table->next_idx ++;
1002 values = table->values + table_idx * MONO_GENERICPARAM_SIZE;
1004 MonoType *gparam_type = mono_reflection_type_get_handle ((MonoReflectionType*)entry->gparam, error);
1005 return_val_if_nok (error, FALSE);
1007 param = gparam_type->data.generic_param;
1009 values [MONO_GENERICPARAM_OWNER] = entry->owner;
1010 values [MONO_GENERICPARAM_FLAGS] = entry->gparam->attrs;
1011 values [MONO_GENERICPARAM_NUMBER] = mono_generic_param_num (param);
1012 values [MONO_GENERICPARAM_NAME] = string_heap_insert (&assembly->sheap, mono_generic_param_name (param));
1014 if (!mono_image_add_cattrs (assembly, table_idx, MONO_CUSTOM_ATTR_GENERICPAR, entry->gparam->cattrs, error))
1015 return FALSE;
1017 encode_constraints (entry->gparam, table_idx, assembly, error);
1018 return_val_if_nok (error, FALSE);
1020 return TRUE;
1023 static void
1024 collect_types (MonoPtrArray *types, MonoReflectionTypeBuilder *type)
1026 int i;
1028 mono_ptr_array_append (*types, type);
1030 if (!type->subtypes)
1031 return;
1033 for (i = 0; i < mono_array_length_internal (type->subtypes); ++i) {
1034 MonoReflectionTypeBuilder *subtype = mono_array_get_internal (type->subtypes, MonoReflectionTypeBuilder*, i);
1035 collect_types (types, subtype);
1039 static gint
1040 compare_types_by_table_idx (MonoReflectionTypeBuilder **type1, MonoReflectionTypeBuilder **type2)
1042 if ((*type1)->table_idx < (*type2)->table_idx)
1043 return -1;
1044 else
1045 if ((*type1)->table_idx > (*type2)->table_idx)
1046 return 1;
1047 else
1048 return 0;
1051 static gboolean
1052 params_add_cattrs (MonoDynamicImage *assembly, MonoArray *pinfo, MonoError *error) {
1053 int i;
1055 error_init (error);
1056 if (!pinfo)
1057 return TRUE;
1058 for (i = 0; i < mono_array_length_internal (pinfo); ++i) {
1059 MonoReflectionParamBuilder *pb;
1060 pb = mono_array_get_internal (pinfo, MonoReflectionParamBuilder *, i);
1061 if (!pb)
1062 continue;
1063 if (!mono_image_add_cattrs (assembly, pb->table_idx, MONO_CUSTOM_ATTR_PARAMDEF, pb->cattrs, error))
1064 return FALSE;
1067 return TRUE;
1070 static guint32
1071 field_builder_table_index (MonoDynamicImage* assembly, MonoReflectionFieldBuilder *fb)
1073 return GPOINTER_TO_UINT (g_hash_table_lookup (assembly->field_to_table_idx, fb->handle));
1076 static gboolean
1077 type_add_cattrs (MonoDynamicImage *assembly, MonoReflectionTypeBuilder *tb, MonoError *error) {
1078 int i;
1080 error_init (error);
1082 if (!mono_image_add_cattrs (assembly, tb->table_idx, MONO_CUSTOM_ATTR_TYPEDEF, tb->cattrs, error))
1083 return FALSE;
1084 if (tb->fields) {
1085 for (i = 0; i < tb->num_fields; ++i) {
1086 MonoReflectionFieldBuilder* fb;
1087 fb = mono_array_get_internal (tb->fields, MonoReflectionFieldBuilder*, i);
1088 if (!mono_image_add_cattrs (assembly, field_builder_table_index (assembly, fb), MONO_CUSTOM_ATTR_FIELDDEF, fb->cattrs, error))
1089 return FALSE;
1092 if (tb->events) {
1093 for (i = 0; i < mono_array_length_internal (tb->events); ++i) {
1094 MonoReflectionEventBuilder* eb;
1095 eb = mono_array_get_internal (tb->events, MonoReflectionEventBuilder*, i);
1096 if (!mono_image_add_cattrs (assembly, eb->table_idx, MONO_CUSTOM_ATTR_EVENT, eb->cattrs, error))
1097 return FALSE;
1100 if (tb->properties) {
1101 for (i = 0; i < mono_array_length_internal (tb->properties); ++i) {
1102 MonoReflectionPropertyBuilder* pb;
1103 pb = mono_array_get_internal (tb->properties, MonoReflectionPropertyBuilder*, i);
1104 if (!mono_image_add_cattrs (assembly, pb->table_idx, MONO_CUSTOM_ATTR_PROPERTY, pb->cattrs, error))
1105 return FALSE;
1108 if (tb->ctors) {
1109 for (i = 0; i < mono_array_length_internal (tb->ctors); ++i) {
1110 MonoReflectionCtorBuilder* cb;
1111 cb = mono_array_get_internal (tb->ctors, MonoReflectionCtorBuilder*, i);
1112 if (!mono_image_add_cattrs (assembly, cb->table_idx, MONO_CUSTOM_ATTR_METHODDEF, cb->cattrs, error) ||
1113 !params_add_cattrs (assembly, cb->pinfo, error))
1114 return FALSE;
1118 if (tb->methods) {
1119 for (i = 0; i < tb->num_methods; ++i) {
1120 MonoReflectionMethodBuilder* mb;
1121 mb = mono_array_get_internal (tb->methods, MonoReflectionMethodBuilder*, i);
1122 if (!mono_image_add_cattrs (assembly, mb->table_idx, MONO_CUSTOM_ATTR_METHODDEF, mb->cattrs, error) ||
1123 !params_add_cattrs (assembly, mb->pinfo, error))
1124 return FALSE;
1128 if (tb->subtypes) {
1129 for (i = 0; i < mono_array_length_internal (tb->subtypes); ++i) {
1130 if (!type_add_cattrs (assembly, mono_array_get_internal (tb->subtypes, MonoReflectionTypeBuilder*, i), error))
1131 return FALSE;
1135 return TRUE;
1138 static gboolean
1139 module_add_cattrs (MonoDynamicImage *assembly, MonoReflectionModuleBuilder *moduleb, MonoError *error)
1141 int i;
1143 error_init (error);
1145 if (!mono_image_add_cattrs (assembly, moduleb->table_idx, MONO_CUSTOM_ATTR_MODULE, moduleb->cattrs, error))
1146 return FALSE;
1148 if (moduleb->global_methods) {
1149 for (i = 0; i < mono_array_length_internal (moduleb->global_methods); ++i) {
1150 MonoReflectionMethodBuilder* mb = mono_array_get_internal (moduleb->global_methods, MonoReflectionMethodBuilder*, i);
1151 if (!mono_image_add_cattrs (assembly, mb->table_idx, MONO_CUSTOM_ATTR_METHODDEF, mb->cattrs, error) ||
1152 !params_add_cattrs (assembly, mb->pinfo, error))
1153 return FALSE;
1157 if (moduleb->global_fields) {
1158 for (i = 0; i < mono_array_length_internal (moduleb->global_fields); ++i) {
1159 MonoReflectionFieldBuilder *fb = mono_array_get_internal (moduleb->global_fields, MonoReflectionFieldBuilder*, i);
1160 if (!mono_image_add_cattrs (assembly, field_builder_table_index (assembly, fb), MONO_CUSTOM_ATTR_FIELDDEF, fb->cattrs, error))
1161 return FALSE;
1165 if (moduleb->types) {
1166 for (i = 0; i < moduleb->num_types; ++i) {
1167 if (!type_add_cattrs (assembly, mono_array_get_internal (moduleb->types, MonoReflectionTypeBuilder*, i), error))
1168 return FALSE;
1172 return TRUE;
1175 static gboolean
1176 mono_image_fill_file_table (MonoDomain *domain, MonoReflectionModule *module, MonoDynamicImage *assembly, MonoError *error)
1178 MonoDynamicTable *table;
1179 guint32 *values;
1180 char blob_size [6];
1181 guchar hash [20];
1182 char *b = blob_size;
1183 char *dir, *path;
1185 error_init (error);
1187 table = &assembly->tables [MONO_TABLE_FILE];
1188 table->rows++;
1189 alloc_table (table, table->rows);
1190 values = table->values + table->next_idx * MONO_FILE_SIZE;
1191 values [MONO_FILE_FLAGS] = FILE_CONTAINS_METADATA;
1192 values [MONO_FILE_NAME] = string_heap_insert (&assembly->sheap, module->image->module_name);
1193 if (image_is_dynamic (module->image)) {
1194 /* This depends on the fact that the main module is emitted last */
1195 dir = mono_string_to_utf8_checked_internal (((MonoReflectionModuleBuilder*)module)->assemblyb->dir, error);
1196 return_val_if_nok (error, FALSE);
1197 path = g_strdup_printf ("%s%c%s", dir, G_DIR_SEPARATOR, module->image->module_name);
1198 } else {
1199 dir = NULL;
1200 path = g_strdup (module->image->name);
1202 mono_sha1_get_digest_from_file (path, hash);
1203 g_free (dir);
1204 g_free (path);
1205 mono_metadata_encode_value (20, b, &b);
1206 values [MONO_FILE_HASH_VALUE] = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
1207 mono_image_add_stream_data (&assembly->blob, (char*)hash, 20);
1208 table->next_idx ++;
1209 return TRUE;
1212 static void
1213 mono_image_fill_module_table (MonoDomain *domain, MonoReflectionModuleBuilder *mb, MonoDynamicImage *assembly, MonoError *error)
1215 MonoDynamicTable *table;
1216 int i;
1218 error_init (error);
1220 table = &assembly->tables [MONO_TABLE_MODULE];
1221 mb->table_idx = table->next_idx ++;
1222 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->module.name, error);
1223 return_if_nok (error);
1224 i = mono_image_add_stream_data (&assembly->guid, mono_array_addr_internal (mb->guid, char, 0), 16);
1225 i /= 16;
1226 ++i;
1227 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_GENERATION] = 0;
1228 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_MVID] = i;
1229 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_ENC] = 0;
1230 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_ENCBASE] = 0;
1233 static guint32
1234 mono_image_fill_export_table_from_class (MonoDomain *domain, MonoClass *klass,
1235 guint32 module_index, guint32 parent_index, MonoDynamicImage *assembly)
1237 MonoDynamicTable *table;
1238 guint32 *values;
1239 guint32 visib, res;
1241 visib = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_VISIBILITY_MASK;
1242 if (! ((visib & TYPE_ATTRIBUTE_PUBLIC) || (visib & TYPE_ATTRIBUTE_NESTED_PUBLIC)))
1243 return 0;
1245 table = &assembly->tables [MONO_TABLE_EXPORTEDTYPE];
1246 table->rows++;
1247 alloc_table (table, table->rows);
1248 values = table->values + table->next_idx * MONO_EXP_TYPE_SIZE;
1250 values [MONO_EXP_TYPE_FLAGS] = mono_class_get_flags (klass);
1251 values [MONO_EXP_TYPE_TYPEDEF] = m_class_get_type_token (klass);
1252 if (m_class_get_nested_in (klass))
1253 values [MONO_EXP_TYPE_IMPLEMENTATION] = (parent_index << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_EXP_TYPE;
1254 else
1255 values [MONO_EXP_TYPE_IMPLEMENTATION] = (module_index << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_FILE;
1256 values [MONO_EXP_TYPE_NAME] = string_heap_insert (&assembly->sheap, m_class_get_name (klass));
1257 values [MONO_EXP_TYPE_NAMESPACE] = string_heap_insert (&assembly->sheap, m_class_get_name_space (klass));
1259 res = table->next_idx;
1261 table->next_idx ++;
1263 /* Emit nested types */
1264 GList *nested_classes = mono_class_get_nested_classes_property (klass);
1265 GList *tmp;
1266 for (tmp = nested_classes; tmp; tmp = tmp->next)
1267 mono_image_fill_export_table_from_class (domain, (MonoClass *)tmp->data, module_index, table->next_idx - 1, assembly);
1269 return res;
1272 static void
1273 mono_image_fill_export_table (MonoDomain *domain, MonoReflectionTypeBuilder *tb,
1274 guint32 module_index, guint32 parent_index, MonoDynamicImage *assembly,
1275 MonoError *error)
1277 MonoClass *klass;
1278 guint32 idx, i;
1280 error_init (error);
1282 MonoType *t = mono_reflection_type_get_handle ((MonoReflectionType*)tb, error);
1283 return_if_nok (error);
1285 klass = mono_class_from_mono_type_internal (t);
1287 guint32 tb_token = mono_metadata_make_token (MONO_TABLE_TYPEDEF, tb->table_idx);
1288 if (m_class_get_type_token (klass) != tb_token) {
1289 g_error ("TypeBuilder token %08x does not match klass token %08x", tb_token, m_class_get_type_token (klass));
1292 idx = mono_image_fill_export_table_from_class (domain, klass, module_index,
1293 parent_index, assembly);
1296 * Emit nested types
1297 * We need to do this ourselves since klass->nested_classes is not set up.
1299 if (tb->subtypes) {
1300 for (i = 0; i < mono_array_length_internal (tb->subtypes); ++i) {
1301 mono_image_fill_export_table (domain, mono_array_get_internal (tb->subtypes, MonoReflectionTypeBuilder*, i), module_index, idx, assembly, error);
1302 return_if_nok (error);
1307 static void
1308 mono_image_fill_export_table_from_module (MonoDomain *domain, MonoReflectionModule *module,
1309 guint32 module_index, MonoDynamicImage *assembly)
1311 MonoImage *image = module->image;
1312 MonoTableInfo *t;
1313 guint32 i;
1315 t = &image->tables [MONO_TABLE_TYPEDEF];
1317 for (i = 0; i < t->rows; ++i) {
1318 ERROR_DECL (error);
1319 MonoClass *klass = mono_class_get_checked (image, mono_metadata_make_token (MONO_TABLE_TYPEDEF, i + 1), error);
1320 g_assert (is_ok (error)); /* FIXME don't swallow the error */
1322 if (mono_class_is_public (klass))
1323 mono_image_fill_export_table_from_class (domain, klass, module_index, 0, assembly);
1327 static void
1328 add_exported_type (MonoReflectionAssemblyBuilder *assemblyb, MonoDynamicImage *assembly, MonoClass *klass, guint32 parent_index)
1330 MonoDynamicTable *table;
1331 guint32 *values;
1332 guint32 scope, scope_idx, impl, current_idx;
1333 gboolean forwarder = TRUE;
1334 gpointer iter = NULL;
1335 MonoClass *nested;
1337 if (m_class_get_nested_in (klass)) {
1338 impl = (parent_index << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_EXP_TYPE;
1339 forwarder = FALSE;
1340 } else {
1341 scope = mono_reflection_resolution_scope_from_image (assembly, m_class_get_image (klass));
1342 g_assert ((scope & MONO_RESOLUTION_SCOPE_MASK) == MONO_RESOLUTION_SCOPE_ASSEMBLYREF);
1343 scope_idx = scope >> MONO_RESOLUTION_SCOPE_BITS;
1344 impl = (scope_idx << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_ASSEMBLYREF;
1347 table = &assembly->tables [MONO_TABLE_EXPORTEDTYPE];
1349 table->rows++;
1350 alloc_table (table, table->rows);
1351 current_idx = table->next_idx;
1352 values = table->values + current_idx * MONO_EXP_TYPE_SIZE;
1354 values [MONO_EXP_TYPE_FLAGS] = forwarder ? TYPE_ATTRIBUTE_FORWARDER : 0;
1355 values [MONO_EXP_TYPE_TYPEDEF] = 0;
1356 values [MONO_EXP_TYPE_IMPLEMENTATION] = impl;
1357 values [MONO_EXP_TYPE_NAME] = string_heap_insert (&assembly->sheap, m_class_get_name (klass));
1358 values [MONO_EXP_TYPE_NAMESPACE] = string_heap_insert (&assembly->sheap, m_class_get_name_space (klass));
1360 table->next_idx++;
1362 while ((nested = mono_class_get_nested_types (klass, &iter)))
1363 add_exported_type (assemblyb, assembly, nested, current_idx);
1366 static void
1367 mono_image_fill_export_table_from_type_forwarders (MonoReflectionAssemblyBuilder *assemblyb, MonoDynamicImage *assembly)
1369 ERROR_DECL (error);
1370 MonoClass *klass;
1371 int i;
1373 if (!assemblyb->type_forwarders)
1374 return;
1376 for (i = 0; i < mono_array_length_internal (assemblyb->type_forwarders); ++i) {
1377 MonoReflectionType *t = mono_array_get_internal (assemblyb->type_forwarders, MonoReflectionType *, i);
1378 MonoType *type;
1379 if (!t)
1380 continue;
1382 type = mono_reflection_type_get_handle (t, error);
1383 mono_error_assert_ok (error);
1384 g_assert (type);
1386 klass = mono_class_from_mono_type_internal (type);
1388 add_exported_type (assemblyb, assembly, klass, 0);
1392 #define align_pointer(base,p)\
1393 do {\
1394 guint32 __diff = (unsigned char*)(p)-(unsigned char*)(base);\
1395 if (__diff & 3)\
1396 (p) += 4 - (__diff & 3);\
1397 } while (0)
1399 static int
1400 compare_constants (const void *a, const void *b)
1402 const guint32 *a_values = (const guint32 *)a;
1403 const guint32 *b_values = (const guint32 *)b;
1404 return a_values [MONO_CONSTANT_PARENT] - b_values [MONO_CONSTANT_PARENT];
1407 static int
1408 compare_semantics (const void *a, const void *b)
1410 const guint32 *a_values = (const guint32 *)a;
1411 const guint32 *b_values = (const guint32 *)b;
1412 int assoc = a_values [MONO_METHOD_SEMA_ASSOCIATION] - b_values [MONO_METHOD_SEMA_ASSOCIATION];
1413 if (assoc)
1414 return assoc;
1415 return a_values [MONO_METHOD_SEMA_SEMANTICS] - b_values [MONO_METHOD_SEMA_SEMANTICS];
1418 static int
1419 compare_custom_attrs (const void *a, const void *b)
1421 const guint32 *a_values = (const guint32 *)a;
1422 const guint32 *b_values = (const guint32 *)b;
1424 return a_values [MONO_CUSTOM_ATTR_PARENT] - b_values [MONO_CUSTOM_ATTR_PARENT];
1427 static int
1428 compare_field_marshal (const void *a, const void *b)
1430 const guint32 *a_values = (const guint32 *)a;
1431 const guint32 *b_values = (const guint32 *)b;
1433 return a_values [MONO_FIELD_MARSHAL_PARENT] - b_values [MONO_FIELD_MARSHAL_PARENT];
1436 static int
1437 compare_nested (const void *a, const void *b)
1439 const guint32 *a_values = (const guint32 *)a;
1440 const guint32 *b_values = (const guint32 *)b;
1442 return a_values [MONO_NESTED_CLASS_NESTED] - b_values [MONO_NESTED_CLASS_NESTED];
1445 static int
1446 compare_genericparam (const void *a, const void *b)
1448 ERROR_DECL (error);
1449 const GenericParamTableEntry **a_entry = (const GenericParamTableEntry **) a;
1450 const GenericParamTableEntry **b_entry = (const GenericParamTableEntry **) b;
1452 if ((*b_entry)->owner == (*a_entry)->owner) {
1453 MonoType *a_type = mono_reflection_type_get_handle ((MonoReflectionType*)(*a_entry)->gparam, error);
1454 mono_error_assert_ok (error);
1455 MonoType *b_type = mono_reflection_type_get_handle ((MonoReflectionType*)(*b_entry)->gparam, error);
1456 mono_error_assert_ok (error);
1457 return
1458 mono_type_get_generic_param_num (a_type) -
1459 mono_type_get_generic_param_num (b_type);
1460 } else
1461 return (*a_entry)->owner - (*b_entry)->owner;
1464 static int
1465 compare_declsecurity_attrs (const void *a, const void *b)
1467 const guint32 *a_values = (const guint32 *)a;
1468 const guint32 *b_values = (const guint32 *)b;
1470 return a_values [MONO_DECL_SECURITY_PARENT] - b_values [MONO_DECL_SECURITY_PARENT];
1473 static int
1474 compare_interface_impl (const void *a, const void *b)
1476 const guint32 *a_values = (const guint32 *)a;
1477 const guint32 *b_values = (const guint32 *)b;
1479 int klass = a_values [MONO_INTERFACEIMPL_CLASS] - b_values [MONO_INTERFACEIMPL_CLASS];
1480 if (klass)
1481 return klass;
1483 return a_values [MONO_INTERFACEIMPL_INTERFACE] - b_values [MONO_INTERFACEIMPL_INTERFACE];
1486 struct StreamDesc {
1487 const char *name;
1488 MonoDynamicStream *stream;
1492 * build_compressed_metadata() fills in the blob of data that represents the
1493 * raw metadata as it will be saved in the PE file. The five streams are output
1494 * and the metadata tables are comnpressed from the guint32 array representation,
1495 * to the compressed on-disk format.
1497 static gboolean
1498 build_compressed_metadata (MonoDynamicImage *assembly, MonoError *error)
1500 MonoDynamicTable *table;
1501 int i;
1502 guint64 valid_mask = 0;
1503 guint64 sorted_mask;
1504 guint32 heapt_size = 0;
1505 guint32 meta_size = 256; /* allow for header and other stuff */
1506 guint32 table_offset;
1507 guint32 ntables = 0;
1508 guint64 *int64val;
1509 guint32 *int32val;
1510 guint16 *int16val;
1511 MonoImage *meta;
1512 unsigned char *p;
1513 struct StreamDesc stream_desc [5];
1515 error_init (error);
1517 mono_qsort (assembly->gen_params->pdata, assembly->gen_params->len, sizeof (gpointer), compare_genericparam);
1518 for (i = 0; i < assembly->gen_params->len; i++) {
1519 GenericParamTableEntry *entry = (GenericParamTableEntry *)g_ptr_array_index (assembly->gen_params, i);
1520 if (!write_generic_param_entry (assembly, entry, error))
1521 return FALSE;
1524 stream_desc [0].name = "#~";
1525 stream_desc [0].stream = &assembly->tstream;
1526 stream_desc [1].name = "#Strings";
1527 stream_desc [1].stream = &assembly->sheap;
1528 stream_desc [2].name = "#US";
1529 stream_desc [2].stream = &assembly->us;
1530 stream_desc [3].name = "#Blob";
1531 stream_desc [3].stream = &assembly->blob;
1532 stream_desc [4].name = "#GUID";
1533 stream_desc [4].stream = &assembly->guid;
1535 /* tables that are sorted */
1536 sorted_mask = ((guint64)1 << MONO_TABLE_CONSTANT) | ((guint64)1 << MONO_TABLE_FIELDMARSHAL)
1537 | ((guint64)1 << MONO_TABLE_METHODSEMANTICS) | ((guint64)1 << MONO_TABLE_CLASSLAYOUT)
1538 | ((guint64)1 << MONO_TABLE_FIELDLAYOUT) | ((guint64)1 << MONO_TABLE_FIELDRVA)
1539 | ((guint64)1 << MONO_TABLE_IMPLMAP) | ((guint64)1 << MONO_TABLE_NESTEDCLASS)
1540 | ((guint64)1 << MONO_TABLE_METHODIMPL) | ((guint64)1 << MONO_TABLE_CUSTOMATTRIBUTE)
1541 | ((guint64)1 << MONO_TABLE_DECLSECURITY) | ((guint64)1 << MONO_TABLE_GENERICPARAM)
1542 | ((guint64)1 << MONO_TABLE_INTERFACEIMPL);
1544 /* Compute table sizes */
1545 /* the MonoImage has already been created in mono_reflection_dynimage_basic_init() */
1546 meta = &assembly->image;
1548 /* sizes should be multiple of 4 */
1549 mono_dynstream_data_align (&assembly->blob);
1550 mono_dynstream_data_align (&assembly->guid);
1551 mono_dynstream_data_align (&assembly->sheap);
1552 mono_dynstream_data_align (&assembly->us);
1554 /* Setup the info used by compute_sizes () */
1555 meta->idx_blob_wide = assembly->blob.index >= 65536 ? 1 : 0;
1556 meta->idx_guid_wide = assembly->guid.index >= 65536 ? 1 : 0;
1557 meta->idx_string_wide = assembly->sheap.index >= 65536 ? 1 : 0;
1559 meta_size += assembly->blob.index;
1560 meta_size += assembly->guid.index;
1561 meta_size += assembly->sheap.index;
1562 meta_size += assembly->us.index;
1564 for (i=0; i < MONO_TABLE_NUM; ++i)
1565 meta->tables [i].rows = assembly->tables [i].rows;
1567 for (i = 0; i < MONO_TABLE_NUM; i++){
1568 if (meta->tables [i].rows == 0)
1569 continue;
1570 valid_mask |= (guint64)1 << i;
1571 ntables ++;
1572 meta->tables [i].row_size = mono_metadata_compute_size (
1573 meta, i, &meta->tables [i].size_bitfield);
1574 heapt_size += meta->tables [i].row_size * meta->tables [i].rows;
1576 heapt_size += 24; /* #~ header size */
1577 heapt_size += ntables * 4;
1578 /* make multiple of 4 */
1579 heapt_size += 3;
1580 heapt_size &= ~3;
1581 meta_size += heapt_size;
1582 meta->raw_metadata = (char *)g_malloc0 (meta_size);
1583 p = (unsigned char*)meta->raw_metadata;
1584 /* the metadata signature */
1585 *p++ = 'B'; *p++ = 'S'; *p++ = 'J'; *p++ = 'B';
1586 /* version numbers and 4 bytes reserved */
1587 int16val = (guint16*)p;
1588 *int16val++ = GUINT16_TO_LE (meta->md_version_major);
1589 *int16val = GUINT16_TO_LE (meta->md_version_minor);
1590 p += 8;
1591 /* version string */
1592 int32val = (guint32*)p;
1593 *int32val = GUINT32_TO_LE ((strlen (meta->version) + 3) & (~3)); /* needs to be multiple of 4 */
1594 p += 4;
1595 memcpy (p, meta->version, strlen (meta->version));
1596 p += GUINT32_FROM_LE (*int32val);
1597 align_pointer (meta->raw_metadata, p);
1598 int16val = (guint16*)p;
1599 *int16val++ = GUINT16_TO_LE (0); /* flags must be 0 */
1600 *int16val = GUINT16_TO_LE (5); /* number of streams */
1601 p += 4;
1604 * write the stream info.
1606 table_offset = (p - (unsigned char*)meta->raw_metadata) + 5 * 8 + 40; /* room needed for stream headers */
1607 table_offset += 3; table_offset &= ~3;
1609 assembly->tstream.index = heapt_size;
1610 for (i = 0; i < 5; ++i) {
1611 int32val = (guint32*)p;
1612 stream_desc [i].stream->offset = table_offset;
1613 *int32val++ = GUINT32_TO_LE (table_offset);
1614 *int32val = GUINT32_TO_LE (stream_desc [i].stream->index);
1615 table_offset += GUINT32_FROM_LE (*int32val);
1616 table_offset += 3; table_offset &= ~3;
1617 p += 8;
1618 strcpy ((char*)p, stream_desc [i].name);
1619 p += strlen (stream_desc [i].name) + 1;
1620 align_pointer (meta->raw_metadata, p);
1623 * now copy the data, the table stream header and contents goes first.
1625 g_assert ((p - (unsigned char*)meta->raw_metadata) < assembly->tstream.offset);
1626 p = (guchar*)meta->raw_metadata + assembly->tstream.offset;
1627 int32val = (guint32*)p;
1628 *int32val = GUINT32_TO_LE (0); /* reserved */
1629 p += 4;
1631 *p++ = 2; /* version */
1632 *p++ = 0;
1634 if (meta->idx_string_wide)
1635 *p |= 0x01;
1636 if (meta->idx_guid_wide)
1637 *p |= 0x02;
1638 if (meta->idx_blob_wide)
1639 *p |= 0x04;
1640 ++p;
1641 *p++ = 1; /* reserved */
1642 int64val = (guint64*)p;
1643 *int64val++ = GUINT64_TO_LE (valid_mask);
1644 *int64val++ = GUINT64_TO_LE (valid_mask & sorted_mask); /* bitvector of sorted tables */
1645 p += 16;
1646 int32val = (guint32*)p;
1647 for (i = 0; i < MONO_TABLE_NUM; i++){
1648 if (meta->tables [i].rows == 0)
1649 continue;
1650 *int32val++ = GUINT32_TO_LE (meta->tables [i].rows);
1652 p = (unsigned char*)int32val;
1654 /* sort the tables that still need sorting */
1655 table = &assembly->tables [MONO_TABLE_CONSTANT];
1656 if (table->rows)
1657 mono_qsort (table->values + MONO_CONSTANT_SIZE, table->rows, sizeof (guint32) * MONO_CONSTANT_SIZE, compare_constants);
1658 table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
1659 if (table->rows)
1660 mono_qsort (table->values + MONO_METHOD_SEMA_SIZE, table->rows, sizeof (guint32) * MONO_METHOD_SEMA_SIZE, compare_semantics);
1661 table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1662 if (table->rows)
1663 mono_qsort (table->values + MONO_CUSTOM_ATTR_SIZE, table->rows, sizeof (guint32) * MONO_CUSTOM_ATTR_SIZE, compare_custom_attrs);
1664 table = &assembly->tables [MONO_TABLE_FIELDMARSHAL];
1665 if (table->rows)
1666 mono_qsort (table->values + MONO_FIELD_MARSHAL_SIZE, table->rows, sizeof (guint32) * MONO_FIELD_MARSHAL_SIZE, compare_field_marshal);
1667 table = &assembly->tables [MONO_TABLE_NESTEDCLASS];
1668 if (table->rows)
1669 mono_qsort (table->values + MONO_NESTED_CLASS_SIZE, table->rows, sizeof (guint32) * MONO_NESTED_CLASS_SIZE, compare_nested);
1670 /* Section 21.11 DeclSecurity in Partition II doesn't specify this to be sorted by MS implementation requires it */
1671 table = &assembly->tables [MONO_TABLE_DECLSECURITY];
1672 if (table->rows)
1673 mono_qsort (table->values + MONO_DECL_SECURITY_SIZE, table->rows, sizeof (guint32) * MONO_DECL_SECURITY_SIZE, compare_declsecurity_attrs);
1674 table = &assembly->tables [MONO_TABLE_INTERFACEIMPL];
1675 if (table->rows)
1676 mono_qsort (table->values + MONO_INTERFACEIMPL_SIZE, table->rows, sizeof (guint32) * MONO_INTERFACEIMPL_SIZE, compare_interface_impl);
1678 /* compress the tables */
1679 for (i = 0; i < MONO_TABLE_NUM; i++){
1680 int row, col;
1681 guint32 *values;
1682 guint32 bitfield = meta->tables [i].size_bitfield;
1683 if (!meta->tables [i].rows)
1684 continue;
1685 if (assembly->tables [i].columns != mono_metadata_table_count (bitfield))
1686 g_error ("col count mismatch in %d: %d %d", i, assembly->tables [i].columns, mono_metadata_table_count (bitfield));
1687 meta->tables [i].base = (char*)p;
1688 for (row = 1; row <= meta->tables [i].rows; ++row) {
1689 values = assembly->tables [i].values + row * assembly->tables [i].columns;
1690 for (col = 0; col < assembly->tables [i].columns; ++col) {
1691 switch (mono_metadata_table_size (bitfield, col)) {
1692 case 1:
1693 *p++ = values [col];
1694 break;
1695 case 2:
1696 *p++ = values [col] & 0xff;
1697 *p++ = (values [col] >> 8) & 0xff;
1698 break;
1699 case 4:
1700 *p++ = values [col] & 0xff;
1701 *p++ = (values [col] >> 8) & 0xff;
1702 *p++ = (values [col] >> 16) & 0xff;
1703 *p++ = (values [col] >> 24) & 0xff;
1704 break;
1705 default:
1706 g_assert_not_reached ();
1710 g_assert ((p - (const unsigned char*)meta->tables [i].base) == (meta->tables [i].rows * meta->tables [i].row_size));
1713 g_assert (assembly->guid.offset + assembly->guid.index < meta_size);
1714 memcpy (meta->raw_metadata + assembly->sheap.offset, assembly->sheap.data, assembly->sheap.index);
1715 memcpy (meta->raw_metadata + assembly->us.offset, assembly->us.data, assembly->us.index);
1716 memcpy (meta->raw_metadata + assembly->blob.offset, assembly->blob.data, assembly->blob.index);
1717 memcpy (meta->raw_metadata + assembly->guid.offset, assembly->guid.data, assembly->guid.index);
1719 assembly->meta_size = assembly->guid.offset + assembly->guid.index;
1721 return TRUE;
1725 * Some tables in metadata need to be sorted according to some criteria, but
1726 * when methods and fields are first created with reflection, they may be assigned a token
1727 * that doesn't correspond to the final token they will get assigned after the sorting.
1728 * ILGenerator.cs keeps a fixup table that maps the position of tokens in the IL code stream
1729 * with the reflection objects that represent them. Once all the tables are set up, the
1730 * reflection objects will contains the correct table index. fixup_method() will fixup the
1731 * tokens for the method with ILGenerator @ilgen.
1733 static void
1734 fixup_method (MonoReflectionILGen *ilgen, gpointer value, MonoDynamicImage *assembly)
1736 guint32 code_idx = GPOINTER_TO_UINT (value);
1737 MonoReflectionILTokenInfo *iltoken;
1738 MonoReflectionTypeBuilder *tb;
1739 MonoReflectionArrayMethod *am;
1740 guint32 i, idx = 0;
1741 unsigned char *target;
1743 for (i = 0; i < ilgen->num_token_fixups; ++i) {
1744 iltoken = (MonoReflectionILTokenInfo *)mono_array_addr_with_size_internal (ilgen->token_fixups, sizeof (MonoReflectionILTokenInfo), i);
1745 target = (guchar*)assembly->code.data + code_idx + iltoken->code_pos;
1746 MonoClass *iltoken_member_class = mono_object_class (iltoken->member);
1747 const char *iltoken_member_class_name = m_class_get_name (iltoken_member_class);
1748 switch (target [3]) {
1749 case MONO_TABLE_FIELD:
1750 if (!strcmp (iltoken_member_class_name, "FieldBuilder")) {
1751 g_assert_not_reached ();
1752 } else if (!strcmp (iltoken_member_class_name, "RuntimeFieldInfo")) {
1753 MonoClassField *f = ((MonoReflectionField*)iltoken->member)->field;
1754 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->field_to_table_idx, f));
1755 } else {
1756 g_assert_not_reached ();
1758 break;
1759 case MONO_TABLE_METHOD:
1760 if (!strcmp (iltoken_member_class_name, "MethodBuilder")) {
1761 g_assert_not_reached ();
1762 } else if (!strcmp (iltoken_member_class_name, "ConstructorBuilder")) {
1763 g_assert_not_reached ();
1764 } else if (!strcmp (iltoken_member_class_name, "RuntimeMethodInfo") ||
1765 !strcmp (iltoken_member_class_name, "RuntimeConstructorInfo")) {
1766 MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
1767 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, m));
1768 } else {
1769 g_assert_not_reached ();
1771 break;
1772 case MONO_TABLE_TYPEDEF:
1773 if (!strcmp (iltoken_member_class_name, "TypeBuilder")) {
1774 g_assert_not_reached ();
1775 } else if (!strcmp (iltoken_member_class_name, "RuntimeType")) {
1776 MonoClass *k = mono_class_from_mono_type_internal (((MonoReflectionType*)iltoken->member)->type);
1777 MonoObject *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 tb = (MonoReflectionTypeBuilder*)obj;
1781 idx = tb->table_idx;
1782 } else {
1783 g_assert_not_reached ();
1785 break;
1786 case MONO_TABLE_TYPEREF:
1787 g_assert (!strcmp (iltoken_member_class_name, "RuntimeType"));
1788 MonoClass *k;
1789 k = mono_class_from_mono_type_internal (((MonoReflectionType*)iltoken->member)->type);
1790 MonoObject *obj;
1791 obj = &mono_class_get_ref_info_raw (k)->type.object; /* FIXME use handles */
1792 g_assert (obj);
1793 g_assert (!strcmp (m_class_get_name (mono_object_class (obj)), "TypeBuilder"));
1794 g_assert (((MonoReflectionTypeBuilder*)obj)->module->dynamic_image != assembly);
1795 continue;
1796 case MONO_TABLE_MEMBERREF:
1797 if (!strcmp (iltoken_member_class_name, "MonoArrayMethod")) {
1798 am = (MonoReflectionArrayMethod*)iltoken->member;
1799 idx = am->table_idx;
1800 } else if (!strcmp (iltoken_member_class_name, "RuntimeMethodInfo") ||
1801 !strcmp (iltoken_member_class_name, "RuntimeConstructorInfo")) {
1802 MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
1803 g_assert (mono_class_is_ginst (m->klass) || mono_class_is_gtd (m->klass));
1804 continue;
1805 } else if (!strcmp (iltoken_member_class_name, "FieldBuilder")) {
1806 g_assert_not_reached ();
1807 continue;
1808 } else if (!strcmp (iltoken_member_class_name, "RuntimeFieldInfo")) {
1809 continue;
1810 } else if (!strcmp (iltoken_member_class_name, "MethodBuilder") ||
1811 !strcmp (iltoken_member_class_name, "ConstructorBuilder")) {
1812 g_assert_not_reached ();
1813 continue;
1814 } else if (!strcmp (iltoken_member_class_name, "FieldOnTypeBuilderInst")) {
1815 g_assert_not_reached ();
1816 continue;
1817 } else if (!strcmp (iltoken_member_class_name, "MethodOnTypeBuilderInst")) {
1818 g_assert_not_reached ();
1819 continue;
1820 } else if (!strcmp (iltoken_member_class_name, "ConstructorOnTypeBuilderInst")) {
1821 g_assert_not_reached ();
1822 continue;
1823 } else {
1824 g_assert_not_reached ();
1826 break;
1827 case MONO_TABLE_METHODSPEC:
1828 if (!strcmp (iltoken_member_class_name, "RuntimeMethodInfo")) {
1829 MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
1830 g_assert (mono_method_signature_internal (m)->generic_param_count);
1831 continue;
1832 } else if (!strcmp (iltoken_member_class_name, "MethodBuilder")) {
1833 g_assert_not_reached ();
1834 continue;
1835 } else if (!strcmp (iltoken_member_class_name, "MethodOnTypeBuilderInst")) {
1836 g_assert_not_reached ();
1837 continue;
1838 } else {
1839 g_assert_not_reached ();
1841 break;
1842 case MONO_TABLE_TYPESPEC:
1843 if (!strcmp (iltoken_member_class_name, "RuntimeType")) {
1844 continue;
1845 } else {
1846 g_assert_not_reached ();
1848 break;
1849 default:
1850 g_error ("got unexpected table 0x%02x in fixup", target [3]);
1852 target [0] = idx & 0xff;
1853 target [1] = (idx >> 8) & 0xff;
1854 target [2] = (idx >> 16) & 0xff;
1859 * fixup_cattrs:
1861 * The CUSTOM_ATTRIBUTE table might contain METHODDEF tokens whose final
1862 * value is not known when the table is emitted.
1864 static void
1865 fixup_cattrs (MonoDynamicImage *assembly)
1867 MonoDynamicTable *table;
1868 guint32 *values;
1869 guint32 type, i, idx, token;
1870 MonoObject *ctor;
1872 table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1874 for (i = 0; i < table->rows; ++i) {
1875 values = table->values + ((i + 1) * MONO_CUSTOM_ATTR_SIZE);
1877 type = values [MONO_CUSTOM_ATTR_TYPE];
1878 if ((type & MONO_CUSTOM_ATTR_TYPE_MASK) == MONO_CUSTOM_ATTR_TYPE_METHODDEF) {
1879 idx = type >> MONO_CUSTOM_ATTR_TYPE_BITS;
1880 token = mono_metadata_make_token (MONO_TABLE_METHOD, idx);
1881 ctor = (MonoObject *)mono_g_hash_table_lookup (assembly->remapped_tokens, GUINT_TO_POINTER (token));
1882 g_assert (ctor);
1884 if (!strcmp (m_class_get_name (mono_object_class (ctor)), "RuntimeConstructorInfo")) {
1885 MonoMethod *m = ((MonoReflectionMethod*)ctor)->method;
1886 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, m));
1887 values [MONO_CUSTOM_ATTR_TYPE] = (idx << MONO_CUSTOM_ATTR_TYPE_BITS) | MONO_CUSTOM_ATTR_TYPE_METHODDEF;
1888 } else if (!strcmp (m_class_get_name (mono_object_class (ctor)), "ConstructorBuilder")) {
1889 MonoMethod *m = ((MonoReflectionCtorBuilder*)ctor)->mhandle;
1890 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, m));
1891 values [MONO_CUSTOM_ATTR_TYPE] = (idx << MONO_CUSTOM_ATTR_TYPE_BITS) | MONO_CUSTOM_ATTR_TYPE_METHODDEF;
1897 static gboolean
1898 assembly_add_resource_manifest (MonoReflectionModuleBuilder *mb, MonoDynamicImage *assembly, MonoReflectionResource *rsrc, guint32 implementation, MonoError *error)
1900 MonoDynamicTable *table;
1901 guint32 *values;
1903 error_init (error);
1905 table = &assembly->tables [MONO_TABLE_MANIFESTRESOURCE];
1906 table->rows++;
1907 alloc_table (table, table->rows);
1908 values = table->values + table->next_idx * MONO_MANIFEST_SIZE;
1909 values [MONO_MANIFEST_OFFSET] = rsrc->offset;
1910 values [MONO_MANIFEST_FLAGS] = rsrc->attrs;
1911 values [MONO_MANIFEST_NAME] = string_heap_insert_mstring (&assembly->sheap, rsrc->name, error);
1912 return_val_if_nok (error, FALSE);
1913 values [MONO_MANIFEST_IMPLEMENTATION] = implementation;
1914 table->next_idx++;
1915 return TRUE;
1918 static gboolean
1919 assembly_add_resource (MonoReflectionModuleBuilder *mb, MonoDynamicImage *assembly, MonoReflectionResource *rsrc, MonoError *error)
1921 MonoDynamicTable *table;
1922 guint32 *values;
1923 char blob_size [6];
1924 guchar hash [20];
1925 char *b = blob_size;
1926 char *name, *sname;
1927 guint32 idx, offset;
1929 error_init (error);
1931 if (rsrc->filename) {
1932 name = mono_string_to_utf8_checked_internal (rsrc->filename, error);
1933 return_val_if_nok (error, FALSE);
1934 sname = g_path_get_basename (name);
1936 table = &assembly->tables [MONO_TABLE_FILE];
1937 table->rows++;
1938 alloc_table (table, table->rows);
1939 values = table->values + table->next_idx * MONO_FILE_SIZE;
1940 values [MONO_FILE_FLAGS] = FILE_CONTAINS_NO_METADATA;
1941 values [MONO_FILE_NAME] = string_heap_insert (&assembly->sheap, sname);
1942 g_free (sname);
1944 mono_sha1_get_digest_from_file (name, hash);
1945 mono_metadata_encode_value (20, b, &b);
1946 values [MONO_FILE_HASH_VALUE] = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
1947 mono_image_add_stream_data (&assembly->blob, (char*)hash, 20);
1948 g_free (name);
1949 idx = table->next_idx++;
1950 rsrc->offset = 0;
1951 idx = MONO_IMPLEMENTATION_FILE | (idx << MONO_IMPLEMENTATION_BITS);
1952 } else {
1953 char sizebuf [4];
1954 char *data;
1955 guint len;
1956 if (rsrc->data) {
1957 data = mono_array_addr_internal (rsrc->data, char, 0);
1958 len = mono_array_length_internal (rsrc->data);
1959 } else {
1960 data = NULL;
1961 len = 0;
1963 offset = len;
1964 sizebuf [0] = offset; sizebuf [1] = offset >> 8;
1965 sizebuf [2] = offset >> 16; sizebuf [3] = offset >> 24;
1966 rsrc->offset = mono_image_add_stream_data (&assembly->resources, sizebuf, 4);
1967 mono_image_add_stream_data (&assembly->resources, data, len);
1969 if (!mb->is_main)
1971 * The entry should be emitted into the MANIFESTRESOURCE table of
1972 * the main module, but that needs to reference the FILE table
1973 * which isn't emitted yet.
1975 return TRUE;
1976 else
1977 idx = 0;
1980 return assembly_add_resource_manifest (mb, assembly, rsrc, idx, error);
1983 static gboolean
1984 set_version_from_string (MonoString *version, guint32 *values, MonoError *error)
1986 gchar *ver, *p, *str;
1987 guint32 i;
1989 error_init (error);
1991 values [MONO_ASSEMBLY_MAJOR_VERSION] = 0;
1992 values [MONO_ASSEMBLY_MINOR_VERSION] = 0;
1993 values [MONO_ASSEMBLY_REV_NUMBER] = 0;
1994 values [MONO_ASSEMBLY_BUILD_NUMBER] = 0;
1995 if (!version)
1996 return TRUE;
1997 ver = str = mono_string_to_utf8_checked_internal (version, error);
1998 return_val_if_nok (error, FALSE);
1999 for (i = 0; i < 4; ++i) {
2000 values [MONO_ASSEMBLY_MAJOR_VERSION + i] = strtol (ver, &p, 10);
2001 switch (*p) {
2002 case '.':
2003 p++;
2004 break;
2005 case '*':
2006 /* handle Revision and Build */
2007 p++;
2008 break;
2010 ver = p;
2012 g_free (str);
2013 return TRUE;
2016 static guint32
2017 load_public_key (MonoArray *pkey, MonoDynamicImage *assembly) {
2018 gsize len;
2019 guint32 token = 0;
2020 char blob_size [6];
2021 char *b = blob_size;
2023 if (!pkey)
2024 return token;
2026 len = mono_array_length_internal (pkey);
2027 mono_metadata_encode_value (len, b, &b);
2028 token = mono_image_add_stream_data (&assembly->blob, blob_size, b - blob_size);
2029 mono_image_add_stream_data (&assembly->blob, mono_array_addr_internal (pkey, char, 0), len);
2031 assembly->public_key = (guint8 *)g_malloc (len);
2032 memcpy (assembly->public_key, mono_array_addr_internal (pkey, char, 0), len);
2033 assembly->public_key_len = len;
2035 /* Special case: check for ECMA key (16 bytes) */
2036 if ((len == MONO_ECMA_KEY_LENGTH) && mono_is_ecma_key (mono_array_addr_internal (pkey, char, 0), len)) {
2037 /* In this case we must reserve 128 bytes (1024 bits) for the signature */
2038 assembly->strong_name_size = MONO_DEFAULT_PUBLIC_KEY_LENGTH;
2039 } else if (len >= MONO_PUBLIC_KEY_HEADER_LENGTH + MONO_MINIMUM_PUBLIC_KEY_LENGTH) {
2040 /* minimum key size (in 2.0) is 384 bits */
2041 assembly->strong_name_size = len - MONO_PUBLIC_KEY_HEADER_LENGTH;
2042 } else {
2043 /* FIXME - verifier */
2044 g_warning ("Invalid public key length: %d bits (total: %d)", (int)MONO_PUBLIC_KEY_BIT_SIZE (len), (int)len);
2045 assembly->strong_name_size = MONO_DEFAULT_PUBLIC_KEY_LENGTH; /* to be safe */
2047 assembly->strong_name = (char *)g_malloc0 (assembly->strong_name_size);
2049 return token;
2052 static gboolean
2053 mono_image_emit_manifest (MonoReflectionModuleBuilder *moduleb, MonoError *error)
2055 MonoDynamicTable *table;
2056 MonoDynamicImage *assembly;
2057 MonoReflectionAssemblyBuilder *assemblyb;
2058 MonoDomain *domain;
2059 guint32 *values;
2060 int i;
2061 guint32 module_index;
2063 error_init (error);
2065 assemblyb = moduleb->assemblyb;
2066 assembly = moduleb->dynamic_image;
2067 domain = mono_object_domain (assemblyb);
2069 /* Emit ASSEMBLY table */
2070 table = &assembly->tables [MONO_TABLE_ASSEMBLY];
2071 alloc_table (table, 1);
2072 values = table->values + MONO_ASSEMBLY_SIZE;
2073 values [MONO_ASSEMBLY_HASH_ALG] = assemblyb->algid? assemblyb->algid: ASSEMBLY_HASH_SHA1;
2074 values [MONO_ASSEMBLY_NAME] = string_heap_insert_mstring (&assembly->sheap, assemblyb->name, error);
2075 return_val_if_nok (error, FALSE);
2076 if (assemblyb->culture) {
2077 values [MONO_ASSEMBLY_CULTURE] = string_heap_insert_mstring (&assembly->sheap, assemblyb->culture, error);
2078 return_val_if_nok (error, FALSE);
2079 } else {
2080 values [MONO_ASSEMBLY_CULTURE] = string_heap_insert (&assembly->sheap, "");
2082 values [MONO_ASSEMBLY_PUBLIC_KEY] = load_public_key (assemblyb->public_key, assembly);
2083 values [MONO_ASSEMBLY_FLAGS] = assemblyb->flags;
2084 if (!set_version_from_string (assemblyb->version, values, error))
2085 return FALSE;
2087 /* Emit FILE + EXPORTED_TYPE table */
2088 module_index = 0;
2089 for (i = 0; i < mono_array_length_internal (assemblyb->modules); ++i) {
2090 int j;
2091 MonoReflectionModuleBuilder *file_module =
2092 mono_array_get_internal (assemblyb->modules, MonoReflectionModuleBuilder*, i);
2093 if (file_module != moduleb) {
2094 if (!mono_image_fill_file_table (domain, (MonoReflectionModule*)file_module, assembly, error))
2095 return FALSE;
2096 module_index ++;
2097 if (file_module->types) {
2098 for (j = 0; j < file_module->num_types; ++j) {
2099 MonoReflectionTypeBuilder *tb = mono_array_get_internal (file_module->types, MonoReflectionTypeBuilder*, j);
2100 mono_image_fill_export_table (domain, tb, module_index, 0, assembly, error);
2101 return_val_if_nok (error, FALSE);
2106 if (assemblyb->loaded_modules) {
2107 for (i = 0; i < mono_array_length_internal (assemblyb->loaded_modules); ++i) {
2108 MonoReflectionModule *file_module =
2109 mono_array_get_internal (assemblyb->loaded_modules, MonoReflectionModule*, i);
2110 if (!mono_image_fill_file_table (domain, file_module, assembly, error))
2111 return FALSE;
2112 module_index ++;
2113 mono_image_fill_export_table_from_module (domain, file_module, module_index, assembly);
2116 if (assemblyb->type_forwarders)
2117 mono_image_fill_export_table_from_type_forwarders (assemblyb, assembly);
2119 /* Emit MANIFESTRESOURCE table */
2120 module_index = 0;
2121 for (i = 0; i < mono_array_length_internal (assemblyb->modules); ++i) {
2122 int j;
2123 MonoReflectionModuleBuilder *file_module =
2124 mono_array_get_internal (assemblyb->modules, MonoReflectionModuleBuilder*, i);
2125 /* The table for the main module is emitted later */
2126 if (file_module != moduleb) {
2127 module_index ++;
2128 if (file_module->resources) {
2129 int len = mono_array_length_internal (file_module->resources);
2130 for (j = 0; j < len; ++j) {
2131 MonoReflectionResource* res = (MonoReflectionResource*)mono_array_addr_internal (file_module->resources, MonoReflectionResource, j);
2132 if (!assembly_add_resource_manifest (file_module, assembly, res, MONO_IMPLEMENTATION_FILE | (module_index << MONO_IMPLEMENTATION_BITS), error))
2133 return FALSE;
2138 return TRUE;
2141 #ifndef DISABLE_REFLECTION_EMIT_SAVE
2144 * Insert into the metadata tables all the info about the TypeBuilder tb.
2145 * Data in the tables is inserted in a predefined order, since some tables need to be sorted.
2147 static gboolean
2148 mono_image_get_type_info (MonoDomain *domain, MonoReflectionTypeBuilder *tb, MonoDynamicImage *assembly, MonoError *error)
2150 MonoDynamicTable *table;
2151 guint *values;
2152 int i, is_object = 0, is_system = 0;
2153 char *n;
2155 error_init (error);
2157 table = &assembly->tables [MONO_TABLE_TYPEDEF];
2158 values = table->values + tb->table_idx * MONO_TYPEDEF_SIZE;
2159 values [MONO_TYPEDEF_FLAGS] = tb->attrs;
2160 n = mono_string_to_utf8_checked_internal (tb->name, error);
2161 return_val_if_nok (error, FALSE);
2162 if (strcmp (n, "Object") == 0)
2163 is_object++;
2164 values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, n);
2165 g_free (n);
2166 n = mono_string_to_utf8_checked_internal (tb->nspace, error);
2167 return_val_if_nok (error, FALSE);
2168 if (strcmp (n, "System") == 0)
2169 is_system++;
2170 values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, n);
2171 g_free (n);
2172 if (tb->parent && !(is_system && is_object) &&
2173 !(tb->attrs & TYPE_ATTRIBUTE_INTERFACE)) { /* interfaces don't have a parent */
2174 MonoType *parent_type = mono_reflection_type_get_handle ((MonoReflectionType*)tb->parent, error);
2175 return_val_if_nok (error, FALSE);
2176 values [MONO_TYPEDEF_EXTENDS] = mono_image_typedef_or_ref (assembly, parent_type);
2177 } else {
2178 values [MONO_TYPEDEF_EXTENDS] = 0;
2180 values [MONO_TYPEDEF_FIELD_LIST] = assembly->tables [MONO_TABLE_FIELD].next_idx;
2181 values [MONO_TYPEDEF_METHOD_LIST] = assembly->tables [MONO_TABLE_METHOD].next_idx;
2184 * if we have explicitlayout or sequentiallayouts, output data in the
2185 * ClassLayout table.
2187 if (((tb->attrs & TYPE_ATTRIBUTE_LAYOUT_MASK) != TYPE_ATTRIBUTE_AUTO_LAYOUT) &&
2188 ((tb->class_size > 0) || (tb->packing_size > 0))) {
2189 table = &assembly->tables [MONO_TABLE_CLASSLAYOUT];
2190 table->rows++;
2191 alloc_table (table, table->rows);
2192 values = table->values + table->rows * MONO_CLASS_LAYOUT_SIZE;
2193 values [MONO_CLASS_LAYOUT_PARENT] = tb->table_idx;
2194 values [MONO_CLASS_LAYOUT_CLASS_SIZE] = tb->class_size;
2195 values [MONO_CLASS_LAYOUT_PACKING_SIZE] = tb->packing_size;
2198 /* handle interfaces */
2199 if (tb->interfaces) {
2200 table = &assembly->tables [MONO_TABLE_INTERFACEIMPL];
2201 i = table->rows;
2202 table->rows += mono_array_length_internal (tb->interfaces);
2203 alloc_table (table, table->rows);
2204 values = table->values + (i + 1) * MONO_INTERFACEIMPL_SIZE;
2205 for (i = 0; i < mono_array_length_internal (tb->interfaces); ++i) {
2206 MonoReflectionType* iface = (MonoReflectionType*) mono_array_get_internal (tb->interfaces, gpointer, i);
2207 MonoType *iface_type = mono_reflection_type_get_handle (iface, error);
2208 return_val_if_nok (error, FALSE);
2209 values [MONO_INTERFACEIMPL_CLASS] = tb->table_idx;
2210 values [MONO_INTERFACEIMPL_INTERFACE] = mono_image_typedef_or_ref (assembly, iface_type);
2211 values += MONO_INTERFACEIMPL_SIZE;
2215 /* handle fields */
2216 if (tb->fields) {
2217 table = &assembly->tables [MONO_TABLE_FIELD];
2218 table->rows += tb->num_fields;
2219 alloc_table (table, table->rows);
2220 for (i = 0; i < tb->num_fields; ++i) {
2221 mono_image_get_field_info (
2222 mono_array_get_internal (tb->fields, MonoReflectionFieldBuilder*, i), assembly, error);
2223 return_val_if_nok (error, FALSE);
2227 /* handle constructors */
2228 if (tb->ctors) {
2229 table = &assembly->tables [MONO_TABLE_METHOD];
2230 table->rows += mono_array_length_internal (tb->ctors);
2231 alloc_table (table, table->rows);
2232 for (i = 0; i < mono_array_length_internal (tb->ctors); ++i) {
2233 if (!mono_image_get_ctor_info (domain,
2234 mono_array_get_internal (tb->ctors, MonoReflectionCtorBuilder*, i),
2235 assembly, error))
2236 return FALSE;
2240 /* handle methods */
2241 if (tb->methods) {
2242 table = &assembly->tables [MONO_TABLE_METHOD];
2243 table->rows += tb->num_methods;
2244 alloc_table (table, table->rows);
2245 for (i = 0; i < tb->num_methods; ++i) {
2246 if (!mono_image_get_method_info (
2247 mono_array_get_internal (tb->methods, MonoReflectionMethodBuilder*, i), assembly, error))
2248 return FALSE;
2252 /* Do the same with properties etc.. */
2253 if (tb->events && mono_array_length_internal (tb->events)) {
2254 table = &assembly->tables [MONO_TABLE_EVENT];
2255 table->rows += mono_array_length_internal (tb->events);
2256 alloc_table (table, table->rows);
2257 table = &assembly->tables [MONO_TABLE_EVENTMAP];
2258 table->rows ++;
2259 alloc_table (table, table->rows);
2260 values = table->values + table->rows * MONO_EVENT_MAP_SIZE;
2261 values [MONO_EVENT_MAP_PARENT] = tb->table_idx;
2262 values [MONO_EVENT_MAP_EVENTLIST] = assembly->tables [MONO_TABLE_EVENT].next_idx;
2263 for (i = 0; i < mono_array_length_internal (tb->events); ++i) {
2264 mono_image_get_event_info (
2265 mono_array_get_internal (tb->events, MonoReflectionEventBuilder*, i), assembly, error);
2266 return_val_if_nok (error, FALSE);
2269 if (tb->properties && mono_array_length_internal (tb->properties)) {
2270 table = &assembly->tables [MONO_TABLE_PROPERTY];
2271 table->rows += mono_array_length_internal (tb->properties);
2272 alloc_table (table, table->rows);
2273 table = &assembly->tables [MONO_TABLE_PROPERTYMAP];
2274 table->rows ++;
2275 alloc_table (table, table->rows);
2276 values = table->values + table->rows * MONO_PROPERTY_MAP_SIZE;
2277 values [MONO_PROPERTY_MAP_PARENT] = tb->table_idx;
2278 values [MONO_PROPERTY_MAP_PROPERTY_LIST] = assembly->tables [MONO_TABLE_PROPERTY].next_idx;
2279 for (i = 0; i < mono_array_length_internal (tb->properties); ++i) {
2280 mono_image_get_property_info (
2281 mono_array_get_internal (tb->properties, MonoReflectionPropertyBuilder*, i), assembly, error);
2282 return_val_if_nok (error, FALSE);
2286 /* handle generic parameters */
2287 if (tb->generic_params) {
2288 table = &assembly->tables [MONO_TABLE_GENERICPARAM];
2289 table->rows += mono_array_length_internal (tb->generic_params);
2290 alloc_table (table, table->rows);
2291 for (i = 0; i < mono_array_length_internal (tb->generic_params); ++i) {
2292 guint32 owner = MONO_TYPEORMETHOD_TYPE | (tb->table_idx << MONO_TYPEORMETHOD_BITS);
2294 mono_image_get_generic_param_info (
2295 mono_array_get_internal (tb->generic_params, MonoReflectionGenericParam*, i), owner, assembly);
2299 mono_image_add_decl_security (assembly,
2300 mono_metadata_make_token (MONO_TABLE_TYPEDEF, tb->table_idx), tb->permissions);
2302 if (tb->subtypes) {
2303 MonoDynamicTable *ntable;
2305 ntable = &assembly->tables [MONO_TABLE_NESTEDCLASS];
2306 ntable->rows += mono_array_length_internal (tb->subtypes);
2307 alloc_table (ntable, ntable->rows);
2308 values = ntable->values + ntable->next_idx * MONO_NESTED_CLASS_SIZE;
2310 for (i = 0; i < mono_array_length_internal (tb->subtypes); ++i) {
2311 MonoReflectionTypeBuilder *subtype = mono_array_get_internal (tb->subtypes, MonoReflectionTypeBuilder*, i);
2313 values [MONO_NESTED_CLASS_NESTED] = subtype->table_idx;
2314 values [MONO_NESTED_CLASS_ENCLOSING] = tb->table_idx;
2315 /*g_print ("nesting %s (%d) in %s (%d) (rows %d/%d)\n",
2316 mono_string_to_utf8 (subtype->name), subtype->table_idx,
2317 mono_string_to_utf8 (tb->name), tb->table_idx,
2318 ntable->next_idx, ntable->rows);*/
2319 values += MONO_NESTED_CLASS_SIZE;
2320 ntable->next_idx++;
2324 return TRUE;
2329 * mono_image_build_metadata() will fill the info in all the needed metadata tables
2330 * for the modulebuilder @moduleb.
2331 * At the end of the process, method and field tokens are fixed up and the
2332 * on-disk compressed metadata representation is created.
2333 * Return TRUE on success, or FALSE on failure and sets @error
2335 gboolean
2336 mono_image_build_metadata (MonoReflectionModuleBuilder *moduleb, MonoError *error)
2338 MonoDynamicTable *table;
2339 MonoDynamicImage *assembly;
2340 MonoReflectionAssemblyBuilder *assemblyb;
2341 MonoDomain *domain;
2342 MonoPtrArray types;
2343 guint32 *values;
2344 int i, j;
2346 error_init (error);
2348 assemblyb = moduleb->assemblyb;
2349 assembly = moduleb->dynamic_image;
2350 domain = mono_object_domain (assemblyb);
2352 if (assembly->text_rva)
2353 return TRUE;
2355 assembly->text_rva = START_TEXT_RVA;
2357 if (moduleb->is_main) {
2358 mono_image_emit_manifest (moduleb, error);
2359 return_val_if_nok (error, FALSE);
2362 table = &assembly->tables [MONO_TABLE_TYPEDEF];
2363 table->rows = 1; /* .<Module> */
2364 table->next_idx++;
2365 alloc_table (table, table->rows);
2367 * Set the first entry.
2369 values = table->values + table->columns;
2370 values [MONO_TYPEDEF_FLAGS] = 0;
2371 values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, "<Module>") ;
2372 values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, "") ;
2373 values [MONO_TYPEDEF_EXTENDS] = 0;
2374 values [MONO_TYPEDEF_FIELD_LIST] = 1;
2375 values [MONO_TYPEDEF_METHOD_LIST] = 1;
2378 * handle global methods
2379 * FIXME: test what to do when global methods are defined in multiple modules.
2381 if (moduleb->global_methods) {
2382 table = &assembly->tables [MONO_TABLE_METHOD];
2383 table->rows += mono_array_length_internal (moduleb->global_methods);
2384 alloc_table (table, table->rows);
2385 for (i = 0; i < mono_array_length_internal (moduleb->global_methods); ++i) {
2386 if (!mono_image_get_method_info (
2387 mono_array_get_internal (moduleb->global_methods, MonoReflectionMethodBuilder*, i), assembly, error))
2388 goto leave;
2391 if (moduleb->global_fields) {
2392 table = &assembly->tables [MONO_TABLE_FIELD];
2393 table->rows += mono_array_length_internal (moduleb->global_fields);
2394 alloc_table (table, table->rows);
2395 for (i = 0; i < mono_array_length_internal (moduleb->global_fields); ++i) {
2396 mono_image_get_field_info (
2397 mono_array_get_internal (moduleb->global_fields, MonoReflectionFieldBuilder*, i), assembly,
2398 error);
2399 goto_if_nok (error, leave);
2403 table = &assembly->tables [MONO_TABLE_MODULE];
2404 alloc_table (table, 1);
2405 mono_image_fill_module_table (domain, moduleb, assembly, error);
2406 goto_if_nok (error, leave);
2408 /* Collect all types into a list sorted by their table_idx */
2409 mono_ptr_array_init (types, moduleb->num_types, MONO_ROOT_SOURCE_REFLECTION, NULL, "Reflection Dynamic Image Type List");
2411 if (moduleb->types)
2412 for (i = 0; i < moduleb->num_types; ++i) {
2413 MonoReflectionTypeBuilder *type = mono_array_get_internal (moduleb->types, MonoReflectionTypeBuilder*, i);
2414 collect_types (&types, type);
2417 mono_ptr_array_sort (types, (int (*)(const void *, const void *))compare_types_by_table_idx);
2418 table = &assembly->tables [MONO_TABLE_TYPEDEF];
2419 table->rows += mono_ptr_array_size (types);
2420 alloc_table (table, table->rows);
2423 * Emit type names + namespaces at one place inside the string heap,
2424 * so load_class_names () needs to touch fewer pages.
2426 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2427 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2428 string_heap_insert_mstring (&assembly->sheap, tb->nspace, error);
2429 goto_if_nok (error, leave_types);
2431 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2432 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2433 string_heap_insert_mstring (&assembly->sheap, tb->name, error);
2434 goto_if_nok (error, leave_types);
2437 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2438 MonoReflectionTypeBuilder *type = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2439 if (!mono_image_get_type_info (domain, type, assembly, error))
2440 goto leave_types;
2444 * table->rows is already set above and in mono_image_fill_module_table.
2446 /* add all the custom attributes at the end, once all the indexes are stable */
2447 if (!mono_image_add_cattrs (assembly, 1, MONO_CUSTOM_ATTR_ASSEMBLY, assemblyb->cattrs, error))
2448 goto leave_types;
2450 /* CAS assembly permissions */
2451 if (assemblyb->permissions_minimum)
2452 mono_image_add_decl_security (assembly, mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1), assemblyb->permissions_minimum);
2453 if (assemblyb->permissions_optional)
2454 mono_image_add_decl_security (assembly, mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1), assemblyb->permissions_optional);
2455 if (assemblyb->permissions_refused)
2456 mono_image_add_decl_security (assembly, mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1), assemblyb->permissions_refused);
2458 if (!module_add_cattrs (assembly, moduleb, error))
2459 goto leave_types;
2461 /* fixup tokens */
2462 mono_g_hash_table_foreach (assembly->token_fixups, (GHFunc)fixup_method, assembly);
2464 /* Create the MethodImpl table. We do this after emitting all methods so we already know
2465 * the final tokens and don't need another fixup pass. */
2467 if (moduleb->global_methods) {
2468 for (i = 0; i < mono_array_length_internal (moduleb->global_methods); ++i) {
2469 MonoReflectionMethodBuilder *mb = mono_array_get_internal (
2470 moduleb->global_methods, MonoReflectionMethodBuilder*, i);
2471 if (!mono_image_add_methodimpl (assembly, mb, error))
2472 goto leave_types;
2476 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2477 MonoReflectionTypeBuilder *type = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2478 if (type->methods) {
2479 for (j = 0; j < type->num_methods; ++j) {
2480 MonoReflectionMethodBuilder *mb = mono_array_get_internal (
2481 type->methods, MonoReflectionMethodBuilder*, j);
2483 if (!mono_image_add_methodimpl (assembly, mb, error))
2484 goto leave_types;
2489 fixup_cattrs (assembly);
2491 leave_types:
2492 mono_ptr_array_destroy (types);
2493 leave:
2495 return is_ok (error);
2498 #else /* DISABLE_REFLECTION_EMIT_SAVE */
2500 gboolean
2501 mono_image_build_metadata (MonoReflectionModuleBuilder *moduleb, MonoError *error)
2503 g_error ("This mono runtime was configured with --enable-minimal=reflection_emit_save, so saving of dynamic assemblies is not supported.");
2506 #endif /* DISABLE_REFLECTION_EMIT_SAVE */
2508 #ifndef DISABLE_REFLECTION_EMIT_SAVE
2510 static int
2511 calc_section_size (MonoDynamicImage *assembly)
2513 int nsections = 0;
2515 /* alignment constraints */
2516 mono_image_add_stream_zero (&assembly->code, 4 - (assembly->code.index % 4));
2517 g_assert ((assembly->code.index % 4) == 0);
2518 assembly->meta_size += 3;
2519 assembly->meta_size &= ~3;
2520 mono_image_add_stream_zero (&assembly->resources, 4 - (assembly->resources.index % 4));
2521 g_assert ((assembly->resources.index % 4) == 0);
2523 assembly->sections [MONO_SECTION_TEXT].size = assembly->meta_size + assembly->code.index + assembly->resources.index + assembly->strong_name_size;
2524 assembly->sections [MONO_SECTION_TEXT].attrs = SECT_FLAGS_HAS_CODE | SECT_FLAGS_MEM_EXECUTE | SECT_FLAGS_MEM_READ;
2525 nsections++;
2527 if (assembly->win32_res) {
2528 guint32 res_size = (assembly->win32_res_size + 3) & ~3;
2530 assembly->sections [MONO_SECTION_RSRC].size = res_size;
2531 assembly->sections [MONO_SECTION_RSRC].attrs = SECT_FLAGS_HAS_INITIALIZED_DATA | SECT_FLAGS_MEM_READ;
2532 nsections++;
2535 assembly->sections [MONO_SECTION_RELOC].size = 12;
2536 assembly->sections [MONO_SECTION_RELOC].attrs = SECT_FLAGS_MEM_READ | SECT_FLAGS_MEM_DISCARDABLE | SECT_FLAGS_HAS_INITIALIZED_DATA;
2537 nsections++;
2539 return nsections;
2542 typedef struct {
2543 guint32 id;
2544 guint32 offset;
2545 GSList *children;
2546 MonoReflectionWin32Resource *win32_res; /* Only for leaf nodes */
2547 } ResTreeNode;
2549 static int
2550 resource_tree_compare_by_id (gconstpointer a, gconstpointer b)
2552 ResTreeNode *t1 = (ResTreeNode*)a;
2553 ResTreeNode *t2 = (ResTreeNode*)b;
2555 return t1->id - t2->id;
2559 * resource_tree_create:
2561 * Organize the resources into a resource tree.
2563 static ResTreeNode *
2564 resource_tree_create (MonoArray *win32_resources)
2566 ResTreeNode *tree, *res_node, *type_node, *lang_node;
2567 GSList *l;
2568 int i;
2570 tree = g_new0 (ResTreeNode, 1);
2572 for (i = 0; i < mono_array_length_internal (win32_resources); ++i) {
2573 MonoReflectionWin32Resource *win32_res =
2574 (MonoReflectionWin32Resource*)mono_array_addr_internal (win32_resources, MonoReflectionWin32Resource, i);
2576 /* Create node */
2578 /* FIXME: BUG: this stores managed references in unmanaged memory */
2579 lang_node = g_new0 (ResTreeNode, 1);
2580 lang_node->id = win32_res->lang_id;
2581 lang_node->win32_res = win32_res;
2583 /* Create type node if neccesary */
2584 type_node = NULL;
2585 for (l = tree->children; l; l = l->next)
2586 if (((ResTreeNode*)(l->data))->id == win32_res->res_type) {
2587 type_node = (ResTreeNode*)l->data;
2588 break;
2591 if (!type_node) {
2592 type_node = g_new0 (ResTreeNode, 1);
2593 type_node->id = win32_res->res_type;
2596 * The resource types have to be sorted otherwise
2597 * Windows Explorer can't display the version information.
2599 tree->children = g_slist_insert_sorted (tree->children,
2600 type_node, resource_tree_compare_by_id);
2603 /* Create res node if neccesary */
2604 res_node = NULL;
2605 for (l = type_node->children; l; l = l->next)
2606 if (((ResTreeNode*)(l->data))->id == win32_res->res_id) {
2607 res_node = (ResTreeNode*)l->data;
2608 break;
2611 if (!res_node) {
2612 res_node = g_new0 (ResTreeNode, 1);
2613 res_node->id = win32_res->res_id;
2614 type_node->children = g_slist_append (type_node->children, res_node);
2617 res_node->children = g_slist_append (res_node->children, lang_node);
2620 return tree;
2624 * resource_tree_encode:
2626 * Encode the resource tree into the format used in the PE file.
2628 static void
2629 resource_tree_encode (ResTreeNode *node, char *begin, char *p, char **endbuf)
2631 char *entries;
2632 MonoPEResourceDir dir;
2633 MonoPEResourceDirEntry dir_entry;
2634 MonoPEResourceDataEntry data_entry;
2635 GSList *l;
2636 guint32 res_id_entries;
2639 * For the format of the resource directory, see the article
2640 * "An In-Depth Look into the Win32 Portable Executable File Format" by
2641 * Matt Pietrek
2644 memset (&dir, 0, sizeof (dir));
2645 memset (&dir_entry, 0, sizeof (dir_entry));
2646 memset (&data_entry, 0, sizeof (data_entry));
2648 g_assert (sizeof (dir) == 16);
2649 g_assert (sizeof (dir_entry) == 8);
2650 g_assert (sizeof (data_entry) == 16);
2652 node->offset = p - begin;
2654 /* IMAGE_RESOURCE_DIRECTORY */
2655 res_id_entries = g_slist_length (node->children);
2656 dir.res_id_entries = GUINT16_TO_LE (res_id_entries);
2658 memcpy (p, &dir, sizeof (dir));
2659 p += sizeof (dir);
2661 /* Reserve space for entries */
2662 entries = p;
2663 p += sizeof (dir_entry) * res_id_entries;
2665 /* Write children */
2666 for (l = node->children; l; l = l->next) {
2667 ResTreeNode *child = (ResTreeNode*)l->data;
2669 if (child->win32_res) {
2670 guint32 size;
2672 child->offset = p - begin;
2674 /* IMAGE_RESOURCE_DATA_ENTRY */
2675 data_entry.rde_data_offset = GUINT32_TO_LE (p - begin + sizeof (data_entry));
2676 size = mono_array_length_internal (child->win32_res->res_data);
2677 data_entry.rde_size = GUINT32_TO_LE (size);
2679 memcpy (p, &data_entry, sizeof (data_entry));
2680 p += sizeof (data_entry);
2682 memcpy (p, mono_array_addr_internal (child->win32_res->res_data, char, 0), size);
2683 p += size;
2684 } else {
2685 resource_tree_encode (child, begin, p, &p);
2689 /* IMAGE_RESOURCE_ENTRY */
2690 for (l = node->children; l; l = l->next) {
2691 ResTreeNode *child = (ResTreeNode*)l->data;
2693 MONO_PE_RES_DIR_ENTRY_SET_NAME (dir_entry, FALSE, child->id);
2694 MONO_PE_RES_DIR_ENTRY_SET_DIR (dir_entry, !child->win32_res, child->offset);
2696 memcpy (entries, &dir_entry, sizeof (dir_entry));
2697 entries += sizeof (dir_entry);
2700 *endbuf = p;
2703 static void
2704 resource_tree_free (ResTreeNode * node)
2706 GSList * list;
2707 for (list = node->children; list; list = list->next)
2708 resource_tree_free ((ResTreeNode*)list->data);
2709 g_slist_free(node->children);
2710 g_free (node);
2713 static void
2714 assembly_add_win32_resources (MonoDynamicImage *assembly, MonoReflectionAssemblyBuilder *assemblyb)
2716 char *buf;
2717 char *p;
2718 guint32 size, i;
2719 MonoReflectionWin32Resource *win32_res;
2720 ResTreeNode *tree;
2722 if (!assemblyb->win32_resources)
2723 return;
2726 * Resources are stored in a three level tree inside the PE file.
2727 * - level one contains a node for each type of resource
2728 * - level two contains a node for each resource
2729 * - level three contains a node for each instance of a resource for a
2730 * specific language.
2733 tree = resource_tree_create (assemblyb->win32_resources);
2735 /* Estimate the size of the encoded tree */
2736 size = 0;
2737 for (i = 0; i < mono_array_length_internal (assemblyb->win32_resources); ++i) {
2738 win32_res = (MonoReflectionWin32Resource*)mono_array_addr_internal (assemblyb->win32_resources, MonoReflectionWin32Resource, i);
2739 size += mono_array_length_internal (win32_res->res_data);
2741 /* Directory structure */
2742 size += mono_array_length_internal (assemblyb->win32_resources) * 256;
2743 p = buf = (char *)g_malloc (size);
2745 resource_tree_encode (tree, p, p, &p);
2747 g_assert (p - buf <= size);
2749 assembly->win32_res = (char *)g_malloc (p - buf);
2750 assembly->win32_res_size = p - buf;
2751 memcpy (assembly->win32_res, buf, p - buf);
2753 g_free (buf);
2754 resource_tree_free (tree);
2757 static void
2758 fixup_resource_directory (char *res_section, char *p, guint32 rva)
2760 MonoPEResourceDir *dir = (MonoPEResourceDir*)p;
2761 int i;
2763 p += sizeof (MonoPEResourceDir);
2764 for (i = 0; i < GUINT16_FROM_LE (dir->res_named_entries) + GUINT16_FROM_LE (dir->res_id_entries); ++i) {
2765 MonoPEResourceDirEntry *dir_entry = (MonoPEResourceDirEntry*)p;
2766 char *child = res_section + MONO_PE_RES_DIR_ENTRY_DIR_OFFSET (*dir_entry);
2767 if (MONO_PE_RES_DIR_ENTRY_IS_DIR (*dir_entry)) {
2768 fixup_resource_directory (res_section, child, rva);
2769 } else {
2770 MonoPEResourceDataEntry *data_entry = (MonoPEResourceDataEntry*)child;
2771 data_entry->rde_data_offset = GUINT32_TO_LE (GUINT32_FROM_LE (data_entry->rde_data_offset) + rva);
2774 p += sizeof (MonoPEResourceDirEntry);
2778 static void
2779 checked_write_file (HANDLE f, gconstpointer buffer, guint32 numbytes)
2781 guint32 dummy;
2782 gint32 win32error = 0;
2783 if (!mono_w32file_write (f, buffer, numbytes, &dummy, &win32error))
2784 g_error ("mono_w32file_write returned %d\n", win32error);
2788 * mono_image_create_pefile:
2789 * @mb: a module builder object
2791 * This function creates the PE-COFF header, the image sections, the CLI header * etc. all the data is written in
2792 * assembly->pefile where it can be easily retrieved later in chunks.
2794 gboolean
2795 mono_image_create_pefile (MonoReflectionModuleBuilder *mb, HANDLE file, MonoError *error)
2797 MonoMSDOSHeader *msdos;
2798 MonoDotNetHeader *header;
2799 MonoSectionTable *section;
2800 MonoCLIHeader *cli_header;
2801 guint32 size, image_size, virtual_base, text_offset;
2802 guint32 header_start, section_start, file_offset, virtual_offset;
2803 MonoDynamicImage *assembly;
2804 MonoReflectionAssemblyBuilder *assemblyb;
2805 MonoDynamicStream pefile_stream = {0};
2806 MonoDynamicStream *pefile = &pefile_stream;
2807 int i, nsections;
2808 guint32 *rva, value;
2809 guchar *p;
2810 static const unsigned char msheader[] = {
2811 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
2812 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2813 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2814 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
2815 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68,
2816 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f,
2817 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,
2818 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
2821 error_init (error);
2823 assemblyb = mb->assemblyb;
2825 mono_reflection_dynimage_basic_init (assemblyb, error);
2826 return_val_if_nok (error, FALSE);
2827 assembly = mb->dynamic_image;
2829 assembly->pe_kind = assemblyb->pe_kind;
2830 assembly->machine = assemblyb->machine;
2831 ((MonoDynamicImage*)assemblyb->dynamic_assembly->assembly.image)->pe_kind = assemblyb->pe_kind;
2832 ((MonoDynamicImage*)assemblyb->dynamic_assembly->assembly.image)->machine = assemblyb->machine;
2834 if (!mono_image_build_metadata (mb, error))
2835 return FALSE;
2838 if (mb->is_main && assemblyb->resources) {
2839 int len = mono_array_length_internal (assemblyb->resources);
2840 for (i = 0; i < len; ++i) {
2841 if (!assembly_add_resource (mb, assembly, (MonoReflectionResource*)mono_array_addr_internal (assemblyb->resources, MonoReflectionResource, i), error))
2842 return FALSE;
2846 if (mb->resources) {
2847 int len = mono_array_length_internal (mb->resources);
2848 for (i = 0; i < len; ++i) {
2849 if (!assembly_add_resource (mb, assembly, (MonoReflectionResource*)mono_array_addr_internal (mb->resources, MonoReflectionResource, i), error))
2850 return FALSE;
2854 if (!build_compressed_metadata (assembly, error))
2855 return FALSE;
2857 if (mb->is_main)
2858 assembly_add_win32_resources (assembly, assemblyb);
2860 nsections = calc_section_size (assembly);
2862 /* The DOS header and stub */
2863 g_assert (sizeof (MonoMSDOSHeader) == sizeof (msheader));
2864 mono_image_add_stream_data (pefile, (char*)msheader, sizeof (msheader));
2866 /* the dotnet header */
2867 header_start = mono_image_add_stream_zero (pefile, sizeof (MonoDotNetHeader));
2869 /* the section tables */
2870 section_start = mono_image_add_stream_zero (pefile, sizeof (MonoSectionTable) * nsections);
2872 file_offset = section_start + sizeof (MonoSectionTable) * nsections;
2873 virtual_offset = VIRT_ALIGN;
2874 image_size = 0;
2876 for (i = 0; i < MONO_SECTION_MAX; ++i) {
2877 if (!assembly->sections [i].size)
2878 continue;
2879 /* align offsets */
2880 file_offset += FILE_ALIGN - 1;
2881 file_offset &= ~(FILE_ALIGN - 1);
2882 virtual_offset += VIRT_ALIGN - 1;
2883 virtual_offset &= ~(VIRT_ALIGN - 1);
2885 assembly->sections [i].offset = file_offset;
2886 assembly->sections [i].rva = virtual_offset;
2888 file_offset += assembly->sections [i].size;
2889 virtual_offset += assembly->sections [i].size;
2890 image_size += (assembly->sections [i].size + VIRT_ALIGN - 1) & ~(VIRT_ALIGN - 1);
2893 file_offset += FILE_ALIGN - 1;
2894 file_offset &= ~(FILE_ALIGN - 1);
2896 image_size += section_start + sizeof (MonoSectionTable) * nsections;
2898 /* back-patch info */
2899 msdos = (MonoMSDOSHeader*)pefile->data;
2900 msdos->pe_offset = GUINT32_FROM_LE (sizeof (MonoMSDOSHeader));
2902 header = (MonoDotNetHeader*)(pefile->data + header_start);
2903 header->pesig [0] = 'P';
2904 header->pesig [1] = 'E';
2906 header->coff.coff_machine = GUINT16_FROM_LE (assemblyb->machine);
2907 header->coff.coff_sections = GUINT16_FROM_LE (nsections);
2908 header->coff.coff_time = GUINT32_FROM_LE (time (NULL));
2909 header->coff.coff_opt_header_size = GUINT16_FROM_LE (sizeof (MonoDotNetHeader) - sizeof (MonoCOFFHeader) - 4);
2910 if (assemblyb->pekind == 1) {
2911 /* it's a dll */
2912 header->coff.coff_attributes = GUINT16_FROM_LE (0x210e);
2913 } else {
2914 /* it's an exe */
2915 header->coff.coff_attributes = GUINT16_FROM_LE (0x010e);
2918 virtual_base = 0x400000; /* FIXME: 0x10000000 if a DLL */
2920 header->pe.pe_magic = GUINT16_FROM_LE (0x10B);
2921 header->pe.pe_major = 6;
2922 header->pe.pe_minor = 0;
2923 size = assembly->sections [MONO_SECTION_TEXT].size;
2924 size += FILE_ALIGN - 1;
2925 size &= ~(FILE_ALIGN - 1);
2926 header->pe.pe_code_size = GUINT32_FROM_LE(size);
2927 size = assembly->sections [MONO_SECTION_RSRC].size;
2928 size += FILE_ALIGN - 1;
2929 size &= ~(FILE_ALIGN - 1);
2930 header->pe.pe_data_size = GUINT32_FROM_LE(size);
2931 g_assert (START_TEXT_RVA == assembly->sections [MONO_SECTION_TEXT].rva);
2932 header->pe.pe_rva_code_base = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_TEXT].rva);
2933 header->pe.pe_rva_data_base = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].rva);
2934 /* pe_rva_entry_point always at the beginning of the text section */
2935 header->pe.pe_rva_entry_point = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_TEXT].rva);
2937 header->nt.pe_image_base = GUINT32_FROM_LE (virtual_base);
2938 header->nt.pe_section_align = GUINT32_FROM_LE (VIRT_ALIGN);
2939 header->nt.pe_file_alignment = GUINT32_FROM_LE (FILE_ALIGN);
2940 header->nt.pe_os_major = GUINT16_FROM_LE (4);
2941 header->nt.pe_os_minor = GUINT16_FROM_LE (0);
2942 header->nt.pe_subsys_major = GUINT16_FROM_LE (4);
2943 size = section_start;
2944 size += FILE_ALIGN - 1;
2945 size &= ~(FILE_ALIGN - 1);
2946 header->nt.pe_header_size = GUINT32_FROM_LE (size);
2947 size = image_size;
2948 size += VIRT_ALIGN - 1;
2949 size &= ~(VIRT_ALIGN - 1);
2950 header->nt.pe_image_size = GUINT32_FROM_LE (size);
2953 // Translate the PEFileKind value to the value expected by the Windows loader
2956 short kind;
2959 // PEFileKinds.Dll == 1
2960 // PEFileKinds.ConsoleApplication == 2
2961 // PEFileKinds.WindowApplication == 3
2963 // need to get:
2964 // IMAGE_SUBSYSTEM_WINDOWS_GUI 2 // Image runs in the Windows GUI subsystem.
2965 // IMAGE_SUBSYSTEM_WINDOWS_CUI 3 // Image runs in the Windows character subsystem.
2967 if (assemblyb->pekind == 3)
2968 kind = 2;
2969 else
2970 kind = 3;
2972 header->nt.pe_subsys_required = GUINT16_FROM_LE (kind);
2974 header->nt.pe_stack_reserve = GUINT32_FROM_LE (0x00100000);
2975 header->nt.pe_stack_commit = GUINT32_FROM_LE (0x00001000);
2976 header->nt.pe_heap_reserve = GUINT32_FROM_LE (0x00100000);
2977 header->nt.pe_heap_commit = GUINT32_FROM_LE (0x00001000);
2978 header->nt.pe_loader_flags = GUINT32_FROM_LE (0);
2979 header->nt.pe_data_dir_count = GUINT32_FROM_LE (16);
2981 /* fill data directory entries */
2983 header->datadir.pe_resource_table.size = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].size);
2984 header->datadir.pe_resource_table.rva = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].rva);
2986 header->datadir.pe_reloc_table.size = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RELOC].size);
2987 header->datadir.pe_reloc_table.rva = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RELOC].rva);
2989 header->datadir.pe_cli_header.size = GUINT32_FROM_LE (72);
2990 header->datadir.pe_cli_header.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->cli_header_offset);
2991 header->datadir.pe_iat.size = GUINT32_FROM_LE (8);
2992 header->datadir.pe_iat.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->iat_offset);
2993 /* patch entrypoint name */
2994 if (assemblyb->pekind == 1)
2995 memcpy (assembly->code.data + assembly->imp_names_offset + 2, "_CorDllMain", 12);
2996 else
2997 memcpy (assembly->code.data + assembly->imp_names_offset + 2, "_CorExeMain", 12);
2998 /* patch imported function RVA name */
2999 rva = (guint32*)(assembly->code.data + assembly->iat_offset);
3000 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->imp_names_offset);
3002 /* the import table */
3003 header->datadir.pe_import_table.size = GUINT32_FROM_LE (79); /* FIXME: magic number? */
3004 header->datadir.pe_import_table.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->idt_offset);
3005 /* patch imported dll RVA name and other entries in the dir */
3006 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, name_rva));
3007 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->imp_names_offset + 14); /* 14 is hint+strlen+1 of func name */
3008 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, import_address_table_rva));
3009 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->iat_offset);
3010 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, import_lookup_table));
3011 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->ilt_offset);
3013 p = (guchar*)(assembly->code.data + assembly->ilt_offset);
3014 value = (assembly->text_rva + assembly->imp_names_offset);
3015 *p++ = (value) & 0xff;
3016 *p++ = (value >> 8) & (0xff);
3017 *p++ = (value >> 16) & (0xff);
3018 *p++ = (value >> 24) & (0xff);
3020 /* the CLI header info */
3021 cli_header = (MonoCLIHeader*)(assembly->code.data + assembly->cli_header_offset);
3022 cli_header->ch_size = GUINT32_FROM_LE (72);
3023 cli_header->ch_runtime_major = GUINT16_FROM_LE (2);
3024 cli_header->ch_runtime_minor = GUINT16_FROM_LE (5);
3025 cli_header->ch_flags = GUINT32_FROM_LE (assemblyb->pe_kind);
3026 if (assemblyb->entry_point) {
3027 guint32 table_idx = 0;
3028 if (!strcmp (m_class_get_name (mono_object_class (&assemblyb->entry_point->object)), "MethodBuilder")) {
3029 MonoReflectionMethodBuilder *methodb = (MonoReflectionMethodBuilder*)assemblyb->entry_point;
3030 table_idx = methodb->table_idx;
3031 } else {
3032 table_idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, assemblyb->entry_point->method));
3034 cli_header->ch_entry_point = GUINT32_FROM_LE (table_idx | MONO_TOKEN_METHOD_DEF);
3035 } else {
3036 cli_header->ch_entry_point = GUINT32_FROM_LE (0);
3038 /* The embedded managed resources */
3039 text_offset = assembly->text_rva + assembly->code.index;
3040 cli_header->ch_resources.rva = GUINT32_FROM_LE (text_offset);
3041 cli_header->ch_resources.size = GUINT32_FROM_LE (assembly->resources.index);
3042 text_offset += assembly->resources.index;
3043 cli_header->ch_metadata.rva = GUINT32_FROM_LE (text_offset);
3044 cli_header->ch_metadata.size = GUINT32_FROM_LE (assembly->meta_size);
3045 text_offset += assembly->meta_size;
3046 if (assembly->strong_name_size) {
3047 cli_header->ch_strong_name.rva = GUINT32_FROM_LE (text_offset);
3048 cli_header->ch_strong_name.size = GUINT32_FROM_LE (assembly->strong_name_size);
3049 text_offset += assembly->strong_name_size;
3052 /* write the section tables and section content */
3053 section = (MonoSectionTable*)(pefile->data + section_start);
3054 for (i = 0; i < MONO_SECTION_MAX; ++i) {
3055 static const char section_names [][7] = {
3056 ".text", ".rsrc", ".reloc"
3058 if (!assembly->sections [i].size)
3059 continue;
3060 strcpy (section->st_name, section_names [i]);
3061 /*g_print ("output section %s (%d), size: %d\n", section->st_name, i, assembly->sections [i].size);*/
3062 section->st_virtual_address = GUINT32_FROM_LE (assembly->sections [i].rva);
3063 section->st_virtual_size = GUINT32_FROM_LE (assembly->sections [i].size);
3064 section->st_raw_data_size = GUINT32_FROM_LE (GUINT32_TO_LE (section->st_virtual_size) + (FILE_ALIGN - 1));
3065 section->st_raw_data_size &= GUINT32_FROM_LE (~(FILE_ALIGN - 1));
3066 section->st_raw_data_ptr = GUINT32_FROM_LE (assembly->sections [i].offset);
3067 section->st_flags = GUINT32_FROM_LE (assembly->sections [i].attrs);
3068 section ++;
3071 checked_write_file (file, pefile->data, pefile->index);
3073 mono_dynamic_stream_reset (pefile);
3075 for (i = 0; i < MONO_SECTION_MAX; ++i) {
3076 if (!assembly->sections [i].size)
3077 continue;
3079 if (mono_w32file_seek (file, assembly->sections [i].offset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
3080 g_error ("mono_w32file_seek returned %d\n", mono_w32error_get_last ());
3082 switch (i) {
3083 case MONO_SECTION_TEXT:
3084 /* patch entry point */
3085 p = (guchar*)(assembly->code.data + 2);
3086 value = (virtual_base + assembly->text_rva + assembly->iat_offset);
3087 *p++ = (value) & 0xff;
3088 *p++ = (value >> 8) & 0xff;
3089 *p++ = (value >> 16) & 0xff;
3090 *p++ = (value >> 24) & 0xff;
3092 checked_write_file (file, assembly->code.data, assembly->code.index);
3093 checked_write_file (file, assembly->resources.data, assembly->resources.index);
3094 checked_write_file (file, assembly->image.raw_metadata, assembly->meta_size);
3095 checked_write_file (file, assembly->strong_name, assembly->strong_name_size);
3098 g_free (assembly->image.raw_metadata);
3099 break;
3100 case MONO_SECTION_RELOC: {
3101 struct {
3102 guint32 page_rva;
3103 guint32 block_size;
3104 guint16 type_and_offset;
3105 guint16 term;
3106 } reloc;
3108 g_assert (sizeof (reloc) == 12);
3110 reloc.page_rva = GUINT32_FROM_LE (assembly->text_rva);
3111 reloc.block_size = GUINT32_FROM_LE (12);
3114 * the entrypoint is always at the start of the text section
3115 * 3 is IMAGE_REL_BASED_HIGHLOW
3116 * 2 is patch_size_rva - text_rva
3118 reloc.type_and_offset = GUINT16_FROM_LE ((3 << 12) + (2));
3119 reloc.term = 0;
3121 checked_write_file (file, &reloc, sizeof (reloc));
3123 break;
3125 case MONO_SECTION_RSRC:
3126 if (assembly->win32_res) {
3128 /* Fixup the offsets in the IMAGE_RESOURCE_DATA_ENTRY structures */
3129 fixup_resource_directory (assembly->win32_res, assembly->win32_res, assembly->sections [i].rva);
3130 checked_write_file (file, assembly->win32_res, assembly->win32_res_size);
3132 break;
3133 default:
3134 g_assert_not_reached ();
3138 /* check that the file is properly padded */
3139 if (mono_w32file_seek (file, file_offset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
3140 g_error ("mono_w32file_seek returned %d\n", mono_w32error_get_last ());
3141 if (! mono_w32file_truncate (file))
3142 g_error ("mono_w32file_truncate returned %d\n", mono_w32error_get_last ());
3144 mono_dynamic_stream_reset (&assembly->code);
3145 mono_dynamic_stream_reset (&assembly->us);
3146 mono_dynamic_stream_reset (&assembly->blob);
3147 mono_dynamic_stream_reset (&assembly->guid);
3148 mono_dynamic_stream_reset (&assembly->sheap);
3150 g_hash_table_foreach (assembly->blob_cache, (GHFunc)g_free, NULL);
3151 g_hash_table_destroy (assembly->blob_cache);
3152 assembly->blob_cache = NULL;
3154 return TRUE;
3157 #else /* DISABLE_REFLECTION_EMIT_SAVE */
3159 gboolean
3160 mono_image_create_pefile (MonoReflectionModuleBuilder *mb, HANDLE file, MonoError *error)
3162 g_assert_not_reached ();
3165 #endif /* DISABLE_REFLECTION_EMIT_SAVE */