[netcore] Make the load hook ALC-aware (#16012)
[mono-project.git] / mono / metadata / sre-save.c
blob0af60e50d721615d32af6cf5c46120ce39d96376
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 (!mono_error_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;
634 MonoDynamicTable *table;
635 guint32 *values;
636 ReflectionMethodBuilder rmb;
637 int i;
639 error_init (error);
641 if (!mono_reflection_methodbuilder_from_method_builder (&rmb, mb, error) ||
642 !mono_image_basic_method (&rmb, assembly, error))
643 return FALSE;
645 mb->table_idx = *rmb.table_idx;
647 if (mb->dll) { /* It's a P/Invoke method */
648 guint32 moduleref;
649 /* map CharSet values to on-disk values */
650 int ncharset = (mb->charset ? (mb->charset - 1) * 2 : 0);
651 int extra_flags = mb->extra_flags;
652 table = &assembly->tables [MONO_TABLE_IMPLMAP];
653 table->rows ++;
654 alloc_table (table, table->rows);
655 values = table->values + table->rows * MONO_IMPLMAP_SIZE;
657 values [MONO_IMPLMAP_FLAGS] = (mb->native_cc << 8) | ncharset | extra_flags;
658 values [MONO_IMPLMAP_MEMBER] = (mb->table_idx << 1) | 1; /* memberforwarded: method */
659 if (mb->dllentry) {
660 values [MONO_IMPLMAP_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->dllentry, error);
661 return_val_if_nok (error, FALSE);
662 } else {
663 values [MONO_IMPLMAP_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->name, error);
664 return_val_if_nok (error, FALSE);
666 moduleref = string_heap_insert_mstring (&assembly->sheap, mb->dll, error);
667 return_val_if_nok (error, FALSE);
668 if (!(values [MONO_IMPLMAP_SCOPE] = find_index_in_table (assembly, MONO_TABLE_MODULEREF, MONO_MODULEREF_NAME, moduleref))) {
669 table = &assembly->tables [MONO_TABLE_MODULEREF];
670 table->rows ++;
671 alloc_table (table, table->rows);
672 table->values [table->rows * MONO_MODULEREF_SIZE + MONO_MODULEREF_NAME] = moduleref;
673 values [MONO_IMPLMAP_SCOPE] = table->rows;
677 if (mb->generic_params) {
678 table = &assembly->tables [MONO_TABLE_GENERICPARAM];
679 table->rows += mono_array_length_internal (mb->generic_params);
680 alloc_table (table, table->rows);
681 for (i = 0; i < mono_array_length_internal (mb->generic_params); ++i) {
682 guint32 owner = MONO_TYPEORMETHOD_METHOD | (mb->table_idx << MONO_TYPEORMETHOD_BITS);
684 mono_image_get_generic_param_info (
685 (MonoReflectionGenericParam *)mono_array_get_internal (mb->generic_params, gpointer, i), owner, assembly);
689 return TRUE;
692 static gboolean
693 mono_image_get_ctor_info (MonoDomain *domain, MonoReflectionCtorBuilder *mb, MonoDynamicImage *assembly, MonoError *error)
695 MONO_REQ_GC_UNSAFE_MODE;
697 ReflectionMethodBuilder rmb;
699 if (!mono_reflection_methodbuilder_from_ctor_builder (&rmb, mb, error))
700 return FALSE;
702 if (!mono_image_basic_method (&rmb, assembly, error))
703 return FALSE;
705 mb->table_idx = *rmb.table_idx;
707 return TRUE;
709 #endif
711 static void
712 mono_image_get_field_info (MonoReflectionFieldBuilder *fb, MonoDynamicImage *assembly, MonoError *error)
714 MONO_REQ_GC_UNSAFE_MODE;
716 error_init (error);
718 MonoDynamicTable *table;
719 guint32 *values;
721 /* maybe this fixup should be done in the C# code */
722 if (fb->attrs & FIELD_ATTRIBUTE_LITERAL)
723 fb->attrs |= FIELD_ATTRIBUTE_HAS_DEFAULT;
724 table = &assembly->tables [MONO_TABLE_FIELD];
725 guint32 fb_table_idx = table->next_idx ++;
726 g_hash_table_insert (assembly->field_to_table_idx, fb->handle, GUINT_TO_POINTER (fb_table_idx));
727 values = table->values + fb_table_idx * MONO_FIELD_SIZE;
728 values [MONO_FIELD_NAME] = string_heap_insert_mstring (&assembly->sheap, fb->name, error);
729 return_if_nok (error);
730 values [MONO_FIELD_FLAGS] = fb->attrs;
731 values [MONO_FIELD_SIGNATURE] = mono_dynimage_encode_field_signature (assembly, fb, error);
732 return_if_nok (error);
734 if (fb->offset != -1) {
735 table = &assembly->tables [MONO_TABLE_FIELDLAYOUT];
736 table->rows ++;
737 alloc_table (table, table->rows);
738 values = table->values + table->rows * MONO_FIELD_LAYOUT_SIZE;
739 values [MONO_FIELD_LAYOUT_FIELD] = fb_table_idx;
740 values [MONO_FIELD_LAYOUT_OFFSET] = fb->offset;
742 if (fb->attrs & FIELD_ATTRIBUTE_LITERAL) {
743 MonoTypeEnum field_type = (MonoTypeEnum)0;
744 table = &assembly->tables [MONO_TABLE_CONSTANT];
745 table->rows ++;
746 alloc_table (table, table->rows);
747 values = table->values + table->rows * MONO_CONSTANT_SIZE;
748 values [MONO_CONSTANT_PARENT] = MONO_HASCONSTANT_FIEDDEF | (fb_table_idx << MONO_HASCONSTANT_BITS);
749 values [MONO_CONSTANT_VALUE] = mono_dynimage_encode_constant (assembly, fb->def_value, &field_type);
750 values [MONO_CONSTANT_TYPE] = field_type;
751 values [MONO_CONSTANT_PADDING] = 0;
753 if (fb->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA) {
754 guint32 rva_idx;
755 table = &assembly->tables [MONO_TABLE_FIELDRVA];
756 table->rows ++;
757 alloc_table (table, table->rows);
758 values = table->values + table->rows * MONO_FIELD_RVA_SIZE;
759 values [MONO_FIELD_RVA_FIELD] = fb_table_idx;
761 * We store it in the code section because it's simpler for now.
763 if (fb->rva_data) {
764 if (mono_array_length_internal (fb->rva_data) >= 10)
765 stream_data_align (&assembly->code);
766 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));
767 } else
768 rva_idx = mono_image_add_stream_zero (&assembly->code, mono_class_value_size (fb->handle->parent, NULL));
769 values [MONO_FIELD_RVA_RVA] = rva_idx + assembly->text_rva;
771 if (fb->marshal_info) {
772 table = &assembly->tables [MONO_TABLE_FIELDMARSHAL];
773 table->rows ++;
774 alloc_table (table, table->rows);
775 values = table->values + table->rows * MONO_FIELD_MARSHAL_SIZE;
776 values [MONO_FIELD_MARSHAL_PARENT] = (fb_table_idx << MONO_HAS_FIELD_MARSHAL_BITS) | MONO_HAS_FIELD_MARSHAL_FIELDSREF;
777 values [MONO_FIELD_MARSHAL_NATIVE_TYPE] = mono_dynimage_save_encode_marshal_blob (assembly, fb->marshal_info, error);
778 return_if_nok (error);
782 static void
783 mono_image_get_property_info (MonoReflectionPropertyBuilder *pb, MonoDynamicImage *assembly, MonoError *error)
785 MONO_REQ_GC_UNSAFE_MODE;
787 error_init (error);
789 MonoDynamicTable *table;
790 guint32 *values;
791 guint num_methods = 0;
792 guint32 semaidx;
795 * we need to set things in the following tables:
796 * PROPERTYMAP (info already filled in _get_type_info ())
797 * PROPERTY (rows already preallocated in _get_type_info ())
798 * METHOD (method info already done with the generic method code)
799 * METHODSEMANTICS
800 * CONSTANT
802 table = &assembly->tables [MONO_TABLE_PROPERTY];
803 pb->table_idx = table->next_idx ++;
804 values = table->values + pb->table_idx * MONO_PROPERTY_SIZE;
805 values [MONO_PROPERTY_NAME] = string_heap_insert_mstring (&assembly->sheap, pb->name, error);
806 return_if_nok (error);
807 values [MONO_PROPERTY_FLAGS] = pb->attrs;
808 values [MONO_PROPERTY_TYPE] = mono_dynimage_save_encode_property_signature (assembly, pb, error);
809 return_if_nok (error);
812 /* FIXME: we still don't handle 'other' methods */
813 if (pb->get_method) num_methods ++;
814 if (pb->set_method) num_methods ++;
816 table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
817 table->rows += num_methods;
818 alloc_table (table, table->rows);
820 if (pb->get_method) {
821 semaidx = table->next_idx ++;
822 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
823 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_GETTER;
824 values [MONO_METHOD_SEMA_METHOD] = pb->get_method->table_idx;
825 values [MONO_METHOD_SEMA_ASSOCIATION] = (pb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_PROPERTY;
827 if (pb->set_method) {
828 semaidx = table->next_idx ++;
829 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
830 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_SETTER;
831 values [MONO_METHOD_SEMA_METHOD] = pb->set_method->table_idx;
832 values [MONO_METHOD_SEMA_ASSOCIATION] = (pb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_PROPERTY;
834 if (pb->attrs & PROPERTY_ATTRIBUTE_HAS_DEFAULT) {
835 MonoTypeEnum field_type = (MonoTypeEnum)0;
836 table = &assembly->tables [MONO_TABLE_CONSTANT];
837 table->rows ++;
838 alloc_table (table, table->rows);
839 values = table->values + table->rows * MONO_CONSTANT_SIZE;
840 values [MONO_CONSTANT_PARENT] = MONO_HASCONSTANT_PROPERTY | (pb->table_idx << MONO_HASCONSTANT_BITS);
841 values [MONO_CONSTANT_VALUE] = mono_dynimage_encode_constant (assembly, pb->def_value, &field_type);
842 values [MONO_CONSTANT_TYPE] = field_type;
843 values [MONO_CONSTANT_PADDING] = 0;
847 static void
848 mono_image_get_event_info (MonoReflectionEventBuilder *eb, MonoDynamicImage *assembly, MonoError *error)
850 MONO_REQ_GC_UNSAFE_MODE;
852 MonoDynamicTable *table;
853 guint32 *values;
854 guint num_methods = 0;
855 guint32 semaidx;
858 * we need to set things in the following tables:
859 * EVENTMAP (info already filled in _get_type_info ())
860 * EVENT (rows already preallocated in _get_type_info ())
861 * METHOD (method info already done with the generic method code)
862 * METHODSEMANTICS
864 table = &assembly->tables [MONO_TABLE_EVENT];
865 eb->table_idx = table->next_idx ++;
866 values = table->values + eb->table_idx * MONO_EVENT_SIZE;
867 values [MONO_EVENT_NAME] = string_heap_insert_mstring (&assembly->sheap, eb->name, error);
868 return_if_nok (error);
869 values [MONO_EVENT_FLAGS] = eb->attrs;
870 MonoType *ebtype = mono_reflection_type_get_handle (eb->type, error);
871 return_if_nok (error);
872 values [MONO_EVENT_TYPE] = mono_image_typedef_or_ref (assembly, ebtype);
875 * FIXME: we still don't handle 'other' methods
877 if (eb->add_method) num_methods ++;
878 if (eb->remove_method) num_methods ++;
879 if (eb->raise_method) num_methods ++;
881 table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
882 table->rows += num_methods;
883 alloc_table (table, table->rows);
885 if (eb->add_method) {
886 semaidx = table->next_idx ++;
887 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
888 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_ADD_ON;
889 values [MONO_METHOD_SEMA_METHOD] = eb->add_method->table_idx;
890 values [MONO_METHOD_SEMA_ASSOCIATION] = (eb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_EVENT;
892 if (eb->remove_method) {
893 semaidx = table->next_idx ++;
894 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
895 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_REMOVE_ON;
896 values [MONO_METHOD_SEMA_METHOD] = eb->remove_method->table_idx;
897 values [MONO_METHOD_SEMA_ASSOCIATION] = (eb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_EVENT;
899 if (eb->raise_method) {
900 semaidx = table->next_idx ++;
901 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
902 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_FIRE;
903 values [MONO_METHOD_SEMA_METHOD] = eb->raise_method->table_idx;
904 values [MONO_METHOD_SEMA_ASSOCIATION] = (eb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_EVENT;
908 static void
909 encode_constraints (MonoReflectionGenericParam *gparam, guint32 owner, MonoDynamicImage *assembly, MonoError *error)
911 MONO_REQ_GC_UNSAFE_MODE;
913 error_init (error);
915 MonoDynamicTable *table;
916 guint32 num_constraints, i;
917 guint32 *values;
918 guint32 table_idx;
920 table = &assembly->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
921 num_constraints = gparam->iface_constraints ?
922 mono_array_length_internal (gparam->iface_constraints) : 0;
923 table->rows += num_constraints;
924 if (gparam->base_type)
925 table->rows++;
926 alloc_table (table, table->rows);
928 if (gparam->base_type) {
929 table_idx = table->next_idx ++;
930 values = table->values + table_idx * MONO_GENPARCONSTRAINT_SIZE;
932 MonoType *gpbasetype = mono_reflection_type_get_handle (gparam->base_type, error);
933 return_if_nok (error);
934 values [MONO_GENPARCONSTRAINT_GENERICPAR] = owner;
935 values [MONO_GENPARCONSTRAINT_CONSTRAINT] = mono_image_typedef_or_ref (assembly, gpbasetype);
938 for (i = 0; i < num_constraints; i++) {
939 MonoReflectionType *constraint = (MonoReflectionType *)mono_array_get_internal (
940 gparam->iface_constraints, gpointer, i);
942 table_idx = table->next_idx ++;
943 values = table->values + table_idx * MONO_GENPARCONSTRAINT_SIZE;
945 MonoType *constraint_type = mono_reflection_type_get_handle (constraint, error);
946 return_if_nok (error);
948 values [MONO_GENPARCONSTRAINT_GENERICPAR] = owner;
949 values [MONO_GENPARCONSTRAINT_CONSTRAINT] = mono_image_typedef_or_ref (assembly, constraint_type);
953 static void
954 mono_image_get_generic_param_info (MonoReflectionGenericParam *gparam, guint32 owner, MonoDynamicImage *assembly)
956 MONO_REQ_GC_UNSAFE_MODE;
958 GenericParamTableEntry *entry;
961 * The GenericParam table must be sorted according to the `owner' field.
962 * We need to do this sorting prior to writing the GenericParamConstraint
963 * table, since we have to use the final GenericParam table indices there
964 * and they must also be sorted.
967 entry = g_new0 (GenericParamTableEntry, 1);
968 entry->owner = owner;
969 /* FIXME: track where gen_params should be freed and remove the GC root as well */
970 MONO_GC_REGISTER_ROOT_IF_MOVING (entry->gparam, MONO_ROOT_SOURCE_REFLECTION, NULL, "Reflection Generic Parameter");
971 entry->gparam = gparam;
973 g_ptr_array_add (assembly->gen_params, entry);
976 static gboolean
977 write_generic_param_entry (MonoDynamicImage *assembly, GenericParamTableEntry *entry, MonoError *error)
979 MONO_REQ_GC_UNSAFE_MODE;
981 MonoDynamicTable *table;
982 MonoGenericParam *param;
983 guint32 *values;
984 guint32 table_idx;
986 error_init (error);
988 table = &assembly->tables [MONO_TABLE_GENERICPARAM];
989 table_idx = table->next_idx ++;
990 values = table->values + table_idx * MONO_GENERICPARAM_SIZE;
992 MonoType *gparam_type = mono_reflection_type_get_handle ((MonoReflectionType*)entry->gparam, error);
993 return_val_if_nok (error, FALSE);
995 param = gparam_type->data.generic_param;
997 values [MONO_GENERICPARAM_OWNER] = entry->owner;
998 values [MONO_GENERICPARAM_FLAGS] = entry->gparam->attrs;
999 values [MONO_GENERICPARAM_NUMBER] = mono_generic_param_num (param);
1000 values [MONO_GENERICPARAM_NAME] = string_heap_insert (&assembly->sheap, mono_generic_param_name (param));
1002 if (!mono_image_add_cattrs (assembly, table_idx, MONO_CUSTOM_ATTR_GENERICPAR, entry->gparam->cattrs, error))
1003 return FALSE;
1005 encode_constraints (entry->gparam, table_idx, assembly, error);
1006 return_val_if_nok (error, FALSE);
1008 return TRUE;
1011 static void
1012 collect_types (MonoPtrArray *types, MonoReflectionTypeBuilder *type)
1014 int i;
1016 mono_ptr_array_append (*types, type);
1018 if (!type->subtypes)
1019 return;
1021 for (i = 0; i < mono_array_length_internal (type->subtypes); ++i) {
1022 MonoReflectionTypeBuilder *subtype = mono_array_get_internal (type->subtypes, MonoReflectionTypeBuilder*, i);
1023 collect_types (types, subtype);
1027 static gint
1028 compare_types_by_table_idx (MonoReflectionTypeBuilder **type1, MonoReflectionTypeBuilder **type2)
1030 if ((*type1)->table_idx < (*type2)->table_idx)
1031 return -1;
1032 else
1033 if ((*type1)->table_idx > (*type2)->table_idx)
1034 return 1;
1035 else
1036 return 0;
1039 static gboolean
1040 params_add_cattrs (MonoDynamicImage *assembly, MonoArray *pinfo, MonoError *error) {
1041 int i;
1043 error_init (error);
1044 if (!pinfo)
1045 return TRUE;
1046 for (i = 0; i < mono_array_length_internal (pinfo); ++i) {
1047 MonoReflectionParamBuilder *pb;
1048 pb = mono_array_get_internal (pinfo, MonoReflectionParamBuilder *, i);
1049 if (!pb)
1050 continue;
1051 if (!mono_image_add_cattrs (assembly, pb->table_idx, MONO_CUSTOM_ATTR_PARAMDEF, pb->cattrs, error))
1052 return FALSE;
1055 return TRUE;
1058 static guint32
1059 field_builder_table_index (MonoDynamicImage* assembly, MonoReflectionFieldBuilder *fb)
1061 return GPOINTER_TO_UINT (g_hash_table_lookup (assembly->field_to_table_idx, fb->handle));
1064 static gboolean
1065 type_add_cattrs (MonoDynamicImage *assembly, MonoReflectionTypeBuilder *tb, MonoError *error) {
1066 int i;
1068 error_init (error);
1070 if (!mono_image_add_cattrs (assembly, tb->table_idx, MONO_CUSTOM_ATTR_TYPEDEF, tb->cattrs, error))
1071 return FALSE;
1072 if (tb->fields) {
1073 for (i = 0; i < tb->num_fields; ++i) {
1074 MonoReflectionFieldBuilder* fb;
1075 fb = mono_array_get_internal (tb->fields, MonoReflectionFieldBuilder*, i);
1076 if (!mono_image_add_cattrs (assembly, field_builder_table_index (assembly, fb), MONO_CUSTOM_ATTR_FIELDDEF, fb->cattrs, error))
1077 return FALSE;
1080 if (tb->events) {
1081 for (i = 0; i < mono_array_length_internal (tb->events); ++i) {
1082 MonoReflectionEventBuilder* eb;
1083 eb = mono_array_get_internal (tb->events, MonoReflectionEventBuilder*, i);
1084 if (!mono_image_add_cattrs (assembly, eb->table_idx, MONO_CUSTOM_ATTR_EVENT, eb->cattrs, error))
1085 return FALSE;
1088 if (tb->properties) {
1089 for (i = 0; i < mono_array_length_internal (tb->properties); ++i) {
1090 MonoReflectionPropertyBuilder* pb;
1091 pb = mono_array_get_internal (tb->properties, MonoReflectionPropertyBuilder*, i);
1092 if (!mono_image_add_cattrs (assembly, pb->table_idx, MONO_CUSTOM_ATTR_PROPERTY, pb->cattrs, error))
1093 return FALSE;
1096 if (tb->ctors) {
1097 for (i = 0; i < mono_array_length_internal (tb->ctors); ++i) {
1098 MonoReflectionCtorBuilder* cb;
1099 cb = mono_array_get_internal (tb->ctors, MonoReflectionCtorBuilder*, i);
1100 if (!mono_image_add_cattrs (assembly, cb->table_idx, MONO_CUSTOM_ATTR_METHODDEF, cb->cattrs, error) ||
1101 !params_add_cattrs (assembly, cb->pinfo, error))
1102 return FALSE;
1106 if (tb->methods) {
1107 for (i = 0; i < tb->num_methods; ++i) {
1108 MonoReflectionMethodBuilder* mb;
1109 mb = mono_array_get_internal (tb->methods, MonoReflectionMethodBuilder*, i);
1110 if (!mono_image_add_cattrs (assembly, mb->table_idx, MONO_CUSTOM_ATTR_METHODDEF, mb->cattrs, error) ||
1111 !params_add_cattrs (assembly, mb->pinfo, error))
1112 return FALSE;
1116 if (tb->subtypes) {
1117 for (i = 0; i < mono_array_length_internal (tb->subtypes); ++i) {
1118 if (!type_add_cattrs (assembly, mono_array_get_internal (tb->subtypes, MonoReflectionTypeBuilder*, i), error))
1119 return FALSE;
1123 return TRUE;
1126 static gboolean
1127 module_add_cattrs (MonoDynamicImage *assembly, MonoReflectionModuleBuilder *moduleb, MonoError *error)
1129 int i;
1131 error_init (error);
1133 if (!mono_image_add_cattrs (assembly, moduleb->table_idx, MONO_CUSTOM_ATTR_MODULE, moduleb->cattrs, error))
1134 return FALSE;
1136 if (moduleb->global_methods) {
1137 for (i = 0; i < mono_array_length_internal (moduleb->global_methods); ++i) {
1138 MonoReflectionMethodBuilder* mb = mono_array_get_internal (moduleb->global_methods, MonoReflectionMethodBuilder*, i);
1139 if (!mono_image_add_cattrs (assembly, mb->table_idx, MONO_CUSTOM_ATTR_METHODDEF, mb->cattrs, error) ||
1140 !params_add_cattrs (assembly, mb->pinfo, error))
1141 return FALSE;
1145 if (moduleb->global_fields) {
1146 for (i = 0; i < mono_array_length_internal (moduleb->global_fields); ++i) {
1147 MonoReflectionFieldBuilder *fb = mono_array_get_internal (moduleb->global_fields, MonoReflectionFieldBuilder*, i);
1148 if (!mono_image_add_cattrs (assembly, field_builder_table_index (assembly, fb), MONO_CUSTOM_ATTR_FIELDDEF, fb->cattrs, error))
1149 return FALSE;
1153 if (moduleb->types) {
1154 for (i = 0; i < moduleb->num_types; ++i) {
1155 if (!type_add_cattrs (assembly, mono_array_get_internal (moduleb->types, MonoReflectionTypeBuilder*, i), error))
1156 return FALSE;
1160 return TRUE;
1163 static gboolean
1164 mono_image_fill_file_table (MonoDomain *domain, MonoReflectionModule *module, MonoDynamicImage *assembly, MonoError *error)
1166 MonoDynamicTable *table;
1167 guint32 *values;
1168 char blob_size [6];
1169 guchar hash [20];
1170 char *b = blob_size;
1171 char *dir, *path;
1173 error_init (error);
1175 table = &assembly->tables [MONO_TABLE_FILE];
1176 table->rows++;
1177 alloc_table (table, table->rows);
1178 values = table->values + table->next_idx * MONO_FILE_SIZE;
1179 values [MONO_FILE_FLAGS] = FILE_CONTAINS_METADATA;
1180 values [MONO_FILE_NAME] = string_heap_insert (&assembly->sheap, module->image->module_name);
1181 if (image_is_dynamic (module->image)) {
1182 /* This depends on the fact that the main module is emitted last */
1183 dir = mono_string_to_utf8_checked_internal (((MonoReflectionModuleBuilder*)module)->assemblyb->dir, error);
1184 return_val_if_nok (error, FALSE);
1185 path = g_strdup_printf ("%s%c%s", dir, G_DIR_SEPARATOR, module->image->module_name);
1186 } else {
1187 dir = NULL;
1188 path = g_strdup (module->image->name);
1190 mono_sha1_get_digest_from_file (path, hash);
1191 g_free (dir);
1192 g_free (path);
1193 mono_metadata_encode_value (20, b, &b);
1194 values [MONO_FILE_HASH_VALUE] = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
1195 mono_image_add_stream_data (&assembly->blob, (char*)hash, 20);
1196 table->next_idx ++;
1197 return TRUE;
1200 static void
1201 mono_image_fill_module_table (MonoDomain *domain, MonoReflectionModuleBuilder *mb, MonoDynamicImage *assembly, MonoError *error)
1203 MonoDynamicTable *table;
1204 int i;
1206 error_init (error);
1208 table = &assembly->tables [MONO_TABLE_MODULE];
1209 mb->table_idx = table->next_idx ++;
1210 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->module.name, error);
1211 return_if_nok (error);
1212 i = mono_image_add_stream_data (&assembly->guid, mono_array_addr_internal (mb->guid, char, 0), 16);
1213 i /= 16;
1214 ++i;
1215 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_GENERATION] = 0;
1216 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_MVID] = i;
1217 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_ENC] = 0;
1218 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_ENCBASE] = 0;
1221 static guint32
1222 mono_image_fill_export_table_from_class (MonoDomain *domain, MonoClass *klass,
1223 guint32 module_index, guint32 parent_index, MonoDynamicImage *assembly)
1225 MonoDynamicTable *table;
1226 guint32 *values;
1227 guint32 visib, res;
1229 visib = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_VISIBILITY_MASK;
1230 if (! ((visib & TYPE_ATTRIBUTE_PUBLIC) || (visib & TYPE_ATTRIBUTE_NESTED_PUBLIC)))
1231 return 0;
1233 table = &assembly->tables [MONO_TABLE_EXPORTEDTYPE];
1234 table->rows++;
1235 alloc_table (table, table->rows);
1236 values = table->values + table->next_idx * MONO_EXP_TYPE_SIZE;
1238 values [MONO_EXP_TYPE_FLAGS] = mono_class_get_flags (klass);
1239 values [MONO_EXP_TYPE_TYPEDEF] = m_class_get_type_token (klass);
1240 if (m_class_get_nested_in (klass))
1241 values [MONO_EXP_TYPE_IMPLEMENTATION] = (parent_index << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_EXP_TYPE;
1242 else
1243 values [MONO_EXP_TYPE_IMPLEMENTATION] = (module_index << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_FILE;
1244 values [MONO_EXP_TYPE_NAME] = string_heap_insert (&assembly->sheap, m_class_get_name (klass));
1245 values [MONO_EXP_TYPE_NAMESPACE] = string_heap_insert (&assembly->sheap, m_class_get_name_space (klass));
1247 res = table->next_idx;
1249 table->next_idx ++;
1251 /* Emit nested types */
1252 GList *nested_classes = mono_class_get_nested_classes_property (klass);
1253 GList *tmp;
1254 for (tmp = nested_classes; tmp; tmp = tmp->next)
1255 mono_image_fill_export_table_from_class (domain, (MonoClass *)tmp->data, module_index, table->next_idx - 1, assembly);
1257 return res;
1260 static void
1261 mono_image_fill_export_table (MonoDomain *domain, MonoReflectionTypeBuilder *tb,
1262 guint32 module_index, guint32 parent_index, MonoDynamicImage *assembly,
1263 MonoError *error)
1265 MonoClass *klass;
1266 guint32 idx, i;
1268 error_init (error);
1270 MonoType *t = mono_reflection_type_get_handle ((MonoReflectionType*)tb, error);
1271 return_if_nok (error);
1273 klass = mono_class_from_mono_type_internal (t);
1275 guint32 tb_token = mono_metadata_make_token (MONO_TABLE_TYPEDEF, tb->table_idx);
1276 if (m_class_get_type_token (klass) != tb_token) {
1277 g_error ("TypeBuilder token %08x does not match klass token %08x", tb_token, m_class_get_type_token (klass));
1280 idx = mono_image_fill_export_table_from_class (domain, klass, module_index,
1281 parent_index, assembly);
1284 * Emit nested types
1285 * We need to do this ourselves since klass->nested_classes is not set up.
1287 if (tb->subtypes) {
1288 for (i = 0; i < mono_array_length_internal (tb->subtypes); ++i) {
1289 mono_image_fill_export_table (domain, mono_array_get_internal (tb->subtypes, MonoReflectionTypeBuilder*, i), module_index, idx, assembly, error);
1290 return_if_nok (error);
1295 static void
1296 mono_image_fill_export_table_from_module (MonoDomain *domain, MonoReflectionModule *module,
1297 guint32 module_index, MonoDynamicImage *assembly)
1299 MonoImage *image = module->image;
1300 MonoTableInfo *t;
1301 guint32 i;
1303 t = &image->tables [MONO_TABLE_TYPEDEF];
1305 for (i = 0; i < t->rows; ++i) {
1306 ERROR_DECL (error);
1307 MonoClass *klass = mono_class_get_checked (image, mono_metadata_make_token (MONO_TABLE_TYPEDEF, i + 1), error);
1308 g_assert (mono_error_ok (error)); /* FIXME don't swallow the error */
1310 if (mono_class_is_public (klass))
1311 mono_image_fill_export_table_from_class (domain, klass, module_index, 0, assembly);
1315 static void
1316 add_exported_type (MonoReflectionAssemblyBuilder *assemblyb, MonoDynamicImage *assembly, MonoClass *klass, guint32 parent_index)
1318 MonoDynamicTable *table;
1319 guint32 *values;
1320 guint32 scope, scope_idx, impl, current_idx;
1321 gboolean forwarder = TRUE;
1322 gpointer iter = NULL;
1323 MonoClass *nested;
1325 if (m_class_get_nested_in (klass)) {
1326 impl = (parent_index << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_EXP_TYPE;
1327 forwarder = FALSE;
1328 } else {
1329 scope = mono_reflection_resolution_scope_from_image (assembly, m_class_get_image (klass));
1330 g_assert ((scope & MONO_RESOLUTION_SCOPE_MASK) == MONO_RESOLUTION_SCOPE_ASSEMBLYREF);
1331 scope_idx = scope >> MONO_RESOLUTION_SCOPE_BITS;
1332 impl = (scope_idx << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_ASSEMBLYREF;
1335 table = &assembly->tables [MONO_TABLE_EXPORTEDTYPE];
1337 table->rows++;
1338 alloc_table (table, table->rows);
1339 current_idx = table->next_idx;
1340 values = table->values + current_idx * MONO_EXP_TYPE_SIZE;
1342 values [MONO_EXP_TYPE_FLAGS] = forwarder ? TYPE_ATTRIBUTE_FORWARDER : 0;
1343 values [MONO_EXP_TYPE_TYPEDEF] = 0;
1344 values [MONO_EXP_TYPE_IMPLEMENTATION] = impl;
1345 values [MONO_EXP_TYPE_NAME] = string_heap_insert (&assembly->sheap, m_class_get_name (klass));
1346 values [MONO_EXP_TYPE_NAMESPACE] = string_heap_insert (&assembly->sheap, m_class_get_name_space (klass));
1348 table->next_idx++;
1350 while ((nested = mono_class_get_nested_types (klass, &iter)))
1351 add_exported_type (assemblyb, assembly, nested, current_idx);
1354 static void
1355 mono_image_fill_export_table_from_type_forwarders (MonoReflectionAssemblyBuilder *assemblyb, MonoDynamicImage *assembly)
1357 ERROR_DECL (error);
1358 MonoClass *klass;
1359 int i;
1361 if (!assemblyb->type_forwarders)
1362 return;
1364 for (i = 0; i < mono_array_length_internal (assemblyb->type_forwarders); ++i) {
1365 MonoReflectionType *t = mono_array_get_internal (assemblyb->type_forwarders, MonoReflectionType *, i);
1366 MonoType *type;
1367 if (!t)
1368 continue;
1370 type = mono_reflection_type_get_handle (t, error);
1371 mono_error_assert_ok (error);
1372 g_assert (type);
1374 klass = mono_class_from_mono_type_internal (type);
1376 add_exported_type (assemblyb, assembly, klass, 0);
1380 #define align_pointer(base,p)\
1381 do {\
1382 guint32 __diff = (unsigned char*)(p)-(unsigned char*)(base);\
1383 if (__diff & 3)\
1384 (p) += 4 - (__diff & 3);\
1385 } while (0)
1387 static int
1388 compare_constants (const void *a, const void *b)
1390 const guint32 *a_values = (const guint32 *)a;
1391 const guint32 *b_values = (const guint32 *)b;
1392 return a_values [MONO_CONSTANT_PARENT] - b_values [MONO_CONSTANT_PARENT];
1395 static int
1396 compare_semantics (const void *a, const void *b)
1398 const guint32 *a_values = (const guint32 *)a;
1399 const guint32 *b_values = (const guint32 *)b;
1400 int assoc = a_values [MONO_METHOD_SEMA_ASSOCIATION] - b_values [MONO_METHOD_SEMA_ASSOCIATION];
1401 if (assoc)
1402 return assoc;
1403 return a_values [MONO_METHOD_SEMA_SEMANTICS] - b_values [MONO_METHOD_SEMA_SEMANTICS];
1406 static int
1407 compare_custom_attrs (const void *a, const void *b)
1409 const guint32 *a_values = (const guint32 *)a;
1410 const guint32 *b_values = (const guint32 *)b;
1412 return a_values [MONO_CUSTOM_ATTR_PARENT] - b_values [MONO_CUSTOM_ATTR_PARENT];
1415 static int
1416 compare_field_marshal (const void *a, const void *b)
1418 const guint32 *a_values = (const guint32 *)a;
1419 const guint32 *b_values = (const guint32 *)b;
1421 return a_values [MONO_FIELD_MARSHAL_PARENT] - b_values [MONO_FIELD_MARSHAL_PARENT];
1424 static int
1425 compare_nested (const void *a, const void *b)
1427 const guint32 *a_values = (const guint32 *)a;
1428 const guint32 *b_values = (const guint32 *)b;
1430 return a_values [MONO_NESTED_CLASS_NESTED] - b_values [MONO_NESTED_CLASS_NESTED];
1433 static int
1434 compare_genericparam (const void *a, const void *b)
1436 ERROR_DECL (error);
1437 const GenericParamTableEntry **a_entry = (const GenericParamTableEntry **) a;
1438 const GenericParamTableEntry **b_entry = (const GenericParamTableEntry **) b;
1440 if ((*b_entry)->owner == (*a_entry)->owner) {
1441 MonoType *a_type = mono_reflection_type_get_handle ((MonoReflectionType*)(*a_entry)->gparam, error);
1442 mono_error_assert_ok (error);
1443 MonoType *b_type = mono_reflection_type_get_handle ((MonoReflectionType*)(*b_entry)->gparam, error);
1444 mono_error_assert_ok (error);
1445 return
1446 mono_type_get_generic_param_num (a_type) -
1447 mono_type_get_generic_param_num (b_type);
1448 } else
1449 return (*a_entry)->owner - (*b_entry)->owner;
1452 static int
1453 compare_declsecurity_attrs (const void *a, const void *b)
1455 const guint32 *a_values = (const guint32 *)a;
1456 const guint32 *b_values = (const guint32 *)b;
1458 return a_values [MONO_DECL_SECURITY_PARENT] - b_values [MONO_DECL_SECURITY_PARENT];
1461 static int
1462 compare_interface_impl (const void *a, const void *b)
1464 const guint32 *a_values = (const guint32 *)a;
1465 const guint32 *b_values = (const guint32 *)b;
1467 int klass = a_values [MONO_INTERFACEIMPL_CLASS] - b_values [MONO_INTERFACEIMPL_CLASS];
1468 if (klass)
1469 return klass;
1471 return a_values [MONO_INTERFACEIMPL_INTERFACE] - b_values [MONO_INTERFACEIMPL_INTERFACE];
1474 struct StreamDesc {
1475 const char *name;
1476 MonoDynamicStream *stream;
1480 * build_compressed_metadata() fills in the blob of data that represents the
1481 * raw metadata as it will be saved in the PE file. The five streams are output
1482 * and the metadata tables are comnpressed from the guint32 array representation,
1483 * to the compressed on-disk format.
1485 static gboolean
1486 build_compressed_metadata (MonoDynamicImage *assembly, MonoError *error)
1488 MonoDynamicTable *table;
1489 int i;
1490 guint64 valid_mask = 0;
1491 guint64 sorted_mask;
1492 guint32 heapt_size = 0;
1493 guint32 meta_size = 256; /* allow for header and other stuff */
1494 guint32 table_offset;
1495 guint32 ntables = 0;
1496 guint64 *int64val;
1497 guint32 *int32val;
1498 guint16 *int16val;
1499 MonoImage *meta;
1500 unsigned char *p;
1501 struct StreamDesc stream_desc [5];
1503 error_init (error);
1505 qsort (assembly->gen_params->pdata, assembly->gen_params->len, sizeof (gpointer), compare_genericparam);
1506 for (i = 0; i < assembly->gen_params->len; i++) {
1507 GenericParamTableEntry *entry = (GenericParamTableEntry *)g_ptr_array_index (assembly->gen_params, i);
1508 if (!write_generic_param_entry (assembly, entry, error))
1509 return FALSE;
1512 stream_desc [0].name = "#~";
1513 stream_desc [0].stream = &assembly->tstream;
1514 stream_desc [1].name = "#Strings";
1515 stream_desc [1].stream = &assembly->sheap;
1516 stream_desc [2].name = "#US";
1517 stream_desc [2].stream = &assembly->us;
1518 stream_desc [3].name = "#Blob";
1519 stream_desc [3].stream = &assembly->blob;
1520 stream_desc [4].name = "#GUID";
1521 stream_desc [4].stream = &assembly->guid;
1523 /* tables that are sorted */
1524 sorted_mask = ((guint64)1 << MONO_TABLE_CONSTANT) | ((guint64)1 << MONO_TABLE_FIELDMARSHAL)
1525 | ((guint64)1 << MONO_TABLE_METHODSEMANTICS) | ((guint64)1 << MONO_TABLE_CLASSLAYOUT)
1526 | ((guint64)1 << MONO_TABLE_FIELDLAYOUT) | ((guint64)1 << MONO_TABLE_FIELDRVA)
1527 | ((guint64)1 << MONO_TABLE_IMPLMAP) | ((guint64)1 << MONO_TABLE_NESTEDCLASS)
1528 | ((guint64)1 << MONO_TABLE_METHODIMPL) | ((guint64)1 << MONO_TABLE_CUSTOMATTRIBUTE)
1529 | ((guint64)1 << MONO_TABLE_DECLSECURITY) | ((guint64)1 << MONO_TABLE_GENERICPARAM)
1530 | ((guint64)1 << MONO_TABLE_INTERFACEIMPL);
1532 /* Compute table sizes */
1533 /* the MonoImage has already been created in mono_reflection_dynimage_basic_init() */
1534 meta = &assembly->image;
1536 /* sizes should be multiple of 4 */
1537 mono_dynstream_data_align (&assembly->blob);
1538 mono_dynstream_data_align (&assembly->guid);
1539 mono_dynstream_data_align (&assembly->sheap);
1540 mono_dynstream_data_align (&assembly->us);
1542 /* Setup the info used by compute_sizes () */
1543 meta->idx_blob_wide = assembly->blob.index >= 65536 ? 1 : 0;
1544 meta->idx_guid_wide = assembly->guid.index >= 65536 ? 1 : 0;
1545 meta->idx_string_wide = assembly->sheap.index >= 65536 ? 1 : 0;
1547 meta_size += assembly->blob.index;
1548 meta_size += assembly->guid.index;
1549 meta_size += assembly->sheap.index;
1550 meta_size += assembly->us.index;
1552 for (i=0; i < MONO_TABLE_NUM; ++i)
1553 meta->tables [i].rows = assembly->tables [i].rows;
1555 for (i = 0; i < MONO_TABLE_NUM; i++){
1556 if (meta->tables [i].rows == 0)
1557 continue;
1558 valid_mask |= (guint64)1 << i;
1559 ntables ++;
1560 meta->tables [i].row_size = mono_metadata_compute_size (
1561 meta, i, &meta->tables [i].size_bitfield);
1562 heapt_size += meta->tables [i].row_size * meta->tables [i].rows;
1564 heapt_size += 24; /* #~ header size */
1565 heapt_size += ntables * 4;
1566 /* make multiple of 4 */
1567 heapt_size += 3;
1568 heapt_size &= ~3;
1569 meta_size += heapt_size;
1570 meta->raw_metadata = (char *)g_malloc0 (meta_size);
1571 p = (unsigned char*)meta->raw_metadata;
1572 /* the metadata signature */
1573 *p++ = 'B'; *p++ = 'S'; *p++ = 'J'; *p++ = 'B';
1574 /* version numbers and 4 bytes reserved */
1575 int16val = (guint16*)p;
1576 *int16val++ = GUINT16_TO_LE (meta->md_version_major);
1577 *int16val = GUINT16_TO_LE (meta->md_version_minor);
1578 p += 8;
1579 /* version string */
1580 int32val = (guint32*)p;
1581 *int32val = GUINT32_TO_LE ((strlen (meta->version) + 3) & (~3)); /* needs to be multiple of 4 */
1582 p += 4;
1583 memcpy (p, meta->version, strlen (meta->version));
1584 p += GUINT32_FROM_LE (*int32val);
1585 align_pointer (meta->raw_metadata, p);
1586 int16val = (guint16*)p;
1587 *int16val++ = GUINT16_TO_LE (0); /* flags must be 0 */
1588 *int16val = GUINT16_TO_LE (5); /* number of streams */
1589 p += 4;
1592 * write the stream info.
1594 table_offset = (p - (unsigned char*)meta->raw_metadata) + 5 * 8 + 40; /* room needed for stream headers */
1595 table_offset += 3; table_offset &= ~3;
1597 assembly->tstream.index = heapt_size;
1598 for (i = 0; i < 5; ++i) {
1599 int32val = (guint32*)p;
1600 stream_desc [i].stream->offset = table_offset;
1601 *int32val++ = GUINT32_TO_LE (table_offset);
1602 *int32val = GUINT32_TO_LE (stream_desc [i].stream->index);
1603 table_offset += GUINT32_FROM_LE (*int32val);
1604 table_offset += 3; table_offset &= ~3;
1605 p += 8;
1606 strcpy ((char*)p, stream_desc [i].name);
1607 p += strlen (stream_desc [i].name) + 1;
1608 align_pointer (meta->raw_metadata, p);
1611 * now copy the data, the table stream header and contents goes first.
1613 g_assert ((p - (unsigned char*)meta->raw_metadata) < assembly->tstream.offset);
1614 p = (guchar*)meta->raw_metadata + assembly->tstream.offset;
1615 int32val = (guint32*)p;
1616 *int32val = GUINT32_TO_LE (0); /* reserved */
1617 p += 4;
1619 *p++ = 2; /* version */
1620 *p++ = 0;
1622 if (meta->idx_string_wide)
1623 *p |= 0x01;
1624 if (meta->idx_guid_wide)
1625 *p |= 0x02;
1626 if (meta->idx_blob_wide)
1627 *p |= 0x04;
1628 ++p;
1629 *p++ = 1; /* reserved */
1630 int64val = (guint64*)p;
1631 *int64val++ = GUINT64_TO_LE (valid_mask);
1632 *int64val++ = GUINT64_TO_LE (valid_mask & sorted_mask); /* bitvector of sorted tables */
1633 p += 16;
1634 int32val = (guint32*)p;
1635 for (i = 0; i < MONO_TABLE_NUM; i++){
1636 if (meta->tables [i].rows == 0)
1637 continue;
1638 *int32val++ = GUINT32_TO_LE (meta->tables [i].rows);
1640 p = (unsigned char*)int32val;
1642 /* sort the tables that still need sorting */
1643 table = &assembly->tables [MONO_TABLE_CONSTANT];
1644 if (table->rows)
1645 qsort (table->values + MONO_CONSTANT_SIZE, table->rows, sizeof (guint32) * MONO_CONSTANT_SIZE, compare_constants);
1646 table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
1647 if (table->rows)
1648 qsort (table->values + MONO_METHOD_SEMA_SIZE, table->rows, sizeof (guint32) * MONO_METHOD_SEMA_SIZE, compare_semantics);
1649 table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1650 if (table->rows)
1651 qsort (table->values + MONO_CUSTOM_ATTR_SIZE, table->rows, sizeof (guint32) * MONO_CUSTOM_ATTR_SIZE, compare_custom_attrs);
1652 table = &assembly->tables [MONO_TABLE_FIELDMARSHAL];
1653 if (table->rows)
1654 qsort (table->values + MONO_FIELD_MARSHAL_SIZE, table->rows, sizeof (guint32) * MONO_FIELD_MARSHAL_SIZE, compare_field_marshal);
1655 table = &assembly->tables [MONO_TABLE_NESTEDCLASS];
1656 if (table->rows)
1657 qsort (table->values + MONO_NESTED_CLASS_SIZE, table->rows, sizeof (guint32) * MONO_NESTED_CLASS_SIZE, compare_nested);
1658 /* Section 21.11 DeclSecurity in Partition II doesn't specify this to be sorted by MS implementation requires it */
1659 table = &assembly->tables [MONO_TABLE_DECLSECURITY];
1660 if (table->rows)
1661 qsort (table->values + MONO_DECL_SECURITY_SIZE, table->rows, sizeof (guint32) * MONO_DECL_SECURITY_SIZE, compare_declsecurity_attrs);
1662 table = &assembly->tables [MONO_TABLE_INTERFACEIMPL];
1663 if (table->rows)
1664 qsort (table->values + MONO_INTERFACEIMPL_SIZE, table->rows, sizeof (guint32) * MONO_INTERFACEIMPL_SIZE, compare_interface_impl);
1666 /* compress the tables */
1667 for (i = 0; i < MONO_TABLE_NUM; i++){
1668 int row, col;
1669 guint32 *values;
1670 guint32 bitfield = meta->tables [i].size_bitfield;
1671 if (!meta->tables [i].rows)
1672 continue;
1673 if (assembly->tables [i].columns != mono_metadata_table_count (bitfield))
1674 g_error ("col count mismatch in %d: %d %d", i, assembly->tables [i].columns, mono_metadata_table_count (bitfield));
1675 meta->tables [i].base = (char*)p;
1676 for (row = 1; row <= meta->tables [i].rows; ++row) {
1677 values = assembly->tables [i].values + row * assembly->tables [i].columns;
1678 for (col = 0; col < assembly->tables [i].columns; ++col) {
1679 switch (mono_metadata_table_size (bitfield, col)) {
1680 case 1:
1681 *p++ = values [col];
1682 break;
1683 case 2:
1684 *p++ = values [col] & 0xff;
1685 *p++ = (values [col] >> 8) & 0xff;
1686 break;
1687 case 4:
1688 *p++ = values [col] & 0xff;
1689 *p++ = (values [col] >> 8) & 0xff;
1690 *p++ = (values [col] >> 16) & 0xff;
1691 *p++ = (values [col] >> 24) & 0xff;
1692 break;
1693 default:
1694 g_assert_not_reached ();
1698 g_assert ((p - (const unsigned char*)meta->tables [i].base) == (meta->tables [i].rows * meta->tables [i].row_size));
1701 g_assert (assembly->guid.offset + assembly->guid.index < meta_size);
1702 memcpy (meta->raw_metadata + assembly->sheap.offset, assembly->sheap.data, assembly->sheap.index);
1703 memcpy (meta->raw_metadata + assembly->us.offset, assembly->us.data, assembly->us.index);
1704 memcpy (meta->raw_metadata + assembly->blob.offset, assembly->blob.data, assembly->blob.index);
1705 memcpy (meta->raw_metadata + assembly->guid.offset, assembly->guid.data, assembly->guid.index);
1707 assembly->meta_size = assembly->guid.offset + assembly->guid.index;
1709 return TRUE;
1713 * Some tables in metadata need to be sorted according to some criteria, but
1714 * when methods and fields are first created with reflection, they may be assigned a token
1715 * that doesn't correspond to the final token they will get assigned after the sorting.
1716 * ILGenerator.cs keeps a fixup table that maps the position of tokens in the IL code stream
1717 * with the reflection objects that represent them. Once all the tables are set up, the
1718 * reflection objects will contains the correct table index. fixup_method() will fixup the
1719 * tokens for the method with ILGenerator @ilgen.
1721 static void
1722 fixup_method (MonoReflectionILGen *ilgen, gpointer value, MonoDynamicImage *assembly)
1724 guint32 code_idx = GPOINTER_TO_UINT (value);
1725 MonoReflectionILTokenInfo *iltoken;
1726 MonoReflectionTypeBuilder *tb;
1727 MonoReflectionArrayMethod *am;
1728 guint32 i, idx = 0;
1729 unsigned char *target;
1731 for (i = 0; i < ilgen->num_token_fixups; ++i) {
1732 iltoken = (MonoReflectionILTokenInfo *)mono_array_addr_with_size_internal (ilgen->token_fixups, sizeof (MonoReflectionILTokenInfo), i);
1733 target = (guchar*)assembly->code.data + code_idx + iltoken->code_pos;
1734 MonoClass *iltoken_member_class = mono_object_class (iltoken->member);
1735 const char *iltoken_member_class_name = m_class_get_name (iltoken_member_class);
1736 switch (target [3]) {
1737 case MONO_TABLE_FIELD:
1738 if (!strcmp (iltoken_member_class_name, "FieldBuilder")) {
1739 g_assert_not_reached ();
1740 } else if (!strcmp (iltoken_member_class_name, "RuntimeFieldInfo")) {
1741 MonoClassField *f = ((MonoReflectionField*)iltoken->member)->field;
1742 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->field_to_table_idx, f));
1743 } else {
1744 g_assert_not_reached ();
1746 break;
1747 case MONO_TABLE_METHOD:
1748 if (!strcmp (iltoken_member_class_name, "MethodBuilder")) {
1749 g_assert_not_reached ();
1750 } else if (!strcmp (iltoken_member_class_name, "ConstructorBuilder")) {
1751 g_assert_not_reached ();
1752 } else if (!strcmp (iltoken_member_class_name, "RuntimeMethodInfo") ||
1753 !strcmp (iltoken_member_class_name, "RuntimeConstructorInfo")) {
1754 MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
1755 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, m));
1756 } else {
1757 g_assert_not_reached ();
1759 break;
1760 case MONO_TABLE_TYPEDEF:
1761 if (!strcmp (iltoken_member_class_name, "TypeBuilder")) {
1762 g_assert_not_reached ();
1763 } else if (!strcmp (iltoken_member_class_name, "RuntimeType")) {
1764 MonoClass *k = mono_class_from_mono_type_internal (((MonoReflectionType*)iltoken->member)->type);
1765 MonoObject *obj = &mono_class_get_ref_info_raw (k)->type.object; /* FIXME use handles */
1766 g_assert (obj);
1767 g_assert (!strcmp (m_class_get_name (mono_object_class (obj)), "TypeBuilder"));
1768 tb = (MonoReflectionTypeBuilder*)obj;
1769 idx = tb->table_idx;
1770 } else {
1771 g_assert_not_reached ();
1773 break;
1774 case MONO_TABLE_TYPEREF:
1775 g_assert (!strcmp (iltoken_member_class_name, "RuntimeType"));
1776 MonoClass *k;
1777 k = mono_class_from_mono_type_internal (((MonoReflectionType*)iltoken->member)->type);
1778 MonoObject *obj;
1779 obj = &mono_class_get_ref_info_raw (k)->type.object; /* FIXME use handles */
1780 g_assert (obj);
1781 g_assert (!strcmp (m_class_get_name (mono_object_class (obj)), "TypeBuilder"));
1782 g_assert (((MonoReflectionTypeBuilder*)obj)->module->dynamic_image != assembly);
1783 continue;
1784 case MONO_TABLE_MEMBERREF:
1785 if (!strcmp (iltoken_member_class_name, "MonoArrayMethod")) {
1786 am = (MonoReflectionArrayMethod*)iltoken->member;
1787 idx = am->table_idx;
1788 } else if (!strcmp (iltoken_member_class_name, "RuntimeMethodInfo") ||
1789 !strcmp (iltoken_member_class_name, "RuntimeConstructorInfo")) {
1790 MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
1791 g_assert (mono_class_is_ginst (m->klass) || mono_class_is_gtd (m->klass));
1792 continue;
1793 } else if (!strcmp (iltoken_member_class_name, "FieldBuilder")) {
1794 g_assert_not_reached ();
1795 continue;
1796 } else if (!strcmp (iltoken_member_class_name, "RuntimeFieldInfo")) {
1797 continue;
1798 } else if (!strcmp (iltoken_member_class_name, "MethodBuilder") ||
1799 !strcmp (iltoken_member_class_name, "ConstructorBuilder")) {
1800 g_assert_not_reached ();
1801 continue;
1802 } else if (!strcmp (iltoken_member_class_name, "FieldOnTypeBuilderInst")) {
1803 g_assert_not_reached ();
1804 continue;
1805 } else if (!strcmp (iltoken_member_class_name, "MethodOnTypeBuilderInst")) {
1806 g_assert_not_reached ();
1807 continue;
1808 } else if (!strcmp (iltoken_member_class_name, "ConstructorOnTypeBuilderInst")) {
1809 g_assert_not_reached ();
1810 continue;
1811 } else {
1812 g_assert_not_reached ();
1814 break;
1815 case MONO_TABLE_METHODSPEC:
1816 if (!strcmp (iltoken_member_class_name, "RuntimeMethodInfo")) {
1817 MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
1818 g_assert (mono_method_signature_internal (m)->generic_param_count);
1819 continue;
1820 } else if (!strcmp (iltoken_member_class_name, "MethodBuilder")) {
1821 g_assert_not_reached ();
1822 continue;
1823 } else if (!strcmp (iltoken_member_class_name, "MethodOnTypeBuilderInst")) {
1824 g_assert_not_reached ();
1825 continue;
1826 } else {
1827 g_assert_not_reached ();
1829 break;
1830 case MONO_TABLE_TYPESPEC:
1831 if (!strcmp (iltoken_member_class_name, "RuntimeType")) {
1832 continue;
1833 } else {
1834 g_assert_not_reached ();
1836 break;
1837 default:
1838 g_error ("got unexpected table 0x%02x in fixup", target [3]);
1840 target [0] = idx & 0xff;
1841 target [1] = (idx >> 8) & 0xff;
1842 target [2] = (idx >> 16) & 0xff;
1847 * fixup_cattrs:
1849 * The CUSTOM_ATTRIBUTE table might contain METHODDEF tokens whose final
1850 * value is not known when the table is emitted.
1852 static void
1853 fixup_cattrs (MonoDynamicImage *assembly)
1855 MonoDynamicTable *table;
1856 guint32 *values;
1857 guint32 type, i, idx, token;
1858 MonoObject *ctor;
1860 table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1862 for (i = 0; i < table->rows; ++i) {
1863 values = table->values + ((i + 1) * MONO_CUSTOM_ATTR_SIZE);
1865 type = values [MONO_CUSTOM_ATTR_TYPE];
1866 if ((type & MONO_CUSTOM_ATTR_TYPE_MASK) == MONO_CUSTOM_ATTR_TYPE_METHODDEF) {
1867 idx = type >> MONO_CUSTOM_ATTR_TYPE_BITS;
1868 token = mono_metadata_make_token (MONO_TABLE_METHOD, idx);
1869 ctor = (MonoObject *)mono_g_hash_table_lookup (assembly->remapped_tokens, GUINT_TO_POINTER (token));
1870 g_assert (ctor);
1872 if (!strcmp (m_class_get_name (mono_object_class (ctor)), "RuntimeConstructorInfo")) {
1873 MonoMethod *m = ((MonoReflectionMethod*)ctor)->method;
1874 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, m));
1875 values [MONO_CUSTOM_ATTR_TYPE] = (idx << MONO_CUSTOM_ATTR_TYPE_BITS) | MONO_CUSTOM_ATTR_TYPE_METHODDEF;
1876 } else if (!strcmp (m_class_get_name (mono_object_class (ctor)), "ConstructorBuilder")) {
1877 MonoMethod *m = ((MonoReflectionCtorBuilder*)ctor)->mhandle;
1878 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, m));
1879 values [MONO_CUSTOM_ATTR_TYPE] = (idx << MONO_CUSTOM_ATTR_TYPE_BITS) | MONO_CUSTOM_ATTR_TYPE_METHODDEF;
1885 static gboolean
1886 assembly_add_resource_manifest (MonoReflectionModuleBuilder *mb, MonoDynamicImage *assembly, MonoReflectionResource *rsrc, guint32 implementation, MonoError *error)
1888 MonoDynamicTable *table;
1889 guint32 *values;
1891 error_init (error);
1893 table = &assembly->tables [MONO_TABLE_MANIFESTRESOURCE];
1894 table->rows++;
1895 alloc_table (table, table->rows);
1896 values = table->values + table->next_idx * MONO_MANIFEST_SIZE;
1897 values [MONO_MANIFEST_OFFSET] = rsrc->offset;
1898 values [MONO_MANIFEST_FLAGS] = rsrc->attrs;
1899 values [MONO_MANIFEST_NAME] = string_heap_insert_mstring (&assembly->sheap, rsrc->name, error);
1900 return_val_if_nok (error, FALSE);
1901 values [MONO_MANIFEST_IMPLEMENTATION] = implementation;
1902 table->next_idx++;
1903 return TRUE;
1906 static gboolean
1907 assembly_add_resource (MonoReflectionModuleBuilder *mb, MonoDynamicImage *assembly, MonoReflectionResource *rsrc, MonoError *error)
1909 MonoDynamicTable *table;
1910 guint32 *values;
1911 char blob_size [6];
1912 guchar hash [20];
1913 char *b = blob_size;
1914 char *name, *sname;
1915 guint32 idx, offset;
1917 error_init (error);
1919 if (rsrc->filename) {
1920 name = mono_string_to_utf8_checked_internal (rsrc->filename, error);
1921 return_val_if_nok (error, FALSE);
1922 sname = g_path_get_basename (name);
1924 table = &assembly->tables [MONO_TABLE_FILE];
1925 table->rows++;
1926 alloc_table (table, table->rows);
1927 values = table->values + table->next_idx * MONO_FILE_SIZE;
1928 values [MONO_FILE_FLAGS] = FILE_CONTAINS_NO_METADATA;
1929 values [MONO_FILE_NAME] = string_heap_insert (&assembly->sheap, sname);
1930 g_free (sname);
1932 mono_sha1_get_digest_from_file (name, hash);
1933 mono_metadata_encode_value (20, b, &b);
1934 values [MONO_FILE_HASH_VALUE] = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
1935 mono_image_add_stream_data (&assembly->blob, (char*)hash, 20);
1936 g_free (name);
1937 idx = table->next_idx++;
1938 rsrc->offset = 0;
1939 idx = MONO_IMPLEMENTATION_FILE | (idx << MONO_IMPLEMENTATION_BITS);
1940 } else {
1941 char sizebuf [4];
1942 char *data;
1943 guint len;
1944 if (rsrc->data) {
1945 data = mono_array_addr_internal (rsrc->data, char, 0);
1946 len = mono_array_length_internal (rsrc->data);
1947 } else {
1948 data = NULL;
1949 len = 0;
1951 offset = len;
1952 sizebuf [0] = offset; sizebuf [1] = offset >> 8;
1953 sizebuf [2] = offset >> 16; sizebuf [3] = offset >> 24;
1954 rsrc->offset = mono_image_add_stream_data (&assembly->resources, sizebuf, 4);
1955 mono_image_add_stream_data (&assembly->resources, data, len);
1957 if (!mb->is_main)
1959 * The entry should be emitted into the MANIFESTRESOURCE table of
1960 * the main module, but that needs to reference the FILE table
1961 * which isn't emitted yet.
1963 return TRUE;
1964 else
1965 idx = 0;
1968 return assembly_add_resource_manifest (mb, assembly, rsrc, idx, error);
1971 static gboolean
1972 set_version_from_string (MonoString *version, guint32 *values, MonoError *error)
1974 gchar *ver, *p, *str;
1975 guint32 i;
1977 error_init (error);
1979 values [MONO_ASSEMBLY_MAJOR_VERSION] = 0;
1980 values [MONO_ASSEMBLY_MINOR_VERSION] = 0;
1981 values [MONO_ASSEMBLY_REV_NUMBER] = 0;
1982 values [MONO_ASSEMBLY_BUILD_NUMBER] = 0;
1983 if (!version)
1984 return TRUE;
1985 ver = str = mono_string_to_utf8_checked_internal (version, error);
1986 return_val_if_nok (error, FALSE);
1987 for (i = 0; i < 4; ++i) {
1988 values [MONO_ASSEMBLY_MAJOR_VERSION + i] = strtol (ver, &p, 10);
1989 switch (*p) {
1990 case '.':
1991 p++;
1992 break;
1993 case '*':
1994 /* handle Revision and Build */
1995 p++;
1996 break;
1998 ver = p;
2000 g_free (str);
2001 return TRUE;
2004 static guint32
2005 load_public_key (MonoArray *pkey, MonoDynamicImage *assembly) {
2006 gsize len;
2007 guint32 token = 0;
2008 char blob_size [6];
2009 char *b = blob_size;
2011 if (!pkey)
2012 return token;
2014 len = mono_array_length_internal (pkey);
2015 mono_metadata_encode_value (len, b, &b);
2016 token = mono_image_add_stream_data (&assembly->blob, blob_size, b - blob_size);
2017 mono_image_add_stream_data (&assembly->blob, mono_array_addr_internal (pkey, char, 0), len);
2019 assembly->public_key = (guint8 *)g_malloc (len);
2020 memcpy (assembly->public_key, mono_array_addr_internal (pkey, char, 0), len);
2021 assembly->public_key_len = len;
2023 /* Special case: check for ECMA key (16 bytes) */
2024 if ((len == MONO_ECMA_KEY_LENGTH) && mono_is_ecma_key (mono_array_addr_internal (pkey, char, 0), len)) {
2025 /* In this case we must reserve 128 bytes (1024 bits) for the signature */
2026 assembly->strong_name_size = MONO_DEFAULT_PUBLIC_KEY_LENGTH;
2027 } else if (len >= MONO_PUBLIC_KEY_HEADER_LENGTH + MONO_MINIMUM_PUBLIC_KEY_LENGTH) {
2028 /* minimum key size (in 2.0) is 384 bits */
2029 assembly->strong_name_size = len - MONO_PUBLIC_KEY_HEADER_LENGTH;
2030 } else {
2031 /* FIXME - verifier */
2032 g_warning ("Invalid public key length: %d bits (total: %d)", (int)MONO_PUBLIC_KEY_BIT_SIZE (len), (int)len);
2033 assembly->strong_name_size = MONO_DEFAULT_PUBLIC_KEY_LENGTH; /* to be safe */
2035 assembly->strong_name = (char *)g_malloc0 (assembly->strong_name_size);
2037 return token;
2040 static gboolean
2041 mono_image_emit_manifest (MonoReflectionModuleBuilder *moduleb, MonoError *error)
2043 MonoDynamicTable *table;
2044 MonoDynamicImage *assembly;
2045 MonoReflectionAssemblyBuilder *assemblyb;
2046 MonoDomain *domain;
2047 guint32 *values;
2048 int i;
2049 guint32 module_index;
2051 error_init (error);
2053 assemblyb = moduleb->assemblyb;
2054 assembly = moduleb->dynamic_image;
2055 domain = mono_object_domain (assemblyb);
2057 /* Emit ASSEMBLY table */
2058 table = &assembly->tables [MONO_TABLE_ASSEMBLY];
2059 alloc_table (table, 1);
2060 values = table->values + MONO_ASSEMBLY_SIZE;
2061 values [MONO_ASSEMBLY_HASH_ALG] = assemblyb->algid? assemblyb->algid: ASSEMBLY_HASH_SHA1;
2062 values [MONO_ASSEMBLY_NAME] = string_heap_insert_mstring (&assembly->sheap, assemblyb->name, error);
2063 return_val_if_nok (error, FALSE);
2064 if (assemblyb->culture) {
2065 values [MONO_ASSEMBLY_CULTURE] = string_heap_insert_mstring (&assembly->sheap, assemblyb->culture, error);
2066 return_val_if_nok (error, FALSE);
2067 } else {
2068 values [MONO_ASSEMBLY_CULTURE] = string_heap_insert (&assembly->sheap, "");
2070 values [MONO_ASSEMBLY_PUBLIC_KEY] = load_public_key (assemblyb->public_key, assembly);
2071 values [MONO_ASSEMBLY_FLAGS] = assemblyb->flags;
2072 if (!set_version_from_string (assemblyb->version, values, error))
2073 return FALSE;
2075 /* Emit FILE + EXPORTED_TYPE table */
2076 module_index = 0;
2077 for (i = 0; i < mono_array_length_internal (assemblyb->modules); ++i) {
2078 int j;
2079 MonoReflectionModuleBuilder *file_module =
2080 mono_array_get_internal (assemblyb->modules, MonoReflectionModuleBuilder*, i);
2081 if (file_module != moduleb) {
2082 if (!mono_image_fill_file_table (domain, (MonoReflectionModule*)file_module, assembly, error))
2083 return FALSE;
2084 module_index ++;
2085 if (file_module->types) {
2086 for (j = 0; j < file_module->num_types; ++j) {
2087 MonoReflectionTypeBuilder *tb = mono_array_get_internal (file_module->types, MonoReflectionTypeBuilder*, j);
2088 mono_image_fill_export_table (domain, tb, module_index, 0, assembly, error);
2089 return_val_if_nok (error, FALSE);
2094 if (assemblyb->loaded_modules) {
2095 for (i = 0; i < mono_array_length_internal (assemblyb->loaded_modules); ++i) {
2096 MonoReflectionModule *file_module =
2097 mono_array_get_internal (assemblyb->loaded_modules, MonoReflectionModule*, i);
2098 if (!mono_image_fill_file_table (domain, file_module, assembly, error))
2099 return FALSE;
2100 module_index ++;
2101 mono_image_fill_export_table_from_module (domain, file_module, module_index, assembly);
2104 if (assemblyb->type_forwarders)
2105 mono_image_fill_export_table_from_type_forwarders (assemblyb, assembly);
2107 /* Emit MANIFESTRESOURCE table */
2108 module_index = 0;
2109 for (i = 0; i < mono_array_length_internal (assemblyb->modules); ++i) {
2110 int j;
2111 MonoReflectionModuleBuilder *file_module =
2112 mono_array_get_internal (assemblyb->modules, MonoReflectionModuleBuilder*, i);
2113 /* The table for the main module is emitted later */
2114 if (file_module != moduleb) {
2115 module_index ++;
2116 if (file_module->resources) {
2117 int len = mono_array_length_internal (file_module->resources);
2118 for (j = 0; j < len; ++j) {
2119 MonoReflectionResource* res = (MonoReflectionResource*)mono_array_addr_internal (file_module->resources, MonoReflectionResource, j);
2120 if (!assembly_add_resource_manifest (file_module, assembly, res, MONO_IMPLEMENTATION_FILE | (module_index << MONO_IMPLEMENTATION_BITS), error))
2121 return FALSE;
2126 return TRUE;
2129 #ifndef DISABLE_REFLECTION_EMIT_SAVE
2132 * Insert into the metadata tables all the info about the TypeBuilder tb.
2133 * Data in the tables is inserted in a predefined order, since some tables need to be sorted.
2135 static gboolean
2136 mono_image_get_type_info (MonoDomain *domain, MonoReflectionTypeBuilder *tb, MonoDynamicImage *assembly, MonoError *error)
2138 MonoDynamicTable *table;
2139 guint *values;
2140 int i, is_object = 0, is_system = 0;
2141 char *n;
2143 error_init (error);
2145 table = &assembly->tables [MONO_TABLE_TYPEDEF];
2146 values = table->values + tb->table_idx * MONO_TYPEDEF_SIZE;
2147 values [MONO_TYPEDEF_FLAGS] = tb->attrs;
2148 n = mono_string_to_utf8_checked_internal (tb->name, error);
2149 return_val_if_nok (error, FALSE);
2150 if (strcmp (n, "Object") == 0)
2151 is_object++;
2152 values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, n);
2153 g_free (n);
2154 n = mono_string_to_utf8_checked_internal (tb->nspace, error);
2155 return_val_if_nok (error, FALSE);
2156 if (strcmp (n, "System") == 0)
2157 is_system++;
2158 values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, n);
2159 g_free (n);
2160 if (tb->parent && !(is_system && is_object) &&
2161 !(tb->attrs & TYPE_ATTRIBUTE_INTERFACE)) { /* interfaces don't have a parent */
2162 MonoType *parent_type = mono_reflection_type_get_handle ((MonoReflectionType*)tb->parent, error);
2163 return_val_if_nok (error, FALSE);
2164 values [MONO_TYPEDEF_EXTENDS] = mono_image_typedef_or_ref (assembly, parent_type);
2165 } else {
2166 values [MONO_TYPEDEF_EXTENDS] = 0;
2168 values [MONO_TYPEDEF_FIELD_LIST] = assembly->tables [MONO_TABLE_FIELD].next_idx;
2169 values [MONO_TYPEDEF_METHOD_LIST] = assembly->tables [MONO_TABLE_METHOD].next_idx;
2172 * if we have explicitlayout or sequentiallayouts, output data in the
2173 * ClassLayout table.
2175 if (((tb->attrs & TYPE_ATTRIBUTE_LAYOUT_MASK) != TYPE_ATTRIBUTE_AUTO_LAYOUT) &&
2176 ((tb->class_size > 0) || (tb->packing_size > 0))) {
2177 table = &assembly->tables [MONO_TABLE_CLASSLAYOUT];
2178 table->rows++;
2179 alloc_table (table, table->rows);
2180 values = table->values + table->rows * MONO_CLASS_LAYOUT_SIZE;
2181 values [MONO_CLASS_LAYOUT_PARENT] = tb->table_idx;
2182 values [MONO_CLASS_LAYOUT_CLASS_SIZE] = tb->class_size;
2183 values [MONO_CLASS_LAYOUT_PACKING_SIZE] = tb->packing_size;
2186 /* handle interfaces */
2187 if (tb->interfaces) {
2188 table = &assembly->tables [MONO_TABLE_INTERFACEIMPL];
2189 i = table->rows;
2190 table->rows += mono_array_length_internal (tb->interfaces);
2191 alloc_table (table, table->rows);
2192 values = table->values + (i + 1) * MONO_INTERFACEIMPL_SIZE;
2193 for (i = 0; i < mono_array_length_internal (tb->interfaces); ++i) {
2194 MonoReflectionType* iface = (MonoReflectionType*) mono_array_get_internal (tb->interfaces, gpointer, i);
2195 MonoType *iface_type = mono_reflection_type_get_handle (iface, error);
2196 return_val_if_nok (error, FALSE);
2197 values [MONO_INTERFACEIMPL_CLASS] = tb->table_idx;
2198 values [MONO_INTERFACEIMPL_INTERFACE] = mono_image_typedef_or_ref (assembly, iface_type);
2199 values += MONO_INTERFACEIMPL_SIZE;
2203 /* handle fields */
2204 if (tb->fields) {
2205 table = &assembly->tables [MONO_TABLE_FIELD];
2206 table->rows += tb->num_fields;
2207 alloc_table (table, table->rows);
2208 for (i = 0; i < tb->num_fields; ++i) {
2209 mono_image_get_field_info (
2210 mono_array_get_internal (tb->fields, MonoReflectionFieldBuilder*, i), assembly, error);
2211 return_val_if_nok (error, FALSE);
2215 /* handle constructors */
2216 if (tb->ctors) {
2217 table = &assembly->tables [MONO_TABLE_METHOD];
2218 table->rows += mono_array_length_internal (tb->ctors);
2219 alloc_table (table, table->rows);
2220 for (i = 0; i < mono_array_length_internal (tb->ctors); ++i) {
2221 if (!mono_image_get_ctor_info (domain,
2222 mono_array_get_internal (tb->ctors, MonoReflectionCtorBuilder*, i),
2223 assembly, error))
2224 return FALSE;
2228 /* handle methods */
2229 if (tb->methods) {
2230 table = &assembly->tables [MONO_TABLE_METHOD];
2231 table->rows += tb->num_methods;
2232 alloc_table (table, table->rows);
2233 for (i = 0; i < tb->num_methods; ++i) {
2234 if (!mono_image_get_method_info (
2235 mono_array_get_internal (tb->methods, MonoReflectionMethodBuilder*, i), assembly, error))
2236 return FALSE;
2240 /* Do the same with properties etc.. */
2241 if (tb->events && mono_array_length_internal (tb->events)) {
2242 table = &assembly->tables [MONO_TABLE_EVENT];
2243 table->rows += mono_array_length_internal (tb->events);
2244 alloc_table (table, table->rows);
2245 table = &assembly->tables [MONO_TABLE_EVENTMAP];
2246 table->rows ++;
2247 alloc_table (table, table->rows);
2248 values = table->values + table->rows * MONO_EVENT_MAP_SIZE;
2249 values [MONO_EVENT_MAP_PARENT] = tb->table_idx;
2250 values [MONO_EVENT_MAP_EVENTLIST] = assembly->tables [MONO_TABLE_EVENT].next_idx;
2251 for (i = 0; i < mono_array_length_internal (tb->events); ++i) {
2252 mono_image_get_event_info (
2253 mono_array_get_internal (tb->events, MonoReflectionEventBuilder*, i), assembly, error);
2254 return_val_if_nok (error, FALSE);
2257 if (tb->properties && mono_array_length_internal (tb->properties)) {
2258 table = &assembly->tables [MONO_TABLE_PROPERTY];
2259 table->rows += mono_array_length_internal (tb->properties);
2260 alloc_table (table, table->rows);
2261 table = &assembly->tables [MONO_TABLE_PROPERTYMAP];
2262 table->rows ++;
2263 alloc_table (table, table->rows);
2264 values = table->values + table->rows * MONO_PROPERTY_MAP_SIZE;
2265 values [MONO_PROPERTY_MAP_PARENT] = tb->table_idx;
2266 values [MONO_PROPERTY_MAP_PROPERTY_LIST] = assembly->tables [MONO_TABLE_PROPERTY].next_idx;
2267 for (i = 0; i < mono_array_length_internal (tb->properties); ++i) {
2268 mono_image_get_property_info (
2269 mono_array_get_internal (tb->properties, MonoReflectionPropertyBuilder*, i), assembly, error);
2270 return_val_if_nok (error, FALSE);
2274 /* handle generic parameters */
2275 if (tb->generic_params) {
2276 table = &assembly->tables [MONO_TABLE_GENERICPARAM];
2277 table->rows += mono_array_length_internal (tb->generic_params);
2278 alloc_table (table, table->rows);
2279 for (i = 0; i < mono_array_length_internal (tb->generic_params); ++i) {
2280 guint32 owner = MONO_TYPEORMETHOD_TYPE | (tb->table_idx << MONO_TYPEORMETHOD_BITS);
2282 mono_image_get_generic_param_info (
2283 mono_array_get_internal (tb->generic_params, MonoReflectionGenericParam*, i), owner, assembly);
2287 mono_image_add_decl_security (assembly,
2288 mono_metadata_make_token (MONO_TABLE_TYPEDEF, tb->table_idx), tb->permissions);
2290 if (tb->subtypes) {
2291 MonoDynamicTable *ntable;
2293 ntable = &assembly->tables [MONO_TABLE_NESTEDCLASS];
2294 ntable->rows += mono_array_length_internal (tb->subtypes);
2295 alloc_table (ntable, ntable->rows);
2296 values = ntable->values + ntable->next_idx * MONO_NESTED_CLASS_SIZE;
2298 for (i = 0; i < mono_array_length_internal (tb->subtypes); ++i) {
2299 MonoReflectionTypeBuilder *subtype = mono_array_get_internal (tb->subtypes, MonoReflectionTypeBuilder*, i);
2301 values [MONO_NESTED_CLASS_NESTED] = subtype->table_idx;
2302 values [MONO_NESTED_CLASS_ENCLOSING] = tb->table_idx;
2303 /*g_print ("nesting %s (%d) in %s (%d) (rows %d/%d)\n",
2304 mono_string_to_utf8 (subtype->name), subtype->table_idx,
2305 mono_string_to_utf8 (tb->name), tb->table_idx,
2306 ntable->next_idx, ntable->rows);*/
2307 values += MONO_NESTED_CLASS_SIZE;
2308 ntable->next_idx++;
2312 return TRUE;
2317 * mono_image_build_metadata() will fill the info in all the needed metadata tables
2318 * for the modulebuilder @moduleb.
2319 * At the end of the process, method and field tokens are fixed up and the
2320 * on-disk compressed metadata representation is created.
2321 * Return TRUE on success, or FALSE on failure and sets @error
2323 gboolean
2324 mono_image_build_metadata (MonoReflectionModuleBuilder *moduleb, MonoError *error)
2326 MonoDynamicTable *table;
2327 MonoDynamicImage *assembly;
2328 MonoReflectionAssemblyBuilder *assemblyb;
2329 MonoDomain *domain;
2330 MonoPtrArray types;
2331 guint32 *values;
2332 int i, j;
2334 error_init (error);
2336 assemblyb = moduleb->assemblyb;
2337 assembly = moduleb->dynamic_image;
2338 domain = mono_object_domain (assemblyb);
2340 if (assembly->text_rva)
2341 return TRUE;
2343 assembly->text_rva = START_TEXT_RVA;
2345 if (moduleb->is_main) {
2346 mono_image_emit_manifest (moduleb, error);
2347 return_val_if_nok (error, FALSE);
2350 table = &assembly->tables [MONO_TABLE_TYPEDEF];
2351 table->rows = 1; /* .<Module> */
2352 table->next_idx++;
2353 alloc_table (table, table->rows);
2355 * Set the first entry.
2357 values = table->values + table->columns;
2358 values [MONO_TYPEDEF_FLAGS] = 0;
2359 values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, "<Module>") ;
2360 values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, "") ;
2361 values [MONO_TYPEDEF_EXTENDS] = 0;
2362 values [MONO_TYPEDEF_FIELD_LIST] = 1;
2363 values [MONO_TYPEDEF_METHOD_LIST] = 1;
2366 * handle global methods
2367 * FIXME: test what to do when global methods are defined in multiple modules.
2369 if (moduleb->global_methods) {
2370 table = &assembly->tables [MONO_TABLE_METHOD];
2371 table->rows += mono_array_length_internal (moduleb->global_methods);
2372 alloc_table (table, table->rows);
2373 for (i = 0; i < mono_array_length_internal (moduleb->global_methods); ++i) {
2374 if (!mono_image_get_method_info (
2375 mono_array_get_internal (moduleb->global_methods, MonoReflectionMethodBuilder*, i), assembly, error))
2376 goto leave;
2379 if (moduleb->global_fields) {
2380 table = &assembly->tables [MONO_TABLE_FIELD];
2381 table->rows += mono_array_length_internal (moduleb->global_fields);
2382 alloc_table (table, table->rows);
2383 for (i = 0; i < mono_array_length_internal (moduleb->global_fields); ++i) {
2384 mono_image_get_field_info (
2385 mono_array_get_internal (moduleb->global_fields, MonoReflectionFieldBuilder*, i), assembly,
2386 error);
2387 goto_if_nok (error, leave);
2391 table = &assembly->tables [MONO_TABLE_MODULE];
2392 alloc_table (table, 1);
2393 mono_image_fill_module_table (domain, moduleb, assembly, error);
2394 goto_if_nok (error, leave);
2396 /* Collect all types into a list sorted by their table_idx */
2397 mono_ptr_array_init (types, moduleb->num_types, MONO_ROOT_SOURCE_REFLECTION, NULL, "Reflection Dynamic Image Type List");
2399 if (moduleb->types)
2400 for (i = 0; i < moduleb->num_types; ++i) {
2401 MonoReflectionTypeBuilder *type = mono_array_get_internal (moduleb->types, MonoReflectionTypeBuilder*, i);
2402 collect_types (&types, type);
2405 mono_ptr_array_sort (types, (int (*)(const void *, const void *))compare_types_by_table_idx);
2406 table = &assembly->tables [MONO_TABLE_TYPEDEF];
2407 table->rows += mono_ptr_array_size (types);
2408 alloc_table (table, table->rows);
2411 * Emit type names + namespaces at one place inside the string heap,
2412 * so load_class_names () needs to touch fewer pages.
2414 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2415 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2416 string_heap_insert_mstring (&assembly->sheap, tb->nspace, error);
2417 goto_if_nok (error, leave_types);
2419 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2420 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2421 string_heap_insert_mstring (&assembly->sheap, tb->name, error);
2422 goto_if_nok (error, leave_types);
2425 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2426 MonoReflectionTypeBuilder *type = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2427 if (!mono_image_get_type_info (domain, type, assembly, error))
2428 goto leave_types;
2432 * table->rows is already set above and in mono_image_fill_module_table.
2434 /* add all the custom attributes at the end, once all the indexes are stable */
2435 if (!mono_image_add_cattrs (assembly, 1, MONO_CUSTOM_ATTR_ASSEMBLY, assemblyb->cattrs, error))
2436 goto leave_types;
2438 /* CAS assembly permissions */
2439 if (assemblyb->permissions_minimum)
2440 mono_image_add_decl_security (assembly, mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1), assemblyb->permissions_minimum);
2441 if (assemblyb->permissions_optional)
2442 mono_image_add_decl_security (assembly, mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1), assemblyb->permissions_optional);
2443 if (assemblyb->permissions_refused)
2444 mono_image_add_decl_security (assembly, mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1), assemblyb->permissions_refused);
2446 if (!module_add_cattrs (assembly, moduleb, error))
2447 goto leave_types;
2449 /* fixup tokens */
2450 mono_g_hash_table_foreach (assembly->token_fixups, (GHFunc)fixup_method, assembly);
2452 /* Create the MethodImpl table. We do this after emitting all methods so we already know
2453 * the final tokens and don't need another fixup pass. */
2455 if (moduleb->global_methods) {
2456 for (i = 0; i < mono_array_length_internal (moduleb->global_methods); ++i) {
2457 MonoReflectionMethodBuilder *mb = mono_array_get_internal (
2458 moduleb->global_methods, MonoReflectionMethodBuilder*, i);
2459 if (!mono_image_add_methodimpl (assembly, mb, error))
2460 goto leave_types;
2464 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2465 MonoReflectionTypeBuilder *type = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2466 if (type->methods) {
2467 for (j = 0; j < type->num_methods; ++j) {
2468 MonoReflectionMethodBuilder *mb = mono_array_get_internal (
2469 type->methods, MonoReflectionMethodBuilder*, j);
2471 if (!mono_image_add_methodimpl (assembly, mb, error))
2472 goto leave_types;
2477 fixup_cattrs (assembly);
2479 leave_types:
2480 mono_ptr_array_destroy (types);
2481 leave:
2483 return mono_error_ok (error);
2486 #else /* DISABLE_REFLECTION_EMIT_SAVE */
2488 gboolean
2489 mono_image_build_metadata (MonoReflectionModuleBuilder *moduleb, MonoError *error)
2491 g_error ("This mono runtime was configured with --enable-minimal=reflection_emit_save, so saving of dynamic assemblies is not supported.");
2494 #endif /* DISABLE_REFLECTION_EMIT_SAVE */
2496 #ifndef DISABLE_REFLECTION_EMIT_SAVE
2498 static int
2499 calc_section_size (MonoDynamicImage *assembly)
2501 int nsections = 0;
2503 /* alignment constraints */
2504 mono_image_add_stream_zero (&assembly->code, 4 - (assembly->code.index % 4));
2505 g_assert ((assembly->code.index % 4) == 0);
2506 assembly->meta_size += 3;
2507 assembly->meta_size &= ~3;
2508 mono_image_add_stream_zero (&assembly->resources, 4 - (assembly->resources.index % 4));
2509 g_assert ((assembly->resources.index % 4) == 0);
2511 assembly->sections [MONO_SECTION_TEXT].size = assembly->meta_size + assembly->code.index + assembly->resources.index + assembly->strong_name_size;
2512 assembly->sections [MONO_SECTION_TEXT].attrs = SECT_FLAGS_HAS_CODE | SECT_FLAGS_MEM_EXECUTE | SECT_FLAGS_MEM_READ;
2513 nsections++;
2515 if (assembly->win32_res) {
2516 guint32 res_size = (assembly->win32_res_size + 3) & ~3;
2518 assembly->sections [MONO_SECTION_RSRC].size = res_size;
2519 assembly->sections [MONO_SECTION_RSRC].attrs = SECT_FLAGS_HAS_INITIALIZED_DATA | SECT_FLAGS_MEM_READ;
2520 nsections++;
2523 assembly->sections [MONO_SECTION_RELOC].size = 12;
2524 assembly->sections [MONO_SECTION_RELOC].attrs = SECT_FLAGS_MEM_READ | SECT_FLAGS_MEM_DISCARDABLE | SECT_FLAGS_HAS_INITIALIZED_DATA;
2525 nsections++;
2527 return nsections;
2530 typedef struct {
2531 guint32 id;
2532 guint32 offset;
2533 GSList *children;
2534 MonoReflectionWin32Resource *win32_res; /* Only for leaf nodes */
2535 } ResTreeNode;
2537 static int
2538 resource_tree_compare_by_id (gconstpointer a, gconstpointer b)
2540 ResTreeNode *t1 = (ResTreeNode*)a;
2541 ResTreeNode *t2 = (ResTreeNode*)b;
2543 return t1->id - t2->id;
2547 * resource_tree_create:
2549 * Organize the resources into a resource tree.
2551 static ResTreeNode *
2552 resource_tree_create (MonoArray *win32_resources)
2554 ResTreeNode *tree, *res_node, *type_node, *lang_node;
2555 GSList *l;
2556 int i;
2558 tree = g_new0 (ResTreeNode, 1);
2560 for (i = 0; i < mono_array_length_internal (win32_resources); ++i) {
2561 MonoReflectionWin32Resource *win32_res =
2562 (MonoReflectionWin32Resource*)mono_array_addr_internal (win32_resources, MonoReflectionWin32Resource, i);
2564 /* Create node */
2566 /* FIXME: BUG: this stores managed references in unmanaged memory */
2567 lang_node = g_new0 (ResTreeNode, 1);
2568 lang_node->id = win32_res->lang_id;
2569 lang_node->win32_res = win32_res;
2571 /* Create type node if neccesary */
2572 type_node = NULL;
2573 for (l = tree->children; l; l = l->next)
2574 if (((ResTreeNode*)(l->data))->id == win32_res->res_type) {
2575 type_node = (ResTreeNode*)l->data;
2576 break;
2579 if (!type_node) {
2580 type_node = g_new0 (ResTreeNode, 1);
2581 type_node->id = win32_res->res_type;
2584 * The resource types have to be sorted otherwise
2585 * Windows Explorer can't display the version information.
2587 tree->children = g_slist_insert_sorted (tree->children,
2588 type_node, resource_tree_compare_by_id);
2591 /* Create res node if neccesary */
2592 res_node = NULL;
2593 for (l = type_node->children; l; l = l->next)
2594 if (((ResTreeNode*)(l->data))->id == win32_res->res_id) {
2595 res_node = (ResTreeNode*)l->data;
2596 break;
2599 if (!res_node) {
2600 res_node = g_new0 (ResTreeNode, 1);
2601 res_node->id = win32_res->res_id;
2602 type_node->children = g_slist_append (type_node->children, res_node);
2605 res_node->children = g_slist_append (res_node->children, lang_node);
2608 return tree;
2612 * resource_tree_encode:
2614 * Encode the resource tree into the format used in the PE file.
2616 static void
2617 resource_tree_encode (ResTreeNode *node, char *begin, char *p, char **endbuf)
2619 char *entries;
2620 MonoPEResourceDir dir;
2621 MonoPEResourceDirEntry dir_entry;
2622 MonoPEResourceDataEntry data_entry;
2623 GSList *l;
2624 guint32 res_id_entries;
2627 * For the format of the resource directory, see the article
2628 * "An In-Depth Look into the Win32 Portable Executable File Format" by
2629 * Matt Pietrek
2632 memset (&dir, 0, sizeof (dir));
2633 memset (&dir_entry, 0, sizeof (dir_entry));
2634 memset (&data_entry, 0, sizeof (data_entry));
2636 g_assert (sizeof (dir) == 16);
2637 g_assert (sizeof (dir_entry) == 8);
2638 g_assert (sizeof (data_entry) == 16);
2640 node->offset = p - begin;
2642 /* IMAGE_RESOURCE_DIRECTORY */
2643 res_id_entries = g_slist_length (node->children);
2644 dir.res_id_entries = GUINT16_TO_LE (res_id_entries);
2646 memcpy (p, &dir, sizeof (dir));
2647 p += sizeof (dir);
2649 /* Reserve space for entries */
2650 entries = p;
2651 p += sizeof (dir_entry) * res_id_entries;
2653 /* Write children */
2654 for (l = node->children; l; l = l->next) {
2655 ResTreeNode *child = (ResTreeNode*)l->data;
2657 if (child->win32_res) {
2658 guint32 size;
2660 child->offset = p - begin;
2662 /* IMAGE_RESOURCE_DATA_ENTRY */
2663 data_entry.rde_data_offset = GUINT32_TO_LE (p - begin + sizeof (data_entry));
2664 size = mono_array_length_internal (child->win32_res->res_data);
2665 data_entry.rde_size = GUINT32_TO_LE (size);
2667 memcpy (p, &data_entry, sizeof (data_entry));
2668 p += sizeof (data_entry);
2670 memcpy (p, mono_array_addr_internal (child->win32_res->res_data, char, 0), size);
2671 p += size;
2672 } else {
2673 resource_tree_encode (child, begin, p, &p);
2677 /* IMAGE_RESOURCE_ENTRY */
2678 for (l = node->children; l; l = l->next) {
2679 ResTreeNode *child = (ResTreeNode*)l->data;
2681 MONO_PE_RES_DIR_ENTRY_SET_NAME (dir_entry, FALSE, child->id);
2682 MONO_PE_RES_DIR_ENTRY_SET_DIR (dir_entry, !child->win32_res, child->offset);
2684 memcpy (entries, &dir_entry, sizeof (dir_entry));
2685 entries += sizeof (dir_entry);
2688 *endbuf = p;
2691 static void
2692 resource_tree_free (ResTreeNode * node)
2694 GSList * list;
2695 for (list = node->children; list; list = list->next)
2696 resource_tree_free ((ResTreeNode*)list->data);
2697 g_slist_free(node->children);
2698 g_free (node);
2701 static void
2702 assembly_add_win32_resources (MonoDynamicImage *assembly, MonoReflectionAssemblyBuilder *assemblyb)
2704 char *buf;
2705 char *p;
2706 guint32 size, i;
2707 MonoReflectionWin32Resource *win32_res;
2708 ResTreeNode *tree;
2710 if (!assemblyb->win32_resources)
2711 return;
2714 * Resources are stored in a three level tree inside the PE file.
2715 * - level one contains a node for each type of resource
2716 * - level two contains a node for each resource
2717 * - level three contains a node for each instance of a resource for a
2718 * specific language.
2721 tree = resource_tree_create (assemblyb->win32_resources);
2723 /* Estimate the size of the encoded tree */
2724 size = 0;
2725 for (i = 0; i < mono_array_length_internal (assemblyb->win32_resources); ++i) {
2726 win32_res = (MonoReflectionWin32Resource*)mono_array_addr_internal (assemblyb->win32_resources, MonoReflectionWin32Resource, i);
2727 size += mono_array_length_internal (win32_res->res_data);
2729 /* Directory structure */
2730 size += mono_array_length_internal (assemblyb->win32_resources) * 256;
2731 p = buf = (char *)g_malloc (size);
2733 resource_tree_encode (tree, p, p, &p);
2735 g_assert (p - buf <= size);
2737 assembly->win32_res = (char *)g_malloc (p - buf);
2738 assembly->win32_res_size = p - buf;
2739 memcpy (assembly->win32_res, buf, p - buf);
2741 g_free (buf);
2742 resource_tree_free (tree);
2745 static void
2746 fixup_resource_directory (char *res_section, char *p, guint32 rva)
2748 MonoPEResourceDir *dir = (MonoPEResourceDir*)p;
2749 int i;
2751 p += sizeof (MonoPEResourceDir);
2752 for (i = 0; i < GUINT16_FROM_LE (dir->res_named_entries) + GUINT16_FROM_LE (dir->res_id_entries); ++i) {
2753 MonoPEResourceDirEntry *dir_entry = (MonoPEResourceDirEntry*)p;
2754 char *child = res_section + MONO_PE_RES_DIR_ENTRY_DIR_OFFSET (*dir_entry);
2755 if (MONO_PE_RES_DIR_ENTRY_IS_DIR (*dir_entry)) {
2756 fixup_resource_directory (res_section, child, rva);
2757 } else {
2758 MonoPEResourceDataEntry *data_entry = (MonoPEResourceDataEntry*)child;
2759 data_entry->rde_data_offset = GUINT32_TO_LE (GUINT32_FROM_LE (data_entry->rde_data_offset) + rva);
2762 p += sizeof (MonoPEResourceDirEntry);
2766 static void
2767 checked_write_file (HANDLE f, gconstpointer buffer, guint32 numbytes)
2769 guint32 dummy;
2770 gint32 win32error = 0;
2771 if (!mono_w32file_write (f, buffer, numbytes, &dummy, &win32error))
2772 g_error ("mono_w32file_write returned %d\n", win32error);
2776 * mono_image_create_pefile:
2777 * @mb: a module builder object
2779 * This function creates the PE-COFF header, the image sections, the CLI header * etc. all the data is written in
2780 * assembly->pefile where it can be easily retrieved later in chunks.
2782 gboolean
2783 mono_image_create_pefile (MonoReflectionModuleBuilder *mb, HANDLE file, MonoError *error)
2785 MonoMSDOSHeader *msdos;
2786 MonoDotNetHeader *header;
2787 MonoSectionTable *section;
2788 MonoCLIHeader *cli_header;
2789 guint32 size, image_size, virtual_base, text_offset;
2790 guint32 header_start, section_start, file_offset, virtual_offset;
2791 MonoDynamicImage *assembly;
2792 MonoReflectionAssemblyBuilder *assemblyb;
2793 MonoDynamicStream pefile_stream = {0};
2794 MonoDynamicStream *pefile = &pefile_stream;
2795 int i, nsections;
2796 guint32 *rva, value;
2797 guchar *p;
2798 static const unsigned char msheader[] = {
2799 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
2800 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2801 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2802 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
2803 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68,
2804 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f,
2805 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,
2806 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
2809 error_init (error);
2811 assemblyb = mb->assemblyb;
2813 mono_reflection_dynimage_basic_init (assemblyb, error);
2814 return_val_if_nok (error, FALSE);
2815 assembly = mb->dynamic_image;
2817 assembly->pe_kind = assemblyb->pe_kind;
2818 assembly->machine = assemblyb->machine;
2819 ((MonoDynamicImage*)assemblyb->dynamic_assembly->assembly.image)->pe_kind = assemblyb->pe_kind;
2820 ((MonoDynamicImage*)assemblyb->dynamic_assembly->assembly.image)->machine = assemblyb->machine;
2822 if (!mono_image_build_metadata (mb, error))
2823 return FALSE;
2826 if (mb->is_main && assemblyb->resources) {
2827 int len = mono_array_length_internal (assemblyb->resources);
2828 for (i = 0; i < len; ++i) {
2829 if (!assembly_add_resource (mb, assembly, (MonoReflectionResource*)mono_array_addr_internal (assemblyb->resources, MonoReflectionResource, i), error))
2830 return FALSE;
2834 if (mb->resources) {
2835 int len = mono_array_length_internal (mb->resources);
2836 for (i = 0; i < len; ++i) {
2837 if (!assembly_add_resource (mb, assembly, (MonoReflectionResource*)mono_array_addr_internal (mb->resources, MonoReflectionResource, i), error))
2838 return FALSE;
2842 if (!build_compressed_metadata (assembly, error))
2843 return FALSE;
2845 if (mb->is_main)
2846 assembly_add_win32_resources (assembly, assemblyb);
2848 nsections = calc_section_size (assembly);
2850 /* The DOS header and stub */
2851 g_assert (sizeof (MonoMSDOSHeader) == sizeof (msheader));
2852 mono_image_add_stream_data (pefile, (char*)msheader, sizeof (msheader));
2854 /* the dotnet header */
2855 header_start = mono_image_add_stream_zero (pefile, sizeof (MonoDotNetHeader));
2857 /* the section tables */
2858 section_start = mono_image_add_stream_zero (pefile, sizeof (MonoSectionTable) * nsections);
2860 file_offset = section_start + sizeof (MonoSectionTable) * nsections;
2861 virtual_offset = VIRT_ALIGN;
2862 image_size = 0;
2864 for (i = 0; i < MONO_SECTION_MAX; ++i) {
2865 if (!assembly->sections [i].size)
2866 continue;
2867 /* align offsets */
2868 file_offset += FILE_ALIGN - 1;
2869 file_offset &= ~(FILE_ALIGN - 1);
2870 virtual_offset += VIRT_ALIGN - 1;
2871 virtual_offset &= ~(VIRT_ALIGN - 1);
2873 assembly->sections [i].offset = file_offset;
2874 assembly->sections [i].rva = virtual_offset;
2876 file_offset += assembly->sections [i].size;
2877 virtual_offset += assembly->sections [i].size;
2878 image_size += (assembly->sections [i].size + VIRT_ALIGN - 1) & ~(VIRT_ALIGN - 1);
2881 file_offset += FILE_ALIGN - 1;
2882 file_offset &= ~(FILE_ALIGN - 1);
2884 image_size += section_start + sizeof (MonoSectionTable) * nsections;
2886 /* back-patch info */
2887 msdos = (MonoMSDOSHeader*)pefile->data;
2888 msdos->pe_offset = GUINT32_FROM_LE (sizeof (MonoMSDOSHeader));
2890 header = (MonoDotNetHeader*)(pefile->data + header_start);
2891 header->pesig [0] = 'P';
2892 header->pesig [1] = 'E';
2894 header->coff.coff_machine = GUINT16_FROM_LE (assemblyb->machine);
2895 header->coff.coff_sections = GUINT16_FROM_LE (nsections);
2896 header->coff.coff_time = GUINT32_FROM_LE (time (NULL));
2897 header->coff.coff_opt_header_size = GUINT16_FROM_LE (sizeof (MonoDotNetHeader) - sizeof (MonoCOFFHeader) - 4);
2898 if (assemblyb->pekind == 1) {
2899 /* it's a dll */
2900 header->coff.coff_attributes = GUINT16_FROM_LE (0x210e);
2901 } else {
2902 /* it's an exe */
2903 header->coff.coff_attributes = GUINT16_FROM_LE (0x010e);
2906 virtual_base = 0x400000; /* FIXME: 0x10000000 if a DLL */
2908 header->pe.pe_magic = GUINT16_FROM_LE (0x10B);
2909 header->pe.pe_major = 6;
2910 header->pe.pe_minor = 0;
2911 size = assembly->sections [MONO_SECTION_TEXT].size;
2912 size += FILE_ALIGN - 1;
2913 size &= ~(FILE_ALIGN - 1);
2914 header->pe.pe_code_size = GUINT32_FROM_LE(size);
2915 size = assembly->sections [MONO_SECTION_RSRC].size;
2916 size += FILE_ALIGN - 1;
2917 size &= ~(FILE_ALIGN - 1);
2918 header->pe.pe_data_size = GUINT32_FROM_LE(size);
2919 g_assert (START_TEXT_RVA == assembly->sections [MONO_SECTION_TEXT].rva);
2920 header->pe.pe_rva_code_base = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_TEXT].rva);
2921 header->pe.pe_rva_data_base = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].rva);
2922 /* pe_rva_entry_point always at the beginning of the text section */
2923 header->pe.pe_rva_entry_point = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_TEXT].rva);
2925 header->nt.pe_image_base = GUINT32_FROM_LE (virtual_base);
2926 header->nt.pe_section_align = GUINT32_FROM_LE (VIRT_ALIGN);
2927 header->nt.pe_file_alignment = GUINT32_FROM_LE (FILE_ALIGN);
2928 header->nt.pe_os_major = GUINT16_FROM_LE (4);
2929 header->nt.pe_os_minor = GUINT16_FROM_LE (0);
2930 header->nt.pe_subsys_major = GUINT16_FROM_LE (4);
2931 size = section_start;
2932 size += FILE_ALIGN - 1;
2933 size &= ~(FILE_ALIGN - 1);
2934 header->nt.pe_header_size = GUINT32_FROM_LE (size);
2935 size = image_size;
2936 size += VIRT_ALIGN - 1;
2937 size &= ~(VIRT_ALIGN - 1);
2938 header->nt.pe_image_size = GUINT32_FROM_LE (size);
2941 // Translate the PEFileKind value to the value expected by the Windows loader
2944 short kind;
2947 // PEFileKinds.Dll == 1
2948 // PEFileKinds.ConsoleApplication == 2
2949 // PEFileKinds.WindowApplication == 3
2951 // need to get:
2952 // IMAGE_SUBSYSTEM_WINDOWS_GUI 2 // Image runs in the Windows GUI subsystem.
2953 // IMAGE_SUBSYSTEM_WINDOWS_CUI 3 // Image runs in the Windows character subsystem.
2955 if (assemblyb->pekind == 3)
2956 kind = 2;
2957 else
2958 kind = 3;
2960 header->nt.pe_subsys_required = GUINT16_FROM_LE (kind);
2962 header->nt.pe_stack_reserve = GUINT32_FROM_LE (0x00100000);
2963 header->nt.pe_stack_commit = GUINT32_FROM_LE (0x00001000);
2964 header->nt.pe_heap_reserve = GUINT32_FROM_LE (0x00100000);
2965 header->nt.pe_heap_commit = GUINT32_FROM_LE (0x00001000);
2966 header->nt.pe_loader_flags = GUINT32_FROM_LE (0);
2967 header->nt.pe_data_dir_count = GUINT32_FROM_LE (16);
2969 /* fill data directory entries */
2971 header->datadir.pe_resource_table.size = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].size);
2972 header->datadir.pe_resource_table.rva = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].rva);
2974 header->datadir.pe_reloc_table.size = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RELOC].size);
2975 header->datadir.pe_reloc_table.rva = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RELOC].rva);
2977 header->datadir.pe_cli_header.size = GUINT32_FROM_LE (72);
2978 header->datadir.pe_cli_header.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->cli_header_offset);
2979 header->datadir.pe_iat.size = GUINT32_FROM_LE (8);
2980 header->datadir.pe_iat.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->iat_offset);
2981 /* patch entrypoint name */
2982 if (assemblyb->pekind == 1)
2983 memcpy (assembly->code.data + assembly->imp_names_offset + 2, "_CorDllMain", 12);
2984 else
2985 memcpy (assembly->code.data + assembly->imp_names_offset + 2, "_CorExeMain", 12);
2986 /* patch imported function RVA name */
2987 rva = (guint32*)(assembly->code.data + assembly->iat_offset);
2988 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->imp_names_offset);
2990 /* the import table */
2991 header->datadir.pe_import_table.size = GUINT32_FROM_LE (79); /* FIXME: magic number? */
2992 header->datadir.pe_import_table.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->idt_offset);
2993 /* patch imported dll RVA name and other entries in the dir */
2994 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, name_rva));
2995 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->imp_names_offset + 14); /* 14 is hint+strlen+1 of func name */
2996 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, import_address_table_rva));
2997 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->iat_offset);
2998 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, import_lookup_table));
2999 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->ilt_offset);
3001 p = (guchar*)(assembly->code.data + assembly->ilt_offset);
3002 value = (assembly->text_rva + assembly->imp_names_offset);
3003 *p++ = (value) & 0xff;
3004 *p++ = (value >> 8) & (0xff);
3005 *p++ = (value >> 16) & (0xff);
3006 *p++ = (value >> 24) & (0xff);
3008 /* the CLI header info */
3009 cli_header = (MonoCLIHeader*)(assembly->code.data + assembly->cli_header_offset);
3010 cli_header->ch_size = GUINT32_FROM_LE (72);
3011 cli_header->ch_runtime_major = GUINT16_FROM_LE (2);
3012 cli_header->ch_runtime_minor = GUINT16_FROM_LE (5);
3013 cli_header->ch_flags = GUINT32_FROM_LE (assemblyb->pe_kind);
3014 if (assemblyb->entry_point) {
3015 guint32 table_idx = 0;
3016 if (!strcmp (m_class_get_name (mono_object_class (&assemblyb->entry_point->object)), "MethodBuilder")) {
3017 MonoReflectionMethodBuilder *methodb = (MonoReflectionMethodBuilder*)assemblyb->entry_point;
3018 table_idx = methodb->table_idx;
3019 } else {
3020 table_idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, assemblyb->entry_point->method));
3022 cli_header->ch_entry_point = GUINT32_FROM_LE (table_idx | MONO_TOKEN_METHOD_DEF);
3023 } else {
3024 cli_header->ch_entry_point = GUINT32_FROM_LE (0);
3026 /* The embedded managed resources */
3027 text_offset = assembly->text_rva + assembly->code.index;
3028 cli_header->ch_resources.rva = GUINT32_FROM_LE (text_offset);
3029 cli_header->ch_resources.size = GUINT32_FROM_LE (assembly->resources.index);
3030 text_offset += assembly->resources.index;
3031 cli_header->ch_metadata.rva = GUINT32_FROM_LE (text_offset);
3032 cli_header->ch_metadata.size = GUINT32_FROM_LE (assembly->meta_size);
3033 text_offset += assembly->meta_size;
3034 if (assembly->strong_name_size) {
3035 cli_header->ch_strong_name.rva = GUINT32_FROM_LE (text_offset);
3036 cli_header->ch_strong_name.size = GUINT32_FROM_LE (assembly->strong_name_size);
3037 text_offset += assembly->strong_name_size;
3040 /* write the section tables and section content */
3041 section = (MonoSectionTable*)(pefile->data + section_start);
3042 for (i = 0; i < MONO_SECTION_MAX; ++i) {
3043 static const char section_names [][7] = {
3044 ".text", ".rsrc", ".reloc"
3046 if (!assembly->sections [i].size)
3047 continue;
3048 strcpy (section->st_name, section_names [i]);
3049 /*g_print ("output section %s (%d), size: %d\n", section->st_name, i, assembly->sections [i].size);*/
3050 section->st_virtual_address = GUINT32_FROM_LE (assembly->sections [i].rva);
3051 section->st_virtual_size = GUINT32_FROM_LE (assembly->sections [i].size);
3052 section->st_raw_data_size = GUINT32_FROM_LE (GUINT32_TO_LE (section->st_virtual_size) + (FILE_ALIGN - 1));
3053 section->st_raw_data_size &= GUINT32_FROM_LE (~(FILE_ALIGN - 1));
3054 section->st_raw_data_ptr = GUINT32_FROM_LE (assembly->sections [i].offset);
3055 section->st_flags = GUINT32_FROM_LE (assembly->sections [i].attrs);
3056 section ++;
3059 checked_write_file (file, pefile->data, pefile->index);
3061 mono_dynamic_stream_reset (pefile);
3063 for (i = 0; i < MONO_SECTION_MAX; ++i) {
3064 if (!assembly->sections [i].size)
3065 continue;
3067 if (mono_w32file_seek (file, assembly->sections [i].offset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
3068 g_error ("mono_w32file_seek returned %d\n", mono_w32error_get_last ());
3070 switch (i) {
3071 case MONO_SECTION_TEXT:
3072 /* patch entry point */
3073 p = (guchar*)(assembly->code.data + 2);
3074 value = (virtual_base + assembly->text_rva + assembly->iat_offset);
3075 *p++ = (value) & 0xff;
3076 *p++ = (value >> 8) & 0xff;
3077 *p++ = (value >> 16) & 0xff;
3078 *p++ = (value >> 24) & 0xff;
3080 checked_write_file (file, assembly->code.data, assembly->code.index);
3081 checked_write_file (file, assembly->resources.data, assembly->resources.index);
3082 checked_write_file (file, assembly->image.raw_metadata, assembly->meta_size);
3083 checked_write_file (file, assembly->strong_name, assembly->strong_name_size);
3086 g_free (assembly->image.raw_metadata);
3087 break;
3088 case MONO_SECTION_RELOC: {
3089 struct {
3090 guint32 page_rva;
3091 guint32 block_size;
3092 guint16 type_and_offset;
3093 guint16 term;
3094 } reloc;
3096 g_assert (sizeof (reloc) == 12);
3098 reloc.page_rva = GUINT32_FROM_LE (assembly->text_rva);
3099 reloc.block_size = GUINT32_FROM_LE (12);
3102 * the entrypoint is always at the start of the text section
3103 * 3 is IMAGE_REL_BASED_HIGHLOW
3104 * 2 is patch_size_rva - text_rva
3106 reloc.type_and_offset = GUINT16_FROM_LE ((3 << 12) + (2));
3107 reloc.term = 0;
3109 checked_write_file (file, &reloc, sizeof (reloc));
3111 break;
3113 case MONO_SECTION_RSRC:
3114 if (assembly->win32_res) {
3116 /* Fixup the offsets in the IMAGE_RESOURCE_DATA_ENTRY structures */
3117 fixup_resource_directory (assembly->win32_res, assembly->win32_res, assembly->sections [i].rva);
3118 checked_write_file (file, assembly->win32_res, assembly->win32_res_size);
3120 break;
3121 default:
3122 g_assert_not_reached ();
3126 /* check that the file is properly padded */
3127 if (mono_w32file_seek (file, file_offset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
3128 g_error ("mono_w32file_seek returned %d\n", mono_w32error_get_last ());
3129 if (! mono_w32file_truncate (file))
3130 g_error ("mono_w32file_truncate returned %d\n", mono_w32error_get_last ());
3132 mono_dynamic_stream_reset (&assembly->code);
3133 mono_dynamic_stream_reset (&assembly->us);
3134 mono_dynamic_stream_reset (&assembly->blob);
3135 mono_dynamic_stream_reset (&assembly->guid);
3136 mono_dynamic_stream_reset (&assembly->sheap);
3138 g_hash_table_foreach (assembly->blob_cache, (GHFunc)g_free, NULL);
3139 g_hash_table_destroy (assembly->blob_cache);
3140 assembly->blob_cache = NULL;
3142 return TRUE;
3145 #else /* DISABLE_REFLECTION_EMIT_SAVE */
3147 gboolean
3148 mono_image_create_pefile (MonoReflectionModuleBuilder *mb, HANDLE file, MonoError *error)
3150 g_assert_not_reached ();
3153 #endif /* DISABLE_REFLECTION_EMIT_SAVE */