[linker] We need to mark nested types even if the declaring type isn't marked.
[mono-project.git] / mono / metadata / sre-save.c
blob3256f8cb1990d4e3b18a5d2e8e92d668ada6fa08
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"
28 #include "mono/utils/checked-build.h"
29 #include "mono/utils/mono-digest.h"
30 #include "mono/utils/mono-error-internals.h"
32 #define TEXT_OFFSET 512
33 #define CLI_H_SIZE 136
34 #define FILE_ALIGN 512
35 #define VIRT_ALIGN 8192
36 #define START_TEXT_RVA 0x00002000
38 static void mono_image_get_generic_param_info (MonoReflectionGenericParam *gparam, guint32 owner, MonoDynamicImage *assembly);
40 static void
41 alloc_table (MonoDynamicTable *table, guint nrows)
43 mono_dynimage_alloc_table (table, nrows);
46 static guint32
47 string_heap_insert (MonoDynamicStream *sh, const char *str)
49 return mono_dynstream_insert_string (sh, str);
52 static guint32
53 string_heap_insert_mstring (MonoDynamicStream *sh, MonoString *str, MonoError *error)
55 return mono_dynstream_insert_mstring (sh, str, error);
58 static guint32
59 mono_image_add_stream_data (MonoDynamicStream *stream, const char *data, guint32 len)
61 return mono_dynstream_add_data (stream, data, len);
64 static guint32
65 mono_image_add_stream_zero (MonoDynamicStream *stream, guint32 len)
67 return mono_dynstream_add_zero (stream, len);
70 static void
71 stream_data_align (MonoDynamicStream *stream)
73 mono_dynstream_data_align (stream);
76 static guint32
77 mono_image_typedef_or_ref (MonoDynamicImage *assembly, MonoType *type)
79 return mono_dynimage_encode_typedef_or_ref_full (assembly, type, TRUE);
82 static guint32
83 find_index_in_table (MonoDynamicImage *assembly, int table_idx, int col, guint32 token)
85 MONO_REQ_GC_NEUTRAL_MODE;
87 int i;
88 MonoDynamicTable *table;
89 guint32 *values;
91 table = &assembly->tables [table_idx];
93 g_assert (col < table->columns);
95 values = table->values + table->columns;
96 for (i = 1; i <= table->rows; ++i) {
97 if (values [col] == token)
98 return i;
99 values += table->columns;
101 return 0;
105 * Copy len * nelem bytes from val to dest, swapping bytes to LE if necessary.
106 * dest may be misaligned.
108 static void
109 swap_with_size (char *dest, const char* val, int len, int nelem) {
110 MONO_REQ_GC_NEUTRAL_MODE;
111 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
112 int elem;
114 for (elem = 0; elem < nelem; ++elem) {
115 switch (len) {
116 case 1:
117 *dest = *val;
118 break;
119 case 2:
120 dest [0] = val [1];
121 dest [1] = val [0];
122 break;
123 case 4:
124 dest [0] = val [3];
125 dest [1] = val [2];
126 dest [2] = val [1];
127 dest [3] = val [0];
128 break;
129 case 8:
130 dest [0] = val [7];
131 dest [1] = val [6];
132 dest [2] = val [5];
133 dest [3] = val [4];
134 dest [4] = val [3];
135 dest [5] = val [2];
136 dest [6] = val [1];
137 dest [7] = val [0];
138 break;
139 default:
140 g_assert_not_reached ();
142 dest += len;
143 val += len;
145 #else
146 memcpy (dest, val, len * nelem);
147 #endif
150 static guint32
151 add_mono_string_to_blob_cached (MonoDynamicImage *assembly, MonoString *str)
153 MONO_REQ_GC_UNSAFE_MODE;
155 char blob_size [64];
156 char *b = blob_size;
157 guint32 idx = 0, len;
159 len = str->length * 2;
160 mono_metadata_encode_value (len, b, &b);
161 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
163 char *swapped = g_malloc (2 * mono_string_length (str));
164 const char *p = (const char*)mono_string_chars (str);
166 swap_with_size (swapped, p, 2, mono_string_length (str));
167 idx = mono_dynamic_image_add_to_blob_cached (assembly, blob_size, b-blob_size, swapped, len);
168 g_free (swapped);
170 #else
171 idx = mono_dynamic_image_add_to_blob_cached (assembly, blob_size, b-blob_size, (char*)mono_string_chars (str), len);
172 #endif
173 return idx;
177 * idx is the table index of the object
178 * type is one of MONO_CUSTOM_ATTR_*
180 static gboolean
181 mono_image_add_cattrs (MonoDynamicImage *assembly, guint32 idx, guint32 type, MonoArray *cattrs, MonoError *error)
183 MONO_REQ_GC_UNSAFE_MODE;
185 MonoDynamicTable *table;
186 MonoReflectionCustomAttr *cattr;
187 guint32 *values;
188 guint32 count, i, token;
189 char blob_size [6];
190 char *p = blob_size;
192 mono_error_init (error);
194 /* it is legal to pass a NULL cattrs: we avoid to use the if in a lot of places */
195 if (!cattrs)
196 return TRUE;
197 count = mono_array_length (cattrs);
198 table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
199 table->rows += count;
200 alloc_table (table, table->rows);
201 values = table->values + table->next_idx * MONO_CUSTOM_ATTR_SIZE;
202 idx <<= MONO_CUSTOM_ATTR_BITS;
203 idx |= type;
204 for (i = 0; i < count; ++i) {
205 cattr = (MonoReflectionCustomAttr*)mono_array_get (cattrs, gpointer, i);
206 values [MONO_CUSTOM_ATTR_PARENT] = idx;
207 token = mono_image_create_token (assembly, (MonoObject*)cattr->ctor, FALSE, FALSE, error);
208 if (!mono_error_ok (error)) goto fail;
209 type = mono_metadata_token_index (token);
210 type <<= MONO_CUSTOM_ATTR_TYPE_BITS;
211 switch (mono_metadata_token_table (token)) {
212 case MONO_TABLE_METHOD:
213 type |= MONO_CUSTOM_ATTR_TYPE_METHODDEF;
215 * fixup_cattrs () needs to fix this up. We can't use image->tokens, since it contains the old token for the
216 * method, not the one returned by mono_image_create_token ().
218 mono_g_hash_table_insert (assembly->remapped_tokens, GUINT_TO_POINTER (token), cattr->ctor);
219 break;
220 case MONO_TABLE_MEMBERREF:
221 type |= MONO_CUSTOM_ATTR_TYPE_MEMBERREF;
222 break;
223 default:
224 g_warning ("got wrong token in custom attr");
225 continue;
227 values [MONO_CUSTOM_ATTR_TYPE] = type;
228 p = blob_size;
229 mono_metadata_encode_value (mono_array_length (cattr->data), p, &p);
230 values [MONO_CUSTOM_ATTR_VALUE] = mono_dynamic_image_add_to_blob_cached (assembly, blob_size, p - blob_size,
231 mono_array_addr (cattr->data, char, 0), mono_array_length (cattr->data));
232 values += MONO_CUSTOM_ATTR_SIZE;
233 ++table->next_idx;
236 return TRUE;
238 fail:
239 return FALSE;
242 static void
243 mono_image_add_decl_security (MonoDynamicImage *assembly, guint32 parent_token, MonoArray *permissions)
245 MONO_REQ_GC_UNSAFE_MODE;
247 MonoDynamicTable *table;
248 guint32 *values;
249 guint32 count, i, idx;
250 MonoReflectionPermissionSet *perm;
252 if (!permissions)
253 return;
255 count = mono_array_length (permissions);
256 table = &assembly->tables [MONO_TABLE_DECLSECURITY];
257 table->rows += count;
258 alloc_table (table, table->rows);
260 for (i = 0; i < mono_array_length (permissions); ++i) {
261 perm = (MonoReflectionPermissionSet*)mono_array_addr (permissions, MonoReflectionPermissionSet, i);
263 values = table->values + table->next_idx * MONO_DECL_SECURITY_SIZE;
265 idx = mono_metadata_token_index (parent_token);
266 idx <<= MONO_HAS_DECL_SECURITY_BITS;
267 switch (mono_metadata_token_table (parent_token)) {
268 case MONO_TABLE_TYPEDEF:
269 idx |= MONO_HAS_DECL_SECURITY_TYPEDEF;
270 break;
271 case MONO_TABLE_METHOD:
272 idx |= MONO_HAS_DECL_SECURITY_METHODDEF;
273 break;
274 case MONO_TABLE_ASSEMBLY:
275 idx |= MONO_HAS_DECL_SECURITY_ASSEMBLY;
276 break;
277 default:
278 g_assert_not_reached ();
281 values [MONO_DECL_SECURITY_ACTION] = perm->action;
282 values [MONO_DECL_SECURITY_PARENT] = idx;
283 values [MONO_DECL_SECURITY_PERMISSIONSET] = add_mono_string_to_blob_cached (assembly, perm->pset);
285 ++table->next_idx;
290 * method_encode_code:
292 * @assembly the assembly
293 * @mb the managed MethodBuilder
294 * @error set on error
296 * Note that the return value is not sensible if @error is set.
298 static guint32
299 method_encode_code (MonoDynamicImage *assembly, ReflectionMethodBuilder *mb, MonoError *error)
301 MONO_REQ_GC_UNSAFE_MODE;
303 char flags = 0;
304 guint32 idx;
305 guint32 code_size;
306 gint32 max_stack, i;
307 gint32 num_locals = 0;
308 gint32 num_exception = 0;
309 gint maybe_small;
310 guint32 fat_flags;
311 char fat_header [12];
312 guint32 int_value;
313 guint16 short_value;
314 guint32 local_sig = 0;
315 guint32 header_size = 12;
316 MonoArray *code;
318 mono_error_init (error);
320 if ((mb->attrs & (METHOD_ATTRIBUTE_PINVOKE_IMPL | METHOD_ATTRIBUTE_ABSTRACT)) ||
321 (mb->iattrs & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)))
322 return 0;
324 /*if (mb->name)
325 g_print ("Encode method %s\n", mono_string_to_utf8 (mb->name));*/
326 if (mb->ilgen) {
327 code = mb->ilgen->code;
328 code_size = mb->ilgen->code_len;
329 max_stack = mb->ilgen->max_stack;
330 num_locals = mb->ilgen->locals ? mono_array_length (mb->ilgen->locals) : 0;
331 if (mb->ilgen->ex_handlers)
332 num_exception = mono_reflection_method_count_clauses (mb->ilgen);
333 } else {
334 code = mb->code;
335 if (code == NULL){
336 MonoError inner_error;
337 char *name = mono_string_to_utf8_checked (mb->name, &inner_error);
338 if (!is_ok (&inner_error)) {
339 name = g_strdup ("");
340 mono_error_cleanup (&inner_error);
342 char *str = g_strdup_printf ("Method %s does not have any IL associated", name);
343 mono_error_set_argument (error, NULL, "a method does not have any IL associated");
344 g_free (str);
345 g_free (name);
346 return 0;
349 code_size = mono_array_length (code);
350 max_stack = 8; /* we probably need to run a verifier on the code... */
353 stream_data_align (&assembly->code);
355 /* check for exceptions, maxstack, locals */
356 maybe_small = (max_stack <= 8) && (!num_locals) && (!num_exception);
357 if (maybe_small) {
358 if (code_size < 64 && !(code_size & 1)) {
359 flags = (code_size << 2) | 0x2;
360 } else if (code_size < 32 && (code_size & 1)) {
361 flags = (code_size << 2) | 0x6; /* LAMESPEC: see metadata.c */
362 } else {
363 goto fat_header;
365 idx = mono_image_add_stream_data (&assembly->code, &flags, 1);
366 /* add to the fixup todo list */
367 if (mb->ilgen && mb->ilgen->num_token_fixups)
368 mono_g_hash_table_insert (assembly->token_fixups, mb->ilgen, GUINT_TO_POINTER (idx + 1));
369 mono_image_add_stream_data (&assembly->code, mono_array_addr (code, char, 0), code_size);
370 return assembly->text_rva + idx;
372 fat_header:
373 if (num_locals) {
374 local_sig = MONO_TOKEN_SIGNATURE | mono_dynimage_encode_locals (assembly, mb->ilgen, error);
375 return_val_if_nok (error, 0);
378 * FIXME: need to set also the header size in fat_flags.
379 * (and more sects and init locals flags)
381 fat_flags = 0x03;
382 if (num_exception)
383 fat_flags |= METHOD_HEADER_MORE_SECTS;
384 if (mb->init_locals)
385 fat_flags |= METHOD_HEADER_INIT_LOCALS;
386 fat_header [0] = fat_flags;
387 fat_header [1] = (header_size / 4 ) << 4;
388 short_value = GUINT16_TO_LE (max_stack);
389 memcpy (fat_header + 2, &short_value, 2);
390 int_value = GUINT32_TO_LE (code_size);
391 memcpy (fat_header + 4, &int_value, 4);
392 int_value = GUINT32_TO_LE (local_sig);
393 memcpy (fat_header + 8, &int_value, 4);
394 idx = mono_image_add_stream_data (&assembly->code, fat_header, 12);
395 /* add to the fixup todo list */
396 if (mb->ilgen && mb->ilgen->num_token_fixups)
397 mono_g_hash_table_insert (assembly->token_fixups, mb->ilgen, GUINT_TO_POINTER (idx + 12));
399 mono_image_add_stream_data (&assembly->code, mono_array_addr (code, char, 0), code_size);
400 if (num_exception) {
401 unsigned char sheader [4];
402 MonoILExceptionInfo * ex_info;
403 MonoILExceptionBlock * ex_block;
404 int j;
406 stream_data_align (&assembly->code);
407 /* always use fat format for now */
408 sheader [0] = METHOD_HEADER_SECTION_FAT_FORMAT | METHOD_HEADER_SECTION_EHTABLE;
409 num_exception *= 6 * sizeof (guint32);
410 num_exception += 4; /* include the size of the header */
411 sheader [1] = num_exception & 0xff;
412 sheader [2] = (num_exception >> 8) & 0xff;
413 sheader [3] = (num_exception >> 16) & 0xff;
414 mono_image_add_stream_data (&assembly->code, (char*)sheader, 4);
415 /* fat header, so we are already aligned */
416 /* reverse order */
417 for (i = mono_array_length (mb->ilgen->ex_handlers) - 1; i >= 0; --i) {
418 ex_info = (MonoILExceptionInfo *)mono_array_addr (mb->ilgen->ex_handlers, MonoILExceptionInfo, i);
419 if (ex_info->handlers) {
420 int finally_start = ex_info->start + ex_info->len;
421 for (j = 0; j < mono_array_length (ex_info->handlers); ++j) {
422 guint32 val;
423 ex_block = (MonoILExceptionBlock*)mono_array_addr (ex_info->handlers, MonoILExceptionBlock, j);
424 /* the flags */
425 val = GUINT32_TO_LE (ex_block->type);
426 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
427 /* try offset */
428 val = GUINT32_TO_LE (ex_info->start);
429 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
430 /* need fault, too, probably */
431 if (ex_block->type == MONO_EXCEPTION_CLAUSE_FINALLY)
432 val = GUINT32_TO_LE (finally_start - ex_info->start);
433 else
434 val = GUINT32_TO_LE (ex_info->len);
435 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
436 /* handler offset */
437 val = GUINT32_TO_LE (ex_block->start);
438 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
439 /* handler len */
440 val = GUINT32_TO_LE (ex_block->len);
441 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
442 finally_start = ex_block->start + ex_block->len;
443 if (ex_block->extype) {
444 MonoType *extype = mono_reflection_type_get_handle ((MonoReflectionType*)ex_block->extype, error);
445 return_val_if_nok (error, 0);
447 val = mono_metadata_token_from_dor (mono_image_typedef_or_ref (assembly, extype));
448 } else {
449 if (ex_block->type == MONO_EXCEPTION_CLAUSE_FILTER)
450 val = ex_block->filter_offset;
451 else
452 val = 0;
454 val = GUINT32_TO_LE (val);
455 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
456 /*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",
457 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);*/
459 } else {
460 g_error ("No clauses for ex info block %d", i);
464 return assembly->text_rva + idx;
468 * Fill in the MethodDef and ParamDef tables for a method.
469 * This is used for both normal methods and constructors.
471 static gboolean
472 mono_image_basic_method (ReflectionMethodBuilder *mb, MonoDynamicImage *assembly, MonoError *error)
474 MONO_REQ_GC_UNSAFE_MODE;
476 MonoDynamicTable *table;
477 guint32 *values;
478 guint i, count;
480 mono_error_init (error);
482 /* room in this table is already allocated */
483 table = &assembly->tables [MONO_TABLE_METHOD];
484 *mb->table_idx = table->next_idx ++;
485 g_hash_table_insert (assembly->method_to_table_idx, mb->mhandle, GUINT_TO_POINTER ((*mb->table_idx)));
486 values = table->values + *mb->table_idx * MONO_METHOD_SIZE;
487 values [MONO_METHOD_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->name, error);
488 return_val_if_nok (error, FALSE);
489 values [MONO_METHOD_FLAGS] = mb->attrs;
490 values [MONO_METHOD_IMPLFLAGS] = mb->iattrs;
491 values [MONO_METHOD_SIGNATURE] = mono_dynimage_encode_method_builder_signature (assembly, mb, error);
492 return_val_if_nok (error, FALSE);
493 values [MONO_METHOD_RVA] = method_encode_code (assembly, mb, error);
494 return_val_if_nok (error, FALSE);
496 table = &assembly->tables [MONO_TABLE_PARAM];
497 values [MONO_METHOD_PARAMLIST] = table->next_idx;
499 mono_image_add_decl_security (assembly,
500 mono_metadata_make_token (MONO_TABLE_METHOD, *mb->table_idx), mb->permissions);
502 if (mb->pinfo) {
503 MonoDynamicTable *mtable;
504 guint32 *mvalues;
506 mtable = &assembly->tables [MONO_TABLE_FIELDMARSHAL];
507 mvalues = mtable->values + mtable->next_idx * MONO_FIELD_MARSHAL_SIZE;
509 count = 0;
510 for (i = 0; i < mono_array_length (mb->pinfo); ++i) {
511 if (mono_array_get (mb->pinfo, gpointer, i))
512 count++;
514 table->rows += count;
515 alloc_table (table, table->rows);
516 values = table->values + table->next_idx * MONO_PARAM_SIZE;
517 for (i = 0; i < mono_array_length (mb->pinfo); ++i) {
518 MonoReflectionParamBuilder *pb;
519 if ((pb = mono_array_get (mb->pinfo, MonoReflectionParamBuilder*, i))) {
520 values [MONO_PARAM_FLAGS] = pb->attrs;
521 values [MONO_PARAM_SEQUENCE] = i;
522 if (pb->name != NULL) {
523 values [MONO_PARAM_NAME] = string_heap_insert_mstring (&assembly->sheap, pb->name, error);
524 return_val_if_nok (error, FALSE);
525 } else {
526 values [MONO_PARAM_NAME] = 0;
528 values += MONO_PARAM_SIZE;
529 if (pb->marshal_info) {
530 mtable->rows++;
531 alloc_table (mtable, mtable->rows);
532 mvalues = mtable->values + mtable->rows * MONO_FIELD_MARSHAL_SIZE;
533 mvalues [MONO_FIELD_MARSHAL_PARENT] = (table->next_idx << MONO_HAS_FIELD_MARSHAL_BITS) | MONO_HAS_FIELD_MARSHAL_PARAMDEF;
534 mvalues [MONO_FIELD_MARSHAL_NATIVE_TYPE] = mono_dynimage_save_encode_marshal_blob (assembly, pb->marshal_info, error);
535 return_val_if_nok (error, FALSE);
537 pb->table_idx = table->next_idx++;
538 if (pb->attrs & PARAM_ATTRIBUTE_HAS_DEFAULT) {
539 guint32 field_type = 0;
540 mtable = &assembly->tables [MONO_TABLE_CONSTANT];
541 mtable->rows ++;
542 alloc_table (mtable, mtable->rows);
543 mvalues = mtable->values + mtable->rows * MONO_CONSTANT_SIZE;
544 mvalues [MONO_CONSTANT_PARENT] = MONO_HASCONSTANT_PARAM | (pb->table_idx << MONO_HASCONSTANT_BITS);
545 mvalues [MONO_CONSTANT_VALUE] = mono_dynimage_encode_constant (assembly, pb->def_value, &field_type);
546 mvalues [MONO_CONSTANT_TYPE] = field_type;
547 mvalues [MONO_CONSTANT_PADDING] = 0;
553 return TRUE;
556 static gboolean
557 mono_image_add_methodimpl (MonoDynamicImage *assembly, MonoReflectionMethodBuilder *mb, MonoError *error)
559 MONO_REQ_GC_UNSAFE_MODE;
561 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mb->type;
562 MonoDynamicTable *table;
563 guint32 *values;
564 guint32 tok;
565 MonoReflectionMethod *m;
566 int i;
568 mono_error_init (error);
570 if (!mb->override_methods)
571 return TRUE;
573 for (i = 0; i < mono_array_length (mb->override_methods); ++i) {
574 m = mono_array_get (mb->override_methods, MonoReflectionMethod*, i);
576 table = &assembly->tables [MONO_TABLE_METHODIMPL];
577 table->rows ++;
578 alloc_table (table, table->rows);
579 values = table->values + table->rows * MONO_METHODIMPL_SIZE;
580 values [MONO_METHODIMPL_CLASS] = tb->table_idx;
581 values [MONO_METHODIMPL_BODY] = MONO_METHODDEFORREF_METHODDEF | (mb->table_idx << MONO_METHODDEFORREF_BITS);
583 tok = mono_image_create_token (assembly, (MonoObject*)m, FALSE, FALSE, error);
584 return_val_if_nok (error, FALSE);
586 switch (mono_metadata_token_table (tok)) {
587 case MONO_TABLE_MEMBERREF:
588 tok = (mono_metadata_token_index (tok) << MONO_METHODDEFORREF_BITS ) | MONO_METHODDEFORREF_METHODREF;
589 break;
590 case MONO_TABLE_METHOD:
591 tok = (mono_metadata_token_index (tok) << MONO_METHODDEFORREF_BITS ) | MONO_METHODDEFORREF_METHODDEF;
592 break;
593 default:
594 g_assert_not_reached ();
596 values [MONO_METHODIMPL_DECLARATION] = tok;
599 return TRUE;
602 #ifndef DISABLE_REFLECTION_EMIT
603 static gboolean
604 mono_image_get_method_info (MonoReflectionMethodBuilder *mb, MonoDynamicImage *assembly, MonoError *error)
606 MONO_REQ_GC_UNSAFE_MODE;
608 MonoDynamicTable *table;
609 guint32 *values;
610 ReflectionMethodBuilder rmb;
611 int i;
613 mono_error_init (error);
615 if (!mono_reflection_methodbuilder_from_method_builder (&rmb, mb, error) ||
616 !mono_image_basic_method (&rmb, assembly, error))
617 return FALSE;
619 mb->table_idx = *rmb.table_idx;
621 if (mb->dll) { /* It's a P/Invoke method */
622 guint32 moduleref;
623 /* map CharSet values to on-disk values */
624 int ncharset = (mb->charset ? (mb->charset - 1) * 2 : 0);
625 int extra_flags = mb->extra_flags;
626 table = &assembly->tables [MONO_TABLE_IMPLMAP];
627 table->rows ++;
628 alloc_table (table, table->rows);
629 values = table->values + table->rows * MONO_IMPLMAP_SIZE;
631 values [MONO_IMPLMAP_FLAGS] = (mb->native_cc << 8) | ncharset | extra_flags;
632 values [MONO_IMPLMAP_MEMBER] = (mb->table_idx << 1) | 1; /* memberforwarded: method */
633 if (mb->dllentry) {
634 values [MONO_IMPLMAP_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->dllentry, error);
635 return_val_if_nok (error, FALSE);
636 } else {
637 values [MONO_IMPLMAP_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->name, error);
638 return_val_if_nok (error, FALSE);
640 moduleref = string_heap_insert_mstring (&assembly->sheap, mb->dll, error);
641 return_val_if_nok (error, FALSE);
642 if (!(values [MONO_IMPLMAP_SCOPE] = find_index_in_table (assembly, MONO_TABLE_MODULEREF, MONO_MODULEREF_NAME, moduleref))) {
643 table = &assembly->tables [MONO_TABLE_MODULEREF];
644 table->rows ++;
645 alloc_table (table, table->rows);
646 table->values [table->rows * MONO_MODULEREF_SIZE + MONO_MODULEREF_NAME] = moduleref;
647 values [MONO_IMPLMAP_SCOPE] = table->rows;
651 if (mb->generic_params) {
652 table = &assembly->tables [MONO_TABLE_GENERICPARAM];
653 table->rows += mono_array_length (mb->generic_params);
654 alloc_table (table, table->rows);
655 for (i = 0; i < mono_array_length (mb->generic_params); ++i) {
656 guint32 owner = MONO_TYPEORMETHOD_METHOD | (mb->table_idx << MONO_TYPEORMETHOD_BITS);
658 mono_image_get_generic_param_info (
659 (MonoReflectionGenericParam *)mono_array_get (mb->generic_params, gpointer, i), owner, assembly);
663 return TRUE;
666 static gboolean
667 mono_image_get_ctor_info (MonoDomain *domain, MonoReflectionCtorBuilder *mb, MonoDynamicImage *assembly, MonoError *error)
669 MONO_REQ_GC_UNSAFE_MODE;
671 ReflectionMethodBuilder rmb;
673 if (!mono_reflection_methodbuilder_from_ctor_builder (&rmb, mb, error))
674 return FALSE;
676 if (!mono_image_basic_method (&rmb, assembly, error))
677 return FALSE;
679 mb->table_idx = *rmb.table_idx;
681 return TRUE;
683 #endif
685 static void
686 mono_image_get_field_info (MonoReflectionFieldBuilder *fb, MonoDynamicImage *assembly, MonoError *error)
688 MONO_REQ_GC_UNSAFE_MODE;
690 mono_error_init (error);
692 MonoDynamicTable *table;
693 guint32 *values;
695 /* maybe this fixup should be done in the C# code */
696 if (fb->attrs & FIELD_ATTRIBUTE_LITERAL)
697 fb->attrs |= FIELD_ATTRIBUTE_HAS_DEFAULT;
698 table = &assembly->tables [MONO_TABLE_FIELD];
699 fb->table_idx = table->next_idx ++;
700 g_hash_table_insert (assembly->field_to_table_idx, fb->handle, GUINT_TO_POINTER (fb->table_idx));
701 values = table->values + fb->table_idx * MONO_FIELD_SIZE;
702 values [MONO_FIELD_NAME] = string_heap_insert_mstring (&assembly->sheap, fb->name, error);
703 return_if_nok (error);
704 values [MONO_FIELD_FLAGS] = fb->attrs;
705 values [MONO_FIELD_SIGNATURE] = mono_dynimage_encode_field_signature (assembly, fb, error);
706 return_if_nok (error);
708 if (fb->offset != -1) {
709 table = &assembly->tables [MONO_TABLE_FIELDLAYOUT];
710 table->rows ++;
711 alloc_table (table, table->rows);
712 values = table->values + table->rows * MONO_FIELD_LAYOUT_SIZE;
713 values [MONO_FIELD_LAYOUT_FIELD] = fb->table_idx;
714 values [MONO_FIELD_LAYOUT_OFFSET] = fb->offset;
716 if (fb->attrs & FIELD_ATTRIBUTE_LITERAL) {
717 MonoTypeEnum field_type = (MonoTypeEnum)0;
718 table = &assembly->tables [MONO_TABLE_CONSTANT];
719 table->rows ++;
720 alloc_table (table, table->rows);
721 values = table->values + table->rows * MONO_CONSTANT_SIZE;
722 values [MONO_CONSTANT_PARENT] = MONO_HASCONSTANT_FIEDDEF | (fb->table_idx << MONO_HASCONSTANT_BITS);
723 values [MONO_CONSTANT_VALUE] = mono_dynimage_encode_constant (assembly, fb->def_value, &field_type);
724 values [MONO_CONSTANT_TYPE] = field_type;
725 values [MONO_CONSTANT_PADDING] = 0;
727 if (fb->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA) {
728 guint32 rva_idx;
729 table = &assembly->tables [MONO_TABLE_FIELDRVA];
730 table->rows ++;
731 alloc_table (table, table->rows);
732 values = table->values + table->rows * MONO_FIELD_RVA_SIZE;
733 values [MONO_FIELD_RVA_FIELD] = fb->table_idx;
735 * We store it in the code section because it's simpler for now.
737 if (fb->rva_data) {
738 if (mono_array_length (fb->rva_data) >= 10)
739 stream_data_align (&assembly->code);
740 rva_idx = mono_image_add_stream_data (&assembly->code, mono_array_addr (fb->rva_data, char, 0), mono_array_length (fb->rva_data));
741 } else
742 rva_idx = mono_image_add_stream_zero (&assembly->code, mono_class_value_size (fb->handle->parent, NULL));
743 values [MONO_FIELD_RVA_RVA] = rva_idx + assembly->text_rva;
745 if (fb->marshal_info) {
746 table = &assembly->tables [MONO_TABLE_FIELDMARSHAL];
747 table->rows ++;
748 alloc_table (table, table->rows);
749 values = table->values + table->rows * MONO_FIELD_MARSHAL_SIZE;
750 values [MONO_FIELD_MARSHAL_PARENT] = (fb->table_idx << MONO_HAS_FIELD_MARSHAL_BITS) | MONO_HAS_FIELD_MARSHAL_FIELDSREF;
751 values [MONO_FIELD_MARSHAL_NATIVE_TYPE] = mono_dynimage_save_encode_marshal_blob (assembly, fb->marshal_info, error);
752 return_if_nok (error);
756 static void
757 mono_image_get_property_info (MonoReflectionPropertyBuilder *pb, MonoDynamicImage *assembly, MonoError *error)
759 MONO_REQ_GC_UNSAFE_MODE;
761 mono_error_init (error);
763 MonoDynamicTable *table;
764 guint32 *values;
765 guint num_methods = 0;
766 guint32 semaidx;
769 * we need to set things in the following tables:
770 * PROPERTYMAP (info already filled in _get_type_info ())
771 * PROPERTY (rows already preallocated in _get_type_info ())
772 * METHOD (method info already done with the generic method code)
773 * METHODSEMANTICS
774 * CONSTANT
776 table = &assembly->tables [MONO_TABLE_PROPERTY];
777 pb->table_idx = table->next_idx ++;
778 values = table->values + pb->table_idx * MONO_PROPERTY_SIZE;
779 values [MONO_PROPERTY_NAME] = string_heap_insert_mstring (&assembly->sheap, pb->name, error);
780 return_if_nok (error);
781 values [MONO_PROPERTY_FLAGS] = pb->attrs;
782 values [MONO_PROPERTY_TYPE] = mono_dynimage_save_encode_property_signature (assembly, pb, error);
783 return_if_nok (error);
786 /* FIXME: we still don't handle 'other' methods */
787 if (pb->get_method) num_methods ++;
788 if (pb->set_method) num_methods ++;
790 table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
791 table->rows += num_methods;
792 alloc_table (table, table->rows);
794 if (pb->get_method) {
795 semaidx = table->next_idx ++;
796 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
797 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_GETTER;
798 values [MONO_METHOD_SEMA_METHOD] = pb->get_method->table_idx;
799 values [MONO_METHOD_SEMA_ASSOCIATION] = (pb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_PROPERTY;
801 if (pb->set_method) {
802 semaidx = table->next_idx ++;
803 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
804 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_SETTER;
805 values [MONO_METHOD_SEMA_METHOD] = pb->set_method->table_idx;
806 values [MONO_METHOD_SEMA_ASSOCIATION] = (pb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_PROPERTY;
808 if (pb->attrs & PROPERTY_ATTRIBUTE_HAS_DEFAULT) {
809 MonoTypeEnum field_type = (MonoTypeEnum)0;
810 table = &assembly->tables [MONO_TABLE_CONSTANT];
811 table->rows ++;
812 alloc_table (table, table->rows);
813 values = table->values + table->rows * MONO_CONSTANT_SIZE;
814 values [MONO_CONSTANT_PARENT] = MONO_HASCONSTANT_PROPERTY | (pb->table_idx << MONO_HASCONSTANT_BITS);
815 values [MONO_CONSTANT_VALUE] = mono_dynimage_encode_constant (assembly, pb->def_value, &field_type);
816 values [MONO_CONSTANT_TYPE] = field_type;
817 values [MONO_CONSTANT_PADDING] = 0;
821 static void
822 mono_image_get_event_info (MonoReflectionEventBuilder *eb, MonoDynamicImage *assembly, MonoError *error)
824 MONO_REQ_GC_UNSAFE_MODE;
826 MonoDynamicTable *table;
827 guint32 *values;
828 guint num_methods = 0;
829 guint32 semaidx;
832 * we need to set things in the following tables:
833 * EVENTMAP (info already filled in _get_type_info ())
834 * EVENT (rows already preallocated in _get_type_info ())
835 * METHOD (method info already done with the generic method code)
836 * METHODSEMANTICS
838 table = &assembly->tables [MONO_TABLE_EVENT];
839 eb->table_idx = table->next_idx ++;
840 values = table->values + eb->table_idx * MONO_EVENT_SIZE;
841 values [MONO_EVENT_NAME] = string_heap_insert_mstring (&assembly->sheap, eb->name, error);
842 return_if_nok (error);
843 values [MONO_EVENT_FLAGS] = eb->attrs;
844 MonoType *ebtype = mono_reflection_type_get_handle (eb->type, error);
845 return_if_nok (error);
846 values [MONO_EVENT_TYPE] = mono_image_typedef_or_ref (assembly, ebtype);
849 * FIXME: we still don't handle 'other' methods
851 if (eb->add_method) num_methods ++;
852 if (eb->remove_method) num_methods ++;
853 if (eb->raise_method) num_methods ++;
855 table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
856 table->rows += num_methods;
857 alloc_table (table, table->rows);
859 if (eb->add_method) {
860 semaidx = table->next_idx ++;
861 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
862 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_ADD_ON;
863 values [MONO_METHOD_SEMA_METHOD] = eb->add_method->table_idx;
864 values [MONO_METHOD_SEMA_ASSOCIATION] = (eb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_EVENT;
866 if (eb->remove_method) {
867 semaidx = table->next_idx ++;
868 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
869 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_REMOVE_ON;
870 values [MONO_METHOD_SEMA_METHOD] = eb->remove_method->table_idx;
871 values [MONO_METHOD_SEMA_ASSOCIATION] = (eb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_EVENT;
873 if (eb->raise_method) {
874 semaidx = table->next_idx ++;
875 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
876 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_FIRE;
877 values [MONO_METHOD_SEMA_METHOD] = eb->raise_method->table_idx;
878 values [MONO_METHOD_SEMA_ASSOCIATION] = (eb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_EVENT;
882 static void
883 encode_constraints (MonoReflectionGenericParam *gparam, guint32 owner, MonoDynamicImage *assembly, MonoError *error)
885 MONO_REQ_GC_UNSAFE_MODE;
887 mono_error_init (error);
889 MonoDynamicTable *table;
890 guint32 num_constraints, i;
891 guint32 *values;
892 guint32 table_idx;
894 table = &assembly->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
895 num_constraints = gparam->iface_constraints ?
896 mono_array_length (gparam->iface_constraints) : 0;
897 table->rows += num_constraints;
898 if (gparam->base_type)
899 table->rows++;
900 alloc_table (table, table->rows);
902 if (gparam->base_type) {
903 table_idx = table->next_idx ++;
904 values = table->values + table_idx * MONO_GENPARCONSTRAINT_SIZE;
906 MonoType *gpbasetype = mono_reflection_type_get_handle (gparam->base_type, error);
907 return_if_nok (error);
908 values [MONO_GENPARCONSTRAINT_GENERICPAR] = owner;
909 values [MONO_GENPARCONSTRAINT_CONSTRAINT] = mono_image_typedef_or_ref (assembly, gpbasetype);
912 for (i = 0; i < num_constraints; i++) {
913 MonoReflectionType *constraint = (MonoReflectionType *)mono_array_get (
914 gparam->iface_constraints, gpointer, i);
916 table_idx = table->next_idx ++;
917 values = table->values + table_idx * MONO_GENPARCONSTRAINT_SIZE;
919 MonoType *constraint_type = mono_reflection_type_get_handle (constraint, error);
920 return_if_nok (error);
922 values [MONO_GENPARCONSTRAINT_GENERICPAR] = owner;
923 values [MONO_GENPARCONSTRAINT_CONSTRAINT] = mono_image_typedef_or_ref (assembly, constraint_type);
927 static void
928 mono_image_get_generic_param_info (MonoReflectionGenericParam *gparam, guint32 owner, MonoDynamicImage *assembly)
930 MONO_REQ_GC_UNSAFE_MODE;
932 GenericParamTableEntry *entry;
935 * The GenericParam table must be sorted according to the `owner' field.
936 * We need to do this sorting prior to writing the GenericParamConstraint
937 * table, since we have to use the final GenericParam table indices there
938 * and they must also be sorted.
941 entry = g_new0 (GenericParamTableEntry, 1);
942 entry->owner = owner;
943 /* FIXME: track where gen_params should be freed and remove the GC root as well */
944 MONO_GC_REGISTER_ROOT_IF_MOVING (entry->gparam, MONO_ROOT_SOURCE_REFLECTION, "reflection generic parameter");
945 entry->gparam = gparam;
947 g_ptr_array_add (assembly->gen_params, entry);
950 static gboolean
951 write_generic_param_entry (MonoDynamicImage *assembly, GenericParamTableEntry *entry, MonoError *error)
953 MONO_REQ_GC_UNSAFE_MODE;
955 MonoDynamicTable *table;
956 MonoGenericParam *param;
957 guint32 *values;
958 guint32 table_idx;
960 mono_error_init (error);
962 table = &assembly->tables [MONO_TABLE_GENERICPARAM];
963 table_idx = table->next_idx ++;
964 values = table->values + table_idx * MONO_GENERICPARAM_SIZE;
966 MonoType *gparam_type = mono_reflection_type_get_handle ((MonoReflectionType*)entry->gparam, error);
967 return_val_if_nok (error, FALSE);
969 param = gparam_type->data.generic_param;
971 values [MONO_GENERICPARAM_OWNER] = entry->owner;
972 values [MONO_GENERICPARAM_FLAGS] = entry->gparam->attrs;
973 values [MONO_GENERICPARAM_NUMBER] = mono_generic_param_num (param);
974 values [MONO_GENERICPARAM_NAME] = string_heap_insert (&assembly->sheap, mono_generic_param_info (param)->name);
976 if (!mono_image_add_cattrs (assembly, table_idx, MONO_CUSTOM_ATTR_GENERICPAR, entry->gparam->cattrs, error))
977 return FALSE;
979 encode_constraints (entry->gparam, table_idx, assembly, error);
980 return_val_if_nok (error, FALSE);
982 return TRUE;
985 static void
986 collect_types (MonoPtrArray *types, MonoReflectionTypeBuilder *type)
988 int i;
990 mono_ptr_array_append (*types, type);
992 if (!type->subtypes)
993 return;
995 for (i = 0; i < mono_array_length (type->subtypes); ++i) {
996 MonoReflectionTypeBuilder *subtype = mono_array_get (type->subtypes, MonoReflectionTypeBuilder*, i);
997 collect_types (types, subtype);
1001 static gint
1002 compare_types_by_table_idx (MonoReflectionTypeBuilder **type1, MonoReflectionTypeBuilder **type2)
1004 if ((*type1)->table_idx < (*type2)->table_idx)
1005 return -1;
1006 else
1007 if ((*type1)->table_idx > (*type2)->table_idx)
1008 return 1;
1009 else
1010 return 0;
1013 static gboolean
1014 params_add_cattrs (MonoDynamicImage *assembly, MonoArray *pinfo, MonoError *error) {
1015 int i;
1017 mono_error_init (error);
1018 if (!pinfo)
1019 return TRUE;
1020 for (i = 0; i < mono_array_length (pinfo); ++i) {
1021 MonoReflectionParamBuilder *pb;
1022 pb = mono_array_get (pinfo, MonoReflectionParamBuilder *, i);
1023 if (!pb)
1024 continue;
1025 if (!mono_image_add_cattrs (assembly, pb->table_idx, MONO_CUSTOM_ATTR_PARAMDEF, pb->cattrs, error))
1026 return FALSE;
1029 return TRUE;
1032 static gboolean
1033 type_add_cattrs (MonoDynamicImage *assembly, MonoReflectionTypeBuilder *tb, MonoError *error) {
1034 int i;
1036 mono_error_init (error);
1038 if (!mono_image_add_cattrs (assembly, tb->table_idx, MONO_CUSTOM_ATTR_TYPEDEF, tb->cattrs, error))
1039 return FALSE;
1040 if (tb->fields) {
1041 for (i = 0; i < tb->num_fields; ++i) {
1042 MonoReflectionFieldBuilder* fb;
1043 fb = mono_array_get (tb->fields, MonoReflectionFieldBuilder*, i);
1044 if (!mono_image_add_cattrs (assembly, fb->table_idx, MONO_CUSTOM_ATTR_FIELDDEF, fb->cattrs, error))
1045 return FALSE;
1048 if (tb->events) {
1049 for (i = 0; i < mono_array_length (tb->events); ++i) {
1050 MonoReflectionEventBuilder* eb;
1051 eb = mono_array_get (tb->events, MonoReflectionEventBuilder*, i);
1052 if (!mono_image_add_cattrs (assembly, eb->table_idx, MONO_CUSTOM_ATTR_EVENT, eb->cattrs, error))
1053 return FALSE;
1056 if (tb->properties) {
1057 for (i = 0; i < mono_array_length (tb->properties); ++i) {
1058 MonoReflectionPropertyBuilder* pb;
1059 pb = mono_array_get (tb->properties, MonoReflectionPropertyBuilder*, i);
1060 if (!mono_image_add_cattrs (assembly, pb->table_idx, MONO_CUSTOM_ATTR_PROPERTY, pb->cattrs, error))
1061 return FALSE;
1064 if (tb->ctors) {
1065 for (i = 0; i < mono_array_length (tb->ctors); ++i) {
1066 MonoReflectionCtorBuilder* cb;
1067 cb = mono_array_get (tb->ctors, MonoReflectionCtorBuilder*, i);
1068 if (!mono_image_add_cattrs (assembly, cb->table_idx, MONO_CUSTOM_ATTR_METHODDEF, cb->cattrs, error) ||
1069 !params_add_cattrs (assembly, cb->pinfo, error))
1070 return FALSE;
1074 if (tb->methods) {
1075 for (i = 0; i < tb->num_methods; ++i) {
1076 MonoReflectionMethodBuilder* mb;
1077 mb = mono_array_get (tb->methods, MonoReflectionMethodBuilder*, i);
1078 if (!mono_image_add_cattrs (assembly, mb->table_idx, MONO_CUSTOM_ATTR_METHODDEF, mb->cattrs, error) ||
1079 !params_add_cattrs (assembly, mb->pinfo, error))
1080 return FALSE;
1084 if (tb->subtypes) {
1085 for (i = 0; i < mono_array_length (tb->subtypes); ++i) {
1086 if (!type_add_cattrs (assembly, mono_array_get (tb->subtypes, MonoReflectionTypeBuilder*, i), error))
1087 return FALSE;
1091 return TRUE;
1094 static gboolean
1095 module_add_cattrs (MonoDynamicImage *assembly, MonoReflectionModuleBuilder *moduleb, MonoError *error)
1097 int i;
1099 mono_error_init (error);
1101 if (!mono_image_add_cattrs (assembly, moduleb->table_idx, MONO_CUSTOM_ATTR_MODULE, moduleb->cattrs, error))
1102 return FALSE;
1104 if (moduleb->global_methods) {
1105 for (i = 0; i < mono_array_length (moduleb->global_methods); ++i) {
1106 MonoReflectionMethodBuilder* mb = mono_array_get (moduleb->global_methods, MonoReflectionMethodBuilder*, i);
1107 if (!mono_image_add_cattrs (assembly, mb->table_idx, MONO_CUSTOM_ATTR_METHODDEF, mb->cattrs, error) ||
1108 !params_add_cattrs (assembly, mb->pinfo, error))
1109 return FALSE;
1113 if (moduleb->global_fields) {
1114 for (i = 0; i < mono_array_length (moduleb->global_fields); ++i) {
1115 MonoReflectionFieldBuilder *fb = mono_array_get (moduleb->global_fields, MonoReflectionFieldBuilder*, i);
1116 if (!mono_image_add_cattrs (assembly, fb->table_idx, MONO_CUSTOM_ATTR_FIELDDEF, fb->cattrs, error))
1117 return FALSE;
1121 if (moduleb->types) {
1122 for (i = 0; i < moduleb->num_types; ++i) {
1123 if (!type_add_cattrs (assembly, mono_array_get (moduleb->types, MonoReflectionTypeBuilder*, i), error))
1124 return FALSE;
1128 return TRUE;
1131 static gboolean
1132 mono_image_fill_file_table (MonoDomain *domain, MonoReflectionModule *module, MonoDynamicImage *assembly, MonoError *error)
1134 MonoDynamicTable *table;
1135 guint32 *values;
1136 char blob_size [6];
1137 guchar hash [20];
1138 char *b = blob_size;
1139 char *dir, *path;
1141 mono_error_init (error);
1143 table = &assembly->tables [MONO_TABLE_FILE];
1144 table->rows++;
1145 alloc_table (table, table->rows);
1146 values = table->values + table->next_idx * MONO_FILE_SIZE;
1147 values [MONO_FILE_FLAGS] = FILE_CONTAINS_METADATA;
1148 values [MONO_FILE_NAME] = string_heap_insert (&assembly->sheap, module->image->module_name);
1149 if (image_is_dynamic (module->image)) {
1150 /* This depends on the fact that the main module is emitted last */
1151 dir = mono_string_to_utf8_checked (((MonoReflectionModuleBuilder*)module)->assemblyb->dir, error);
1152 return_val_if_nok (error, FALSE);
1153 path = g_strdup_printf ("%s%c%s", dir, G_DIR_SEPARATOR, module->image->module_name);
1154 } else {
1155 dir = NULL;
1156 path = g_strdup (module->image->name);
1158 mono_sha1_get_digest_from_file (path, hash);
1159 g_free (dir);
1160 g_free (path);
1161 mono_metadata_encode_value (20, b, &b);
1162 values [MONO_FILE_HASH_VALUE] = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
1163 mono_image_add_stream_data (&assembly->blob, (char*)hash, 20);
1164 table->next_idx ++;
1165 return TRUE;
1168 static void
1169 mono_image_fill_module_table (MonoDomain *domain, MonoReflectionModuleBuilder *mb, MonoDynamicImage *assembly, MonoError *error)
1171 MonoDynamicTable *table;
1172 int i;
1174 mono_error_init (error);
1176 table = &assembly->tables [MONO_TABLE_MODULE];
1177 mb->table_idx = table->next_idx ++;
1178 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->module.name, error);
1179 return_if_nok (error);
1180 i = mono_image_add_stream_data (&assembly->guid, mono_array_addr (mb->guid, char, 0), 16);
1181 i /= 16;
1182 ++i;
1183 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_GENERATION] = 0;
1184 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_MVID] = i;
1185 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_ENC] = 0;
1186 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_ENCBASE] = 0;
1189 static guint32
1190 mono_image_fill_export_table_from_class (MonoDomain *domain, MonoClass *klass,
1191 guint32 module_index, guint32 parent_index, MonoDynamicImage *assembly)
1193 MonoDynamicTable *table;
1194 guint32 *values;
1195 guint32 visib, res;
1197 visib = klass->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK;
1198 if (! ((visib & TYPE_ATTRIBUTE_PUBLIC) || (visib & TYPE_ATTRIBUTE_NESTED_PUBLIC)))
1199 return 0;
1201 table = &assembly->tables [MONO_TABLE_EXPORTEDTYPE];
1202 table->rows++;
1203 alloc_table (table, table->rows);
1204 values = table->values + table->next_idx * MONO_EXP_TYPE_SIZE;
1206 values [MONO_EXP_TYPE_FLAGS] = klass->flags;
1207 values [MONO_EXP_TYPE_TYPEDEF] = klass->type_token;
1208 if (klass->nested_in)
1209 values [MONO_EXP_TYPE_IMPLEMENTATION] = (parent_index << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_EXP_TYPE;
1210 else
1211 values [MONO_EXP_TYPE_IMPLEMENTATION] = (module_index << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_FILE;
1212 values [MONO_EXP_TYPE_NAME] = string_heap_insert (&assembly->sheap, klass->name);
1213 values [MONO_EXP_TYPE_NAMESPACE] = string_heap_insert (&assembly->sheap, klass->name_space);
1215 res = table->next_idx;
1217 table->next_idx ++;
1219 /* Emit nested types */
1220 if (klass->ext && klass->ext->nested_classes) {
1221 GList *tmp;
1223 for (tmp = klass->ext->nested_classes; tmp; tmp = tmp->next)
1224 mono_image_fill_export_table_from_class (domain, (MonoClass *)tmp->data, module_index, table->next_idx - 1, assembly);
1227 return res;
1230 static void
1231 mono_image_fill_export_table (MonoDomain *domain, MonoReflectionTypeBuilder *tb,
1232 guint32 module_index, guint32 parent_index, MonoDynamicImage *assembly,
1233 MonoError *error)
1235 MonoClass *klass;
1236 guint32 idx, i;
1238 mono_error_init (error);
1240 MonoType *t = mono_reflection_type_get_handle ((MonoReflectionType*)tb, error);
1241 return_if_nok (error);
1243 klass = mono_class_from_mono_type (t);
1245 klass->type_token = mono_metadata_make_token (MONO_TABLE_TYPEDEF, tb->table_idx);
1247 idx = mono_image_fill_export_table_from_class (domain, klass, module_index,
1248 parent_index, assembly);
1251 * Emit nested types
1252 * We need to do this ourselves since klass->nested_classes is not set up.
1254 if (tb->subtypes) {
1255 for (i = 0; i < mono_array_length (tb->subtypes); ++i) {
1256 mono_image_fill_export_table (domain, mono_array_get (tb->subtypes, MonoReflectionTypeBuilder*, i), module_index, idx, assembly, error);
1257 return_if_nok (error);
1262 static void
1263 mono_image_fill_export_table_from_module (MonoDomain *domain, MonoReflectionModule *module,
1264 guint32 module_index, MonoDynamicImage *assembly)
1266 MonoImage *image = module->image;
1267 MonoTableInfo *t;
1268 guint32 i;
1270 t = &image->tables [MONO_TABLE_TYPEDEF];
1272 for (i = 0; i < t->rows; ++i) {
1273 MonoError error;
1274 MonoClass *klass = mono_class_get_checked (image, mono_metadata_make_token (MONO_TABLE_TYPEDEF, i + 1), &error);
1275 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
1277 if (klass->flags & TYPE_ATTRIBUTE_PUBLIC)
1278 mono_image_fill_export_table_from_class (domain, klass, module_index, 0, assembly);
1282 static void
1283 add_exported_type (MonoReflectionAssemblyBuilder *assemblyb, MonoDynamicImage *assembly, MonoClass *klass, guint32 parent_index)
1285 MonoDynamicTable *table;
1286 guint32 *values;
1287 guint32 scope, scope_idx, impl, current_idx;
1288 gboolean forwarder = TRUE;
1289 gpointer iter = NULL;
1290 MonoClass *nested;
1292 if (klass->nested_in) {
1293 impl = (parent_index << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_EXP_TYPE;
1294 forwarder = FALSE;
1295 } else {
1296 scope = mono_reflection_resolution_scope_from_image (assembly, klass->image);
1297 g_assert ((scope & MONO_RESOLUTION_SCOPE_MASK) == MONO_RESOLUTION_SCOPE_ASSEMBLYREF);
1298 scope_idx = scope >> MONO_RESOLUTION_SCOPE_BITS;
1299 impl = (scope_idx << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_ASSEMBLYREF;
1302 table = &assembly->tables [MONO_TABLE_EXPORTEDTYPE];
1304 table->rows++;
1305 alloc_table (table, table->rows);
1306 current_idx = table->next_idx;
1307 values = table->values + current_idx * MONO_EXP_TYPE_SIZE;
1309 values [MONO_EXP_TYPE_FLAGS] = forwarder ? TYPE_ATTRIBUTE_FORWARDER : 0;
1310 values [MONO_EXP_TYPE_TYPEDEF] = 0;
1311 values [MONO_EXP_TYPE_IMPLEMENTATION] = impl;
1312 values [MONO_EXP_TYPE_NAME] = string_heap_insert (&assembly->sheap, klass->name);
1313 values [MONO_EXP_TYPE_NAMESPACE] = string_heap_insert (&assembly->sheap, klass->name_space);
1315 table->next_idx++;
1317 while ((nested = mono_class_get_nested_types (klass, &iter)))
1318 add_exported_type (assemblyb, assembly, nested, current_idx);
1321 static void
1322 mono_image_fill_export_table_from_type_forwarders (MonoReflectionAssemblyBuilder *assemblyb, MonoDynamicImage *assembly)
1324 MonoError error;
1325 MonoClass *klass;
1326 int i;
1328 if (!assemblyb->type_forwarders)
1329 return;
1331 for (i = 0; i < mono_array_length (assemblyb->type_forwarders); ++i) {
1332 MonoReflectionType *t = mono_array_get (assemblyb->type_forwarders, MonoReflectionType *, i);
1333 MonoType *type;
1334 if (!t)
1335 continue;
1337 type = mono_reflection_type_get_handle (t, &error);
1338 mono_error_assert_ok (&error);
1339 g_assert (type);
1341 klass = mono_class_from_mono_type (type);
1343 add_exported_type (assemblyb, assembly, klass, 0);
1347 #define align_pointer(base,p)\
1348 do {\
1349 guint32 __diff = (unsigned char*)(p)-(unsigned char*)(base);\
1350 if (__diff & 3)\
1351 (p) += 4 - (__diff & 3);\
1352 } while (0)
1354 static int
1355 compare_constants (const void *a, const void *b)
1357 const guint32 *a_values = (const guint32 *)a;
1358 const guint32 *b_values = (const guint32 *)b;
1359 return a_values [MONO_CONSTANT_PARENT] - b_values [MONO_CONSTANT_PARENT];
1362 static int
1363 compare_semantics (const void *a, const void *b)
1365 const guint32 *a_values = (const guint32 *)a;
1366 const guint32 *b_values = (const guint32 *)b;
1367 int assoc = a_values [MONO_METHOD_SEMA_ASSOCIATION] - b_values [MONO_METHOD_SEMA_ASSOCIATION];
1368 if (assoc)
1369 return assoc;
1370 return a_values [MONO_METHOD_SEMA_SEMANTICS] - b_values [MONO_METHOD_SEMA_SEMANTICS];
1373 static int
1374 compare_custom_attrs (const void *a, const void *b)
1376 const guint32 *a_values = (const guint32 *)a;
1377 const guint32 *b_values = (const guint32 *)b;
1379 return a_values [MONO_CUSTOM_ATTR_PARENT] - b_values [MONO_CUSTOM_ATTR_PARENT];
1382 static int
1383 compare_field_marshal (const void *a, const void *b)
1385 const guint32 *a_values = (const guint32 *)a;
1386 const guint32 *b_values = (const guint32 *)b;
1388 return a_values [MONO_FIELD_MARSHAL_PARENT] - b_values [MONO_FIELD_MARSHAL_PARENT];
1391 static int
1392 compare_nested (const void *a, const void *b)
1394 const guint32 *a_values = (const guint32 *)a;
1395 const guint32 *b_values = (const guint32 *)b;
1397 return a_values [MONO_NESTED_CLASS_NESTED] - b_values [MONO_NESTED_CLASS_NESTED];
1400 static int
1401 compare_genericparam (const void *a, const void *b)
1403 MonoError error;
1404 const GenericParamTableEntry **a_entry = (const GenericParamTableEntry **) a;
1405 const GenericParamTableEntry **b_entry = (const GenericParamTableEntry **) b;
1407 if ((*b_entry)->owner == (*a_entry)->owner) {
1408 MonoType *a_type = mono_reflection_type_get_handle ((MonoReflectionType*)(*a_entry)->gparam, &error);
1409 mono_error_assert_ok (&error);
1410 MonoType *b_type = mono_reflection_type_get_handle ((MonoReflectionType*)(*b_entry)->gparam, &error);
1411 mono_error_assert_ok (&error);
1412 return
1413 mono_type_get_generic_param_num (a_type) -
1414 mono_type_get_generic_param_num (b_type);
1415 } else
1416 return (*a_entry)->owner - (*b_entry)->owner;
1419 static int
1420 compare_declsecurity_attrs (const void *a, const void *b)
1422 const guint32 *a_values = (const guint32 *)a;
1423 const guint32 *b_values = (const guint32 *)b;
1425 return a_values [MONO_DECL_SECURITY_PARENT] - b_values [MONO_DECL_SECURITY_PARENT];
1428 static int
1429 compare_interface_impl (const void *a, const void *b)
1431 const guint32 *a_values = (const guint32 *)a;
1432 const guint32 *b_values = (const guint32 *)b;
1434 int klass = a_values [MONO_INTERFACEIMPL_CLASS] - b_values [MONO_INTERFACEIMPL_CLASS];
1435 if (klass)
1436 return klass;
1438 return a_values [MONO_INTERFACEIMPL_INTERFACE] - b_values [MONO_INTERFACEIMPL_INTERFACE];
1441 struct StreamDesc {
1442 const char *name;
1443 MonoDynamicStream *stream;
1447 * build_compressed_metadata() fills in the blob of data that represents the
1448 * raw metadata as it will be saved in the PE file. The five streams are output
1449 * and the metadata tables are comnpressed from the guint32 array representation,
1450 * to the compressed on-disk format.
1452 static gboolean
1453 build_compressed_metadata (MonoDynamicImage *assembly, MonoError *error)
1455 MonoDynamicTable *table;
1456 int i;
1457 guint64 valid_mask = 0;
1458 guint64 sorted_mask;
1459 guint32 heapt_size = 0;
1460 guint32 meta_size = 256; /* allow for header and other stuff */
1461 guint32 table_offset;
1462 guint32 ntables = 0;
1463 guint64 *int64val;
1464 guint32 *int32val;
1465 guint16 *int16val;
1466 MonoImage *meta;
1467 unsigned char *p;
1468 struct StreamDesc stream_desc [5];
1470 mono_error_init (error);
1472 qsort (assembly->gen_params->pdata, assembly->gen_params->len, sizeof (gpointer), compare_genericparam);
1473 for (i = 0; i < assembly->gen_params->len; i++) {
1474 GenericParamTableEntry *entry = (GenericParamTableEntry *)g_ptr_array_index (assembly->gen_params, i);
1475 if (!write_generic_param_entry (assembly, entry, error))
1476 return FALSE;
1479 stream_desc [0].name = "#~";
1480 stream_desc [0].stream = &assembly->tstream;
1481 stream_desc [1].name = "#Strings";
1482 stream_desc [1].stream = &assembly->sheap;
1483 stream_desc [2].name = "#US";
1484 stream_desc [2].stream = &assembly->us;
1485 stream_desc [3].name = "#Blob";
1486 stream_desc [3].stream = &assembly->blob;
1487 stream_desc [4].name = "#GUID";
1488 stream_desc [4].stream = &assembly->guid;
1490 /* tables that are sorted */
1491 sorted_mask = ((guint64)1 << MONO_TABLE_CONSTANT) | ((guint64)1 << MONO_TABLE_FIELDMARSHAL)
1492 | ((guint64)1 << MONO_TABLE_METHODSEMANTICS) | ((guint64)1 << MONO_TABLE_CLASSLAYOUT)
1493 | ((guint64)1 << MONO_TABLE_FIELDLAYOUT) | ((guint64)1 << MONO_TABLE_FIELDRVA)
1494 | ((guint64)1 << MONO_TABLE_IMPLMAP) | ((guint64)1 << MONO_TABLE_NESTEDCLASS)
1495 | ((guint64)1 << MONO_TABLE_METHODIMPL) | ((guint64)1 << MONO_TABLE_CUSTOMATTRIBUTE)
1496 | ((guint64)1 << MONO_TABLE_DECLSECURITY) | ((guint64)1 << MONO_TABLE_GENERICPARAM)
1497 | ((guint64)1 << MONO_TABLE_INTERFACEIMPL);
1499 /* Compute table sizes */
1500 /* the MonoImage has already been created in mono_reflection_dynimage_basic_init() */
1501 meta = &assembly->image;
1503 /* sizes should be multiple of 4 */
1504 mono_dynstream_data_align (&assembly->blob);
1505 mono_dynstream_data_align (&assembly->guid);
1506 mono_dynstream_data_align (&assembly->sheap);
1507 mono_dynstream_data_align (&assembly->us);
1509 /* Setup the info used by compute_sizes () */
1510 meta->idx_blob_wide = assembly->blob.index >= 65536 ? 1 : 0;
1511 meta->idx_guid_wide = assembly->guid.index >= 65536 ? 1 : 0;
1512 meta->idx_string_wide = assembly->sheap.index >= 65536 ? 1 : 0;
1514 meta_size += assembly->blob.index;
1515 meta_size += assembly->guid.index;
1516 meta_size += assembly->sheap.index;
1517 meta_size += assembly->us.index;
1519 for (i=0; i < MONO_TABLE_NUM; ++i)
1520 meta->tables [i].rows = assembly->tables [i].rows;
1522 for (i = 0; i < MONO_TABLE_NUM; i++){
1523 if (meta->tables [i].rows == 0)
1524 continue;
1525 valid_mask |= (guint64)1 << i;
1526 ntables ++;
1527 meta->tables [i].row_size = mono_metadata_compute_size (
1528 meta, i, &meta->tables [i].size_bitfield);
1529 heapt_size += meta->tables [i].row_size * meta->tables [i].rows;
1531 heapt_size += 24; /* #~ header size */
1532 heapt_size += ntables * 4;
1533 /* make multiple of 4 */
1534 heapt_size += 3;
1535 heapt_size &= ~3;
1536 meta_size += heapt_size;
1537 meta->raw_metadata = (char *)g_malloc0 (meta_size);
1538 p = (unsigned char*)meta->raw_metadata;
1539 /* the metadata signature */
1540 *p++ = 'B'; *p++ = 'S'; *p++ = 'J'; *p++ = 'B';
1541 /* version numbers and 4 bytes reserved */
1542 int16val = (guint16*)p;
1543 *int16val++ = GUINT16_TO_LE (meta->md_version_major);
1544 *int16val = GUINT16_TO_LE (meta->md_version_minor);
1545 p += 8;
1546 /* version string */
1547 int32val = (guint32*)p;
1548 *int32val = GUINT32_TO_LE ((strlen (meta->version) + 3) & (~3)); /* needs to be multiple of 4 */
1549 p += 4;
1550 memcpy (p, meta->version, strlen (meta->version));
1551 p += GUINT32_FROM_LE (*int32val);
1552 align_pointer (meta->raw_metadata, p);
1553 int16val = (guint16*)p;
1554 *int16val++ = GUINT16_TO_LE (0); /* flags must be 0 */
1555 *int16val = GUINT16_TO_LE (5); /* number of streams */
1556 p += 4;
1559 * write the stream info.
1561 table_offset = (p - (unsigned char*)meta->raw_metadata) + 5 * 8 + 40; /* room needed for stream headers */
1562 table_offset += 3; table_offset &= ~3;
1564 assembly->tstream.index = heapt_size;
1565 for (i = 0; i < 5; ++i) {
1566 int32val = (guint32*)p;
1567 stream_desc [i].stream->offset = table_offset;
1568 *int32val++ = GUINT32_TO_LE (table_offset);
1569 *int32val = GUINT32_TO_LE (stream_desc [i].stream->index);
1570 table_offset += GUINT32_FROM_LE (*int32val);
1571 table_offset += 3; table_offset &= ~3;
1572 p += 8;
1573 strcpy ((char*)p, stream_desc [i].name);
1574 p += strlen (stream_desc [i].name) + 1;
1575 align_pointer (meta->raw_metadata, p);
1578 * now copy the data, the table stream header and contents goes first.
1580 g_assert ((p - (unsigned char*)meta->raw_metadata) < assembly->tstream.offset);
1581 p = (guchar*)meta->raw_metadata + assembly->tstream.offset;
1582 int32val = (guint32*)p;
1583 *int32val = GUINT32_TO_LE (0); /* reserved */
1584 p += 4;
1586 *p++ = 2; /* version */
1587 *p++ = 0;
1589 if (meta->idx_string_wide)
1590 *p |= 0x01;
1591 if (meta->idx_guid_wide)
1592 *p |= 0x02;
1593 if (meta->idx_blob_wide)
1594 *p |= 0x04;
1595 ++p;
1596 *p++ = 1; /* reserved */
1597 int64val = (guint64*)p;
1598 *int64val++ = GUINT64_TO_LE (valid_mask);
1599 *int64val++ = GUINT64_TO_LE (valid_mask & sorted_mask); /* bitvector of sorted tables */
1600 p += 16;
1601 int32val = (guint32*)p;
1602 for (i = 0; i < MONO_TABLE_NUM; i++){
1603 if (meta->tables [i].rows == 0)
1604 continue;
1605 *int32val++ = GUINT32_TO_LE (meta->tables [i].rows);
1607 p = (unsigned char*)int32val;
1609 /* sort the tables that still need sorting */
1610 table = &assembly->tables [MONO_TABLE_CONSTANT];
1611 if (table->rows)
1612 qsort (table->values + MONO_CONSTANT_SIZE, table->rows, sizeof (guint32) * MONO_CONSTANT_SIZE, compare_constants);
1613 table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
1614 if (table->rows)
1615 qsort (table->values + MONO_METHOD_SEMA_SIZE, table->rows, sizeof (guint32) * MONO_METHOD_SEMA_SIZE, compare_semantics);
1616 table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1617 if (table->rows)
1618 qsort (table->values + MONO_CUSTOM_ATTR_SIZE, table->rows, sizeof (guint32) * MONO_CUSTOM_ATTR_SIZE, compare_custom_attrs);
1619 table = &assembly->tables [MONO_TABLE_FIELDMARSHAL];
1620 if (table->rows)
1621 qsort (table->values + MONO_FIELD_MARSHAL_SIZE, table->rows, sizeof (guint32) * MONO_FIELD_MARSHAL_SIZE, compare_field_marshal);
1622 table = &assembly->tables [MONO_TABLE_NESTEDCLASS];
1623 if (table->rows)
1624 qsort (table->values + MONO_NESTED_CLASS_SIZE, table->rows, sizeof (guint32) * MONO_NESTED_CLASS_SIZE, compare_nested);
1625 /* Section 21.11 DeclSecurity in Partition II doesn't specify this to be sorted by MS implementation requires it */
1626 table = &assembly->tables [MONO_TABLE_DECLSECURITY];
1627 if (table->rows)
1628 qsort (table->values + MONO_DECL_SECURITY_SIZE, table->rows, sizeof (guint32) * MONO_DECL_SECURITY_SIZE, compare_declsecurity_attrs);
1629 table = &assembly->tables [MONO_TABLE_INTERFACEIMPL];
1630 if (table->rows)
1631 qsort (table->values + MONO_INTERFACEIMPL_SIZE, table->rows, sizeof (guint32) * MONO_INTERFACEIMPL_SIZE, compare_interface_impl);
1633 /* compress the tables */
1634 for (i = 0; i < MONO_TABLE_NUM; i++){
1635 int row, col;
1636 guint32 *values;
1637 guint32 bitfield = meta->tables [i].size_bitfield;
1638 if (!meta->tables [i].rows)
1639 continue;
1640 if (assembly->tables [i].columns != mono_metadata_table_count (bitfield))
1641 g_error ("col count mismatch in %d: %d %d", i, assembly->tables [i].columns, mono_metadata_table_count (bitfield));
1642 meta->tables [i].base = (char*)p;
1643 for (row = 1; row <= meta->tables [i].rows; ++row) {
1644 values = assembly->tables [i].values + row * assembly->tables [i].columns;
1645 for (col = 0; col < assembly->tables [i].columns; ++col) {
1646 switch (mono_metadata_table_size (bitfield, col)) {
1647 case 1:
1648 *p++ = values [col];
1649 break;
1650 case 2:
1651 *p++ = values [col] & 0xff;
1652 *p++ = (values [col] >> 8) & 0xff;
1653 break;
1654 case 4:
1655 *p++ = values [col] & 0xff;
1656 *p++ = (values [col] >> 8) & 0xff;
1657 *p++ = (values [col] >> 16) & 0xff;
1658 *p++ = (values [col] >> 24) & 0xff;
1659 break;
1660 default:
1661 g_assert_not_reached ();
1665 g_assert ((p - (const unsigned char*)meta->tables [i].base) == (meta->tables [i].rows * meta->tables [i].row_size));
1668 g_assert (assembly->guid.offset + assembly->guid.index < meta_size);
1669 memcpy (meta->raw_metadata + assembly->sheap.offset, assembly->sheap.data, assembly->sheap.index);
1670 memcpy (meta->raw_metadata + assembly->us.offset, assembly->us.data, assembly->us.index);
1671 memcpy (meta->raw_metadata + assembly->blob.offset, assembly->blob.data, assembly->blob.index);
1672 memcpy (meta->raw_metadata + assembly->guid.offset, assembly->guid.data, assembly->guid.index);
1674 assembly->meta_size = assembly->guid.offset + assembly->guid.index;
1676 return TRUE;
1680 * Some tables in metadata need to be sorted according to some criteria, but
1681 * when methods and fields are first created with reflection, they may be assigned a token
1682 * that doesn't correspond to the final token they will get assigned after the sorting.
1683 * ILGenerator.cs keeps a fixup table that maps the position of tokens in the IL code stream
1684 * with the reflection objects that represent them. Once all the tables are set up, the
1685 * reflection objects will contains the correct table index. fixup_method() will fixup the
1686 * tokens for the method with ILGenerator @ilgen.
1688 static void
1689 fixup_method (MonoReflectionILGen *ilgen, gpointer value, MonoDynamicImage *assembly)
1691 guint32 code_idx = GPOINTER_TO_UINT (value);
1692 MonoReflectionILTokenInfo *iltoken;
1693 MonoReflectionTypeBuilder *tb;
1694 MonoReflectionArrayMethod *am;
1695 guint32 i, idx = 0;
1696 unsigned char *target;
1698 for (i = 0; i < ilgen->num_token_fixups; ++i) {
1699 iltoken = (MonoReflectionILTokenInfo *)mono_array_addr_with_size (ilgen->token_fixups, sizeof (MonoReflectionILTokenInfo), i);
1700 target = (guchar*)assembly->code.data + code_idx + iltoken->code_pos;
1701 switch (target [3]) {
1702 case MONO_TABLE_FIELD:
1703 if (!strcmp (iltoken->member->vtable->klass->name, "FieldBuilder")) {
1704 g_assert_not_reached ();
1705 } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoField")) {
1706 MonoClassField *f = ((MonoReflectionField*)iltoken->member)->field;
1707 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->field_to_table_idx, f));
1708 } else {
1709 g_assert_not_reached ();
1711 break;
1712 case MONO_TABLE_METHOD:
1713 if (!strcmp (iltoken->member->vtable->klass->name, "MethodBuilder")) {
1714 g_assert_not_reached ();
1715 } else if (!strcmp (iltoken->member->vtable->klass->name, "ConstructorBuilder")) {
1716 g_assert_not_reached ();
1717 } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoMethod") ||
1718 !strcmp (iltoken->member->vtable->klass->name, "MonoCMethod")) {
1719 MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
1720 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, m));
1721 } else {
1722 g_assert_not_reached ();
1724 break;
1725 case MONO_TABLE_TYPEDEF:
1726 if (!strcmp (iltoken->member->vtable->klass->name, "TypeBuilder")) {
1727 g_assert_not_reached ();
1728 } else if (!strcmp (iltoken->member->vtable->klass->name, "RuntimeType")) {
1729 MonoClass *k = mono_class_from_mono_type (((MonoReflectionType*)iltoken->member)->type);
1730 MonoObject *obj = mono_class_get_ref_info (k);
1731 g_assert (obj);
1732 g_assert (!strcmp (obj->vtable->klass->name, "TypeBuilder"));
1733 tb = (MonoReflectionTypeBuilder*)obj;
1734 idx = tb->table_idx;
1735 } else {
1736 g_assert_not_reached ();
1738 break;
1739 case MONO_TABLE_MEMBERREF:
1740 if (!strcmp (iltoken->member->vtable->klass->name, "MonoArrayMethod")) {
1741 am = (MonoReflectionArrayMethod*)iltoken->member;
1742 idx = am->table_idx;
1743 } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoMethod") ||
1744 !strcmp (iltoken->member->vtable->klass->name, "MonoCMethod")) {
1745 MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
1746 g_assert (m->klass->generic_class || m->klass->generic_container);
1747 continue;
1748 } else if (!strcmp (iltoken->member->vtable->klass->name, "FieldBuilder")) {
1749 g_assert_not_reached ();
1750 continue;
1751 } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoField")) {
1752 continue;
1753 } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodBuilder") ||
1754 !strcmp (iltoken->member->vtable->klass->name, "ConstructorBuilder")) {
1755 g_assert_not_reached ();
1756 continue;
1757 } else if (!strcmp (iltoken->member->vtable->klass->name, "FieldOnTypeBuilderInst")) {
1758 g_assert_not_reached ();
1759 continue;
1760 } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodOnTypeBuilderInst")) {
1761 g_assert_not_reached ();
1762 continue;
1763 } else if (!strcmp (iltoken->member->vtable->klass->name, "ConstructorOnTypeBuilderInst")) {
1764 g_assert_not_reached ();
1765 continue;
1766 } else {
1767 g_assert_not_reached ();
1769 break;
1770 case MONO_TABLE_METHODSPEC:
1771 if (!strcmp (iltoken->member->vtable->klass->name, "MonoMethod")) {
1772 MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
1773 g_assert (mono_method_signature (m)->generic_param_count);
1774 continue;
1775 } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodBuilder")) {
1776 g_assert_not_reached ();
1777 continue;
1778 } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodOnTypeBuilderInst")) {
1779 g_assert_not_reached ();
1780 continue;
1781 } else {
1782 g_assert_not_reached ();
1784 break;
1785 case MONO_TABLE_TYPESPEC:
1786 if (!strcmp (iltoken->member->vtable->klass->name, "RuntimeType")) {
1787 continue;
1788 } else {
1789 g_assert_not_reached ();
1791 break;
1792 default:
1793 g_error ("got unexpected table 0x%02x in fixup", target [3]);
1795 target [0] = idx & 0xff;
1796 target [1] = (idx >> 8) & 0xff;
1797 target [2] = (idx >> 16) & 0xff;
1802 * fixup_cattrs:
1804 * The CUSTOM_ATTRIBUTE table might contain METHODDEF tokens whose final
1805 * value is not known when the table is emitted.
1807 static void
1808 fixup_cattrs (MonoDynamicImage *assembly)
1810 MonoDynamicTable *table;
1811 guint32 *values;
1812 guint32 type, i, idx, token;
1813 MonoObject *ctor;
1815 table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1817 for (i = 0; i < table->rows; ++i) {
1818 values = table->values + ((i + 1) * MONO_CUSTOM_ATTR_SIZE);
1820 type = values [MONO_CUSTOM_ATTR_TYPE];
1821 if ((type & MONO_CUSTOM_ATTR_TYPE_MASK) == MONO_CUSTOM_ATTR_TYPE_METHODDEF) {
1822 idx = type >> MONO_CUSTOM_ATTR_TYPE_BITS;
1823 token = mono_metadata_make_token (MONO_TABLE_METHOD, idx);
1824 ctor = (MonoObject *)mono_g_hash_table_lookup (assembly->remapped_tokens, GUINT_TO_POINTER (token));
1825 g_assert (ctor);
1827 if (!strcmp (ctor->vtable->klass->name, "MonoCMethod")) {
1828 MonoMethod *m = ((MonoReflectionMethod*)ctor)->method;
1829 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, m));
1830 values [MONO_CUSTOM_ATTR_TYPE] = (idx << MONO_CUSTOM_ATTR_TYPE_BITS) | MONO_CUSTOM_ATTR_TYPE_METHODDEF;
1831 } else if (!strcmp (ctor->vtable->klass->name, "ConstructorBuilder")) {
1832 MonoMethod *m = ((MonoReflectionCtorBuilder*)ctor)->mhandle;
1833 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, m));
1834 values [MONO_CUSTOM_ATTR_TYPE] = (idx << MONO_CUSTOM_ATTR_TYPE_BITS) | MONO_CUSTOM_ATTR_TYPE_METHODDEF;
1840 static gboolean
1841 assembly_add_resource_manifest (MonoReflectionModuleBuilder *mb, MonoDynamicImage *assembly, MonoReflectionResource *rsrc, guint32 implementation, MonoError *error)
1843 MonoDynamicTable *table;
1844 guint32 *values;
1846 mono_error_init (error);
1848 table = &assembly->tables [MONO_TABLE_MANIFESTRESOURCE];
1849 table->rows++;
1850 alloc_table (table, table->rows);
1851 values = table->values + table->next_idx * MONO_MANIFEST_SIZE;
1852 values [MONO_MANIFEST_OFFSET] = rsrc->offset;
1853 values [MONO_MANIFEST_FLAGS] = rsrc->attrs;
1854 values [MONO_MANIFEST_NAME] = string_heap_insert_mstring (&assembly->sheap, rsrc->name, error);
1855 return_val_if_nok (error, FALSE);
1856 values [MONO_MANIFEST_IMPLEMENTATION] = implementation;
1857 table->next_idx++;
1858 return TRUE;
1861 static gboolean
1862 assembly_add_resource (MonoReflectionModuleBuilder *mb, MonoDynamicImage *assembly, MonoReflectionResource *rsrc, MonoError *error)
1864 MonoDynamicTable *table;
1865 guint32 *values;
1866 char blob_size [6];
1867 guchar hash [20];
1868 char *b = blob_size;
1869 char *name, *sname;
1870 guint32 idx, offset;
1872 mono_error_init (error);
1874 if (rsrc->filename) {
1875 name = mono_string_to_utf8_checked (rsrc->filename, error);
1876 return_val_if_nok (error, FALSE);
1877 sname = g_path_get_basename (name);
1879 table = &assembly->tables [MONO_TABLE_FILE];
1880 table->rows++;
1881 alloc_table (table, table->rows);
1882 values = table->values + table->next_idx * MONO_FILE_SIZE;
1883 values [MONO_FILE_FLAGS] = FILE_CONTAINS_NO_METADATA;
1884 values [MONO_FILE_NAME] = string_heap_insert (&assembly->sheap, sname);
1885 g_free (sname);
1887 mono_sha1_get_digest_from_file (name, hash);
1888 mono_metadata_encode_value (20, b, &b);
1889 values [MONO_FILE_HASH_VALUE] = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
1890 mono_image_add_stream_data (&assembly->blob, (char*)hash, 20);
1891 g_free (name);
1892 idx = table->next_idx++;
1893 rsrc->offset = 0;
1894 idx = MONO_IMPLEMENTATION_FILE | (idx << MONO_IMPLEMENTATION_BITS);
1895 } else {
1896 char sizebuf [4];
1897 char *data;
1898 guint len;
1899 if (rsrc->data) {
1900 data = mono_array_addr (rsrc->data, char, 0);
1901 len = mono_array_length (rsrc->data);
1902 } else {
1903 data = NULL;
1904 len = 0;
1906 offset = len;
1907 sizebuf [0] = offset; sizebuf [1] = offset >> 8;
1908 sizebuf [2] = offset >> 16; sizebuf [3] = offset >> 24;
1909 rsrc->offset = mono_image_add_stream_data (&assembly->resources, sizebuf, 4);
1910 mono_image_add_stream_data (&assembly->resources, data, len);
1912 if (!mb->is_main)
1914 * The entry should be emitted into the MANIFESTRESOURCE table of
1915 * the main module, but that needs to reference the FILE table
1916 * which isn't emitted yet.
1918 return TRUE;
1919 else
1920 idx = 0;
1923 return assembly_add_resource_manifest (mb, assembly, rsrc, idx, error);
1926 static gboolean
1927 set_version_from_string (MonoString *version, guint32 *values, MonoError *error)
1929 gchar *ver, *p, *str;
1930 guint32 i;
1932 mono_error_init (error);
1934 values [MONO_ASSEMBLY_MAJOR_VERSION] = 0;
1935 values [MONO_ASSEMBLY_MINOR_VERSION] = 0;
1936 values [MONO_ASSEMBLY_REV_NUMBER] = 0;
1937 values [MONO_ASSEMBLY_BUILD_NUMBER] = 0;
1938 if (!version)
1939 return TRUE;
1940 ver = str = mono_string_to_utf8_checked (version, error);
1941 return_val_if_nok (error, FALSE);
1942 for (i = 0; i < 4; ++i) {
1943 values [MONO_ASSEMBLY_MAJOR_VERSION + i] = strtol (ver, &p, 10);
1944 switch (*p) {
1945 case '.':
1946 p++;
1947 break;
1948 case '*':
1949 /* handle Revision and Build */
1950 p++;
1951 break;
1953 ver = p;
1955 g_free (str);
1956 return TRUE;
1959 static guint32
1960 load_public_key (MonoArray *pkey, MonoDynamicImage *assembly) {
1961 gsize len;
1962 guint32 token = 0;
1963 char blob_size [6];
1964 char *b = blob_size;
1966 if (!pkey)
1967 return token;
1969 len = mono_array_length (pkey);
1970 mono_metadata_encode_value (len, b, &b);
1971 token = mono_image_add_stream_data (&assembly->blob, blob_size, b - blob_size);
1972 mono_image_add_stream_data (&assembly->blob, mono_array_addr (pkey, char, 0), len);
1974 assembly->public_key = (guint8 *)g_malloc (len);
1975 memcpy (assembly->public_key, mono_array_addr (pkey, char, 0), len);
1976 assembly->public_key_len = len;
1978 /* Special case: check for ECMA key (16 bytes) */
1979 if ((len == MONO_ECMA_KEY_LENGTH) && mono_is_ecma_key (mono_array_addr (pkey, char, 0), len)) {
1980 /* In this case we must reserve 128 bytes (1024 bits) for the signature */
1981 assembly->strong_name_size = MONO_DEFAULT_PUBLIC_KEY_LENGTH;
1982 } else if (len >= MONO_PUBLIC_KEY_HEADER_LENGTH + MONO_MINIMUM_PUBLIC_KEY_LENGTH) {
1983 /* minimum key size (in 2.0) is 384 bits */
1984 assembly->strong_name_size = len - MONO_PUBLIC_KEY_HEADER_LENGTH;
1985 } else {
1986 /* FIXME - verifier */
1987 g_warning ("Invalid public key length: %d bits (total: %d)", (int)MONO_PUBLIC_KEY_BIT_SIZE (len), (int)len);
1988 assembly->strong_name_size = MONO_DEFAULT_PUBLIC_KEY_LENGTH; /* to be safe */
1990 assembly->strong_name = (char *)g_malloc0 (assembly->strong_name_size);
1992 return token;
1995 static gboolean
1996 mono_image_emit_manifest (MonoReflectionModuleBuilder *moduleb, MonoError *error)
1998 MonoDynamicTable *table;
1999 MonoDynamicImage *assembly;
2000 MonoReflectionAssemblyBuilder *assemblyb;
2001 MonoDomain *domain;
2002 guint32 *values;
2003 int i;
2004 guint32 module_index;
2006 mono_error_init (error);
2008 assemblyb = moduleb->assemblyb;
2009 assembly = moduleb->dynamic_image;
2010 domain = mono_object_domain (assemblyb);
2012 /* Emit ASSEMBLY table */
2013 table = &assembly->tables [MONO_TABLE_ASSEMBLY];
2014 alloc_table (table, 1);
2015 values = table->values + MONO_ASSEMBLY_SIZE;
2016 values [MONO_ASSEMBLY_HASH_ALG] = assemblyb->algid? assemblyb->algid: ASSEMBLY_HASH_SHA1;
2017 values [MONO_ASSEMBLY_NAME] = string_heap_insert_mstring (&assembly->sheap, assemblyb->name, error);
2018 return_val_if_nok (error, FALSE);
2019 if (assemblyb->culture) {
2020 values [MONO_ASSEMBLY_CULTURE] = string_heap_insert_mstring (&assembly->sheap, assemblyb->culture, error);
2021 return_val_if_nok (error, FALSE);
2022 } else {
2023 values [MONO_ASSEMBLY_CULTURE] = string_heap_insert (&assembly->sheap, "");
2025 values [MONO_ASSEMBLY_PUBLIC_KEY] = load_public_key (assemblyb->public_key, assembly);
2026 values [MONO_ASSEMBLY_FLAGS] = assemblyb->flags;
2027 if (!set_version_from_string (assemblyb->version, values, error))
2028 return FALSE;
2030 /* Emit FILE + EXPORTED_TYPE table */
2031 module_index = 0;
2032 for (i = 0; i < mono_array_length (assemblyb->modules); ++i) {
2033 int j;
2034 MonoReflectionModuleBuilder *file_module =
2035 mono_array_get (assemblyb->modules, MonoReflectionModuleBuilder*, i);
2036 if (file_module != moduleb) {
2037 if (!mono_image_fill_file_table (domain, (MonoReflectionModule*)file_module, assembly, error))
2038 return FALSE;
2039 module_index ++;
2040 if (file_module->types) {
2041 for (j = 0; j < file_module->num_types; ++j) {
2042 MonoReflectionTypeBuilder *tb = mono_array_get (file_module->types, MonoReflectionTypeBuilder*, j);
2043 mono_image_fill_export_table (domain, tb, module_index, 0, assembly, error);
2044 return_val_if_nok (error, FALSE);
2049 if (assemblyb->loaded_modules) {
2050 for (i = 0; i < mono_array_length (assemblyb->loaded_modules); ++i) {
2051 MonoReflectionModule *file_module =
2052 mono_array_get (assemblyb->loaded_modules, MonoReflectionModule*, i);
2053 if (!mono_image_fill_file_table (domain, file_module, assembly, error))
2054 return FALSE;
2055 module_index ++;
2056 mono_image_fill_export_table_from_module (domain, file_module, module_index, assembly);
2059 if (assemblyb->type_forwarders)
2060 mono_image_fill_export_table_from_type_forwarders (assemblyb, assembly);
2062 /* Emit MANIFESTRESOURCE table */
2063 module_index = 0;
2064 for (i = 0; i < mono_array_length (assemblyb->modules); ++i) {
2065 int j;
2066 MonoReflectionModuleBuilder *file_module =
2067 mono_array_get (assemblyb->modules, MonoReflectionModuleBuilder*, i);
2068 /* The table for the main module is emitted later */
2069 if (file_module != moduleb) {
2070 module_index ++;
2071 if (file_module->resources) {
2072 int len = mono_array_length (file_module->resources);
2073 for (j = 0; j < len; ++j) {
2074 MonoReflectionResource* res = (MonoReflectionResource*)mono_array_addr (file_module->resources, MonoReflectionResource, j);
2075 if (!assembly_add_resource_manifest (file_module, assembly, res, MONO_IMPLEMENTATION_FILE | (module_index << MONO_IMPLEMENTATION_BITS), error))
2076 return FALSE;
2081 return TRUE;
2084 #ifndef DISABLE_REFLECTION_EMIT_SAVE
2087 * Insert into the metadata tables all the info about the TypeBuilder tb.
2088 * Data in the tables is inserted in a predefined order, since some tables need to be sorted.
2090 static gboolean
2091 mono_image_get_type_info (MonoDomain *domain, MonoReflectionTypeBuilder *tb, MonoDynamicImage *assembly, MonoError *error)
2093 MonoDynamicTable *table;
2094 guint *values;
2095 int i, is_object = 0, is_system = 0;
2096 char *n;
2098 mono_error_init (error);
2100 table = &assembly->tables [MONO_TABLE_TYPEDEF];
2101 values = table->values + tb->table_idx * MONO_TYPEDEF_SIZE;
2102 values [MONO_TYPEDEF_FLAGS] = tb->attrs;
2103 n = mono_string_to_utf8_checked (tb->name, error);
2104 return_val_if_nok (error, FALSE);
2105 if (strcmp (n, "Object") == 0)
2106 is_object++;
2107 values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, n);
2108 g_free (n);
2109 n = mono_string_to_utf8_checked (tb->nspace, error);
2110 return_val_if_nok (error, FALSE);
2111 if (strcmp (n, "System") == 0)
2112 is_system++;
2113 values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, n);
2114 g_free (n);
2115 if (tb->parent && !(is_system && is_object) &&
2116 !(tb->attrs & TYPE_ATTRIBUTE_INTERFACE)) { /* interfaces don't have a parent */
2117 MonoType *parent_type = mono_reflection_type_get_handle ((MonoReflectionType*)tb->parent, error);
2118 return_val_if_nok (error, FALSE);
2119 values [MONO_TYPEDEF_EXTENDS] = mono_image_typedef_or_ref (assembly, parent_type);
2120 } else {
2121 values [MONO_TYPEDEF_EXTENDS] = 0;
2123 values [MONO_TYPEDEF_FIELD_LIST] = assembly->tables [MONO_TABLE_FIELD].next_idx;
2124 values [MONO_TYPEDEF_METHOD_LIST] = assembly->tables [MONO_TABLE_METHOD].next_idx;
2127 * if we have explicitlayout or sequentiallayouts, output data in the
2128 * ClassLayout table.
2130 if (((tb->attrs & TYPE_ATTRIBUTE_LAYOUT_MASK) != TYPE_ATTRIBUTE_AUTO_LAYOUT) &&
2131 ((tb->class_size > 0) || (tb->packing_size > 0))) {
2132 table = &assembly->tables [MONO_TABLE_CLASSLAYOUT];
2133 table->rows++;
2134 alloc_table (table, table->rows);
2135 values = table->values + table->rows * MONO_CLASS_LAYOUT_SIZE;
2136 values [MONO_CLASS_LAYOUT_PARENT] = tb->table_idx;
2137 values [MONO_CLASS_LAYOUT_CLASS_SIZE] = tb->class_size;
2138 values [MONO_CLASS_LAYOUT_PACKING_SIZE] = tb->packing_size;
2141 /* handle interfaces */
2142 if (tb->interfaces) {
2143 table = &assembly->tables [MONO_TABLE_INTERFACEIMPL];
2144 i = table->rows;
2145 table->rows += mono_array_length (tb->interfaces);
2146 alloc_table (table, table->rows);
2147 values = table->values + (i + 1) * MONO_INTERFACEIMPL_SIZE;
2148 for (i = 0; i < mono_array_length (tb->interfaces); ++i) {
2149 MonoReflectionType* iface = (MonoReflectionType*) mono_array_get (tb->interfaces, gpointer, i);
2150 MonoType *iface_type = mono_reflection_type_get_handle (iface, error);
2151 return_val_if_nok (error, FALSE);
2152 values [MONO_INTERFACEIMPL_CLASS] = tb->table_idx;
2153 values [MONO_INTERFACEIMPL_INTERFACE] = mono_image_typedef_or_ref (assembly, iface_type);
2154 values += MONO_INTERFACEIMPL_SIZE;
2158 /* handle fields */
2159 if (tb->fields) {
2160 table = &assembly->tables [MONO_TABLE_FIELD];
2161 table->rows += tb->num_fields;
2162 alloc_table (table, table->rows);
2163 for (i = 0; i < tb->num_fields; ++i) {
2164 mono_image_get_field_info (
2165 mono_array_get (tb->fields, MonoReflectionFieldBuilder*, i), assembly, error);
2166 return_val_if_nok (error, FALSE);
2170 /* handle constructors */
2171 if (tb->ctors) {
2172 table = &assembly->tables [MONO_TABLE_METHOD];
2173 table->rows += mono_array_length (tb->ctors);
2174 alloc_table (table, table->rows);
2175 for (i = 0; i < mono_array_length (tb->ctors); ++i) {
2176 if (!mono_image_get_ctor_info (domain,
2177 mono_array_get (tb->ctors, MonoReflectionCtorBuilder*, i),
2178 assembly, error))
2179 return FALSE;
2183 /* handle methods */
2184 if (tb->methods) {
2185 table = &assembly->tables [MONO_TABLE_METHOD];
2186 table->rows += tb->num_methods;
2187 alloc_table (table, table->rows);
2188 for (i = 0; i < tb->num_methods; ++i) {
2189 if (!mono_image_get_method_info (
2190 mono_array_get (tb->methods, MonoReflectionMethodBuilder*, i), assembly, error))
2191 return FALSE;
2195 /* Do the same with properties etc.. */
2196 if (tb->events && mono_array_length (tb->events)) {
2197 table = &assembly->tables [MONO_TABLE_EVENT];
2198 table->rows += mono_array_length (tb->events);
2199 alloc_table (table, table->rows);
2200 table = &assembly->tables [MONO_TABLE_EVENTMAP];
2201 table->rows ++;
2202 alloc_table (table, table->rows);
2203 values = table->values + table->rows * MONO_EVENT_MAP_SIZE;
2204 values [MONO_EVENT_MAP_PARENT] = tb->table_idx;
2205 values [MONO_EVENT_MAP_EVENTLIST] = assembly->tables [MONO_TABLE_EVENT].next_idx;
2206 for (i = 0; i < mono_array_length (tb->events); ++i) {
2207 mono_image_get_event_info (
2208 mono_array_get (tb->events, MonoReflectionEventBuilder*, i), assembly, error);
2209 return_val_if_nok (error, FALSE);
2212 if (tb->properties && mono_array_length (tb->properties)) {
2213 table = &assembly->tables [MONO_TABLE_PROPERTY];
2214 table->rows += mono_array_length (tb->properties);
2215 alloc_table (table, table->rows);
2216 table = &assembly->tables [MONO_TABLE_PROPERTYMAP];
2217 table->rows ++;
2218 alloc_table (table, table->rows);
2219 values = table->values + table->rows * MONO_PROPERTY_MAP_SIZE;
2220 values [MONO_PROPERTY_MAP_PARENT] = tb->table_idx;
2221 values [MONO_PROPERTY_MAP_PROPERTY_LIST] = assembly->tables [MONO_TABLE_PROPERTY].next_idx;
2222 for (i = 0; i < mono_array_length (tb->properties); ++i) {
2223 mono_image_get_property_info (
2224 mono_array_get (tb->properties, MonoReflectionPropertyBuilder*, i), assembly, error);
2225 return_val_if_nok (error, FALSE);
2229 /* handle generic parameters */
2230 if (tb->generic_params) {
2231 table = &assembly->tables [MONO_TABLE_GENERICPARAM];
2232 table->rows += mono_array_length (tb->generic_params);
2233 alloc_table (table, table->rows);
2234 for (i = 0; i < mono_array_length (tb->generic_params); ++i) {
2235 guint32 owner = MONO_TYPEORMETHOD_TYPE | (tb->table_idx << MONO_TYPEORMETHOD_BITS);
2237 mono_image_get_generic_param_info (
2238 mono_array_get (tb->generic_params, MonoReflectionGenericParam*, i), owner, assembly);
2242 mono_image_add_decl_security (assembly,
2243 mono_metadata_make_token (MONO_TABLE_TYPEDEF, tb->table_idx), tb->permissions);
2245 if (tb->subtypes) {
2246 MonoDynamicTable *ntable;
2248 ntable = &assembly->tables [MONO_TABLE_NESTEDCLASS];
2249 ntable->rows += mono_array_length (tb->subtypes);
2250 alloc_table (ntable, ntable->rows);
2251 values = ntable->values + ntable->next_idx * MONO_NESTED_CLASS_SIZE;
2253 for (i = 0; i < mono_array_length (tb->subtypes); ++i) {
2254 MonoReflectionTypeBuilder *subtype = mono_array_get (tb->subtypes, MonoReflectionTypeBuilder*, i);
2256 values [MONO_NESTED_CLASS_NESTED] = subtype->table_idx;
2257 values [MONO_NESTED_CLASS_ENCLOSING] = tb->table_idx;
2258 /*g_print ("nesting %s (%d) in %s (%d) (rows %d/%d)\n",
2259 mono_string_to_utf8 (subtype->name), subtype->table_idx,
2260 mono_string_to_utf8 (tb->name), tb->table_idx,
2261 ntable->next_idx, ntable->rows);*/
2262 values += MONO_NESTED_CLASS_SIZE;
2263 ntable->next_idx++;
2267 return TRUE;
2272 * mono_image_build_metadata() will fill the info in all the needed metadata tables
2273 * for the modulebuilder @moduleb.
2274 * At the end of the process, method and field tokens are fixed up and the
2275 * on-disk compressed metadata representation is created.
2276 * Return TRUE on success, or FALSE on failure and sets @error
2278 gboolean
2279 mono_image_build_metadata (MonoReflectionModuleBuilder *moduleb, MonoError *error)
2281 MonoDynamicTable *table;
2282 MonoDynamicImage *assembly;
2283 MonoReflectionAssemblyBuilder *assemblyb;
2284 MonoDomain *domain;
2285 MonoPtrArray types;
2286 guint32 *values;
2287 int i, j;
2289 mono_error_init (error);
2291 assemblyb = moduleb->assemblyb;
2292 assembly = moduleb->dynamic_image;
2293 domain = mono_object_domain (assemblyb);
2295 if (assembly->text_rva)
2296 return TRUE;
2298 assembly->text_rva = START_TEXT_RVA;
2300 if (moduleb->is_main) {
2301 mono_image_emit_manifest (moduleb, error);
2302 return_val_if_nok (error, FALSE);
2305 table = &assembly->tables [MONO_TABLE_TYPEDEF];
2306 table->rows = 1; /* .<Module> */
2307 table->next_idx++;
2308 alloc_table (table, table->rows);
2310 * Set the first entry.
2312 values = table->values + table->columns;
2313 values [MONO_TYPEDEF_FLAGS] = 0;
2314 values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, "<Module>") ;
2315 values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, "") ;
2316 values [MONO_TYPEDEF_EXTENDS] = 0;
2317 values [MONO_TYPEDEF_FIELD_LIST] = 1;
2318 values [MONO_TYPEDEF_METHOD_LIST] = 1;
2321 * handle global methods
2322 * FIXME: test what to do when global methods are defined in multiple modules.
2324 if (moduleb->global_methods) {
2325 table = &assembly->tables [MONO_TABLE_METHOD];
2326 table->rows += mono_array_length (moduleb->global_methods);
2327 alloc_table (table, table->rows);
2328 for (i = 0; i < mono_array_length (moduleb->global_methods); ++i) {
2329 if (!mono_image_get_method_info (
2330 mono_array_get (moduleb->global_methods, MonoReflectionMethodBuilder*, i), assembly, error))
2331 goto leave;
2334 if (moduleb->global_fields) {
2335 table = &assembly->tables [MONO_TABLE_FIELD];
2336 table->rows += mono_array_length (moduleb->global_fields);
2337 alloc_table (table, table->rows);
2338 for (i = 0; i < mono_array_length (moduleb->global_fields); ++i) {
2339 mono_image_get_field_info (
2340 mono_array_get (moduleb->global_fields, MonoReflectionFieldBuilder*, i), assembly,
2341 error);
2342 if (!is_ok (error))
2343 goto leave;
2347 table = &assembly->tables [MONO_TABLE_MODULE];
2348 alloc_table (table, 1);
2349 mono_image_fill_module_table (domain, moduleb, assembly, error);
2350 if (!is_ok (error))
2351 goto leave;
2353 /* Collect all types into a list sorted by their table_idx */
2354 mono_ptr_array_init (types, moduleb->num_types, MONO_ROOT_SOURCE_REFLECTION, "dynamic module types list");
2356 if (moduleb->types)
2357 for (i = 0; i < moduleb->num_types; ++i) {
2358 MonoReflectionTypeBuilder *type = mono_array_get (moduleb->types, MonoReflectionTypeBuilder*, i);
2359 collect_types (&types, type);
2362 mono_ptr_array_sort (types, (int (*)(const void *, const void *))compare_types_by_table_idx);
2363 table = &assembly->tables [MONO_TABLE_TYPEDEF];
2364 table->rows += mono_ptr_array_size (types);
2365 alloc_table (table, table->rows);
2368 * Emit type names + namespaces at one place inside the string heap,
2369 * so load_class_names () needs to touch fewer pages.
2371 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2372 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2373 string_heap_insert_mstring (&assembly->sheap, tb->nspace, error);
2374 if (!is_ok (error))
2375 goto leave_types;
2377 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2378 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2379 string_heap_insert_mstring (&assembly->sheap, tb->name, error);
2380 if (!is_ok (error))
2381 goto leave_types;
2384 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2385 MonoReflectionTypeBuilder *type = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2386 if (!mono_image_get_type_info (domain, type, assembly, error))
2387 goto leave_types;
2391 * table->rows is already set above and in mono_image_fill_module_table.
2393 /* add all the custom attributes at the end, once all the indexes are stable */
2394 if (!mono_image_add_cattrs (assembly, 1, MONO_CUSTOM_ATTR_ASSEMBLY, assemblyb->cattrs, error))
2395 goto leave_types;
2397 /* CAS assembly permissions */
2398 if (assemblyb->permissions_minimum)
2399 mono_image_add_decl_security (assembly, mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1), assemblyb->permissions_minimum);
2400 if (assemblyb->permissions_optional)
2401 mono_image_add_decl_security (assembly, mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1), assemblyb->permissions_optional);
2402 if (assemblyb->permissions_refused)
2403 mono_image_add_decl_security (assembly, mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1), assemblyb->permissions_refused);
2405 if (!module_add_cattrs (assembly, moduleb, error))
2406 goto leave_types;
2408 /* fixup tokens */
2409 mono_g_hash_table_foreach (assembly->token_fixups, (GHFunc)fixup_method, assembly);
2411 /* Create the MethodImpl table. We do this after emitting all methods so we already know
2412 * the final tokens and don't need another fixup pass. */
2414 if (moduleb->global_methods) {
2415 for (i = 0; i < mono_array_length (moduleb->global_methods); ++i) {
2416 MonoReflectionMethodBuilder *mb = mono_array_get (
2417 moduleb->global_methods, MonoReflectionMethodBuilder*, i);
2418 if (!mono_image_add_methodimpl (assembly, mb, error))
2419 goto leave_types;
2423 for (i = 0; i < mono_ptr_array_size (types); ++i) {
2424 MonoReflectionTypeBuilder *type = (MonoReflectionTypeBuilder *)mono_ptr_array_get (types, i);
2425 if (type->methods) {
2426 for (j = 0; j < type->num_methods; ++j) {
2427 MonoReflectionMethodBuilder *mb = mono_array_get (
2428 type->methods, MonoReflectionMethodBuilder*, j);
2430 if (!mono_image_add_methodimpl (assembly, mb, error))
2431 goto leave_types;
2436 fixup_cattrs (assembly);
2438 leave_types:
2439 mono_ptr_array_destroy (types);
2440 leave:
2442 return mono_error_ok (error);
2445 #else /* DISABLE_REFLECTION_EMIT_SAVE */
2447 gboolean
2448 mono_image_build_metadata (MonoReflectionModuleBuilder *moduleb, MonoError *error)
2450 g_error ("This mono runtime was configured with --enable-minimal=reflection_emit_save, so saving of dynamic assemblies is not supported.");
2453 #endif /* DISABLE_REFLECTION_EMIT_SAVE */
2455 #ifndef DISABLE_REFLECTION_EMIT_SAVE
2457 static int
2458 calc_section_size (MonoDynamicImage *assembly)
2460 int nsections = 0;
2462 /* alignment constraints */
2463 mono_image_add_stream_zero (&assembly->code, 4 - (assembly->code.index % 4));
2464 g_assert ((assembly->code.index % 4) == 0);
2465 assembly->meta_size += 3;
2466 assembly->meta_size &= ~3;
2467 mono_image_add_stream_zero (&assembly->resources, 4 - (assembly->resources.index % 4));
2468 g_assert ((assembly->resources.index % 4) == 0);
2470 assembly->sections [MONO_SECTION_TEXT].size = assembly->meta_size + assembly->code.index + assembly->resources.index + assembly->strong_name_size;
2471 assembly->sections [MONO_SECTION_TEXT].attrs = SECT_FLAGS_HAS_CODE | SECT_FLAGS_MEM_EXECUTE | SECT_FLAGS_MEM_READ;
2472 nsections++;
2474 if (assembly->win32_res) {
2475 guint32 res_size = (assembly->win32_res_size + 3) & ~3;
2477 assembly->sections [MONO_SECTION_RSRC].size = res_size;
2478 assembly->sections [MONO_SECTION_RSRC].attrs = SECT_FLAGS_HAS_INITIALIZED_DATA | SECT_FLAGS_MEM_READ;
2479 nsections++;
2482 assembly->sections [MONO_SECTION_RELOC].size = 12;
2483 assembly->sections [MONO_SECTION_RELOC].attrs = SECT_FLAGS_MEM_READ | SECT_FLAGS_MEM_DISCARDABLE | SECT_FLAGS_HAS_INITIALIZED_DATA;
2484 nsections++;
2486 return nsections;
2489 typedef struct {
2490 guint32 id;
2491 guint32 offset;
2492 GSList *children;
2493 MonoReflectionWin32Resource *win32_res; /* Only for leaf nodes */
2494 } ResTreeNode;
2496 static int
2497 resource_tree_compare_by_id (gconstpointer a, gconstpointer b)
2499 ResTreeNode *t1 = (ResTreeNode*)a;
2500 ResTreeNode *t2 = (ResTreeNode*)b;
2502 return t1->id - t2->id;
2506 * resource_tree_create:
2508 * Organize the resources into a resource tree.
2510 static ResTreeNode *
2511 resource_tree_create (MonoArray *win32_resources)
2513 ResTreeNode *tree, *res_node, *type_node, *lang_node;
2514 GSList *l;
2515 int i;
2517 tree = g_new0 (ResTreeNode, 1);
2519 for (i = 0; i < mono_array_length (win32_resources); ++i) {
2520 MonoReflectionWin32Resource *win32_res =
2521 (MonoReflectionWin32Resource*)mono_array_addr (win32_resources, MonoReflectionWin32Resource, i);
2523 /* Create node */
2525 /* FIXME: BUG: this stores managed references in unmanaged memory */
2526 lang_node = g_new0 (ResTreeNode, 1);
2527 lang_node->id = win32_res->lang_id;
2528 lang_node->win32_res = win32_res;
2530 /* Create type node if neccesary */
2531 type_node = NULL;
2532 for (l = tree->children; l; l = l->next)
2533 if (((ResTreeNode*)(l->data))->id == win32_res->res_type) {
2534 type_node = (ResTreeNode*)l->data;
2535 break;
2538 if (!type_node) {
2539 type_node = g_new0 (ResTreeNode, 1);
2540 type_node->id = win32_res->res_type;
2543 * The resource types have to be sorted otherwise
2544 * Windows Explorer can't display the version information.
2546 tree->children = g_slist_insert_sorted (tree->children,
2547 type_node, resource_tree_compare_by_id);
2550 /* Create res node if neccesary */
2551 res_node = NULL;
2552 for (l = type_node->children; l; l = l->next)
2553 if (((ResTreeNode*)(l->data))->id == win32_res->res_id) {
2554 res_node = (ResTreeNode*)l->data;
2555 break;
2558 if (!res_node) {
2559 res_node = g_new0 (ResTreeNode, 1);
2560 res_node->id = win32_res->res_id;
2561 type_node->children = g_slist_append (type_node->children, res_node);
2564 res_node->children = g_slist_append (res_node->children, lang_node);
2567 return tree;
2571 * resource_tree_encode:
2573 * Encode the resource tree into the format used in the PE file.
2575 static void
2576 resource_tree_encode (ResTreeNode *node, char *begin, char *p, char **endbuf)
2578 char *entries;
2579 MonoPEResourceDir dir;
2580 MonoPEResourceDirEntry dir_entry;
2581 MonoPEResourceDataEntry data_entry;
2582 GSList *l;
2583 guint32 res_id_entries;
2586 * For the format of the resource directory, see the article
2587 * "An In-Depth Look into the Win32 Portable Executable File Format" by
2588 * Matt Pietrek
2591 memset (&dir, 0, sizeof (dir));
2592 memset (&dir_entry, 0, sizeof (dir_entry));
2593 memset (&data_entry, 0, sizeof (data_entry));
2595 g_assert (sizeof (dir) == 16);
2596 g_assert (sizeof (dir_entry) == 8);
2597 g_assert (sizeof (data_entry) == 16);
2599 node->offset = p - begin;
2601 /* IMAGE_RESOURCE_DIRECTORY */
2602 res_id_entries = g_slist_length (node->children);
2603 dir.res_id_entries = GUINT16_TO_LE (res_id_entries);
2605 memcpy (p, &dir, sizeof (dir));
2606 p += sizeof (dir);
2608 /* Reserve space for entries */
2609 entries = p;
2610 p += sizeof (dir_entry) * res_id_entries;
2612 /* Write children */
2613 for (l = node->children; l; l = l->next) {
2614 ResTreeNode *child = (ResTreeNode*)l->data;
2616 if (child->win32_res) {
2617 guint32 size;
2619 child->offset = p - begin;
2621 /* IMAGE_RESOURCE_DATA_ENTRY */
2622 data_entry.rde_data_offset = GUINT32_TO_LE (p - begin + sizeof (data_entry));
2623 size = mono_array_length (child->win32_res->res_data);
2624 data_entry.rde_size = GUINT32_TO_LE (size);
2626 memcpy (p, &data_entry, sizeof (data_entry));
2627 p += sizeof (data_entry);
2629 memcpy (p, mono_array_addr (child->win32_res->res_data, char, 0), size);
2630 p += size;
2631 } else {
2632 resource_tree_encode (child, begin, p, &p);
2636 /* IMAGE_RESOURCE_ENTRY */
2637 for (l = node->children; l; l = l->next) {
2638 ResTreeNode *child = (ResTreeNode*)l->data;
2640 MONO_PE_RES_DIR_ENTRY_SET_NAME (dir_entry, FALSE, child->id);
2641 MONO_PE_RES_DIR_ENTRY_SET_DIR (dir_entry, !child->win32_res, child->offset);
2643 memcpy (entries, &dir_entry, sizeof (dir_entry));
2644 entries += sizeof (dir_entry);
2647 *endbuf = p;
2650 static void
2651 resource_tree_free (ResTreeNode * node)
2653 GSList * list;
2654 for (list = node->children; list; list = list->next)
2655 resource_tree_free ((ResTreeNode*)list->data);
2656 g_slist_free(node->children);
2657 g_free (node);
2660 static void
2661 assembly_add_win32_resources (MonoDynamicImage *assembly, MonoReflectionAssemblyBuilder *assemblyb)
2663 char *buf;
2664 char *p;
2665 guint32 size, i;
2666 MonoReflectionWin32Resource *win32_res;
2667 ResTreeNode *tree;
2669 if (!assemblyb->win32_resources)
2670 return;
2673 * Resources are stored in a three level tree inside the PE file.
2674 * - level one contains a node for each type of resource
2675 * - level two contains a node for each resource
2676 * - level three contains a node for each instance of a resource for a
2677 * specific language.
2680 tree = resource_tree_create (assemblyb->win32_resources);
2682 /* Estimate the size of the encoded tree */
2683 size = 0;
2684 for (i = 0; i < mono_array_length (assemblyb->win32_resources); ++i) {
2685 win32_res = (MonoReflectionWin32Resource*)mono_array_addr (assemblyb->win32_resources, MonoReflectionWin32Resource, i);
2686 size += mono_array_length (win32_res->res_data);
2688 /* Directory structure */
2689 size += mono_array_length (assemblyb->win32_resources) * 256;
2690 p = buf = (char *)g_malloc (size);
2692 resource_tree_encode (tree, p, p, &p);
2694 g_assert (p - buf <= size);
2696 assembly->win32_res = (char *)g_malloc (p - buf);
2697 assembly->win32_res_size = p - buf;
2698 memcpy (assembly->win32_res, buf, p - buf);
2700 g_free (buf);
2701 resource_tree_free (tree);
2704 static void
2705 fixup_resource_directory (char *res_section, char *p, guint32 rva)
2707 MonoPEResourceDir *dir = (MonoPEResourceDir*)p;
2708 int i;
2710 p += sizeof (MonoPEResourceDir);
2711 for (i = 0; i < GUINT16_FROM_LE (dir->res_named_entries) + GUINT16_FROM_LE (dir->res_id_entries); ++i) {
2712 MonoPEResourceDirEntry *dir_entry = (MonoPEResourceDirEntry*)p;
2713 char *child = res_section + MONO_PE_RES_DIR_ENTRY_DIR_OFFSET (*dir_entry);
2714 if (MONO_PE_RES_DIR_ENTRY_IS_DIR (*dir_entry)) {
2715 fixup_resource_directory (res_section, child, rva);
2716 } else {
2717 MonoPEResourceDataEntry *data_entry = (MonoPEResourceDataEntry*)child;
2718 data_entry->rde_data_offset = GUINT32_TO_LE (GUINT32_FROM_LE (data_entry->rde_data_offset) + rva);
2721 p += sizeof (MonoPEResourceDirEntry);
2725 static void
2726 checked_write_file (HANDLE f, gconstpointer buffer, guint32 numbytes)
2728 guint32 dummy;
2729 if (!WriteFile (f, buffer, numbytes, &dummy, NULL))
2730 g_error ("WriteFile returned %d\n", GetLastError ());
2734 * mono_image_create_pefile:
2735 * @mb: a module builder object
2737 * This function creates the PE-COFF header, the image sections, the CLI header * etc. all the data is written in
2738 * assembly->pefile where it can be easily retrieved later in chunks.
2740 gboolean
2741 mono_image_create_pefile (MonoReflectionModuleBuilder *mb, HANDLE file, MonoError *error)
2743 MonoMSDOSHeader *msdos;
2744 MonoDotNetHeader *header;
2745 MonoSectionTable *section;
2746 MonoCLIHeader *cli_header;
2747 guint32 size, image_size, virtual_base, text_offset;
2748 guint32 header_start, section_start, file_offset, virtual_offset;
2749 MonoDynamicImage *assembly;
2750 MonoReflectionAssemblyBuilder *assemblyb;
2751 MonoDynamicStream pefile_stream = {0};
2752 MonoDynamicStream *pefile = &pefile_stream;
2753 int i, nsections;
2754 guint32 *rva, value;
2755 guchar *p;
2756 static const unsigned char msheader[] = {
2757 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
2758 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2759 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2760 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
2761 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68,
2762 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f,
2763 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,
2764 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
2767 mono_error_init (error);
2769 assemblyb = mb->assemblyb;
2771 mono_reflection_dynimage_basic_init (assemblyb);
2772 assembly = mb->dynamic_image;
2774 assembly->pe_kind = assemblyb->pe_kind;
2775 assembly->machine = assemblyb->machine;
2776 ((MonoDynamicImage*)assemblyb->dynamic_assembly->assembly.image)->pe_kind = assemblyb->pe_kind;
2777 ((MonoDynamicImage*)assemblyb->dynamic_assembly->assembly.image)->machine = assemblyb->machine;
2779 if (!mono_image_build_metadata (mb, error))
2780 return FALSE;
2783 if (mb->is_main && assemblyb->resources) {
2784 int len = mono_array_length (assemblyb->resources);
2785 for (i = 0; i < len; ++i) {
2786 if (!assembly_add_resource (mb, assembly, (MonoReflectionResource*)mono_array_addr (assemblyb->resources, MonoReflectionResource, i), error))
2787 return FALSE;
2791 if (mb->resources) {
2792 int len = mono_array_length (mb->resources);
2793 for (i = 0; i < len; ++i) {
2794 if (!assembly_add_resource (mb, assembly, (MonoReflectionResource*)mono_array_addr (mb->resources, MonoReflectionResource, i), error))
2795 return FALSE;
2799 if (!build_compressed_metadata (assembly, error))
2800 return FALSE;
2802 if (mb->is_main)
2803 assembly_add_win32_resources (assembly, assemblyb);
2805 nsections = calc_section_size (assembly);
2807 /* The DOS header and stub */
2808 g_assert (sizeof (MonoMSDOSHeader) == sizeof (msheader));
2809 mono_image_add_stream_data (pefile, (char*)msheader, sizeof (msheader));
2811 /* the dotnet header */
2812 header_start = mono_image_add_stream_zero (pefile, sizeof (MonoDotNetHeader));
2814 /* the section tables */
2815 section_start = mono_image_add_stream_zero (pefile, sizeof (MonoSectionTable) * nsections);
2817 file_offset = section_start + sizeof (MonoSectionTable) * nsections;
2818 virtual_offset = VIRT_ALIGN;
2819 image_size = 0;
2821 for (i = 0; i < MONO_SECTION_MAX; ++i) {
2822 if (!assembly->sections [i].size)
2823 continue;
2824 /* align offsets */
2825 file_offset += FILE_ALIGN - 1;
2826 file_offset &= ~(FILE_ALIGN - 1);
2827 virtual_offset += VIRT_ALIGN - 1;
2828 virtual_offset &= ~(VIRT_ALIGN - 1);
2830 assembly->sections [i].offset = file_offset;
2831 assembly->sections [i].rva = virtual_offset;
2833 file_offset += assembly->sections [i].size;
2834 virtual_offset += assembly->sections [i].size;
2835 image_size += (assembly->sections [i].size + VIRT_ALIGN - 1) & ~(VIRT_ALIGN - 1);
2838 file_offset += FILE_ALIGN - 1;
2839 file_offset &= ~(FILE_ALIGN - 1);
2841 image_size += section_start + sizeof (MonoSectionTable) * nsections;
2843 /* back-patch info */
2844 msdos = (MonoMSDOSHeader*)pefile->data;
2845 msdos->pe_offset = GUINT32_FROM_LE (sizeof (MonoMSDOSHeader));
2847 header = (MonoDotNetHeader*)(pefile->data + header_start);
2848 header->pesig [0] = 'P';
2849 header->pesig [1] = 'E';
2851 header->coff.coff_machine = GUINT16_FROM_LE (assemblyb->machine);
2852 header->coff.coff_sections = GUINT16_FROM_LE (nsections);
2853 header->coff.coff_time = GUINT32_FROM_LE (time (NULL));
2854 header->coff.coff_opt_header_size = GUINT16_FROM_LE (sizeof (MonoDotNetHeader) - sizeof (MonoCOFFHeader) - 4);
2855 if (assemblyb->pekind == 1) {
2856 /* it's a dll */
2857 header->coff.coff_attributes = GUINT16_FROM_LE (0x210e);
2858 } else {
2859 /* it's an exe */
2860 header->coff.coff_attributes = GUINT16_FROM_LE (0x010e);
2863 virtual_base = 0x400000; /* FIXME: 0x10000000 if a DLL */
2865 header->pe.pe_magic = GUINT16_FROM_LE (0x10B);
2866 header->pe.pe_major = 6;
2867 header->pe.pe_minor = 0;
2868 size = assembly->sections [MONO_SECTION_TEXT].size;
2869 size += FILE_ALIGN - 1;
2870 size &= ~(FILE_ALIGN - 1);
2871 header->pe.pe_code_size = GUINT32_FROM_LE(size);
2872 size = assembly->sections [MONO_SECTION_RSRC].size;
2873 size += FILE_ALIGN - 1;
2874 size &= ~(FILE_ALIGN - 1);
2875 header->pe.pe_data_size = GUINT32_FROM_LE(size);
2876 g_assert (START_TEXT_RVA == assembly->sections [MONO_SECTION_TEXT].rva);
2877 header->pe.pe_rva_code_base = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_TEXT].rva);
2878 header->pe.pe_rva_data_base = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].rva);
2879 /* pe_rva_entry_point always at the beginning of the text section */
2880 header->pe.pe_rva_entry_point = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_TEXT].rva);
2882 header->nt.pe_image_base = GUINT32_FROM_LE (virtual_base);
2883 header->nt.pe_section_align = GUINT32_FROM_LE (VIRT_ALIGN);
2884 header->nt.pe_file_alignment = GUINT32_FROM_LE (FILE_ALIGN);
2885 header->nt.pe_os_major = GUINT16_FROM_LE (4);
2886 header->nt.pe_os_minor = GUINT16_FROM_LE (0);
2887 header->nt.pe_subsys_major = GUINT16_FROM_LE (4);
2888 size = section_start;
2889 size += FILE_ALIGN - 1;
2890 size &= ~(FILE_ALIGN - 1);
2891 header->nt.pe_header_size = GUINT32_FROM_LE (size);
2892 size = image_size;
2893 size += VIRT_ALIGN - 1;
2894 size &= ~(VIRT_ALIGN - 1);
2895 header->nt.pe_image_size = GUINT32_FROM_LE (size);
2898 // Translate the PEFileKind value to the value expected by the Windows loader
2901 short kind;
2904 // PEFileKinds.Dll == 1
2905 // PEFileKinds.ConsoleApplication == 2
2906 // PEFileKinds.WindowApplication == 3
2908 // need to get:
2909 // IMAGE_SUBSYSTEM_WINDOWS_GUI 2 // Image runs in the Windows GUI subsystem.
2910 // IMAGE_SUBSYSTEM_WINDOWS_CUI 3 // Image runs in the Windows character subsystem.
2912 if (assemblyb->pekind == 3)
2913 kind = 2;
2914 else
2915 kind = 3;
2917 header->nt.pe_subsys_required = GUINT16_FROM_LE (kind);
2919 header->nt.pe_stack_reserve = GUINT32_FROM_LE (0x00100000);
2920 header->nt.pe_stack_commit = GUINT32_FROM_LE (0x00001000);
2921 header->nt.pe_heap_reserve = GUINT32_FROM_LE (0x00100000);
2922 header->nt.pe_heap_commit = GUINT32_FROM_LE (0x00001000);
2923 header->nt.pe_loader_flags = GUINT32_FROM_LE (0);
2924 header->nt.pe_data_dir_count = GUINT32_FROM_LE (16);
2926 /* fill data directory entries */
2928 header->datadir.pe_resource_table.size = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].size);
2929 header->datadir.pe_resource_table.rva = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].rva);
2931 header->datadir.pe_reloc_table.size = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RELOC].size);
2932 header->datadir.pe_reloc_table.rva = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RELOC].rva);
2934 header->datadir.pe_cli_header.size = GUINT32_FROM_LE (72);
2935 header->datadir.pe_cli_header.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->cli_header_offset);
2936 header->datadir.pe_iat.size = GUINT32_FROM_LE (8);
2937 header->datadir.pe_iat.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->iat_offset);
2938 /* patch entrypoint name */
2939 if (assemblyb->pekind == 1)
2940 memcpy (assembly->code.data + assembly->imp_names_offset + 2, "_CorDllMain", 12);
2941 else
2942 memcpy (assembly->code.data + assembly->imp_names_offset + 2, "_CorExeMain", 12);
2943 /* patch imported function RVA name */
2944 rva = (guint32*)(assembly->code.data + assembly->iat_offset);
2945 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->imp_names_offset);
2947 /* the import table */
2948 header->datadir.pe_import_table.size = GUINT32_FROM_LE (79); /* FIXME: magic number? */
2949 header->datadir.pe_import_table.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->idt_offset);
2950 /* patch imported dll RVA name and other entries in the dir */
2951 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, name_rva));
2952 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->imp_names_offset + 14); /* 14 is hint+strlen+1 of func name */
2953 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, import_address_table_rva));
2954 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->iat_offset);
2955 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, import_lookup_table));
2956 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->ilt_offset);
2958 p = (guchar*)(assembly->code.data + assembly->ilt_offset);
2959 value = (assembly->text_rva + assembly->imp_names_offset);
2960 *p++ = (value) & 0xff;
2961 *p++ = (value >> 8) & (0xff);
2962 *p++ = (value >> 16) & (0xff);
2963 *p++ = (value >> 24) & (0xff);
2965 /* the CLI header info */
2966 cli_header = (MonoCLIHeader*)(assembly->code.data + assembly->cli_header_offset);
2967 cli_header->ch_size = GUINT32_FROM_LE (72);
2968 cli_header->ch_runtime_major = GUINT16_FROM_LE (2);
2969 cli_header->ch_runtime_minor = GUINT16_FROM_LE (5);
2970 cli_header->ch_flags = GUINT32_FROM_LE (assemblyb->pe_kind);
2971 if (assemblyb->entry_point) {
2972 guint32 table_idx = 0;
2973 if (!strcmp (assemblyb->entry_point->object.vtable->klass->name, "MethodBuilder")) {
2974 MonoReflectionMethodBuilder *methodb = (MonoReflectionMethodBuilder*)assemblyb->entry_point;
2975 table_idx = methodb->table_idx;
2976 } else {
2977 table_idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, assemblyb->entry_point->method));
2979 cli_header->ch_entry_point = GUINT32_FROM_LE (table_idx | MONO_TOKEN_METHOD_DEF);
2980 } else {
2981 cli_header->ch_entry_point = GUINT32_FROM_LE (0);
2983 /* The embedded managed resources */
2984 text_offset = assembly->text_rva + assembly->code.index;
2985 cli_header->ch_resources.rva = GUINT32_FROM_LE (text_offset);
2986 cli_header->ch_resources.size = GUINT32_FROM_LE (assembly->resources.index);
2987 text_offset += assembly->resources.index;
2988 cli_header->ch_metadata.rva = GUINT32_FROM_LE (text_offset);
2989 cli_header->ch_metadata.size = GUINT32_FROM_LE (assembly->meta_size);
2990 text_offset += assembly->meta_size;
2991 if (assembly->strong_name_size) {
2992 cli_header->ch_strong_name.rva = GUINT32_FROM_LE (text_offset);
2993 cli_header->ch_strong_name.size = GUINT32_FROM_LE (assembly->strong_name_size);
2994 text_offset += assembly->strong_name_size;
2997 /* write the section tables and section content */
2998 section = (MonoSectionTable*)(pefile->data + section_start);
2999 for (i = 0; i < MONO_SECTION_MAX; ++i) {
3000 static const char section_names [][7] = {
3001 ".text", ".rsrc", ".reloc"
3003 if (!assembly->sections [i].size)
3004 continue;
3005 strcpy (section->st_name, section_names [i]);
3006 /*g_print ("output section %s (%d), size: %d\n", section->st_name, i, assembly->sections [i].size);*/
3007 section->st_virtual_address = GUINT32_FROM_LE (assembly->sections [i].rva);
3008 section->st_virtual_size = GUINT32_FROM_LE (assembly->sections [i].size);
3009 section->st_raw_data_size = GUINT32_FROM_LE (GUINT32_TO_LE (section->st_virtual_size) + (FILE_ALIGN - 1));
3010 section->st_raw_data_size &= GUINT32_FROM_LE (~(FILE_ALIGN - 1));
3011 section->st_raw_data_ptr = GUINT32_FROM_LE (assembly->sections [i].offset);
3012 section->st_flags = GUINT32_FROM_LE (assembly->sections [i].attrs);
3013 section ++;
3016 checked_write_file (file, pefile->data, pefile->index);
3018 mono_dynamic_stream_reset (pefile);
3020 for (i = 0; i < MONO_SECTION_MAX; ++i) {
3021 if (!assembly->sections [i].size)
3022 continue;
3024 if (SetFilePointer (file, assembly->sections [i].offset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
3025 g_error ("SetFilePointer returned %d\n", GetLastError ());
3027 switch (i) {
3028 case MONO_SECTION_TEXT:
3029 /* patch entry point */
3030 p = (guchar*)(assembly->code.data + 2);
3031 value = (virtual_base + assembly->text_rva + assembly->iat_offset);
3032 *p++ = (value) & 0xff;
3033 *p++ = (value >> 8) & 0xff;
3034 *p++ = (value >> 16) & 0xff;
3035 *p++ = (value >> 24) & 0xff;
3037 checked_write_file (file, assembly->code.data, assembly->code.index);
3038 checked_write_file (file, assembly->resources.data, assembly->resources.index);
3039 checked_write_file (file, assembly->image.raw_metadata, assembly->meta_size);
3040 checked_write_file (file, assembly->strong_name, assembly->strong_name_size);
3043 g_free (assembly->image.raw_metadata);
3044 break;
3045 case MONO_SECTION_RELOC: {
3046 struct {
3047 guint32 page_rva;
3048 guint32 block_size;
3049 guint16 type_and_offset;
3050 guint16 term;
3051 } reloc;
3053 g_assert (sizeof (reloc) == 12);
3055 reloc.page_rva = GUINT32_FROM_LE (assembly->text_rva);
3056 reloc.block_size = GUINT32_FROM_LE (12);
3059 * the entrypoint is always at the start of the text section
3060 * 3 is IMAGE_REL_BASED_HIGHLOW
3061 * 2 is patch_size_rva - text_rva
3063 reloc.type_and_offset = GUINT16_FROM_LE ((3 << 12) + (2));
3064 reloc.term = 0;
3066 checked_write_file (file, &reloc, sizeof (reloc));
3068 break;
3070 case MONO_SECTION_RSRC:
3071 if (assembly->win32_res) {
3073 /* Fixup the offsets in the IMAGE_RESOURCE_DATA_ENTRY structures */
3074 fixup_resource_directory (assembly->win32_res, assembly->win32_res, assembly->sections [i].rva);
3075 checked_write_file (file, assembly->win32_res, assembly->win32_res_size);
3077 break;
3078 default:
3079 g_assert_not_reached ();
3083 /* check that the file is properly padded */
3084 if (SetFilePointer (file, file_offset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
3085 g_error ("SetFilePointer returned %d\n", GetLastError ());
3086 if (! SetEndOfFile (file))
3087 g_error ("SetEndOfFile returned %d\n", GetLastError ());
3089 mono_dynamic_stream_reset (&assembly->code);
3090 mono_dynamic_stream_reset (&assembly->us);
3091 mono_dynamic_stream_reset (&assembly->blob);
3092 mono_dynamic_stream_reset (&assembly->guid);
3093 mono_dynamic_stream_reset (&assembly->sheap);
3095 g_hash_table_foreach (assembly->blob_cache, (GHFunc)g_free, NULL);
3096 g_hash_table_destroy (assembly->blob_cache);
3097 assembly->blob_cache = NULL;
3099 return TRUE;
3102 #else /* DISABLE_REFLECTION_EMIT_SAVE */
3104 gboolean
3105 mono_image_create_pefile (MonoReflectionModuleBuilder *mb, HANDLE file, MonoError *error)
3107 g_assert_not_reached ();
3110 #endif /* DISABLE_REFLECTION_EMIT_SAVE */