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