[System] Tweak socket test
[mono-project.git] / mono / metadata / sre-save.c
blob20d9e47a4a3945453e3fdd0d96653f273a3722c2
1 /*
2 * sre-save.c: Routine for saving an image to a file.
3 *
4 *
5 * Author:
6 * Paolo Molaro (lupus@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
10 * Copyright 2011 Rodrigo Kumpera
11 * Copyright 2016 Microsoft
13 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
16 #include <config.h>
17 #include <glib.h>
19 #include "mono/metadata/dynamic-image-internals.h"
20 #include "mono/metadata/dynamic-stream-internals.h"
21 #include "mono/metadata/mono-ptr-array.h"
22 #include "mono/metadata/object-internals.h"
23 #include "mono/metadata/sre-internals.h"
24 #include "mono/metadata/security-manager.h"
25 #include "mono/metadata/tabledefs.h"
26 #include "mono/metadata/tokentype.h"
27 #include "mono/metadata/w32file.h"
28 #include "mono/metadata/w32error.h"
30 #include "mono/utils/checked-build.h"
31 #include "mono/utils/mono-digest.h"
32 #include "mono/utils/mono-error-internals.h"
33 #include "mono/utils/w32api.h"
35 #define TEXT_OFFSET 512
36 #define CLI_H_SIZE 136
37 #define FILE_ALIGN 512
38 #define VIRT_ALIGN 8192
39 #define START_TEXT_RVA 0x00002000
41 static void mono_image_get_generic_param_info (MonoReflectionGenericParam *gparam, guint32 owner, MonoDynamicImage *assembly);
43 static void
44 alloc_table (MonoDynamicTable *table, guint nrows)
46 mono_dynimage_alloc_table (table, nrows);
49 static guint32
50 string_heap_insert (MonoDynamicStream *sh, const char *str)
52 return mono_dynstream_insert_string (sh, str);
55 static guint32
56 string_heap_insert_mstring (MonoDynamicStream *sh, MonoString *str, MonoError *error)
58 return mono_dynstream_insert_mstring (sh, str, error);
61 static guint32
62 mono_image_add_stream_data (MonoDynamicStream *stream, const char *data, guint32 len)
64 return mono_dynstream_add_data (stream, data, len);
67 static guint32
68 mono_image_add_stream_zero (MonoDynamicStream *stream, guint32 len)
70 return mono_dynstream_add_zero (stream, len);
73 static void
74 stream_data_align (MonoDynamicStream *stream)
76 mono_dynstream_data_align (stream);
79 static guint32
80 mono_image_typedef_or_ref (MonoDynamicImage *assembly, MonoType *type)
82 return mono_dynimage_encode_typedef_or_ref_full (assembly, type, TRUE);
85 static guint32
86 find_index_in_table (MonoDynamicImage *assembly, int table_idx, int col, guint32 token)
88 MONO_REQ_GC_NEUTRAL_MODE;
90 int i;
91 MonoDynamicTable *table;
92 guint32 *values;
94 table = &assembly->tables [table_idx];
96 g_assert (col < table->columns);
98 values = table->values + table->columns;
99 for (i = 1; i <= table->rows; ++i) {
100 if (values [col] == token)
101 return i;
102 values += table->columns;
104 return 0;
108 * Copy len * nelem bytes from val to dest, swapping bytes to LE if necessary.
109 * dest may be misaligned.
111 static void
112 swap_with_size (char *dest, const char* val, int len, int nelem) {
113 MONO_REQ_GC_NEUTRAL_MODE;
114 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
115 int elem;
117 for (elem = 0; elem < nelem; ++elem) {
118 switch (len) {
119 case 1:
120 *dest = *val;
121 break;
122 case 2:
123 dest [0] = val [1];
124 dest [1] = val [0];
125 break;
126 case 4:
127 dest [0] = val [3];
128 dest [1] = val [2];
129 dest [2] = val [1];
130 dest [3] = val [0];
131 break;
132 case 8:
133 dest [0] = val [7];
134 dest [1] = val [6];
135 dest [2] = val [5];
136 dest [3] = val [4];
137 dest [4] = val [3];
138 dest [5] = val [2];
139 dest [6] = val [1];
140 dest [7] = val [0];
141 break;
142 default:
143 g_assert_not_reached ();
145 dest += len;
146 val += len;
148 #else
149 memcpy (dest, val, len * nelem);
150 #endif
153 static guint32
154 add_mono_string_to_blob_cached (MonoDynamicImage *assembly, MonoString *str)
156 MONO_REQ_GC_UNSAFE_MODE;
158 char blob_size [64];
159 char *b = blob_size;
160 guint32 idx = 0, len;
162 len = str->length * 2;
163 mono_metadata_encode_value (len, b, &b);
164 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
166 char *swapped = g_malloc (2 * mono_string_length (str));
167 const char *p = (const char*)mono_string_chars (str);
169 swap_with_size (swapped, p, 2, mono_string_length (str));
170 idx = mono_dynamic_image_add_to_blob_cached (assembly, blob_size, b-blob_size, swapped, len);
171 g_free (swapped);
173 #else
174 idx = mono_dynamic_image_add_to_blob_cached (assembly, blob_size, b-blob_size, (char*)mono_string_chars (str), len);
175 #endif
176 return idx;
179 static guint32
180 image_create_token_raw (MonoDynamicImage *assembly, MonoObject* obj_raw, gboolean create_methodspec, gboolean register_token, MonoError *error)
182 HANDLE_FUNCTION_ENTER (); /* FIXME callers of image_create_token_raw should use handles */
183 mono_error_init (error);
184 MONO_HANDLE_DCL (MonoObject, obj);
185 guint32 result = mono_image_create_token (assembly, obj, create_methodspec, register_token, error);
186 HANDLE_FUNCTION_RETURN_VAL (result);
191 * idx is the table index of the object
192 * type is one of MONO_CUSTOM_ATTR_*
194 static gboolean
195 mono_image_add_cattrs (MonoDynamicImage *assembly, guint32 idx, guint32 type, MonoArray *cattrs, MonoError *error)
197 MONO_REQ_GC_UNSAFE_MODE;
199 MonoDynamicTable *table;
200 MonoReflectionCustomAttr *cattr;
201 guint32 *values;
202 guint32 count, i, token;
203 char blob_size [6];
204 char *p = blob_size;
206 mono_error_init (error);
208 /* it is legal to pass a NULL cattrs: we avoid to use the if in a lot of places */
209 if (!cattrs)
210 return TRUE;
211 count = mono_array_length (cattrs);
212 table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
213 table->rows += count;
214 alloc_table (table, table->rows);
215 values = table->values + table->next_idx * MONO_CUSTOM_ATTR_SIZE;
216 idx <<= MONO_CUSTOM_ATTR_BITS;
217 idx |= type;
218 for (i = 0; i < count; ++i) {
219 cattr = (MonoReflectionCustomAttr*)mono_array_get (cattrs, gpointer, i);
220 values [MONO_CUSTOM_ATTR_PARENT] = idx;
221 token = image_create_token_raw (assembly, (MonoObject*)cattr->ctor, FALSE, FALSE, error); /* FIXME use handles */
222 if (!mono_error_ok (error)) goto fail;
223 type = mono_metadata_token_index (token);
224 type <<= MONO_CUSTOM_ATTR_TYPE_BITS;
225 switch (mono_metadata_token_table (token)) {
226 case MONO_TABLE_METHOD:
227 type |= MONO_CUSTOM_ATTR_TYPE_METHODDEF;
229 * fixup_cattrs () needs to fix this up. We can't use image->tokens, since it contains the old token for the
230 * method, not the one returned by mono_image_create_token ().
232 mono_g_hash_table_insert (assembly->remapped_tokens, GUINT_TO_POINTER (token), cattr->ctor);
233 break;
234 case MONO_TABLE_MEMBERREF:
235 type |= MONO_CUSTOM_ATTR_TYPE_MEMBERREF;
236 break;
237 default:
238 g_warning ("got wrong token in custom attr");
239 continue;
241 values [MONO_CUSTOM_ATTR_TYPE] = type;
242 p = blob_size;
243 mono_metadata_encode_value (mono_array_length (cattr->data), p, &p);
244 values [MONO_CUSTOM_ATTR_VALUE] = mono_dynamic_image_add_to_blob_cached (assembly, blob_size, p - blob_size,
245 mono_array_addr (cattr->data, char, 0), mono_array_length (cattr->data));
246 values += MONO_CUSTOM_ATTR_SIZE;
247 ++table->next_idx;
250 return TRUE;
252 fail:
253 return FALSE;
256 static void
257 mono_image_add_decl_security (MonoDynamicImage *assembly, guint32 parent_token, MonoArray *permissions)
259 MONO_REQ_GC_UNSAFE_MODE;
261 MonoDynamicTable *table;
262 guint32 *values;
263 guint32 count, i, idx;
264 MonoReflectionPermissionSet *perm;
266 if (!permissions)
267 return;
269 count = mono_array_length (permissions);
270 table = &assembly->tables [MONO_TABLE_DECLSECURITY];
271 table->rows += count;
272 alloc_table (table, table->rows);
274 for (i = 0; i < mono_array_length (permissions); ++i) {
275 perm = (MonoReflectionPermissionSet*)mono_array_addr (permissions, MonoReflectionPermissionSet, i);
277 values = table->values + table->next_idx * MONO_DECL_SECURITY_SIZE;
279 idx = mono_metadata_token_index (parent_token);
280 idx <<= MONO_HAS_DECL_SECURITY_BITS;
281 switch (mono_metadata_token_table (parent_token)) {
282 case MONO_TABLE_TYPEDEF:
283 idx |= MONO_HAS_DECL_SECURITY_TYPEDEF;
284 break;
285 case MONO_TABLE_METHOD:
286 idx |= MONO_HAS_DECL_SECURITY_METHODDEF;
287 break;
288 case MONO_TABLE_ASSEMBLY:
289 idx |= MONO_HAS_DECL_SECURITY_ASSEMBLY;
290 break;
291 default:
292 g_assert_not_reached ();
295 values [MONO_DECL_SECURITY_ACTION] = perm->action;
296 values [MONO_DECL_SECURITY_PARENT] = idx;
297 values [MONO_DECL_SECURITY_PERMISSIONSET] = add_mono_string_to_blob_cached (assembly, perm->pset);
299 ++table->next_idx;
304 * method_encode_code:
306 * @assembly the assembly
307 * @mb the managed MethodBuilder
308 * @error set on error
310 * Note that the return value is not sensible if @error is set.
312 static guint32
313 method_encode_code (MonoDynamicImage *assembly, ReflectionMethodBuilder *mb, MonoError *error)
315 MONO_REQ_GC_UNSAFE_MODE;
317 char flags = 0;
318 guint32 idx;
319 guint32 code_size;
320 gint32 max_stack, i;
321 gint32 num_locals = 0;
322 gint32 num_exception = 0;
323 gint maybe_small;
324 guint32 fat_flags;
325 char fat_header [12];
326 guint32 int_value;
327 guint16 short_value;
328 guint32 local_sig = 0;
329 guint32 header_size = 12;
330 MonoArray *code;
332 mono_error_init (error);
334 if ((mb->attrs & (METHOD_ATTRIBUTE_PINVOKE_IMPL | METHOD_ATTRIBUTE_ABSTRACT)) ||
335 (mb->iattrs & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)))
336 return 0;
338 /*if (mb->name)
339 g_print ("Encode method %s\n", mono_string_to_utf8 (mb->name));*/
340 if (mb->ilgen) {
341 code = mb->ilgen->code;
342 code_size = mb->ilgen->code_len;
343 max_stack = mb->ilgen->max_stack;
344 num_locals = mb->ilgen->locals ? mono_array_length (mb->ilgen->locals) : 0;
345 if (mb->ilgen->ex_handlers)
346 num_exception = mono_reflection_method_count_clauses (mb->ilgen);
347 } else {
348 code = mb->code;
349 if (code == NULL){
350 MonoError inner_error;
351 char *name = mono_string_to_utf8_checked (mb->name, &inner_error);
352 if (!is_ok (&inner_error)) {
353 name = g_strdup ("");
354 mono_error_cleanup (&inner_error);
356 char *str = g_strdup_printf ("Method %s does not have any IL associated", name);
357 mono_error_set_argument (error, NULL, "a method does not have any IL associated");
358 g_free (str);
359 g_free (name);
360 return 0;
363 code_size = mono_array_length (code);
364 max_stack = 8; /* we probably need to run a verifier on the code... */
367 stream_data_align (&assembly->code);
369 /* check for exceptions, maxstack, locals */
370 maybe_small = (max_stack <= 8) && (!num_locals) && (!num_exception);
371 if (maybe_small) {
372 if (code_size < 64 && !(code_size & 1)) {
373 flags = (code_size << 2) | 0x2;
374 } else if (code_size < 32 && (code_size & 1)) {
375 flags = (code_size << 2) | 0x6; /* LAMESPEC: see metadata.c */
376 } else {
377 goto fat_header;
379 idx = mono_image_add_stream_data (&assembly->code, &flags, 1);
380 /* add to the fixup todo list */
381 if (mb->ilgen && mb->ilgen->num_token_fixups)
382 mono_g_hash_table_insert (assembly->token_fixups, mb->ilgen, GUINT_TO_POINTER (idx + 1));
383 mono_image_add_stream_data (&assembly->code, mono_array_addr (code, char, 0), code_size);
384 return assembly->text_rva + idx;
386 fat_header:
387 if (num_locals) {
388 local_sig = MONO_TOKEN_SIGNATURE | mono_dynimage_encode_locals (assembly, mb->ilgen, error);
389 return_val_if_nok (error, 0);
392 * FIXME: need to set also the header size in fat_flags.
393 * (and more sects and init locals flags)
395 fat_flags = 0x03;
396 if (num_exception)
397 fat_flags |= METHOD_HEADER_MORE_SECTS;
398 if (mb->init_locals)
399 fat_flags |= METHOD_HEADER_INIT_LOCALS;
400 fat_header [0] = fat_flags;
401 fat_header [1] = (header_size / 4 ) << 4;
402 short_value = GUINT16_TO_LE (max_stack);
403 memcpy (fat_header + 2, &short_value, 2);
404 int_value = GUINT32_TO_LE (code_size);
405 memcpy (fat_header + 4, &int_value, 4);
406 int_value = GUINT32_TO_LE (local_sig);
407 memcpy (fat_header + 8, &int_value, 4);
408 idx = mono_image_add_stream_data (&assembly->code, fat_header, 12);
409 /* add to the fixup todo list */
410 if (mb->ilgen && mb->ilgen->num_token_fixups)
411 mono_g_hash_table_insert (assembly->token_fixups, mb->ilgen, GUINT_TO_POINTER (idx + 12));
413 mono_image_add_stream_data (&assembly->code, mono_array_addr (code, char, 0), code_size);
414 if (num_exception) {
415 unsigned char sheader [4];
416 MonoILExceptionInfo * ex_info;
417 MonoILExceptionBlock * ex_block;
418 int j;
420 stream_data_align (&assembly->code);
421 /* always use fat format for now */
422 sheader [0] = METHOD_HEADER_SECTION_FAT_FORMAT | METHOD_HEADER_SECTION_EHTABLE;
423 num_exception *= 6 * sizeof (guint32);
424 num_exception += 4; /* include the size of the header */
425 sheader [1] = num_exception & 0xff;
426 sheader [2] = (num_exception >> 8) & 0xff;
427 sheader [3] = (num_exception >> 16) & 0xff;
428 mono_image_add_stream_data (&assembly->code, (char*)sheader, 4);
429 /* fat header, so we are already aligned */
430 /* reverse order */
431 for (i = mono_array_length (mb->ilgen->ex_handlers) - 1; i >= 0; --i) {
432 ex_info = (MonoILExceptionInfo *)mono_array_addr (mb->ilgen->ex_handlers, MonoILExceptionInfo, i);
433 if (ex_info->handlers) {
434 int finally_start = ex_info->start + ex_info->len;
435 for (j = 0; j < mono_array_length (ex_info->handlers); ++j) {
436 guint32 val;
437 ex_block = (MonoILExceptionBlock*)mono_array_addr (ex_info->handlers, MonoILExceptionBlock, j);
438 /* the flags */
439 val = GUINT32_TO_LE (ex_block->type);
440 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
441 /* try offset */
442 val = GUINT32_TO_LE (ex_info->start);
443 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
444 /* need fault, too, probably */
445 if (ex_block->type == MONO_EXCEPTION_CLAUSE_FINALLY)
446 val = GUINT32_TO_LE (finally_start - ex_info->start);
447 else
448 val = GUINT32_TO_LE (ex_info->len);
449 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
450 /* handler offset */
451 val = GUINT32_TO_LE (ex_block->start);
452 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
453 /* handler len */
454 val = GUINT32_TO_LE (ex_block->len);
455 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
456 finally_start = ex_block->start + ex_block->len;
457 if (ex_block->extype) {
458 MonoType *extype = mono_reflection_type_get_handle ((MonoReflectionType*)ex_block->extype, error);
459 return_val_if_nok (error, 0);
461 val = mono_metadata_token_from_dor (mono_image_typedef_or_ref (assembly, extype));
462 } else {
463 if (ex_block->type == MONO_EXCEPTION_CLAUSE_FILTER)
464 val = ex_block->filter_offset;
465 else
466 val = 0;
468 val = GUINT32_TO_LE (val);
469 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
470 /*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",
471 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);*/
473 } else {
474 g_error ("No clauses for ex info block %d", i);
478 return assembly->text_rva + idx;
482 * Fill in the MethodDef and ParamDef tables for a method.
483 * This is used for both normal methods and constructors.
485 static gboolean
486 mono_image_basic_method (ReflectionMethodBuilder *mb, MonoDynamicImage *assembly, MonoError *error)
488 MONO_REQ_GC_UNSAFE_MODE;
490 MonoDynamicTable *table;
491 guint32 *values;
492 guint i, count;
494 mono_error_init (error);
496 /* room in this table is already allocated */
497 table = &assembly->tables [MONO_TABLE_METHOD];
498 *mb->table_idx = table->next_idx ++;
499 g_hash_table_insert (assembly->method_to_table_idx, mb->mhandle, GUINT_TO_POINTER ((*mb->table_idx)));
500 values = table->values + *mb->table_idx * MONO_METHOD_SIZE;
501 values [MONO_METHOD_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->name, error);
502 return_val_if_nok (error, FALSE);
503 values [MONO_METHOD_FLAGS] = mb->attrs;
504 values [MONO_METHOD_IMPLFLAGS] = mb->iattrs;
505 values [MONO_METHOD_SIGNATURE] = mono_dynimage_encode_method_builder_signature (assembly, mb, error);
506 return_val_if_nok (error, FALSE);
507 values [MONO_METHOD_RVA] = method_encode_code (assembly, mb, error);
508 return_val_if_nok (error, FALSE);
510 table = &assembly->tables [MONO_TABLE_PARAM];
511 values [MONO_METHOD_PARAMLIST] = table->next_idx;
513 mono_image_add_decl_security (assembly,
514 mono_metadata_make_token (MONO_TABLE_METHOD, *mb->table_idx), mb->permissions);
516 if (mb->pinfo) {
517 MonoDynamicTable *mtable;
518 guint32 *mvalues;
520 mtable = &assembly->tables [MONO_TABLE_FIELDMARSHAL];
521 mvalues = mtable->values + mtable->next_idx * MONO_FIELD_MARSHAL_SIZE;
523 count = 0;
524 for (i = 0; i < mono_array_length (mb->pinfo); ++i) {
525 if (mono_array_get (mb->pinfo, gpointer, i))
526 count++;
528 table->rows += count;
529 alloc_table (table, table->rows);
530 values = table->values + table->next_idx * MONO_PARAM_SIZE;
531 for (i = 0; i < mono_array_length (mb->pinfo); ++i) {
532 MonoReflectionParamBuilder *pb;
533 if ((pb = mono_array_get (mb->pinfo, MonoReflectionParamBuilder*, i))) {
534 values [MONO_PARAM_FLAGS] = pb->attrs;
535 values [MONO_PARAM_SEQUENCE] = i;
536 if (pb->name != NULL) {
537 values [MONO_PARAM_NAME] = string_heap_insert_mstring (&assembly->sheap, pb->name, error);
538 return_val_if_nok (error, FALSE);
539 } else {
540 values [MONO_PARAM_NAME] = 0;
542 values += MONO_PARAM_SIZE;
543 if (pb->marshal_info) {
544 mtable->rows++;
545 alloc_table (mtable, mtable->rows);
546 mvalues = mtable->values + mtable->rows * MONO_FIELD_MARSHAL_SIZE;
547 mvalues [MONO_FIELD_MARSHAL_PARENT] = (table->next_idx << MONO_HAS_FIELD_MARSHAL_BITS) | MONO_HAS_FIELD_MARSHAL_PARAMDEF;
548 mvalues [MONO_FIELD_MARSHAL_NATIVE_TYPE] = mono_dynimage_save_encode_marshal_blob (assembly, pb->marshal_info, error);
549 return_val_if_nok (error, FALSE);
551 pb->table_idx = table->next_idx++;
552 if (pb->attrs & PARAM_ATTRIBUTE_HAS_DEFAULT) {
553 guint32 field_type = 0;
554 mtable = &assembly->tables [MONO_TABLE_CONSTANT];
555 mtable->rows ++;
556 alloc_table (mtable, mtable->rows);
557 mvalues = mtable->values + mtable->rows * MONO_CONSTANT_SIZE;
558 mvalues [MONO_CONSTANT_PARENT] = MONO_HASCONSTANT_PARAM | (pb->table_idx << MONO_HASCONSTANT_BITS);
559 mvalues [MONO_CONSTANT_VALUE] = mono_dynimage_encode_constant (assembly, pb->def_value, &field_type);
560 mvalues [MONO_CONSTANT_TYPE] = field_type;
561 mvalues [MONO_CONSTANT_PADDING] = 0;
567 return TRUE;
570 static gboolean
571 mono_image_add_methodimpl (MonoDynamicImage *assembly, MonoReflectionMethodBuilder *mb, MonoError *error)
573 MONO_REQ_GC_UNSAFE_MODE;
575 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mb->type;
576 MonoDynamicTable *table;
577 guint32 *values;
578 guint32 tok;
579 MonoReflectionMethod *m;
580 int i;
582 mono_error_init (error);
584 if (!mb->override_methods)
585 return TRUE;
587 for (i = 0; i < mono_array_length (mb->override_methods); ++i) {
588 m = mono_array_get (mb->override_methods, MonoReflectionMethod*, i);
590 table = &assembly->tables [MONO_TABLE_METHODIMPL];
591 table->rows ++;
592 alloc_table (table, table->rows);
593 values = table->values + table->rows * MONO_METHODIMPL_SIZE;
594 values [MONO_METHODIMPL_CLASS] = tb->table_idx;
595 values [MONO_METHODIMPL_BODY] = MONO_METHODDEFORREF_METHODDEF | (mb->table_idx << MONO_METHODDEFORREF_BITS);
597 tok = image_create_token_raw (assembly, (MonoObject*)m, FALSE, FALSE, error); /* FIXME use handles */
598 return_val_if_nok (error, FALSE);
600 switch (mono_metadata_token_table (tok)) {
601 case MONO_TABLE_MEMBERREF:
602 tok = (mono_metadata_token_index (tok) << MONO_METHODDEFORREF_BITS ) | MONO_METHODDEFORREF_METHODREF;
603 break;
604 case MONO_TABLE_METHOD:
605 tok = (mono_metadata_token_index (tok) << MONO_METHODDEFORREF_BITS ) | MONO_METHODDEFORREF_METHODDEF;
606 break;
607 default:
608 g_assert_not_reached ();
610 values [MONO_METHODIMPL_DECLARATION] = tok;
613 return TRUE;
616 #ifndef DISABLE_REFLECTION_EMIT
617 static gboolean
618 mono_image_get_method_info (MonoReflectionMethodBuilder *mb, MonoDynamicImage *assembly, MonoError *error)
620 MONO_REQ_GC_UNSAFE_MODE;
622 MonoDynamicTable *table;
623 guint32 *values;
624 ReflectionMethodBuilder rmb;
625 int i;
627 mono_error_init (error);
629 if (!mono_reflection_methodbuilder_from_method_builder (&rmb, mb, error) ||
630 !mono_image_basic_method (&rmb, assembly, error))
631 return FALSE;
633 mb->table_idx = *rmb.table_idx;
635 if (mb->dll) { /* It's a P/Invoke method */
636 guint32 moduleref;
637 /* map CharSet values to on-disk values */
638 int ncharset = (mb->charset ? (mb->charset - 1) * 2 : 0);
639 int extra_flags = mb->extra_flags;
640 table = &assembly->tables [MONO_TABLE_IMPLMAP];
641 table->rows ++;
642 alloc_table (table, table->rows);
643 values = table->values + table->rows * MONO_IMPLMAP_SIZE;
645 values [MONO_IMPLMAP_FLAGS] = (mb->native_cc << 8) | ncharset | extra_flags;
646 values [MONO_IMPLMAP_MEMBER] = (mb->table_idx << 1) | 1; /* memberforwarded: method */
647 if (mb->dllentry) {
648 values [MONO_IMPLMAP_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->dllentry, error);
649 return_val_if_nok (error, FALSE);
650 } else {
651 values [MONO_IMPLMAP_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->name, error);
652 return_val_if_nok (error, FALSE);
654 moduleref = string_heap_insert_mstring (&assembly->sheap, mb->dll, error);
655 return_val_if_nok (error, FALSE);
656 if (!(values [MONO_IMPLMAP_SCOPE] = find_index_in_table (assembly, MONO_TABLE_MODULEREF, MONO_MODULEREF_NAME, moduleref))) {
657 table = &assembly->tables [MONO_TABLE_MODULEREF];
658 table->rows ++;
659 alloc_table (table, table->rows);
660 table->values [table->rows * MONO_MODULEREF_SIZE + MONO_MODULEREF_NAME] = moduleref;
661 values [MONO_IMPLMAP_SCOPE] = table->rows;
665 if (mb->generic_params) {
666 table = &assembly->tables [MONO_TABLE_GENERICPARAM];
667 table->rows += mono_array_length (mb->generic_params);
668 alloc_table (table, table->rows);
669 for (i = 0; i < mono_array_length (mb->generic_params); ++i) {
670 guint32 owner = MONO_TYPEORMETHOD_METHOD | (mb->table_idx << MONO_TYPEORMETHOD_BITS);
672 mono_image_get_generic_param_info (
673 (MonoReflectionGenericParam *)mono_array_get (mb->generic_params, gpointer, i), owner, assembly);
677 return TRUE;
680 static gboolean
681 mono_image_get_ctor_info (MonoDomain *domain, MonoReflectionCtorBuilder *mb, MonoDynamicImage *assembly, MonoError *error)
683 MONO_REQ_GC_UNSAFE_MODE;
685 ReflectionMethodBuilder rmb;
687 if (!mono_reflection_methodbuilder_from_ctor_builder (&rmb, mb, error))
688 return FALSE;
690 if (!mono_image_basic_method (&rmb, assembly, error))
691 return FALSE;
693 mb->table_idx = *rmb.table_idx;
695 return TRUE;
697 #endif
699 static void
700 mono_image_get_field_info (MonoReflectionFieldBuilder *fb, MonoDynamicImage *assembly, MonoError *error)
702 MONO_REQ_GC_UNSAFE_MODE;
704 mono_error_init (error);
706 MonoDynamicTable *table;
707 guint32 *values;
709 /* maybe this fixup should be done in the C# code */
710 if (fb->attrs & FIELD_ATTRIBUTE_LITERAL)
711 fb->attrs |= FIELD_ATTRIBUTE_HAS_DEFAULT;
712 table = &assembly->tables [MONO_TABLE_FIELD];
713 fb->table_idx = table->next_idx ++;
714 g_hash_table_insert (assembly->field_to_table_idx, fb->handle, GUINT_TO_POINTER (fb->table_idx));
715 values = table->values + fb->table_idx * MONO_FIELD_SIZE;
716 values [MONO_FIELD_NAME] = string_heap_insert_mstring (&assembly->sheap, fb->name, error);
717 return_if_nok (error);
718 values [MONO_FIELD_FLAGS] = fb->attrs;
719 values [MONO_FIELD_SIGNATURE] = mono_dynimage_encode_field_signature (assembly, fb, error);
720 return_if_nok (error);
722 if (fb->offset != -1) {
723 table = &assembly->tables [MONO_TABLE_FIELDLAYOUT];
724 table->rows ++;
725 alloc_table (table, table->rows);
726 values = table->values + table->rows * MONO_FIELD_LAYOUT_SIZE;
727 values [MONO_FIELD_LAYOUT_FIELD] = fb->table_idx;
728 values [MONO_FIELD_LAYOUT_OFFSET] = fb->offset;
730 if (fb->attrs & FIELD_ATTRIBUTE_LITERAL) {
731 MonoTypeEnum field_type = (MonoTypeEnum)0;
732 table = &assembly->tables [MONO_TABLE_CONSTANT];
733 table->rows ++;
734 alloc_table (table, table->rows);
735 values = table->values + table->rows * MONO_CONSTANT_SIZE;
736 values [MONO_CONSTANT_PARENT] = MONO_HASCONSTANT_FIEDDEF | (fb->table_idx << MONO_HASCONSTANT_BITS);
737 values [MONO_CONSTANT_VALUE] = mono_dynimage_encode_constant (assembly, fb->def_value, &field_type);
738 values [MONO_CONSTANT_TYPE] = field_type;
739 values [MONO_CONSTANT_PADDING] = 0;
741 if (fb->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA) {
742 guint32 rva_idx;
743 table = &assembly->tables [MONO_TABLE_FIELDRVA];
744 table->rows ++;
745 alloc_table (table, table->rows);
746 values = table->values + table->rows * MONO_FIELD_RVA_SIZE;
747 values [MONO_FIELD_RVA_FIELD] = fb->table_idx;
749 * We store it in the code section because it's simpler for now.
751 if (fb->rva_data) {
752 if (mono_array_length (fb->rva_data) >= 10)
753 stream_data_align (&assembly->code);
754 rva_idx = mono_image_add_stream_data (&assembly->code, mono_array_addr (fb->rva_data, char, 0), mono_array_length (fb->rva_data));
755 } else
756 rva_idx = mono_image_add_stream_zero (&assembly->code, mono_class_value_size (fb->handle->parent, NULL));
757 values [MONO_FIELD_RVA_RVA] = rva_idx + assembly->text_rva;
759 if (fb->marshal_info) {
760 table = &assembly->tables [MONO_TABLE_FIELDMARSHAL];
761 table->rows ++;
762 alloc_table (table, table->rows);
763 values = table->values + table->rows * MONO_FIELD_MARSHAL_SIZE;
764 values [MONO_FIELD_MARSHAL_PARENT] = (fb->table_idx << MONO_HAS_FIELD_MARSHAL_BITS) | MONO_HAS_FIELD_MARSHAL_FIELDSREF;
765 values [MONO_FIELD_MARSHAL_NATIVE_TYPE] = mono_dynimage_save_encode_marshal_blob (assembly, fb->marshal_info, error);
766 return_if_nok (error);
770 static void
771 mono_image_get_property_info (MonoReflectionPropertyBuilder *pb, MonoDynamicImage *assembly, MonoError *error)
773 MONO_REQ_GC_UNSAFE_MODE;
775 mono_error_init (error);
777 MonoDynamicTable *table;
778 guint32 *values;
779 guint num_methods = 0;
780 guint32 semaidx;
783 * we need to set things in the following tables:
784 * PROPERTYMAP (info already filled in _get_type_info ())
785 * PROPERTY (rows already preallocated in _get_type_info ())
786 * METHOD (method info already done with the generic method code)
787 * METHODSEMANTICS
788 * CONSTANT
790 table = &assembly->tables [MONO_TABLE_PROPERTY];
791 pb->table_idx = table->next_idx ++;
792 values = table->values + pb->table_idx * MONO_PROPERTY_SIZE;
793 values [MONO_PROPERTY_NAME] = string_heap_insert_mstring (&assembly->sheap, pb->name, error);
794 return_if_nok (error);
795 values [MONO_PROPERTY_FLAGS] = pb->attrs;
796 values [MONO_PROPERTY_TYPE] = mono_dynimage_save_encode_property_signature (assembly, pb, error);
797 return_if_nok (error);
800 /* FIXME: we still don't handle 'other' methods */
801 if (pb->get_method) num_methods ++;
802 if (pb->set_method) num_methods ++;
804 table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
805 table->rows += num_methods;
806 alloc_table (table, table->rows);
808 if (pb->get_method) {
809 semaidx = table->next_idx ++;
810 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
811 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_GETTER;
812 values [MONO_METHOD_SEMA_METHOD] = pb->get_method->table_idx;
813 values [MONO_METHOD_SEMA_ASSOCIATION] = (pb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_PROPERTY;
815 if (pb->set_method) {
816 semaidx = table->next_idx ++;
817 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
818 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_SETTER;
819 values [MONO_METHOD_SEMA_METHOD] = pb->set_method->table_idx;
820 values [MONO_METHOD_SEMA_ASSOCIATION] = (pb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_PROPERTY;
822 if (pb->attrs & PROPERTY_ATTRIBUTE_HAS_DEFAULT) {
823 MonoTypeEnum field_type = (MonoTypeEnum)0;
824 table = &assembly->tables [MONO_TABLE_CONSTANT];
825 table->rows ++;
826 alloc_table (table, table->rows);
827 values = table->values + table->rows * MONO_CONSTANT_SIZE;
828 values [MONO_CONSTANT_PARENT] = MONO_HASCONSTANT_PROPERTY | (pb->table_idx << MONO_HASCONSTANT_BITS);
829 values [MONO_CONSTANT_VALUE] = mono_dynimage_encode_constant (assembly, pb->def_value, &field_type);
830 values [MONO_CONSTANT_TYPE] = field_type;
831 values [MONO_CONSTANT_PADDING] = 0;
835 static void
836 mono_image_get_event_info (MonoReflectionEventBuilder *eb, MonoDynamicImage *assembly, MonoError *error)
838 MONO_REQ_GC_UNSAFE_MODE;
840 MonoDynamicTable *table;
841 guint32 *values;
842 guint num_methods = 0;
843 guint32 semaidx;
846 * we need to set things in the following tables:
847 * EVENTMAP (info already filled in _get_type_info ())
848 * EVENT (rows already preallocated in _get_type_info ())
849 * METHOD (method info already done with the generic method code)
850 * METHODSEMANTICS
852 table = &assembly->tables [MONO_TABLE_EVENT];
853 eb->table_idx = table->next_idx ++;
854 values = table->values + eb->table_idx * MONO_EVENT_SIZE;
855 values [MONO_EVENT_NAME] = string_heap_insert_mstring (&assembly->sheap, eb->name, error);
856 return_if_nok (error);
857 values [MONO_EVENT_FLAGS] = eb->attrs;
858 MonoType *ebtype = mono_reflection_type_get_handle (eb->type, error);
859 return_if_nok (error);
860 values [MONO_EVENT_TYPE] = mono_image_typedef_or_ref (assembly, ebtype);
863 * FIXME: we still don't handle 'other' methods
865 if (eb->add_method) num_methods ++;
866 if (eb->remove_method) num_methods ++;
867 if (eb->raise_method) num_methods ++;
869 table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
870 table->rows += num_methods;
871 alloc_table (table, table->rows);
873 if (eb->add_method) {
874 semaidx = table->next_idx ++;
875 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
876 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_ADD_ON;
877 values [MONO_METHOD_SEMA_METHOD] = eb->add_method->table_idx;
878 values [MONO_METHOD_SEMA_ASSOCIATION] = (eb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_EVENT;
880 if (eb->remove_method) {
881 semaidx = table->next_idx ++;
882 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
883 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_REMOVE_ON;
884 values [MONO_METHOD_SEMA_METHOD] = eb->remove_method->table_idx;
885 values [MONO_METHOD_SEMA_ASSOCIATION] = (eb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_EVENT;
887 if (eb->raise_method) {
888 semaidx = table->next_idx ++;
889 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
890 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_FIRE;
891 values [MONO_METHOD_SEMA_METHOD] = eb->raise_method->table_idx;
892 values [MONO_METHOD_SEMA_ASSOCIATION] = (eb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_EVENT;
896 static void
897 encode_constraints (MonoReflectionGenericParam *gparam, guint32 owner, MonoDynamicImage *assembly, MonoError *error)
899 MONO_REQ_GC_UNSAFE_MODE;
901 mono_error_init (error);
903 MonoDynamicTable *table;
904 guint32 num_constraints, i;
905 guint32 *values;
906 guint32 table_idx;
908 table = &assembly->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
909 num_constraints = gparam->iface_constraints ?
910 mono_array_length (gparam->iface_constraints) : 0;
911 table->rows += num_constraints;
912 if (gparam->base_type)
913 table->rows++;
914 alloc_table (table, table->rows);
916 if (gparam->base_type) {
917 table_idx = table->next_idx ++;
918 values = table->values + table_idx * MONO_GENPARCONSTRAINT_SIZE;
920 MonoType *gpbasetype = mono_reflection_type_get_handle (gparam->base_type, error);
921 return_if_nok (error);
922 values [MONO_GENPARCONSTRAINT_GENERICPAR] = owner;
923 values [MONO_GENPARCONSTRAINT_CONSTRAINT] = mono_image_typedef_or_ref (assembly, gpbasetype);
926 for (i = 0; i < num_constraints; i++) {
927 MonoReflectionType *constraint = (MonoReflectionType *)mono_array_get (
928 gparam->iface_constraints, gpointer, i);
930 table_idx = table->next_idx ++;
931 values = table->values + table_idx * MONO_GENPARCONSTRAINT_SIZE;
933 MonoType *constraint_type = mono_reflection_type_get_handle (constraint, error);
934 return_if_nok (error);
936 values [MONO_GENPARCONSTRAINT_GENERICPAR] = owner;
937 values [MONO_GENPARCONSTRAINT_CONSTRAINT] = mono_image_typedef_or_ref (assembly, constraint_type);
941 static void
942 mono_image_get_generic_param_info (MonoReflectionGenericParam *gparam, guint32 owner, MonoDynamicImage *assembly)
944 MONO_REQ_GC_UNSAFE_MODE;
946 GenericParamTableEntry *entry;
949 * The GenericParam table must be sorted according to the `owner' field.
950 * We need to do this sorting prior to writing the GenericParamConstraint
951 * table, since we have to use the final GenericParam table indices there
952 * and they must also be sorted.
955 entry = g_new0 (GenericParamTableEntry, 1);
956 entry->owner = owner;
957 /* FIXME: track where gen_params should be freed and remove the GC root as well */
958 MONO_GC_REGISTER_ROOT_IF_MOVING (entry->gparam, MONO_ROOT_SOURCE_REFLECTION, "reflection generic parameter");
959 entry->gparam = gparam;
961 g_ptr_array_add (assembly->gen_params, entry);
964 static gboolean
965 write_generic_param_entry (MonoDynamicImage *assembly, GenericParamTableEntry *entry, MonoError *error)
967 MONO_REQ_GC_UNSAFE_MODE;
969 MonoDynamicTable *table;
970 MonoGenericParam *param;
971 guint32 *values;
972 guint32 table_idx;
974 mono_error_init (error);
976 table = &assembly->tables [MONO_TABLE_GENERICPARAM];
977 table_idx = table->next_idx ++;
978 values = table->values + table_idx * MONO_GENERICPARAM_SIZE;
980 MonoType *gparam_type = mono_reflection_type_get_handle ((MonoReflectionType*)entry->gparam, error);
981 return_val_if_nok (error, FALSE);
983 param = gparam_type->data.generic_param;
985 values [MONO_GENERICPARAM_OWNER] = entry->owner;
986 values [MONO_GENERICPARAM_FLAGS] = entry->gparam->attrs;
987 values [MONO_GENERICPARAM_NUMBER] = mono_generic_param_num (param);
988 values [MONO_GENERICPARAM_NAME] = string_heap_insert (&assembly->sheap, mono_generic_param_info (param)->name);
990 if (!mono_image_add_cattrs (assembly, table_idx, MONO_CUSTOM_ATTR_GENERICPAR, entry->gparam->cattrs, error))
991 return FALSE;
993 encode_constraints (entry->gparam, table_idx, assembly, error);
994 return_val_if_nok (error, FALSE);
996 return TRUE;
999 static void
1000 collect_types (MonoPtrArray *types, MonoReflectionTypeBuilder *type)
1002 int i;
1004 mono_ptr_array_append (*types, type);
1006 if (!type->subtypes)
1007 return;
1009 for (i = 0; i < mono_array_length (type->subtypes); ++i) {
1010 MonoReflectionTypeBuilder *subtype = mono_array_get (type->subtypes, MonoReflectionTypeBuilder*, i);
1011 collect_types (types, subtype);
1015 static gint
1016 compare_types_by_table_idx (MonoReflectionTypeBuilder **type1, MonoReflectionTypeBuilder **type2)
1018 if ((*type1)->table_idx < (*type2)->table_idx)
1019 return -1;
1020 else
1021 if ((*type1)->table_idx > (*type2)->table_idx)
1022 return 1;
1023 else
1024 return 0;
1027 static gboolean
1028 params_add_cattrs (MonoDynamicImage *assembly, MonoArray *pinfo, MonoError *error) {
1029 int i;
1031 mono_error_init (error);
1032 if (!pinfo)
1033 return TRUE;
1034 for (i = 0; i < mono_array_length (pinfo); ++i) {
1035 MonoReflectionParamBuilder *pb;
1036 pb = mono_array_get (pinfo, MonoReflectionParamBuilder *, i);
1037 if (!pb)
1038 continue;
1039 if (!mono_image_add_cattrs (assembly, pb->table_idx, MONO_CUSTOM_ATTR_PARAMDEF, pb->cattrs, error))
1040 return FALSE;
1043 return TRUE;
1046 static gboolean
1047 type_add_cattrs (MonoDynamicImage *assembly, MonoReflectionTypeBuilder *tb, MonoError *error) {
1048 int i;
1050 mono_error_init (error);
1052 if (!mono_image_add_cattrs (assembly, tb->table_idx, MONO_CUSTOM_ATTR_TYPEDEF, tb->cattrs, error))
1053 return FALSE;
1054 if (tb->fields) {
1055 for (i = 0; i < tb->num_fields; ++i) {
1056 MonoReflectionFieldBuilder* fb;
1057 fb = mono_array_get (tb->fields, MonoReflectionFieldBuilder*, i);
1058 if (!mono_image_add_cattrs (assembly, fb->table_idx, MONO_CUSTOM_ATTR_FIELDDEF, fb->cattrs, error))
1059 return FALSE;
1062 if (tb->events) {
1063 for (i = 0; i < mono_array_length (tb->events); ++i) {
1064 MonoReflectionEventBuilder* eb;
1065 eb = mono_array_get (tb->events, MonoReflectionEventBuilder*, i);
1066 if (!mono_image_add_cattrs (assembly, eb->table_idx, MONO_CUSTOM_ATTR_EVENT, eb->cattrs, error))
1067 return FALSE;
1070 if (tb->properties) {
1071 for (i = 0; i < mono_array_length (tb->properties); ++i) {
1072 MonoReflectionPropertyBuilder* pb;
1073 pb = mono_array_get (tb->properties, MonoReflectionPropertyBuilder*, i);
1074 if (!mono_image_add_cattrs (assembly, pb->table_idx, MONO_CUSTOM_ATTR_PROPERTY, pb->cattrs, error))
1075 return FALSE;
1078 if (tb->ctors) {
1079 for (i = 0; i < mono_array_length (tb->ctors); ++i) {
1080 MonoReflectionCtorBuilder* cb;
1081 cb = mono_array_get (tb->ctors, MonoReflectionCtorBuilder*, i);
1082 if (!mono_image_add_cattrs (assembly, cb->table_idx, MONO_CUSTOM_ATTR_METHODDEF, cb->cattrs, error) ||
1083 !params_add_cattrs (assembly, cb->pinfo, error))
1084 return FALSE;
1088 if (tb->methods) {
1089 for (i = 0; i < tb->num_methods; ++i) {
1090 MonoReflectionMethodBuilder* mb;
1091 mb = mono_array_get (tb->methods, MonoReflectionMethodBuilder*, i);
1092 if (!mono_image_add_cattrs (assembly, mb->table_idx, MONO_CUSTOM_ATTR_METHODDEF, mb->cattrs, error) ||
1093 !params_add_cattrs (assembly, mb->pinfo, error))
1094 return FALSE;
1098 if (tb->subtypes) {
1099 for (i = 0; i < mono_array_length (tb->subtypes); ++i) {
1100 if (!type_add_cattrs (assembly, mono_array_get (tb->subtypes, MonoReflectionTypeBuilder*, i), error))
1101 return FALSE;
1105 return TRUE;
1108 static gboolean
1109 module_add_cattrs (MonoDynamicImage *assembly, MonoReflectionModuleBuilder *moduleb, MonoError *error)
1111 int i;
1113 mono_error_init (error);
1115 if (!mono_image_add_cattrs (assembly, moduleb->table_idx, MONO_CUSTOM_ATTR_MODULE, moduleb->cattrs, error))
1116 return FALSE;
1118 if (moduleb->global_methods) {
1119 for (i = 0; i < mono_array_length (moduleb->global_methods); ++i) {
1120 MonoReflectionMethodBuilder* mb = mono_array_get (moduleb->global_methods, MonoReflectionMethodBuilder*, i);
1121 if (!mono_image_add_cattrs (assembly, mb->table_idx, MONO_CUSTOM_ATTR_METHODDEF, mb->cattrs, error) ||
1122 !params_add_cattrs (assembly, mb->pinfo, error))
1123 return FALSE;
1127 if (moduleb->global_fields) {
1128 for (i = 0; i < mono_array_length (moduleb->global_fields); ++i) {
1129 MonoReflectionFieldBuilder *fb = mono_array_get (moduleb->global_fields, MonoReflectionFieldBuilder*, i);
1130 if (!mono_image_add_cattrs (assembly, fb->table_idx, MONO_CUSTOM_ATTR_FIELDDEF, fb->cattrs, error))
1131 return FALSE;
1135 if (moduleb->types) {
1136 for (i = 0; i < moduleb->num_types; ++i) {
1137 if (!type_add_cattrs (assembly, mono_array_get (moduleb->types, MonoReflectionTypeBuilder*, i), error))
1138 return FALSE;
1142 return TRUE;
1145 static gboolean
1146 mono_image_fill_file_table (MonoDomain *domain, MonoReflectionModule *module, MonoDynamicImage *assembly, MonoError *error)
1148 MonoDynamicTable *table;
1149 guint32 *values;
1150 char blob_size [6];
1151 guchar hash [20];
1152 char *b = blob_size;
1153 char *dir, *path;
1155 mono_error_init (error);
1157 table = &assembly->tables [MONO_TABLE_FILE];
1158 table->rows++;
1159 alloc_table (table, table->rows);
1160 values = table->values + table->next_idx * MONO_FILE_SIZE;
1161 values [MONO_FILE_FLAGS] = FILE_CONTAINS_METADATA;
1162 values [MONO_FILE_NAME] = string_heap_insert (&assembly->sheap, module->image->module_name);
1163 if (image_is_dynamic (module->image)) {
1164 /* This depends on the fact that the main module is emitted last */
1165 dir = mono_string_to_utf8_checked (((MonoReflectionModuleBuilder*)module)->assemblyb->dir, error);
1166 return_val_if_nok (error, FALSE);
1167 path = g_strdup_printf ("%s%c%s", dir, G_DIR_SEPARATOR, module->image->module_name);
1168 } else {
1169 dir = NULL;
1170 path = g_strdup (module->image->name);
1172 mono_sha1_get_digest_from_file (path, hash);
1173 g_free (dir);
1174 g_free (path);
1175 mono_metadata_encode_value (20, b, &b);
1176 values [MONO_FILE_HASH_VALUE] = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
1177 mono_image_add_stream_data (&assembly->blob, (char*)hash, 20);
1178 table->next_idx ++;
1179 return TRUE;
1182 static void
1183 mono_image_fill_module_table (MonoDomain *domain, MonoReflectionModuleBuilder *mb, MonoDynamicImage *assembly, MonoError *error)
1185 MonoDynamicTable *table;
1186 int i;
1188 mono_error_init (error);
1190 table = &assembly->tables [MONO_TABLE_MODULE];
1191 mb->table_idx = table->next_idx ++;
1192 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->module.name, error);
1193 return_if_nok (error);
1194 i = mono_image_add_stream_data (&assembly->guid, mono_array_addr (mb->guid, char, 0), 16);
1195 i /= 16;
1196 ++i;
1197 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_GENERATION] = 0;
1198 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_MVID] = i;
1199 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_ENC] = 0;
1200 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_ENCBASE] = 0;
1203 static guint32
1204 mono_image_fill_export_table_from_class (MonoDomain *domain, MonoClass *klass,
1205 guint32 module_index, guint32 parent_index, MonoDynamicImage *assembly)
1207 MonoDynamicTable *table;
1208 guint32 *values;
1209 guint32 visib, res;
1211 visib = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_VISIBILITY_MASK;
1212 if (! ((visib & TYPE_ATTRIBUTE_PUBLIC) || (visib & TYPE_ATTRIBUTE_NESTED_PUBLIC)))
1213 return 0;
1215 table = &assembly->tables [MONO_TABLE_EXPORTEDTYPE];
1216 table->rows++;
1217 alloc_table (table, table->rows);
1218 values = table->values + table->next_idx * MONO_EXP_TYPE_SIZE;
1220 values [MONO_EXP_TYPE_FLAGS] = mono_class_get_flags (klass);
1221 values [MONO_EXP_TYPE_TYPEDEF] = klass->type_token;
1222 if (klass->nested_in)
1223 values [MONO_EXP_TYPE_IMPLEMENTATION] = (parent_index << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_EXP_TYPE;
1224 else
1225 values [MONO_EXP_TYPE_IMPLEMENTATION] = (module_index << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_FILE;
1226 values [MONO_EXP_TYPE_NAME] = string_heap_insert (&assembly->sheap, klass->name);
1227 values [MONO_EXP_TYPE_NAMESPACE] = string_heap_insert (&assembly->sheap, klass->name_space);
1229 res = table->next_idx;
1231 table->next_idx ++;
1233 /* Emit nested types */
1234 GList *nested_classes = mono_class_get_nested_classes_property (klass);
1235 GList *tmp;
1236 for (tmp = nested_classes; tmp; tmp = tmp->next)
1237 mono_image_fill_export_table_from_class (domain, (MonoClass *)tmp->data, module_index, table->next_idx - 1, assembly);
1239 return res;
1242 static void
1243 mono_image_fill_export_table (MonoDomain *domain, MonoReflectionTypeBuilder *tb,
1244 guint32 module_index, guint32 parent_index, MonoDynamicImage *assembly,
1245 MonoError *error)
1247 MonoClass *klass;
1248 guint32 idx, i;
1250 mono_error_init (error);
1252 MonoType *t = mono_reflection_type_get_handle ((MonoReflectionType*)tb, error);
1253 return_if_nok (error);
1255 klass = mono_class_from_mono_type (t);
1257 klass->type_token = mono_metadata_make_token (MONO_TABLE_TYPEDEF, tb->table_idx);
1259 idx = mono_image_fill_export_table_from_class (domain, klass, module_index,
1260 parent_index, assembly);
1263 * Emit nested types
1264 * We need to do this ourselves since klass->nested_classes is not set up.
1266 if (tb->subtypes) {
1267 for (i = 0; i < mono_array_length (tb->subtypes); ++i) {
1268 mono_image_fill_export_table (domain, mono_array_get (tb->subtypes, MonoReflectionTypeBuilder*, i), module_index, idx, assembly, error);
1269 return_if_nok (error);
1274 static void
1275 mono_image_fill_export_table_from_module (MonoDomain *domain, MonoReflectionModule *module,
1276 guint32 module_index, MonoDynamicImage *assembly)
1278 MonoImage *image = module->image;
1279 MonoTableInfo *t;
1280 guint32 i;
1282 t = &image->tables [MONO_TABLE_TYPEDEF];
1284 for (i = 0; i < t->rows; ++i) {
1285 MonoError error;
1286 MonoClass *klass = mono_class_get_checked (image, mono_metadata_make_token (MONO_TABLE_TYPEDEF, i + 1), &error);
1287 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
1289 if (mono_class_is_public (klass))
1290 mono_image_fill_export_table_from_class (domain, klass, module_index, 0, assembly);
1294 static void
1295 add_exported_type (MonoReflectionAssemblyBuilder *assemblyb, MonoDynamicImage *assembly, MonoClass *klass, guint32 parent_index)
1297 MonoDynamicTable *table;
1298 guint32 *values;
1299 guint32 scope, scope_idx, impl, current_idx;
1300 gboolean forwarder = TRUE;
1301 gpointer iter = NULL;
1302 MonoClass *nested;
1304 if (klass->nested_in) {
1305 impl = (parent_index << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_EXP_TYPE;
1306 forwarder = FALSE;
1307 } else {
1308 scope = mono_reflection_resolution_scope_from_image (assembly, klass->image);
1309 g_assert ((scope & MONO_RESOLUTION_SCOPE_MASK) == MONO_RESOLUTION_SCOPE_ASSEMBLYREF);
1310 scope_idx = scope >> MONO_RESOLUTION_SCOPE_BITS;
1311 impl = (scope_idx << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_ASSEMBLYREF;
1314 table = &assembly->tables [MONO_TABLE_EXPORTEDTYPE];
1316 table->rows++;
1317 alloc_table (table, table->rows);
1318 current_idx = table->next_idx;
1319 values = table->values + current_idx * MONO_EXP_TYPE_SIZE;
1321 values [MONO_EXP_TYPE_FLAGS] = forwarder ? TYPE_ATTRIBUTE_FORWARDER : 0;
1322 values [MONO_EXP_TYPE_TYPEDEF] = 0;
1323 values [MONO_EXP_TYPE_IMPLEMENTATION] = impl;
1324 values [MONO_EXP_TYPE_NAME] = string_heap_insert (&assembly->sheap, klass->name);
1325 values [MONO_EXP_TYPE_NAMESPACE] = string_heap_insert (&assembly->sheap, klass->name_space);
1327 table->next_idx++;
1329 while ((nested = mono_class_get_nested_types (klass, &iter)))
1330 add_exported_type (assemblyb, assembly, nested, current_idx);
1333 static void
1334 mono_image_fill_export_table_from_type_forwarders (MonoReflectionAssemblyBuilder *assemblyb, MonoDynamicImage *assembly)
1336 MonoError error;
1337 MonoClass *klass;
1338 int i;
1340 if (!assemblyb->type_forwarders)
1341 return;
1343 for (i = 0; i < mono_array_length (assemblyb->type_forwarders); ++i) {
1344 MonoReflectionType *t = mono_array_get (assemblyb->type_forwarders, MonoReflectionType *, i);
1345 MonoType *type;
1346 if (!t)
1347 continue;
1349 type = mono_reflection_type_get_handle (t, &error);
1350 mono_error_assert_ok (&error);
1351 g_assert (type);
1353 klass = mono_class_from_mono_type (type);
1355 add_exported_type (assemblyb, assembly, klass, 0);
1359 #define align_pointer(base,p)\
1360 do {\
1361 guint32 __diff = (unsigned char*)(p)-(unsigned char*)(base);\
1362 if (__diff & 3)\
1363 (p) += 4 - (__diff & 3);\
1364 } while (0)
1366 static int
1367 compare_constants (const void *a, const void *b)
1369 const guint32 *a_values = (const guint32 *)a;
1370 const guint32 *b_values = (const guint32 *)b;
1371 return a_values [MONO_CONSTANT_PARENT] - b_values [MONO_CONSTANT_PARENT];
1374 static int
1375 compare_semantics (const void *a, const void *b)
1377 const guint32 *a_values = (const guint32 *)a;
1378 const guint32 *b_values = (const guint32 *)b;
1379 int assoc = a_values [MONO_METHOD_SEMA_ASSOCIATION] - b_values [MONO_METHOD_SEMA_ASSOCIATION];
1380 if (assoc)
1381 return assoc;
1382 return a_values [MONO_METHOD_SEMA_SEMANTICS] - b_values [MONO_METHOD_SEMA_SEMANTICS];
1385 static int
1386 compare_custom_attrs (const void *a, const void *b)
1388 const guint32 *a_values = (const guint32 *)a;
1389 const guint32 *b_values = (const guint32 *)b;
1391 return a_values [MONO_CUSTOM_ATTR_PARENT] - b_values [MONO_CUSTOM_ATTR_PARENT];
1394 static int
1395 compare_field_marshal (const void *a, const void *b)
1397 const guint32 *a_values = (const guint32 *)a;
1398 const guint32 *b_values = (const guint32 *)b;
1400 return a_values [MONO_FIELD_MARSHAL_PARENT] - b_values [MONO_FIELD_MARSHAL_PARENT];
1403 static int
1404 compare_nested (const void *a, const void *b)
1406 const guint32 *a_values = (const guint32 *)a;
1407 const guint32 *b_values = (const guint32 *)b;
1409 return a_values [MONO_NESTED_CLASS_NESTED] - b_values [MONO_NESTED_CLASS_NESTED];
1412 static int
1413 compare_genericparam (const void *a, const void *b)
1415 MonoError error;
1416 const GenericParamTableEntry **a_entry = (const GenericParamTableEntry **) a;
1417 const GenericParamTableEntry **b_entry = (const GenericParamTableEntry **) b;
1419 if ((*b_entry)->owner == (*a_entry)->owner) {
1420 MonoType *a_type = mono_reflection_type_get_handle ((MonoReflectionType*)(*a_entry)->gparam, &error);
1421 mono_error_assert_ok (&error);
1422 MonoType *b_type = mono_reflection_type_get_handle ((MonoReflectionType*)(*b_entry)->gparam, &error);
1423 mono_error_assert_ok (&error);
1424 return
1425 mono_type_get_generic_param_num (a_type) -
1426 mono_type_get_generic_param_num (b_type);
1427 } else
1428 return (*a_entry)->owner - (*b_entry)->owner;
1431 static int
1432 compare_declsecurity_attrs (const void *a, const void *b)
1434 const guint32 *a_values = (const guint32 *)a;
1435 const guint32 *b_values = (const guint32 *)b;
1437 return a_values [MONO_DECL_SECURITY_PARENT] - b_values [MONO_DECL_SECURITY_PARENT];
1440 static int
1441 compare_interface_impl (const void *a, const void *b)
1443 const guint32 *a_values = (const guint32 *)a;
1444 const guint32 *b_values = (const guint32 *)b;
1446 int klass = a_values [MONO_INTERFACEIMPL_CLASS] - b_values [MONO_INTERFACEIMPL_CLASS];
1447 if (klass)
1448 return klass;
1450 return a_values [MONO_INTERFACEIMPL_INTERFACE] - b_values [MONO_INTERFACEIMPL_INTERFACE];
1453 struct StreamDesc {
1454 const char *name;
1455 MonoDynamicStream *stream;
1459 * build_compressed_metadata() fills in the blob of data that represents the
1460 * raw metadata as it will be saved in the PE file. The five streams are output
1461 * and the metadata tables are comnpressed from the guint32 array representation,
1462 * to the compressed on-disk format.
1464 static gboolean
1465 build_compressed_metadata (MonoDynamicImage *assembly, MonoError *error)
1467 MonoDynamicTable *table;
1468 int i;
1469 guint64 valid_mask = 0;
1470 guint64 sorted_mask;
1471 guint32 heapt_size = 0;
1472 guint32 meta_size = 256; /* allow for header and other stuff */
1473 guint32 table_offset;
1474 guint32 ntables = 0;
1475 guint64 *int64val;
1476 guint32 *int32val;
1477 guint16 *int16val;
1478 MonoImage *meta;
1479 unsigned char *p;
1480 struct StreamDesc stream_desc [5];
1482 mono_error_init (error);
1484 qsort (assembly->gen_params->pdata, assembly->gen_params->len, sizeof (gpointer), compare_genericparam);
1485 for (i = 0; i < assembly->gen_params->len; i++) {
1486 GenericParamTableEntry *entry = (GenericParamTableEntry *)g_ptr_array_index (assembly->gen_params, i);
1487 if (!write_generic_param_entry (assembly, entry, error))
1488 return FALSE;
1491 stream_desc [0].name = "#~";
1492 stream_desc [0].stream = &assembly->tstream;
1493 stream_desc [1].name = "#Strings";
1494 stream_desc [1].stream = &assembly->sheap;
1495 stream_desc [2].name = "#US";
1496 stream_desc [2].stream = &assembly->us;
1497 stream_desc [3].name = "#Blob";
1498 stream_desc [3].stream = &assembly->blob;
1499 stream_desc [4].name = "#GUID";
1500 stream_desc [4].stream = &assembly->guid;
1502 /* tables that are sorted */
1503 sorted_mask = ((guint64)1 << MONO_TABLE_CONSTANT) | ((guint64)1 << MONO_TABLE_FIELDMARSHAL)
1504 | ((guint64)1 << MONO_TABLE_METHODSEMANTICS) | ((guint64)1 << MONO_TABLE_CLASSLAYOUT)
1505 | ((guint64)1 << MONO_TABLE_FIELDLAYOUT) | ((guint64)1 << MONO_TABLE_FIELDRVA)
1506 | ((guint64)1 << MONO_TABLE_IMPLMAP) | ((guint64)1 << MONO_TABLE_NESTEDCLASS)
1507 | ((guint64)1 << MONO_TABLE_METHODIMPL) | ((guint64)1 << MONO_TABLE_CUSTOMATTRIBUTE)
1508 | ((guint64)1 << MONO_TABLE_DECLSECURITY) | ((guint64)1 << MONO_TABLE_GENERICPARAM)
1509 | ((guint64)1 << MONO_TABLE_INTERFACEIMPL);
1511 /* Compute table sizes */
1512 /* the MonoImage has already been created in mono_reflection_dynimage_basic_init() */
1513 meta = &assembly->image;
1515 /* sizes should be multiple of 4 */
1516 mono_dynstream_data_align (&assembly->blob);
1517 mono_dynstream_data_align (&assembly->guid);
1518 mono_dynstream_data_align (&assembly->sheap);
1519 mono_dynstream_data_align (&assembly->us);
1521 /* Setup the info used by compute_sizes () */
1522 meta->idx_blob_wide = assembly->blob.index >= 65536 ? 1 : 0;
1523 meta->idx_guid_wide = assembly->guid.index >= 65536 ? 1 : 0;
1524 meta->idx_string_wide = assembly->sheap.index >= 65536 ? 1 : 0;
1526 meta_size += assembly->blob.index;
1527 meta_size += assembly->guid.index;
1528 meta_size += assembly->sheap.index;
1529 meta_size += assembly->us.index;
1531 for (i=0; i < MONO_TABLE_NUM; ++i)
1532 meta->tables [i].rows = assembly->tables [i].rows;
1534 for (i = 0; i < MONO_TABLE_NUM; i++){
1535 if (meta->tables [i].rows == 0)
1536 continue;
1537 valid_mask |= (guint64)1 << i;
1538 ntables ++;
1539 meta->tables [i].row_size = mono_metadata_compute_size (
1540 meta, i, &meta->tables [i].size_bitfield);
1541 heapt_size += meta->tables [i].row_size * meta->tables [i].rows;
1543 heapt_size += 24; /* #~ header size */
1544 heapt_size += ntables * 4;
1545 /* make multiple of 4 */
1546 heapt_size += 3;
1547 heapt_size &= ~3;
1548 meta_size += heapt_size;
1549 meta->raw_metadata = (char *)g_malloc0 (meta_size);
1550 p = (unsigned char*)meta->raw_metadata;
1551 /* the metadata signature */
1552 *p++ = 'B'; *p++ = 'S'; *p++ = 'J'; *p++ = 'B';
1553 /* version numbers and 4 bytes reserved */
1554 int16val = (guint16*)p;
1555 *int16val++ = GUINT16_TO_LE (meta->md_version_major);
1556 *int16val = GUINT16_TO_LE (meta->md_version_minor);
1557 p += 8;
1558 /* version string */
1559 int32val = (guint32*)p;
1560 *int32val = GUINT32_TO_LE ((strlen (meta->version) + 3) & (~3)); /* needs to be multiple of 4 */
1561 p += 4;
1562 memcpy (p, meta->version, strlen (meta->version));
1563 p += GUINT32_FROM_LE (*int32val);
1564 align_pointer (meta->raw_metadata, p);
1565 int16val = (guint16*)p;
1566 *int16val++ = GUINT16_TO_LE (0); /* flags must be 0 */
1567 *int16val = GUINT16_TO_LE (5); /* number of streams */
1568 p += 4;
1571 * write the stream info.
1573 table_offset = (p - (unsigned char*)meta->raw_metadata) + 5 * 8 + 40; /* room needed for stream headers */
1574 table_offset += 3; table_offset &= ~3;
1576 assembly->tstream.index = heapt_size;
1577 for (i = 0; i < 5; ++i) {
1578 int32val = (guint32*)p;
1579 stream_desc [i].stream->offset = table_offset;
1580 *int32val++ = GUINT32_TO_LE (table_offset);
1581 *int32val = GUINT32_TO_LE (stream_desc [i].stream->index);
1582 table_offset += GUINT32_FROM_LE (*int32val);
1583 table_offset += 3; table_offset &= ~3;
1584 p += 8;
1585 strcpy ((char*)p, stream_desc [i].name);
1586 p += strlen (stream_desc [i].name) + 1;
1587 align_pointer (meta->raw_metadata, p);
1590 * now copy the data, the table stream header and contents goes first.
1592 g_assert ((p - (unsigned char*)meta->raw_metadata) < assembly->tstream.offset);
1593 p = (guchar*)meta->raw_metadata + assembly->tstream.offset;
1594 int32val = (guint32*)p;
1595 *int32val = GUINT32_TO_LE (0); /* reserved */
1596 p += 4;
1598 *p++ = 2; /* version */
1599 *p++ = 0;
1601 if (meta->idx_string_wide)
1602 *p |= 0x01;
1603 if (meta->idx_guid_wide)
1604 *p |= 0x02;
1605 if (meta->idx_blob_wide)
1606 *p |= 0x04;
1607 ++p;
1608 *p++ = 1; /* reserved */
1609 int64val = (guint64*)p;
1610 *int64val++ = GUINT64_TO_LE (valid_mask);
1611 *int64val++ = GUINT64_TO_LE (valid_mask & sorted_mask); /* bitvector of sorted tables */
1612 p += 16;
1613 int32val = (guint32*)p;
1614 for (i = 0; i < MONO_TABLE_NUM; i++){
1615 if (meta->tables [i].rows == 0)
1616 continue;
1617 *int32val++ = GUINT32_TO_LE (meta->tables [i].rows);
1619 p = (unsigned char*)int32val;
1621 /* sort the tables that still need sorting */
1622 table = &assembly->tables [MONO_TABLE_CONSTANT];
1623 if (table->rows)
1624 qsort (table->values + MONO_CONSTANT_SIZE, table->rows, sizeof (guint32) * MONO_CONSTANT_SIZE, compare_constants);
1625 table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
1626 if (table->rows)
1627 qsort (table->values + MONO_METHOD_SEMA_SIZE, table->rows, sizeof (guint32) * MONO_METHOD_SEMA_SIZE, compare_semantics);
1628 table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1629 if (table->rows)
1630 qsort (table->values + MONO_CUSTOM_ATTR_SIZE, table->rows, sizeof (guint32) * MONO_CUSTOM_ATTR_SIZE, compare_custom_attrs);
1631 table = &assembly->tables [MONO_TABLE_FIELDMARSHAL];
1632 if (table->rows)
1633 qsort (table->values + MONO_FIELD_MARSHAL_SIZE, table->rows, sizeof (guint32) * MONO_FIELD_MARSHAL_SIZE, compare_field_marshal);
1634 table = &assembly->tables [MONO_TABLE_NESTEDCLASS];
1635 if (table->rows)
1636 qsort (table->values + MONO_NESTED_CLASS_SIZE, table->rows, sizeof (guint32) * MONO_NESTED_CLASS_SIZE, compare_nested);
1637 /* Section 21.11 DeclSecurity in Partition II doesn't specify this to be sorted by MS implementation requires it */
1638 table = &assembly->tables [MONO_TABLE_DECLSECURITY];
1639 if (table->rows)
1640 qsort (table->values + MONO_DECL_SECURITY_SIZE, table->rows, sizeof (guint32) * MONO_DECL_SECURITY_SIZE, compare_declsecurity_attrs);
1641 table = &assembly->tables [MONO_TABLE_INTERFACEIMPL];
1642 if (table->rows)
1643 qsort (table->values + MONO_INTERFACEIMPL_SIZE, table->rows, sizeof (guint32) * MONO_INTERFACEIMPL_SIZE, compare_interface_impl);
1645 /* compress the tables */
1646 for (i = 0; i < MONO_TABLE_NUM; i++){
1647 int row, col;
1648 guint32 *values;
1649 guint32 bitfield = meta->tables [i].size_bitfield;
1650 if (!meta->tables [i].rows)
1651 continue;
1652 if (assembly->tables [i].columns != mono_metadata_table_count (bitfield))
1653 g_error ("col count mismatch in %d: %d %d", i, assembly->tables [i].columns, mono_metadata_table_count (bitfield));
1654 meta->tables [i].base = (char*)p;
1655 for (row = 1; row <= meta->tables [i].rows; ++row) {
1656 values = assembly->tables [i].values + row * assembly->tables [i].columns;
1657 for (col = 0; col < assembly->tables [i].columns; ++col) {
1658 switch (mono_metadata_table_size (bitfield, col)) {
1659 case 1:
1660 *p++ = values [col];
1661 break;
1662 case 2:
1663 *p++ = values [col] & 0xff;
1664 *p++ = (values [col] >> 8) & 0xff;
1665 break;
1666 case 4:
1667 *p++ = values [col] & 0xff;
1668 *p++ = (values [col] >> 8) & 0xff;
1669 *p++ = (values [col] >> 16) & 0xff;
1670 *p++ = (values [col] >> 24) & 0xff;
1671 break;
1672 default:
1673 g_assert_not_reached ();
1677 g_assert ((p - (const unsigned char*)meta->tables [i].base) == (meta->tables [i].rows * meta->tables [i].row_size));
1680 g_assert (assembly->guid.offset + assembly->guid.index < meta_size);
1681 memcpy (meta->raw_metadata + assembly->sheap.offset, assembly->sheap.data, assembly->sheap.index);
1682 memcpy (meta->raw_metadata + assembly->us.offset, assembly->us.data, assembly->us.index);
1683 memcpy (meta->raw_metadata + assembly->blob.offset, assembly->blob.data, assembly->blob.index);
1684 memcpy (meta->raw_metadata + assembly->guid.offset, assembly->guid.data, assembly->guid.index);
1686 assembly->meta_size = assembly->guid.offset + assembly->guid.index;
1688 return TRUE;
1692 * Some tables in metadata need to be sorted according to some criteria, but
1693 * when methods and fields are first created with reflection, they may be assigned a token
1694 * that doesn't correspond to the final token they will get assigned after the sorting.
1695 * ILGenerator.cs keeps a fixup table that maps the position of tokens in the IL code stream
1696 * with the reflection objects that represent them. Once all the tables are set up, the
1697 * reflection objects will contains the correct table index. fixup_method() will fixup the
1698 * tokens for the method with ILGenerator @ilgen.
1700 static void
1701 fixup_method (MonoReflectionILGen *ilgen, gpointer value, MonoDynamicImage *assembly)
1703 guint32 code_idx = GPOINTER_TO_UINT (value);
1704 MonoReflectionILTokenInfo *iltoken;
1705 MonoReflectionTypeBuilder *tb;
1706 MonoReflectionArrayMethod *am;
1707 guint32 i, idx = 0;
1708 unsigned char *target;
1710 for (i = 0; i < ilgen->num_token_fixups; ++i) {
1711 iltoken = (MonoReflectionILTokenInfo *)mono_array_addr_with_size (ilgen->token_fixups, sizeof (MonoReflectionILTokenInfo), i);
1712 target = (guchar*)assembly->code.data + code_idx + iltoken->code_pos;
1713 switch (target [3]) {
1714 case MONO_TABLE_FIELD:
1715 if (!strcmp (iltoken->member->vtable->klass->name, "FieldBuilder")) {
1716 g_assert_not_reached ();
1717 } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoField")) {
1718 MonoClassField *f = ((MonoReflectionField*)iltoken->member)->field;
1719 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->field_to_table_idx, f));
1720 } else {
1721 g_assert_not_reached ();
1723 break;
1724 case MONO_TABLE_METHOD:
1725 if (!strcmp (iltoken->member->vtable->klass->name, "MethodBuilder")) {
1726 g_assert_not_reached ();
1727 } else if (!strcmp (iltoken->member->vtable->klass->name, "ConstructorBuilder")) {
1728 g_assert_not_reached ();
1729 } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoMethod") ||
1730 !strcmp (iltoken->member->vtable->klass->name, "MonoCMethod")) {
1731 MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
1732 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, m));
1733 } else {
1734 g_assert_not_reached ();
1736 break;
1737 case MONO_TABLE_TYPEDEF:
1738 if (!strcmp (iltoken->member->vtable->klass->name, "TypeBuilder")) {
1739 g_assert_not_reached ();
1740 } else if (!strcmp (iltoken->member->vtable->klass->name, "RuntimeType")) {
1741 MonoClass *k = mono_class_from_mono_type (((MonoReflectionType*)iltoken->member)->type);
1742 MonoObject *obj = mono_class_get_ref_info_raw (k); /* FIXME use handles */
1743 g_assert (obj);
1744 g_assert (!strcmp (mono_object_class (obj)->name, "TypeBuilder"));
1745 tb = (MonoReflectionTypeBuilder*)obj;
1746 idx = tb->table_idx;
1747 } else {
1748 g_assert_not_reached ();
1750 break;
1751 case MONO_TABLE_MEMBERREF:
1752 if (!strcmp (iltoken->member->vtable->klass->name, "MonoArrayMethod")) {
1753 am = (MonoReflectionArrayMethod*)iltoken->member;
1754 idx = am->table_idx;
1755 } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoMethod") ||
1756 !strcmp (iltoken->member->vtable->klass->name, "MonoCMethod")) {
1757 MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
1758 g_assert (mono_class_is_ginst (m->klass) || mono_class_is_gtd (m->klass));
1759 continue;
1760 } else if (!strcmp (iltoken->member->vtable->klass->name, "FieldBuilder")) {
1761 g_assert_not_reached ();
1762 continue;
1763 } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoField")) {
1764 continue;
1765 } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodBuilder") ||
1766 !strcmp (iltoken->member->vtable->klass->name, "ConstructorBuilder")) {
1767 g_assert_not_reached ();
1768 continue;
1769 } else if (!strcmp (iltoken->member->vtable->klass->name, "FieldOnTypeBuilderInst")) {
1770 g_assert_not_reached ();
1771 continue;
1772 } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodOnTypeBuilderInst")) {
1773 g_assert_not_reached ();
1774 continue;
1775 } else if (!strcmp (iltoken->member->vtable->klass->name, "ConstructorOnTypeBuilderInst")) {
1776 g_assert_not_reached ();
1777 continue;
1778 } else {
1779 g_assert_not_reached ();
1781 break;
1782 case MONO_TABLE_METHODSPEC:
1783 if (!strcmp (iltoken->member->vtable->klass->name, "MonoMethod")) {
1784 MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
1785 g_assert (mono_method_signature (m)->generic_param_count);
1786 continue;
1787 } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodBuilder")) {
1788 g_assert_not_reached ();
1789 continue;
1790 } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodOnTypeBuilderInst")) {
1791 g_assert_not_reached ();
1792 continue;
1793 } else {
1794 g_assert_not_reached ();
1796 break;
1797 case MONO_TABLE_TYPESPEC:
1798 if (!strcmp (iltoken->member->vtable->klass->name, "RuntimeType")) {
1799 continue;
1800 } else {
1801 g_assert_not_reached ();
1803 break;
1804 default:
1805 g_error ("got unexpected table 0x%02x in fixup", target [3]);
1807 target [0] = idx & 0xff;
1808 target [1] = (idx >> 8) & 0xff;
1809 target [2] = (idx >> 16) & 0xff;
1814 * fixup_cattrs:
1816 * The CUSTOM_ATTRIBUTE table might contain METHODDEF tokens whose final
1817 * value is not known when the table is emitted.
1819 static void
1820 fixup_cattrs (MonoDynamicImage *assembly)
1822 MonoDynamicTable *table;
1823 guint32 *values;
1824 guint32 type, i, idx, token;
1825 MonoObject *ctor;
1827 table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1829 for (i = 0; i < table->rows; ++i) {
1830 values = table->values + ((i + 1) * MONO_CUSTOM_ATTR_SIZE);
1832 type = values [MONO_CUSTOM_ATTR_TYPE];
1833 if ((type & MONO_CUSTOM_ATTR_TYPE_MASK) == MONO_CUSTOM_ATTR_TYPE_METHODDEF) {
1834 idx = type >> MONO_CUSTOM_ATTR_TYPE_BITS;
1835 token = mono_metadata_make_token (MONO_TABLE_METHOD, idx);
1836 ctor = (MonoObject *)mono_g_hash_table_lookup (assembly->remapped_tokens, GUINT_TO_POINTER (token));
1837 g_assert (ctor);
1839 if (!strcmp (ctor->vtable->klass->name, "MonoCMethod")) {
1840 MonoMethod *m = ((MonoReflectionMethod*)ctor)->method;
1841 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, m));
1842 values [MONO_CUSTOM_ATTR_TYPE] = (idx << MONO_CUSTOM_ATTR_TYPE_BITS) | MONO_CUSTOM_ATTR_TYPE_METHODDEF;
1843 } else if (!strcmp (ctor->vtable->klass->name, "ConstructorBuilder")) {
1844 MonoMethod *m = ((MonoReflectionCtorBuilder*)ctor)->mhandle;
1845 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, m));
1846 values [MONO_CUSTOM_ATTR_TYPE] = (idx << MONO_CUSTOM_ATTR_TYPE_BITS) | MONO_CUSTOM_ATTR_TYPE_METHODDEF;
1852 static gboolean
1853 assembly_add_resource_manifest (MonoReflectionModuleBuilder *mb, MonoDynamicImage *assembly, MonoReflectionResource *rsrc, guint32 implementation, MonoError *error)
1855 MonoDynamicTable *table;
1856 guint32 *values;
1858 mono_error_init (error);
1860 table = &assembly->tables [MONO_TABLE_MANIFESTRESOURCE];
1861 table->rows++;
1862 alloc_table (table, table->rows);
1863 values = table->values + table->next_idx * MONO_MANIFEST_SIZE;
1864 values [MONO_MANIFEST_OFFSET] = rsrc->offset;
1865 values [MONO_MANIFEST_FLAGS] = rsrc->attrs;
1866 values [MONO_MANIFEST_NAME] = string_heap_insert_mstring (&assembly->sheap, rsrc->name, error);
1867 return_val_if_nok (error, FALSE);
1868 values [MONO_MANIFEST_IMPLEMENTATION] = implementation;
1869 table->next_idx++;
1870 return TRUE;
1873 static gboolean
1874 assembly_add_resource (MonoReflectionModuleBuilder *mb, MonoDynamicImage *assembly, MonoReflectionResource *rsrc, MonoError *error)
1876 MonoDynamicTable *table;
1877 guint32 *values;
1878 char blob_size [6];
1879 guchar hash [20];
1880 char *b = blob_size;
1881 char *name, *sname;
1882 guint32 idx, offset;
1884 mono_error_init (error);
1886 if (rsrc->filename) {
1887 name = mono_string_to_utf8_checked (rsrc->filename, error);
1888 return_val_if_nok (error, FALSE);
1889 sname = g_path_get_basename (name);
1891 table = &assembly->tables [MONO_TABLE_FILE];
1892 table->rows++;
1893 alloc_table (table, table->rows);
1894 values = table->values + table->next_idx * MONO_FILE_SIZE;
1895 values [MONO_FILE_FLAGS] = FILE_CONTAINS_NO_METADATA;
1896 values [MONO_FILE_NAME] = string_heap_insert (&assembly->sheap, sname);
1897 g_free (sname);
1899 mono_sha1_get_digest_from_file (name, hash);
1900 mono_metadata_encode_value (20, b, &b);
1901 values [MONO_FILE_HASH_VALUE] = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
1902 mono_image_add_stream_data (&assembly->blob, (char*)hash, 20);
1903 g_free (name);
1904 idx = table->next_idx++;
1905 rsrc->offset = 0;
1906 idx = MONO_IMPLEMENTATION_FILE | (idx << MONO_IMPLEMENTATION_BITS);
1907 } else {
1908 char sizebuf [4];
1909 char *data;
1910 guint len;
1911 if (rsrc->data) {
1912 data = mono_array_addr (rsrc->data, char, 0);
1913 len = mono_array_length (rsrc->data);
1914 } else {
1915 data = NULL;
1916 len = 0;
1918 offset = len;
1919 sizebuf [0] = offset; sizebuf [1] = offset >> 8;
1920 sizebuf [2] = offset >> 16; sizebuf [3] = offset >> 24;
1921 rsrc->offset = mono_image_add_stream_data (&assembly->resources, sizebuf, 4);
1922 mono_image_add_stream_data (&assembly->resources, data, len);
1924 if (!mb->is_main)
1926 * The entry should be emitted into the MANIFESTRESOURCE table of
1927 * the main module, but that needs to reference the FILE table
1928 * which isn't emitted yet.
1930 return TRUE;
1931 else
1932 idx = 0;
1935 return assembly_add_resource_manifest (mb, assembly, rsrc, idx, error);
1938 static gboolean
1939 set_version_from_string (MonoString *version, guint32 *values, MonoError *error)
1941 gchar *ver, *p, *str;
1942 guint32 i;
1944 mono_error_init (error);
1946 values [MONO_ASSEMBLY_MAJOR_VERSION] = 0;
1947 values [MONO_ASSEMBLY_MINOR_VERSION] = 0;
1948 values [MONO_ASSEMBLY_REV_NUMBER] = 0;
1949 values [MONO_ASSEMBLY_BUILD_NUMBER] = 0;
1950 if (!version)
1951 return TRUE;
1952 ver = str = mono_string_to_utf8_checked (version, error);
1953 return_val_if_nok (error, FALSE);
1954 for (i = 0; i < 4; ++i) {
1955 values [MONO_ASSEMBLY_MAJOR_VERSION + i] = strtol (ver, &p, 10);
1956 switch (*p) {
1957 case '.':
1958 p++;
1959 break;
1960 case '*':
1961 /* handle Revision and Build */
1962 p++;
1963 break;
1965 ver = p;
1967 g_free (str);
1968 return TRUE;
1971 static guint32
1972 load_public_key (MonoArray *pkey, MonoDynamicImage *assembly) {
1973 gsize len;
1974 guint32 token = 0;
1975 char blob_size [6];
1976 char *b = blob_size;
1978 if (!pkey)
1979 return token;
1981 len = mono_array_length (pkey);
1982 mono_metadata_encode_value (len, b, &b);
1983 token = mono_image_add_stream_data (&assembly->blob, blob_size, b - blob_size);
1984 mono_image_add_stream_data (&assembly->blob, mono_array_addr (pkey, char, 0), len);
1986 assembly->public_key = (guint8 *)g_malloc (len);
1987 memcpy (assembly->public_key, mono_array_addr (pkey, char, 0), len);
1988 assembly->public_key_len = len;
1990 /* Special case: check for ECMA key (16 bytes) */
1991 if ((len == MONO_ECMA_KEY_LENGTH) && mono_is_ecma_key (mono_array_addr (pkey, char, 0), len)) {
1992 /* In this case we must reserve 128 bytes (1024 bits) for the signature */
1993 assembly->strong_name_size = MONO_DEFAULT_PUBLIC_KEY_LENGTH;
1994 } else if (len >= MONO_PUBLIC_KEY_HEADER_LENGTH + MONO_MINIMUM_PUBLIC_KEY_LENGTH) {
1995 /* minimum key size (in 2.0) is 384 bits */
1996 assembly->strong_name_size = len - MONO_PUBLIC_KEY_HEADER_LENGTH;
1997 } else {
1998 /* FIXME - verifier */
1999 g_warning ("Invalid public key length: %d bits (total: %d)", (int)MONO_PUBLIC_KEY_BIT_SIZE (len), (int)len);
2000 assembly->strong_name_size = MONO_DEFAULT_PUBLIC_KEY_LENGTH; /* to be safe */
2002 assembly->strong_name = (char *)g_malloc0 (assembly->strong_name_size);
2004 return token;
2007 static gboolean
2008 mono_image_emit_manifest (MonoReflectionModuleBuilder *moduleb, MonoError *error)
2010 MonoDynamicTable *table;
2011 MonoDynamicImage *assembly;
2012 MonoReflectionAssemblyBuilder *assemblyb;
2013 MonoDomain *domain;
2014 guint32 *values;
2015 int i;
2016 guint32 module_index;
2018 mono_error_init (error);
2020 assemblyb = moduleb->assemblyb;
2021 assembly = moduleb->dynamic_image;
2022 domain = mono_object_domain (assemblyb);
2024 /* Emit ASSEMBLY table */
2025 table = &assembly->tables [MONO_TABLE_ASSEMBLY];
2026 alloc_table (table, 1);
2027 values = table->values + MONO_ASSEMBLY_SIZE;
2028 values [MONO_ASSEMBLY_HASH_ALG] = assemblyb->algid? assemblyb->algid: ASSEMBLY_HASH_SHA1;
2029 values [MONO_ASSEMBLY_NAME] = string_heap_insert_mstring (&assembly->sheap, assemblyb->name, error);
2030 return_val_if_nok (error, FALSE);
2031 if (assemblyb->culture) {
2032 values [MONO_ASSEMBLY_CULTURE] = string_heap_insert_mstring (&assembly->sheap, assemblyb->culture, error);
2033 return_val_if_nok (error, FALSE);
2034 } else {
2035 values [MONO_ASSEMBLY_CULTURE] = string_heap_insert (&assembly->sheap, "");
2037 values [MONO_ASSEMBLY_PUBLIC_KEY] = load_public_key (assemblyb->public_key, assembly);
2038 values [MONO_ASSEMBLY_FLAGS] = assemblyb->flags;
2039 if (!set_version_from_string (assemblyb->version, values, error))
2040 return FALSE;
2042 /* Emit FILE + EXPORTED_TYPE table */
2043 module_index = 0;
2044 for (i = 0; i < mono_array_length (assemblyb->modules); ++i) {
2045 int j;
2046 MonoReflectionModuleBuilder *file_module =
2047 mono_array_get (assemblyb->modules, MonoReflectionModuleBuilder*, i);
2048 if (file_module != moduleb) {
2049 if (!mono_image_fill_file_table (domain, (MonoReflectionModule*)file_module, assembly, error))
2050 return FALSE;
2051 module_index ++;
2052 if (file_module->types) {
2053 for (j = 0; j < file_module->num_types; ++j) {
2054 MonoReflectionTypeBuilder *tb = mono_array_get (file_module->types, MonoReflectionTypeBuilder*, j);
2055 mono_image_fill_export_table (domain, tb, module_index, 0, assembly, error);
2056 return_val_if_nok (error, FALSE);
2061 if (assemblyb->loaded_modules) {
2062 for (i = 0; i < mono_array_length (assemblyb->loaded_modules); ++i) {
2063 MonoReflectionModule *file_module =
2064 mono_array_get (assemblyb->loaded_modules, MonoReflectionModule*, i);
2065 if (!mono_image_fill_file_table (domain, file_module, assembly, error))
2066 return FALSE;
2067 module_index ++;
2068 mono_image_fill_export_table_from_module (domain, file_module, module_index, assembly);
2071 if (assemblyb->type_forwarders)
2072 mono_image_fill_export_table_from_type_forwarders (assemblyb, assembly);
2074 /* Emit MANIFESTRESOURCE table */
2075 module_index = 0;
2076 for (i = 0; i < mono_array_length (assemblyb->modules); ++i) {
2077 int j;
2078 MonoReflectionModuleBuilder *file_module =
2079 mono_array_get (assemblyb->modules, MonoReflectionModuleBuilder*, i);
2080 /* The table for the main module is emitted later */
2081 if (file_module != moduleb) {
2082 module_index ++;
2083 if (file_module->resources) {
2084 int len = mono_array_length (file_module->resources);
2085 for (j = 0; j < len; ++j) {
2086 MonoReflectionResource* res = (MonoReflectionResource*)mono_array_addr (file_module->resources, MonoReflectionResource, j);
2087 if (!assembly_add_resource_manifest (file_module, assembly, res, MONO_IMPLEMENTATION_FILE | (module_index << MONO_IMPLEMENTATION_BITS), error))
2088 return FALSE;
2093 return TRUE;
2096 #ifndef DISABLE_REFLECTION_EMIT_SAVE
2099 * Insert into the metadata tables all the info about the TypeBuilder tb.
2100 * Data in the tables is inserted in a predefined order, since some tables need to be sorted.
2102 static gboolean
2103 mono_image_get_type_info (MonoDomain *domain, MonoReflectionTypeBuilder *tb, MonoDynamicImage *assembly, MonoError *error)
2105 MonoDynamicTable *table;
2106 guint *values;
2107 int i, is_object = 0, is_system = 0;
2108 char *n;
2110 mono_error_init (error);
2112 table = &assembly->tables [MONO_TABLE_TYPEDEF];
2113 values = table->values + tb->table_idx * MONO_TYPEDEF_SIZE;
2114 values [MONO_TYPEDEF_FLAGS] = tb->attrs;
2115 n = mono_string_to_utf8_checked (tb->name, error);
2116 return_val_if_nok (error, FALSE);
2117 if (strcmp (n, "Object") == 0)
2118 is_object++;
2119 values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, n);
2120 g_free (n);
2121 n = mono_string_to_utf8_checked (tb->nspace, error);
2122 return_val_if_nok (error, FALSE);
2123 if (strcmp (n, "System") == 0)
2124 is_system++;
2125 values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, n);
2126 g_free (n);
2127 if (tb->parent && !(is_system && is_object) &&
2128 !(tb->attrs & TYPE_ATTRIBUTE_INTERFACE)) { /* interfaces don't have a parent */
2129 MonoType *parent_type = mono_reflection_type_get_handle ((MonoReflectionType*)tb->parent, error);
2130 return_val_if_nok (error, FALSE);
2131 values [MONO_TYPEDEF_EXTENDS] = mono_image_typedef_or_ref (assembly, parent_type);
2132 } else {
2133 values [MONO_TYPEDEF_EXTENDS] = 0;
2135 values [MONO_TYPEDEF_FIELD_LIST] = assembly->tables [MONO_TABLE_FIELD].next_idx;
2136 values [MONO_TYPEDEF_METHOD_LIST] = assembly->tables [MONO_TABLE_METHOD].next_idx;
2139 * if we have explicitlayout or sequentiallayouts, output data in the
2140 * ClassLayout table.
2142 if (((tb->attrs & TYPE_ATTRIBUTE_LAYOUT_MASK) != TYPE_ATTRIBUTE_AUTO_LAYOUT) &&
2143 ((tb->class_size > 0) || (tb->packing_size > 0))) {
2144 table = &assembly->tables [MONO_TABLE_CLASSLAYOUT];
2145 table->rows++;
2146 alloc_table (table, table->rows);
2147 values = table->values + table->rows * MONO_CLASS_LAYOUT_SIZE;
2148 values [MONO_CLASS_LAYOUT_PARENT] = tb->table_idx;
2149 values [MONO_CLASS_LAYOUT_CLASS_SIZE] = tb->class_size;
2150 values [MONO_CLASS_LAYOUT_PACKING_SIZE] = tb->packing_size;
2153 /* handle interfaces */
2154 if (tb->interfaces) {
2155 table = &assembly->tables [MONO_TABLE_INTERFACEIMPL];
2156 i = table->rows;
2157 table->rows += mono_array_length (tb->interfaces);
2158 alloc_table (table, table->rows);
2159 values = table->values + (i + 1) * MONO_INTERFACEIMPL_SIZE;
2160 for (i = 0; i < mono_array_length (tb->interfaces); ++i) {
2161 MonoReflectionType* iface = (MonoReflectionType*) mono_array_get (tb->interfaces, gpointer, i);
2162 MonoType *iface_type = mono_reflection_type_get_handle (iface, error);
2163 return_val_if_nok (error, FALSE);
2164 values [MONO_INTERFACEIMPL_CLASS] = tb->table_idx;
2165 values [MONO_INTERFACEIMPL_INTERFACE] = mono_image_typedef_or_ref (assembly, iface_type);
2166 values += MONO_INTERFACEIMPL_SIZE;
2170 /* handle fields */
2171 if (tb->fields) {
2172 table = &assembly->tables [MONO_TABLE_FIELD];
2173 table->rows += tb->num_fields;
2174 alloc_table (table, table->rows);
2175 for (i = 0; i < tb->num_fields; ++i) {
2176 mono_image_get_field_info (
2177 mono_array_get (tb->fields, MonoReflectionFieldBuilder*, i), assembly, error);
2178 return_val_if_nok (error, FALSE);
2182 /* handle constructors */
2183 if (tb->ctors) {
2184 table = &assembly->tables [MONO_TABLE_METHOD];
2185 table->rows += mono_array_length (tb->ctors);
2186 alloc_table (table, table->rows);
2187 for (i = 0; i < mono_array_length (tb->ctors); ++i) {
2188 if (!mono_image_get_ctor_info (domain,
2189 mono_array_get (tb->ctors, MonoReflectionCtorBuilder*, i),
2190 assembly, error))
2191 return FALSE;
2195 /* handle methods */
2196 if (tb->methods) {
2197 table = &assembly->tables [MONO_TABLE_METHOD];
2198 table->rows += tb->num_methods;
2199 alloc_table (table, table->rows);
2200 for (i = 0; i < tb->num_methods; ++i) {
2201 if (!mono_image_get_method_info (
2202 mono_array_get (tb->methods, MonoReflectionMethodBuilder*, i), assembly, error))
2203 return FALSE;
2207 /* Do the same with properties etc.. */
2208 if (tb->events && mono_array_length (tb->events)) {
2209 table = &assembly->tables [MONO_TABLE_EVENT];
2210 table->rows += mono_array_length (tb->events);
2211 alloc_table (table, table->rows);
2212 table = &assembly->tables [MONO_TABLE_EVENTMAP];
2213 table->rows ++;
2214 alloc_table (table, table->rows);
2215 values = table->values + table->rows * MONO_EVENT_MAP_SIZE;
2216 values [MONO_EVENT_MAP_PARENT] = tb->table_idx;
2217 values [MONO_EVENT_MAP_EVENTLIST] = assembly->tables [MONO_TABLE_EVENT].next_idx;
2218 for (i = 0; i < mono_array_length (tb->events); ++i) {
2219 mono_image_get_event_info (
2220 mono_array_get (tb->events, MonoReflectionEventBuilder*, i), assembly, error);
2221 return_val_if_nok (error, FALSE);
2224 if (tb->properties && mono_array_length (tb->properties)) {
2225 table = &assembly->tables [MONO_TABLE_PROPERTY];
2226 table->rows += mono_array_length (tb->properties);
2227 alloc_table (table, table->rows);
2228 table = &assembly->tables [MONO_TABLE_PROPERTYMAP];
2229 table->rows ++;
2230 alloc_table (table, table->rows);
2231 values = table->values + table->rows * MONO_PROPERTY_MAP_SIZE;
2232 values [MONO_PROPERTY_MAP_PARENT] = tb->table_idx;
2233 values [MONO_PROPERTY_MAP_PROPERTY_LIST] = assembly->tables [MONO_TABLE_PROPERTY].next_idx;
2234 for (i = 0; i < mono_array_length (tb->properties); ++i) {
2235 mono_image_get_property_info (
2236 mono_array_get (tb->properties, MonoReflectionPropertyBuilder*, i), assembly, error);
2237 return_val_if_nok (error, FALSE);
2241 /* handle generic parameters */
2242 if (tb->generic_params) {
2243 table = &assembly->tables [MONO_TABLE_GENERICPARAM];
2244 table->rows += mono_array_length (tb->generic_params);
2245 alloc_table (table, table->rows);
2246 for (i = 0; i < mono_array_length (tb->generic_params); ++i) {
2247 guint32 owner = MONO_TYPEORMETHOD_TYPE | (tb->table_idx << MONO_TYPEORMETHOD_BITS);
2249 mono_image_get_generic_param_info (
2250 mono_array_get (tb->generic_params, MonoReflectionGenericParam*, i), owner, assembly);
2254 mono_image_add_decl_security (assembly,
2255 mono_metadata_make_token (MONO_TABLE_TYPEDEF, tb->table_idx), tb->permissions);
2257 if (tb->subtypes) {
2258 MonoDynamicTable *ntable;
2260 ntable = &assembly->tables [MONO_TABLE_NESTEDCLASS];
2261 ntable->rows += mono_array_length (tb->subtypes);
2262 alloc_table (ntable, ntable->rows);
2263 values = ntable->values + ntable->next_idx * MONO_NESTED_CLASS_SIZE;
2265 for (i = 0; i < mono_array_length (tb->subtypes); ++i) {
2266 MonoReflectionTypeBuilder *subtype = mono_array_get (tb->subtypes, MonoReflectionTypeBuilder*, i);
2268 values [MONO_NESTED_CLASS_NESTED] = subtype->table_idx;
2269 values [MONO_NESTED_CLASS_ENCLOSING] = tb->table_idx;
2270 /*g_print ("nesting %s (%d) in %s (%d) (rows %d/%d)\n",
2271 mono_string_to_utf8 (subtype->name), subtype->table_idx,
2272 mono_string_to_utf8 (tb->name), tb->table_idx,
2273 ntable->next_idx, ntable->rows);*/
2274 values += MONO_NESTED_CLASS_SIZE;
2275 ntable->next_idx++;
2279 return TRUE;
2284 * mono_image_build_metadata() will fill the info in all the needed metadata tables
2285 * for the modulebuilder @moduleb.
2286 * At the end of the process, method and field tokens are fixed up and the
2287 * on-disk compressed metadata representation is created.
2288 * Return TRUE on success, or FALSE on failure and sets @error
2290 gboolean
2291 mono_image_build_metadata (MonoReflectionModuleBuilder *moduleb, MonoError *error)
2293 MonoDynamicTable *table;
2294 MonoDynamicImage *assembly;
2295 MonoReflectionAssemblyBuilder *assemblyb;
2296 MonoDomain *domain;
2297 MonoPtrArray types;
2298 guint32 *values;
2299 int i, j;
2301 mono_error_init (error);
2303 assemblyb = moduleb->assemblyb;
2304 assembly = moduleb->dynamic_image;
2305 domain = mono_object_domain (assemblyb);
2307 if (assembly->text_rva)
2308 return TRUE;
2310 assembly->text_rva = START_TEXT_RVA;
2312 if (moduleb->is_main) {
2313 mono_image_emit_manifest (moduleb, error);
2314 return_val_if_nok (error, FALSE);
2317 table = &assembly->tables [MONO_TABLE_TYPEDEF];
2318 table->rows = 1; /* .<Module> */
2319 table->next_idx++;
2320 alloc_table (table, table->rows);
2322 * Set the first entry.
2324 values = table->values + table->columns;
2325 values [MONO_TYPEDEF_FLAGS] = 0;
2326 values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, "<Module>") ;
2327 values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, "") ;
2328 values [MONO_TYPEDEF_EXTENDS] = 0;
2329 values [MONO_TYPEDEF_FIELD_LIST] = 1;
2330 values [MONO_TYPEDEF_METHOD_LIST] = 1;
2333 * handle global methods
2334 * FIXME: test what to do when global methods are defined in multiple modules.
2336 if (moduleb->global_methods) {
2337 table = &assembly->tables [MONO_TABLE_METHOD];
2338 table->rows += mono_array_length (moduleb->global_methods);
2339 alloc_table (table, table->rows);
2340 for (i = 0; i < mono_array_length (moduleb->global_methods); ++i) {
2341 if (!mono_image_get_method_info (
2342 mono_array_get (moduleb->global_methods, MonoReflectionMethodBuilder*, i), assembly, error))
2343 goto leave;
2346 if (moduleb->global_fields) {
2347 table = &assembly->tables [MONO_TABLE_FIELD];
2348 table->rows += mono_array_length (moduleb->global_fields);
2349 alloc_table (table, table->rows);
2350 for (i = 0; i < mono_array_length (moduleb->global_fields); ++i) {
2351 mono_image_get_field_info (
2352 mono_array_get (moduleb->global_fields, MonoReflectionFieldBuilder*, i), assembly,
2353 error);
2354 if (!is_ok (error))
2355 goto leave;
2359 table = &assembly->tables [MONO_TABLE_MODULE];
2360 alloc_table (table, 1);
2361 mono_image_fill_module_table (domain, moduleb, assembly, error);
2362 if (!is_ok (error))
2363 goto leave;
2365 /* Collect all types into a list sorted by their table_idx */
2366 mono_ptr_array_init (types, moduleb->num_types, MONO_ROOT_SOURCE_REFLECTION, "dynamic module types list");
2368 if (moduleb->types)
2369 for (i = 0; i < moduleb->num_types; ++i) {
2370 MonoReflectionTypeBuilder *type = mono_array_get (moduleb->types, MonoReflectionTypeBuilder*, i);
2371 collect_types (&types, type);
2374 mono_ptr_array_sort (types, (int (*)(const void *, const void *))compare_types_by_table_idx);
2375 table = &assembly->tables [MONO_TABLE_TYPEDEF];
2376 table->rows += mono_ptr_array_size (types);
2377 alloc_table (table, table->rows);
2380 * Emit type names + namespaces at one place inside the string heap,
2381 * so load_class_names () needs to touch fewer pages.
2383 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2384 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2385 string_heap_insert_mstring (&assembly->sheap, tb->nspace, error);
2386 if (!is_ok (error))
2387 goto leave_types;
2389 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2390 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2391 string_heap_insert_mstring (&assembly->sheap, tb->name, error);
2392 if (!is_ok (error))
2393 goto leave_types;
2396 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2397 MonoReflectionTypeBuilder *type = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2398 if (!mono_image_get_type_info (domain, type, assembly, error))
2399 goto leave_types;
2403 * table->rows is already set above and in mono_image_fill_module_table.
2405 /* add all the custom attributes at the end, once all the indexes are stable */
2406 if (!mono_image_add_cattrs (assembly, 1, MONO_CUSTOM_ATTR_ASSEMBLY, assemblyb->cattrs, error))
2407 goto leave_types;
2409 /* CAS assembly permissions */
2410 if (assemblyb->permissions_minimum)
2411 mono_image_add_decl_security (assembly, mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1), assemblyb->permissions_minimum);
2412 if (assemblyb->permissions_optional)
2413 mono_image_add_decl_security (assembly, mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1), assemblyb->permissions_optional);
2414 if (assemblyb->permissions_refused)
2415 mono_image_add_decl_security (assembly, mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1), assemblyb->permissions_refused);
2417 if (!module_add_cattrs (assembly, moduleb, error))
2418 goto leave_types;
2420 /* fixup tokens */
2421 mono_g_hash_table_foreach (assembly->token_fixups, (GHFunc)fixup_method, assembly);
2423 /* Create the MethodImpl table. We do this after emitting all methods so we already know
2424 * the final tokens and don't need another fixup pass. */
2426 if (moduleb->global_methods) {
2427 for (i = 0; i < mono_array_length (moduleb->global_methods); ++i) {
2428 MonoReflectionMethodBuilder *mb = mono_array_get (
2429 moduleb->global_methods, MonoReflectionMethodBuilder*, i);
2430 if (!mono_image_add_methodimpl (assembly, mb, error))
2431 goto leave_types;
2435 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2436 MonoReflectionTypeBuilder *type = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2437 if (type->methods) {
2438 for (j = 0; j < type->num_methods; ++j) {
2439 MonoReflectionMethodBuilder *mb = mono_array_get (
2440 type->methods, MonoReflectionMethodBuilder*, j);
2442 if (!mono_image_add_methodimpl (assembly, mb, error))
2443 goto leave_types;
2448 fixup_cattrs (assembly);
2450 leave_types:
2451 mono_ptr_array_destroy (types);
2452 leave:
2454 return mono_error_ok (error);
2457 #else /* DISABLE_REFLECTION_EMIT_SAVE */
2459 gboolean
2460 mono_image_build_metadata (MonoReflectionModuleBuilder *moduleb, MonoError *error)
2462 g_error ("This mono runtime was configured with --enable-minimal=reflection_emit_save, so saving of dynamic assemblies is not supported.");
2465 #endif /* DISABLE_REFLECTION_EMIT_SAVE */
2467 #ifndef DISABLE_REFLECTION_EMIT_SAVE
2469 static int
2470 calc_section_size (MonoDynamicImage *assembly)
2472 int nsections = 0;
2474 /* alignment constraints */
2475 mono_image_add_stream_zero (&assembly->code, 4 - (assembly->code.index % 4));
2476 g_assert ((assembly->code.index % 4) == 0);
2477 assembly->meta_size += 3;
2478 assembly->meta_size &= ~3;
2479 mono_image_add_stream_zero (&assembly->resources, 4 - (assembly->resources.index % 4));
2480 g_assert ((assembly->resources.index % 4) == 0);
2482 assembly->sections [MONO_SECTION_TEXT].size = assembly->meta_size + assembly->code.index + assembly->resources.index + assembly->strong_name_size;
2483 assembly->sections [MONO_SECTION_TEXT].attrs = SECT_FLAGS_HAS_CODE | SECT_FLAGS_MEM_EXECUTE | SECT_FLAGS_MEM_READ;
2484 nsections++;
2486 if (assembly->win32_res) {
2487 guint32 res_size = (assembly->win32_res_size + 3) & ~3;
2489 assembly->sections [MONO_SECTION_RSRC].size = res_size;
2490 assembly->sections [MONO_SECTION_RSRC].attrs = SECT_FLAGS_HAS_INITIALIZED_DATA | SECT_FLAGS_MEM_READ;
2491 nsections++;
2494 assembly->sections [MONO_SECTION_RELOC].size = 12;
2495 assembly->sections [MONO_SECTION_RELOC].attrs = SECT_FLAGS_MEM_READ | SECT_FLAGS_MEM_DISCARDABLE | SECT_FLAGS_HAS_INITIALIZED_DATA;
2496 nsections++;
2498 return nsections;
2501 typedef struct {
2502 guint32 id;
2503 guint32 offset;
2504 GSList *children;
2505 MonoReflectionWin32Resource *win32_res; /* Only for leaf nodes */
2506 } ResTreeNode;
2508 static int
2509 resource_tree_compare_by_id (gconstpointer a, gconstpointer b)
2511 ResTreeNode *t1 = (ResTreeNode*)a;
2512 ResTreeNode *t2 = (ResTreeNode*)b;
2514 return t1->id - t2->id;
2518 * resource_tree_create:
2520 * Organize the resources into a resource tree.
2522 static ResTreeNode *
2523 resource_tree_create (MonoArray *win32_resources)
2525 ResTreeNode *tree, *res_node, *type_node, *lang_node;
2526 GSList *l;
2527 int i;
2529 tree = g_new0 (ResTreeNode, 1);
2531 for (i = 0; i < mono_array_length (win32_resources); ++i) {
2532 MonoReflectionWin32Resource *win32_res =
2533 (MonoReflectionWin32Resource*)mono_array_addr (win32_resources, MonoReflectionWin32Resource, i);
2535 /* Create node */
2537 /* FIXME: BUG: this stores managed references in unmanaged memory */
2538 lang_node = g_new0 (ResTreeNode, 1);
2539 lang_node->id = win32_res->lang_id;
2540 lang_node->win32_res = win32_res;
2542 /* Create type node if neccesary */
2543 type_node = NULL;
2544 for (l = tree->children; l; l = l->next)
2545 if (((ResTreeNode*)(l->data))->id == win32_res->res_type) {
2546 type_node = (ResTreeNode*)l->data;
2547 break;
2550 if (!type_node) {
2551 type_node = g_new0 (ResTreeNode, 1);
2552 type_node->id = win32_res->res_type;
2555 * The resource types have to be sorted otherwise
2556 * Windows Explorer can't display the version information.
2558 tree->children = g_slist_insert_sorted (tree->children,
2559 type_node, resource_tree_compare_by_id);
2562 /* Create res node if neccesary */
2563 res_node = NULL;
2564 for (l = type_node->children; l; l = l->next)
2565 if (((ResTreeNode*)(l->data))->id == win32_res->res_id) {
2566 res_node = (ResTreeNode*)l->data;
2567 break;
2570 if (!res_node) {
2571 res_node = g_new0 (ResTreeNode, 1);
2572 res_node->id = win32_res->res_id;
2573 type_node->children = g_slist_append (type_node->children, res_node);
2576 res_node->children = g_slist_append (res_node->children, lang_node);
2579 return tree;
2583 * resource_tree_encode:
2585 * Encode the resource tree into the format used in the PE file.
2587 static void
2588 resource_tree_encode (ResTreeNode *node, char *begin, char *p, char **endbuf)
2590 char *entries;
2591 MonoPEResourceDir dir;
2592 MonoPEResourceDirEntry dir_entry;
2593 MonoPEResourceDataEntry data_entry;
2594 GSList *l;
2595 guint32 res_id_entries;
2598 * For the format of the resource directory, see the article
2599 * "An In-Depth Look into the Win32 Portable Executable File Format" by
2600 * Matt Pietrek
2603 memset (&dir, 0, sizeof (dir));
2604 memset (&dir_entry, 0, sizeof (dir_entry));
2605 memset (&data_entry, 0, sizeof (data_entry));
2607 g_assert (sizeof (dir) == 16);
2608 g_assert (sizeof (dir_entry) == 8);
2609 g_assert (sizeof (data_entry) == 16);
2611 node->offset = p - begin;
2613 /* IMAGE_RESOURCE_DIRECTORY */
2614 res_id_entries = g_slist_length (node->children);
2615 dir.res_id_entries = GUINT16_TO_LE (res_id_entries);
2617 memcpy (p, &dir, sizeof (dir));
2618 p += sizeof (dir);
2620 /* Reserve space for entries */
2621 entries = p;
2622 p += sizeof (dir_entry) * res_id_entries;
2624 /* Write children */
2625 for (l = node->children; l; l = l->next) {
2626 ResTreeNode *child = (ResTreeNode*)l->data;
2628 if (child->win32_res) {
2629 guint32 size;
2631 child->offset = p - begin;
2633 /* IMAGE_RESOURCE_DATA_ENTRY */
2634 data_entry.rde_data_offset = GUINT32_TO_LE (p - begin + sizeof (data_entry));
2635 size = mono_array_length (child->win32_res->res_data);
2636 data_entry.rde_size = GUINT32_TO_LE (size);
2638 memcpy (p, &data_entry, sizeof (data_entry));
2639 p += sizeof (data_entry);
2641 memcpy (p, mono_array_addr (child->win32_res->res_data, char, 0), size);
2642 p += size;
2643 } else {
2644 resource_tree_encode (child, begin, p, &p);
2648 /* IMAGE_RESOURCE_ENTRY */
2649 for (l = node->children; l; l = l->next) {
2650 ResTreeNode *child = (ResTreeNode*)l->data;
2652 MONO_PE_RES_DIR_ENTRY_SET_NAME (dir_entry, FALSE, child->id);
2653 MONO_PE_RES_DIR_ENTRY_SET_DIR (dir_entry, !child->win32_res, child->offset);
2655 memcpy (entries, &dir_entry, sizeof (dir_entry));
2656 entries += sizeof (dir_entry);
2659 *endbuf = p;
2662 static void
2663 resource_tree_free (ResTreeNode * node)
2665 GSList * list;
2666 for (list = node->children; list; list = list->next)
2667 resource_tree_free ((ResTreeNode*)list->data);
2668 g_slist_free(node->children);
2669 g_free (node);
2672 static void
2673 assembly_add_win32_resources (MonoDynamicImage *assembly, MonoReflectionAssemblyBuilder *assemblyb)
2675 char *buf;
2676 char *p;
2677 guint32 size, i;
2678 MonoReflectionWin32Resource *win32_res;
2679 ResTreeNode *tree;
2681 if (!assemblyb->win32_resources)
2682 return;
2685 * Resources are stored in a three level tree inside the PE file.
2686 * - level one contains a node for each type of resource
2687 * - level two contains a node for each resource
2688 * - level three contains a node for each instance of a resource for a
2689 * specific language.
2692 tree = resource_tree_create (assemblyb->win32_resources);
2694 /* Estimate the size of the encoded tree */
2695 size = 0;
2696 for (i = 0; i < mono_array_length (assemblyb->win32_resources); ++i) {
2697 win32_res = (MonoReflectionWin32Resource*)mono_array_addr (assemblyb->win32_resources, MonoReflectionWin32Resource, i);
2698 size += mono_array_length (win32_res->res_data);
2700 /* Directory structure */
2701 size += mono_array_length (assemblyb->win32_resources) * 256;
2702 p = buf = (char *)g_malloc (size);
2704 resource_tree_encode (tree, p, p, &p);
2706 g_assert (p - buf <= size);
2708 assembly->win32_res = (char *)g_malloc (p - buf);
2709 assembly->win32_res_size = p - buf;
2710 memcpy (assembly->win32_res, buf, p - buf);
2712 g_free (buf);
2713 resource_tree_free (tree);
2716 static void
2717 fixup_resource_directory (char *res_section, char *p, guint32 rva)
2719 MonoPEResourceDir *dir = (MonoPEResourceDir*)p;
2720 int i;
2722 p += sizeof (MonoPEResourceDir);
2723 for (i = 0; i < GUINT16_FROM_LE (dir->res_named_entries) + GUINT16_FROM_LE (dir->res_id_entries); ++i) {
2724 MonoPEResourceDirEntry *dir_entry = (MonoPEResourceDirEntry*)p;
2725 char *child = res_section + MONO_PE_RES_DIR_ENTRY_DIR_OFFSET (*dir_entry);
2726 if (MONO_PE_RES_DIR_ENTRY_IS_DIR (*dir_entry)) {
2727 fixup_resource_directory (res_section, child, rva);
2728 } else {
2729 MonoPEResourceDataEntry *data_entry = (MonoPEResourceDataEntry*)child;
2730 data_entry->rde_data_offset = GUINT32_TO_LE (GUINT32_FROM_LE (data_entry->rde_data_offset) + rva);
2733 p += sizeof (MonoPEResourceDirEntry);
2737 static void
2738 checked_write_file (HANDLE f, gconstpointer buffer, guint32 numbytes)
2740 guint32 dummy;
2741 if (!mono_w32file_write (f, buffer, numbytes, &dummy))
2742 g_error ("mono_w32file_write returned %d\n", mono_w32error_get_last ());
2746 * mono_image_create_pefile:
2747 * @mb: a module builder object
2749 * This function creates the PE-COFF header, the image sections, the CLI header * etc. all the data is written in
2750 * assembly->pefile where it can be easily retrieved later in chunks.
2752 gboolean
2753 mono_image_create_pefile (MonoReflectionModuleBuilder *mb, HANDLE file, MonoError *error)
2755 MonoMSDOSHeader *msdos;
2756 MonoDotNetHeader *header;
2757 MonoSectionTable *section;
2758 MonoCLIHeader *cli_header;
2759 guint32 size, image_size, virtual_base, text_offset;
2760 guint32 header_start, section_start, file_offset, virtual_offset;
2761 MonoDynamicImage *assembly;
2762 MonoReflectionAssemblyBuilder *assemblyb;
2763 MonoDynamicStream pefile_stream = {0};
2764 MonoDynamicStream *pefile = &pefile_stream;
2765 int i, nsections;
2766 guint32 *rva, value;
2767 guchar *p;
2768 static const unsigned char msheader[] = {
2769 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
2770 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2771 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2772 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
2773 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68,
2774 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f,
2775 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,
2776 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
2779 mono_error_init (error);
2781 assemblyb = mb->assemblyb;
2783 mono_reflection_dynimage_basic_init (assemblyb);
2784 assembly = mb->dynamic_image;
2786 assembly->pe_kind = assemblyb->pe_kind;
2787 assembly->machine = assemblyb->machine;
2788 ((MonoDynamicImage*)assemblyb->dynamic_assembly->assembly.image)->pe_kind = assemblyb->pe_kind;
2789 ((MonoDynamicImage*)assemblyb->dynamic_assembly->assembly.image)->machine = assemblyb->machine;
2791 if (!mono_image_build_metadata (mb, error))
2792 return FALSE;
2795 if (mb->is_main && assemblyb->resources) {
2796 int len = mono_array_length (assemblyb->resources);
2797 for (i = 0; i < len; ++i) {
2798 if (!assembly_add_resource (mb, assembly, (MonoReflectionResource*)mono_array_addr (assemblyb->resources, MonoReflectionResource, i), error))
2799 return FALSE;
2803 if (mb->resources) {
2804 int len = mono_array_length (mb->resources);
2805 for (i = 0; i < len; ++i) {
2806 if (!assembly_add_resource (mb, assembly, (MonoReflectionResource*)mono_array_addr (mb->resources, MonoReflectionResource, i), error))
2807 return FALSE;
2811 if (!build_compressed_metadata (assembly, error))
2812 return FALSE;
2814 if (mb->is_main)
2815 assembly_add_win32_resources (assembly, assemblyb);
2817 nsections = calc_section_size (assembly);
2819 /* The DOS header and stub */
2820 g_assert (sizeof (MonoMSDOSHeader) == sizeof (msheader));
2821 mono_image_add_stream_data (pefile, (char*)msheader, sizeof (msheader));
2823 /* the dotnet header */
2824 header_start = mono_image_add_stream_zero (pefile, sizeof (MonoDotNetHeader));
2826 /* the section tables */
2827 section_start = mono_image_add_stream_zero (pefile, sizeof (MonoSectionTable) * nsections);
2829 file_offset = section_start + sizeof (MonoSectionTable) * nsections;
2830 virtual_offset = VIRT_ALIGN;
2831 image_size = 0;
2833 for (i = 0; i < MONO_SECTION_MAX; ++i) {
2834 if (!assembly->sections [i].size)
2835 continue;
2836 /* align offsets */
2837 file_offset += FILE_ALIGN - 1;
2838 file_offset &= ~(FILE_ALIGN - 1);
2839 virtual_offset += VIRT_ALIGN - 1;
2840 virtual_offset &= ~(VIRT_ALIGN - 1);
2842 assembly->sections [i].offset = file_offset;
2843 assembly->sections [i].rva = virtual_offset;
2845 file_offset += assembly->sections [i].size;
2846 virtual_offset += assembly->sections [i].size;
2847 image_size += (assembly->sections [i].size + VIRT_ALIGN - 1) & ~(VIRT_ALIGN - 1);
2850 file_offset += FILE_ALIGN - 1;
2851 file_offset &= ~(FILE_ALIGN - 1);
2853 image_size += section_start + sizeof (MonoSectionTable) * nsections;
2855 /* back-patch info */
2856 msdos = (MonoMSDOSHeader*)pefile->data;
2857 msdos->pe_offset = GUINT32_FROM_LE (sizeof (MonoMSDOSHeader));
2859 header = (MonoDotNetHeader*)(pefile->data + header_start);
2860 header->pesig [0] = 'P';
2861 header->pesig [1] = 'E';
2863 header->coff.coff_machine = GUINT16_FROM_LE (assemblyb->machine);
2864 header->coff.coff_sections = GUINT16_FROM_LE (nsections);
2865 header->coff.coff_time = GUINT32_FROM_LE (time (NULL));
2866 header->coff.coff_opt_header_size = GUINT16_FROM_LE (sizeof (MonoDotNetHeader) - sizeof (MonoCOFFHeader) - 4);
2867 if (assemblyb->pekind == 1) {
2868 /* it's a dll */
2869 header->coff.coff_attributes = GUINT16_FROM_LE (0x210e);
2870 } else {
2871 /* it's an exe */
2872 header->coff.coff_attributes = GUINT16_FROM_LE (0x010e);
2875 virtual_base = 0x400000; /* FIXME: 0x10000000 if a DLL */
2877 header->pe.pe_magic = GUINT16_FROM_LE (0x10B);
2878 header->pe.pe_major = 6;
2879 header->pe.pe_minor = 0;
2880 size = assembly->sections [MONO_SECTION_TEXT].size;
2881 size += FILE_ALIGN - 1;
2882 size &= ~(FILE_ALIGN - 1);
2883 header->pe.pe_code_size = GUINT32_FROM_LE(size);
2884 size = assembly->sections [MONO_SECTION_RSRC].size;
2885 size += FILE_ALIGN - 1;
2886 size &= ~(FILE_ALIGN - 1);
2887 header->pe.pe_data_size = GUINT32_FROM_LE(size);
2888 g_assert (START_TEXT_RVA == assembly->sections [MONO_SECTION_TEXT].rva);
2889 header->pe.pe_rva_code_base = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_TEXT].rva);
2890 header->pe.pe_rva_data_base = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].rva);
2891 /* pe_rva_entry_point always at the beginning of the text section */
2892 header->pe.pe_rva_entry_point = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_TEXT].rva);
2894 header->nt.pe_image_base = GUINT32_FROM_LE (virtual_base);
2895 header->nt.pe_section_align = GUINT32_FROM_LE (VIRT_ALIGN);
2896 header->nt.pe_file_alignment = GUINT32_FROM_LE (FILE_ALIGN);
2897 header->nt.pe_os_major = GUINT16_FROM_LE (4);
2898 header->nt.pe_os_minor = GUINT16_FROM_LE (0);
2899 header->nt.pe_subsys_major = GUINT16_FROM_LE (4);
2900 size = section_start;
2901 size += FILE_ALIGN - 1;
2902 size &= ~(FILE_ALIGN - 1);
2903 header->nt.pe_header_size = GUINT32_FROM_LE (size);
2904 size = image_size;
2905 size += VIRT_ALIGN - 1;
2906 size &= ~(VIRT_ALIGN - 1);
2907 header->nt.pe_image_size = GUINT32_FROM_LE (size);
2910 // Translate the PEFileKind value to the value expected by the Windows loader
2913 short kind;
2916 // PEFileKinds.Dll == 1
2917 // PEFileKinds.ConsoleApplication == 2
2918 // PEFileKinds.WindowApplication == 3
2920 // need to get:
2921 // IMAGE_SUBSYSTEM_WINDOWS_GUI 2 // Image runs in the Windows GUI subsystem.
2922 // IMAGE_SUBSYSTEM_WINDOWS_CUI 3 // Image runs in the Windows character subsystem.
2924 if (assemblyb->pekind == 3)
2925 kind = 2;
2926 else
2927 kind = 3;
2929 header->nt.pe_subsys_required = GUINT16_FROM_LE (kind);
2931 header->nt.pe_stack_reserve = GUINT32_FROM_LE (0x00100000);
2932 header->nt.pe_stack_commit = GUINT32_FROM_LE (0x00001000);
2933 header->nt.pe_heap_reserve = GUINT32_FROM_LE (0x00100000);
2934 header->nt.pe_heap_commit = GUINT32_FROM_LE (0x00001000);
2935 header->nt.pe_loader_flags = GUINT32_FROM_LE (0);
2936 header->nt.pe_data_dir_count = GUINT32_FROM_LE (16);
2938 /* fill data directory entries */
2940 header->datadir.pe_resource_table.size = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].size);
2941 header->datadir.pe_resource_table.rva = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].rva);
2943 header->datadir.pe_reloc_table.size = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RELOC].size);
2944 header->datadir.pe_reloc_table.rva = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RELOC].rva);
2946 header->datadir.pe_cli_header.size = GUINT32_FROM_LE (72);
2947 header->datadir.pe_cli_header.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->cli_header_offset);
2948 header->datadir.pe_iat.size = GUINT32_FROM_LE (8);
2949 header->datadir.pe_iat.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->iat_offset);
2950 /* patch entrypoint name */
2951 if (assemblyb->pekind == 1)
2952 memcpy (assembly->code.data + assembly->imp_names_offset + 2, "_CorDllMain", 12);
2953 else
2954 memcpy (assembly->code.data + assembly->imp_names_offset + 2, "_CorExeMain", 12);
2955 /* patch imported function RVA name */
2956 rva = (guint32*)(assembly->code.data + assembly->iat_offset);
2957 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->imp_names_offset);
2959 /* the import table */
2960 header->datadir.pe_import_table.size = GUINT32_FROM_LE (79); /* FIXME: magic number? */
2961 header->datadir.pe_import_table.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->idt_offset);
2962 /* patch imported dll RVA name and other entries in the dir */
2963 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, name_rva));
2964 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->imp_names_offset + 14); /* 14 is hint+strlen+1 of func name */
2965 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, import_address_table_rva));
2966 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->iat_offset);
2967 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, import_lookup_table));
2968 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->ilt_offset);
2970 p = (guchar*)(assembly->code.data + assembly->ilt_offset);
2971 value = (assembly->text_rva + assembly->imp_names_offset);
2972 *p++ = (value) & 0xff;
2973 *p++ = (value >> 8) & (0xff);
2974 *p++ = (value >> 16) & (0xff);
2975 *p++ = (value >> 24) & (0xff);
2977 /* the CLI header info */
2978 cli_header = (MonoCLIHeader*)(assembly->code.data + assembly->cli_header_offset);
2979 cli_header->ch_size = GUINT32_FROM_LE (72);
2980 cli_header->ch_runtime_major = GUINT16_FROM_LE (2);
2981 cli_header->ch_runtime_minor = GUINT16_FROM_LE (5);
2982 cli_header->ch_flags = GUINT32_FROM_LE (assemblyb->pe_kind);
2983 if (assemblyb->entry_point) {
2984 guint32 table_idx = 0;
2985 if (!strcmp (assemblyb->entry_point->object.vtable->klass->name, "MethodBuilder")) {
2986 MonoReflectionMethodBuilder *methodb = (MonoReflectionMethodBuilder*)assemblyb->entry_point;
2987 table_idx = methodb->table_idx;
2988 } else {
2989 table_idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, assemblyb->entry_point->method));
2991 cli_header->ch_entry_point = GUINT32_FROM_LE (table_idx | MONO_TOKEN_METHOD_DEF);
2992 } else {
2993 cli_header->ch_entry_point = GUINT32_FROM_LE (0);
2995 /* The embedded managed resources */
2996 text_offset = assembly->text_rva + assembly->code.index;
2997 cli_header->ch_resources.rva = GUINT32_FROM_LE (text_offset);
2998 cli_header->ch_resources.size = GUINT32_FROM_LE (assembly->resources.index);
2999 text_offset += assembly->resources.index;
3000 cli_header->ch_metadata.rva = GUINT32_FROM_LE (text_offset);
3001 cli_header->ch_metadata.size = GUINT32_FROM_LE (assembly->meta_size);
3002 text_offset += assembly->meta_size;
3003 if (assembly->strong_name_size) {
3004 cli_header->ch_strong_name.rva = GUINT32_FROM_LE (text_offset);
3005 cli_header->ch_strong_name.size = GUINT32_FROM_LE (assembly->strong_name_size);
3006 text_offset += assembly->strong_name_size;
3009 /* write the section tables and section content */
3010 section = (MonoSectionTable*)(pefile->data + section_start);
3011 for (i = 0; i < MONO_SECTION_MAX; ++i) {
3012 static const char section_names [][7] = {
3013 ".text", ".rsrc", ".reloc"
3015 if (!assembly->sections [i].size)
3016 continue;
3017 strcpy (section->st_name, section_names [i]);
3018 /*g_print ("output section %s (%d), size: %d\n", section->st_name, i, assembly->sections [i].size);*/
3019 section->st_virtual_address = GUINT32_FROM_LE (assembly->sections [i].rva);
3020 section->st_virtual_size = GUINT32_FROM_LE (assembly->sections [i].size);
3021 section->st_raw_data_size = GUINT32_FROM_LE (GUINT32_TO_LE (section->st_virtual_size) + (FILE_ALIGN - 1));
3022 section->st_raw_data_size &= GUINT32_FROM_LE (~(FILE_ALIGN - 1));
3023 section->st_raw_data_ptr = GUINT32_FROM_LE (assembly->sections [i].offset);
3024 section->st_flags = GUINT32_FROM_LE (assembly->sections [i].attrs);
3025 section ++;
3028 checked_write_file (file, pefile->data, pefile->index);
3030 mono_dynamic_stream_reset (pefile);
3032 for (i = 0; i < MONO_SECTION_MAX; ++i) {
3033 if (!assembly->sections [i].size)
3034 continue;
3036 if (mono_w32file_seek (file, assembly->sections [i].offset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
3037 g_error ("mono_w32file_seek returned %d\n", mono_w32error_get_last ());
3039 switch (i) {
3040 case MONO_SECTION_TEXT:
3041 /* patch entry point */
3042 p = (guchar*)(assembly->code.data + 2);
3043 value = (virtual_base + assembly->text_rva + assembly->iat_offset);
3044 *p++ = (value) & 0xff;
3045 *p++ = (value >> 8) & 0xff;
3046 *p++ = (value >> 16) & 0xff;
3047 *p++ = (value >> 24) & 0xff;
3049 checked_write_file (file, assembly->code.data, assembly->code.index);
3050 checked_write_file (file, assembly->resources.data, assembly->resources.index);
3051 checked_write_file (file, assembly->image.raw_metadata, assembly->meta_size);
3052 checked_write_file (file, assembly->strong_name, assembly->strong_name_size);
3055 g_free (assembly->image.raw_metadata);
3056 break;
3057 case MONO_SECTION_RELOC: {
3058 struct {
3059 guint32 page_rva;
3060 guint32 block_size;
3061 guint16 type_and_offset;
3062 guint16 term;
3063 } reloc;
3065 g_assert (sizeof (reloc) == 12);
3067 reloc.page_rva = GUINT32_FROM_LE (assembly->text_rva);
3068 reloc.block_size = GUINT32_FROM_LE (12);
3071 * the entrypoint is always at the start of the text section
3072 * 3 is IMAGE_REL_BASED_HIGHLOW
3073 * 2 is patch_size_rva - text_rva
3075 reloc.type_and_offset = GUINT16_FROM_LE ((3 << 12) + (2));
3076 reloc.term = 0;
3078 checked_write_file (file, &reloc, sizeof (reloc));
3080 break;
3082 case MONO_SECTION_RSRC:
3083 if (assembly->win32_res) {
3085 /* Fixup the offsets in the IMAGE_RESOURCE_DATA_ENTRY structures */
3086 fixup_resource_directory (assembly->win32_res, assembly->win32_res, assembly->sections [i].rva);
3087 checked_write_file (file, assembly->win32_res, assembly->win32_res_size);
3089 break;
3090 default:
3091 g_assert_not_reached ();
3095 /* check that the file is properly padded */
3096 if (mono_w32file_seek (file, file_offset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
3097 g_error ("mono_w32file_seek returned %d\n", mono_w32error_get_last ());
3098 if (! mono_w32file_truncate (file))
3099 g_error ("mono_w32file_truncate returned %d\n", mono_w32error_get_last ());
3101 mono_dynamic_stream_reset (&assembly->code);
3102 mono_dynamic_stream_reset (&assembly->us);
3103 mono_dynamic_stream_reset (&assembly->blob);
3104 mono_dynamic_stream_reset (&assembly->guid);
3105 mono_dynamic_stream_reset (&assembly->sheap);
3107 g_hash_table_foreach (assembly->blob_cache, (GHFunc)g_free, NULL);
3108 g_hash_table_destroy (assembly->blob_cache);
3109 assembly->blob_cache = NULL;
3111 return TRUE;
3114 #else /* DISABLE_REFLECTION_EMIT_SAVE */
3116 gboolean
3117 mono_image_create_pefile (MonoReflectionModuleBuilder *mb, HANDLE file, MonoError *error)
3119 g_assert_not_reached ();
3122 #endif /* DISABLE_REFLECTION_EMIT_SAVE */