2 * Create trampolines to invoke arbitrary functions.
4 * Copyright (C) Ximian Inc.
6 * Author: Paolo Molaro (lupus@ximian.com)
12 #include "x86-codegen.h"
13 #include "mono/metadata/class.h"
14 #include "mono/metadata/tabledefs.h"
15 #include "mono/interpreter/interp.h"
16 #include "mono/metadata/appdomain.h"
19 * The resulting function takes the form:
20 * void func (void (*callme)(), void *retval, void *this_obj, stackval *arguments);
22 #define FUNC_ADDR_POS 8
28 #define ARG_SIZE sizeof (stackval)
31 mono_string_new_wrapper (const char *text)
33 MonoDomain *domain = mono_domain_get ();
35 return mono_string_new (domain, text);
39 mono_create_trampoline (MonoMethod *method, int runtime)
41 MonoMethodSignature *sig;
42 unsigned char *p, *code_buffer;
43 guint32 local_size = 0, stack_size = 0, code_size = 30;
44 guint32 arg_pos, simpletype;
47 sig = method->signature;
50 stack_size += sizeof (gpointer);
54 for (i = 0; i < sig->param_count; ++i) {
55 if (sig->params [i]->byref) {
56 stack_size += sizeof (gpointer);
57 code_size += i < 10 ? 5 : 8;
60 simpletype = sig->params [i]->type;
63 case MONO_TYPE_BOOLEAN:
75 case MONO_TYPE_SZARRAY:
77 case MONO_TYPE_OBJECT:
79 code_size += i < 10 ? 5 : 8;
81 case MONO_TYPE_VALUETYPE:
82 if (sig->params [i]->data.klass->enumtype) {
83 simpletype = sig->params [i]->data.klass->enum_basetype->type;
86 if (mono_class_value_size (sig->params [i]->data.klass, NULL) != 4)
87 g_error ("can only marshal enums, not generic structures (size: %d)", mono_class_value_size (sig->params [i]->data.klass, NULL));
89 code_size += i < 10 ? 5 : 8;
91 case MONO_TYPE_STRING:
98 code_size += i < 10 ? 5 : 8;
102 code_size += i < 10 ? 7 : 10;
105 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
109 * FIXME: take into account large return values.
112 code_buffer = p = alloca (code_size);
115 * Standard function prolog.
117 x86_push_reg (p, X86_EBP);
118 x86_mov_reg_reg (p, X86_EBP, X86_ESP, 4);
120 * We store some local vars here to handle string pointers.
121 * and align to 16 byte boundary...
124 x86_alu_reg_imm (p, X86_SUB, X86_ESP, local_size * 4);
125 stack_size = (stack_size * local_size * 4) % 16;
127 stack_size = stack_size % 16;
130 x86_alu_reg_imm (p, X86_SUB, X86_ESP, stack_size);
133 * EDX has the pointer to the args.
135 x86_mov_reg_membase (p, X86_EDX, X86_EBP, ARGP_POS, 4);
138 * Push arguments in reverse order.
141 for (i = sig->param_count; i; --i) {
142 arg_pos = ARG_SIZE * (i - 1);
143 if (sig->params [i - 1]->byref) {
144 x86_push_membase (p, X86_EDX, arg_pos);
147 simpletype = sig->params [i - 1]->type;
149 switch (simpletype) {
150 case MONO_TYPE_BOOLEAN:
161 case MONO_TYPE_SZARRAY:
162 case MONO_TYPE_CLASS:
163 case MONO_TYPE_OBJECT:
165 x86_push_membase (p, X86_EDX, arg_pos);
167 case MONO_TYPE_VALUETYPE:
168 if (!sig->params [i - 1]->data.klass->enumtype) {
169 /* it's a structure that fits in 4 bytes, need to push the value pointed to */
170 x86_mov_reg_membase (p, X86_EAX, X86_EDX, arg_pos, 4);
171 x86_push_regp (p, X86_EAX);
173 /* it's an enum value */
174 simpletype = sig->params [i - 1]->data.klass->enum_basetype->type;
179 x86_alu_reg_imm (p, X86_SUB, X86_ESP, 8);
180 x86_fld_membase (p, X86_EDX, arg_pos, TRUE);
181 x86_fst_membase (p, X86_ESP, 0, TRUE, TRUE);
183 case MONO_TYPE_STRING:
185 * If it is an internalcall we assume it's the object we want.
186 * Yet another reason why MONO_TYPE_STRING should not be used to indicate char*.
188 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || runtime) {
189 x86_push_membase (p, X86_EDX, arg_pos);
192 /*if (frame->method->flags & PINVOKE_ATTRIBUTE_CHAR_SET_ANSI*/
193 x86_push_membase (p, X86_EDX, arg_pos);
194 x86_mov_reg_imm (p, X86_EDX, mono_string_to_utf8);
195 x86_call_reg (p, X86_EDX);
196 x86_alu_reg_imm (p, X86_ADD, X86_ESP, 4);
197 x86_push_reg (p, X86_EAX);
199 * Store the pointer in a local we'll free later.
202 x86_mov_membase_reg (p, X86_EBP, LOC_POS * stringp, X86_EAX, 4);
204 * we didn't save the reg: restore it here.
207 x86_mov_reg_membase (p, X86_EDX, X86_EBP, ARGP_POS, 4);
210 x86_push_membase (p, X86_EDX, arg_pos + 4);
211 x86_push_membase (p, X86_EDX, arg_pos);
214 g_error ("Can't trampoline 0x%x", sig->params [i - 1]->type);
219 if (sig->call_convention != MONO_CALL_THISCALL) {
220 x86_mov_reg_membase (p, X86_EDX, X86_EBP, THIS_POS, 4);
221 x86_push_reg (p, X86_EDX);
223 x86_mov_reg_membase (p, X86_ECX, X86_EBP, THIS_POS, 4);
228 * Insert call to function
230 x86_mov_reg_membase (p, X86_EDX, X86_EBP, FUNC_ADDR_POS, 4);
231 x86_call_reg (p, X86_EDX);
235 * Small integer and pointer values are in EAX.
236 * Long integers are in EAX:EDX.
237 * FP values are on the FP stack.
239 if (sig->ret->byref) {
240 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
241 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
243 simpletype = sig->ret->type;
245 switch (simpletype) {
246 case MONO_TYPE_BOOLEAN:
249 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
250 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 1);
255 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
256 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 2);
262 case MONO_TYPE_CLASS:
263 case MONO_TYPE_OBJECT:
264 case MONO_TYPE_SZARRAY:
265 case MONO_TYPE_ARRAY:
266 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
267 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
269 case MONO_TYPE_STRING:
270 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || runtime) {
271 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
272 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
276 /* If the argument is non-null, then convert the value back */
277 x86_alu_reg_reg (p, X86_OR, X86_EAX, X86_EAX);
278 x86_branch8 (p, X86_CC_EQ, 11, FALSE);
279 x86_push_reg (p, X86_EAX);
280 x86_mov_reg_imm (p, X86_EDX, mono_string_new_wrapper);
281 x86_call_reg (p, X86_EDX);
282 x86_alu_reg_imm (p, X86_ADD, X86_ESP, 4);
284 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
285 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
288 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
289 x86_fst_membase (p, X86_ECX, 0, FALSE, TRUE);
292 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
293 x86_fst_membase (p, X86_ECX, 0, TRUE, TRUE);
296 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
297 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
298 x86_mov_membase_reg (p, X86_ECX, 4, X86_EDX, 4);
300 case MONO_TYPE_VALUETYPE:
301 if (sig->ret->data.klass->enumtype) {
302 simpletype = sig->ret->data.klass->enum_basetype->type;
308 g_error ("Can't handle as return value 0x%x", sig->ret->type);
313 * free the allocated strings.
315 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)) {
316 for (i = 1; i <= local_size; ++i) {
317 x86_mov_reg_imm (p, X86_EDX, g_free);
318 x86_push_membase (p, X86_EBP, LOC_POS * i);
319 x86_call_reg (p, X86_EDX);
328 return g_memdup (code_buffer, p - code_buffer);
331 #define MINV_POS (- sizeof (MonoInvocation))
332 #define STACK_POS (MINV_POS - sizeof (stackval) * sig->param_count)
334 #define TYPE_OFFSET (G_STRUCT_OFFSET (stackval, type))
337 * Returns a pointer to a native function that can be used to
338 * call the specified method.
339 * The function created will receive the arguments according
340 * to the call convention specified in the method.
341 * This function works by creating a MonoInvocation structure,
342 * filling the fields in and calling ves_exec_method on it.
343 * Still need to figure out how to handle the exception stuff
344 * across the managed/unmanaged boundary.
347 mono_create_method_pointer (MonoMethod *method)
349 MonoMethodSignature *sig;
350 unsigned char *p, *code_buffer;
352 gint32 stackval_pos, arg_pos = 8;
356 * If it is a static P/Invoke method, we can just return the pointer
357 * to the method implementation.
359 sig = method->signature;
361 code_buffer = p = alloca (512); /* FIXME: check for overflows... */
363 local_size = sizeof (MonoInvocation) + sizeof (stackval) * (sig->param_count + 1);
364 stackval_pos = -local_size;
367 * Standard function prolog with magic trick.
369 x86_jump_code (p, code_buffer + 8);
374 x86_push_reg (p, X86_EBP);
375 x86_mov_reg_reg (p, X86_EBP, X86_ESP, 4);
376 x86_alu_reg_imm (p, X86_SUB, X86_ESP, local_size);
379 * Initialize MonoInvocation fields, first the ones known now.
381 x86_mov_reg_imm (p, X86_EAX, 0);
382 x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex)), X86_EAX, 4);
383 x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex_handler)), X86_EAX, 4);
384 x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, child)), X86_EAX, 4);
385 x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, parent)), X86_EAX, 4);
387 * Set the method pointer.
389 x86_mov_membase_imm (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, method)), (int)method, 4);
395 if (sig->call_convention != MONO_CALL_THISCALL) {
397 * Grab it from the stack, otherwise it's already in ECX.
399 x86_mov_reg_membase (p, X86_ECX, X86_EBP, OBJ_POS, 4);
402 x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, obj)), X86_ECX, 4);
405 * Handle the arguments. stackval_pos is the posset of the stackval array from EBP.
406 * arg_pos is the offset from EBP to the incoming arg on the stack.
407 * We just call stackval_from_data to handle all the (nasty) issues....
409 x86_lea_membase (p, X86_EAX, X86_EBP, stackval_pos);
410 x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, stack_args)), X86_EAX, 4);
411 for (i = 0; i < sig->param_count; ++i) {
412 x86_mov_reg_imm (p, X86_ECX, stackval_from_data);
413 x86_lea_membase (p, X86_EDX, X86_EBP, arg_pos);
414 x86_lea_membase (p, X86_EAX, X86_EBP, stackval_pos);
415 x86_push_reg (p, X86_EDX);
416 x86_push_reg (p, X86_EAX);
417 x86_push_imm (p, sig->params [i]);
418 x86_call_reg (p, X86_ECX);
419 x86_alu_reg_imm (p, X86_SUB, X86_ESP, 12);
420 stackval_pos += sizeof (stackval);
422 if (!sig->params [i]->byref) {
423 switch (sig->params [i]->type) {
428 case MONO_TYPE_VALUETYPE:
429 g_assert_not_reached (); /* Not implemented yet. */
437 * Handle the return value storage area.
439 x86_lea_membase (p, X86_EAX, X86_EBP, stackval_pos);
440 x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, retval)), X86_EAX, 4);
445 x86_lea_membase (p, X86_EAX, X86_EBP, MINV_POS);
446 x86_push_reg (p, X86_EAX);
447 x86_mov_reg_imm (p, X86_EDX, ves_exec_method);
448 x86_call_reg (p, X86_EDX);
451 * Move the return value to the proper place.
453 x86_lea_membase (p, X86_EAX, X86_EBP, stackval_pos);
454 if (sig->ret->byref) {
455 x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 4);
457 switch (sig->ret->type) {
460 case MONO_TYPE_BOOLEAN:
461 x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 1);
467 case MONO_TYPE_OBJECT:
468 case MONO_TYPE_STRING:
469 case MONO_TYPE_CLASS:
470 x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 4);
473 x86_mov_reg_membase (p, X86_EDX, X86_EAX, 4, 4);
474 x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 4);
477 x86_fld_membase (p, X86_EAX, 0, TRUE);
480 g_error ("Type 0x%x not handled yet in thunk creation", sig->ret->type);
491 g_assert (p - code_buffer < 512);
492 return g_memdup (code_buffer, p - code_buffer);
496 * mono_create_method_pointer () will insert a pointer to the MonoMethod
497 * so that the interp can easily get at the data: this function will retrieve
498 * the method from the code stream.
501 mono_method_pointer_get (void *code)
503 unsigned char *c = code;
504 if (c [2] != 'M' || c [3] != 'o')
506 return *(MonoMethod**)(c + sizeof (gpointer));