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