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"
18 * The resulting function takes the form:
19 * void func (void (*callme)(), void *retval, void *this_obj, stackval *arguments);
21 #define FUNC_ADDR_POS 8
27 #define ARG_SIZE sizeof (stackval)
30 mono_create_trampoline (MonoMethod *method)
32 MonoMethodSignature *sig;
33 unsigned char *p, *code_buffer;
34 guint32 local_size = 0, stack_size = 0, code_size = 30;
35 guint32 arg_pos, simpletype;
38 sig = method->signature;
41 stack_size += sizeof (gpointer);
45 for (i = 0; i < sig->param_count; ++i) {
46 if (sig->params [i]->byref) {
47 stack_size += sizeof (gpointer);
48 code_size += i < 10 ? 5 : 8;
51 simpletype = sig->params [i]->type;
54 case MONO_TYPE_BOOLEAN:
66 case MONO_TYPE_SZARRAY:
68 case MONO_TYPE_OBJECT:
70 code_size += i < 10 ? 5 : 8;
72 case MONO_TYPE_VALUETYPE:
73 if (sig->params [i]->data.klass->enumtype) {
74 simpletype = sig->params [i]->data.klass->enum_basetype->type;
77 if (mono_class_value_size (sig->params [i]->data.klass, NULL) != 4)
78 g_error ("can only marshal enums, not generic structures (size: %d)", mono_class_value_size (sig->params [i]->data.klass, NULL));
80 code_size += i < 10 ? 5 : 8;
82 case MONO_TYPE_STRING:
89 code_size += i < 10 ? 5 : 8;
93 code_size += i < 10 ? 7 : 10;
96 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
100 * FIXME: take into account large return values.
103 code_buffer = p = alloca (code_size);
106 * Standard function prolog.
108 x86_push_reg (p, X86_EBP);
109 x86_mov_reg_reg (p, X86_EBP, X86_ESP, 4);
111 * We store some local vars here to handle string pointers.
112 * and align to 16 byte boundary...
115 x86_alu_reg_imm (p, X86_SUB, X86_ESP, local_size * 4);
116 stack_size = (stack_size * local_size * 4) % 16;
118 stack_size = stack_size % 16;
121 x86_alu_reg_imm (p, X86_SUB, X86_ESP, stack_size);
124 * EDX has the pointer to the args.
126 x86_mov_reg_membase (p, X86_EDX, X86_EBP, ARGP_POS, 4);
129 * Push arguments in reverse order.
132 for (i = sig->param_count; i; --i) {
133 arg_pos = ARG_SIZE * (i - 1);
134 if (sig->params [i - 1]->byref) {
135 x86_push_membase (p, X86_EDX, arg_pos);
138 simpletype = sig->params [i - 1]->type;
140 switch (simpletype) {
141 case MONO_TYPE_BOOLEAN:
152 case MONO_TYPE_SZARRAY:
153 case MONO_TYPE_CLASS:
154 case MONO_TYPE_OBJECT:
156 x86_push_membase (p, X86_EDX, arg_pos);
158 case MONO_TYPE_VALUETYPE:
159 if (!sig->params [i - 1]->data.klass->enumtype) {
160 /* it's a structure that fits in 4 bytes, need to push the value pointed to */
161 x86_mov_reg_membase (p, X86_EAX, X86_EDX, arg_pos, 4);
162 x86_push_regp (p, X86_EAX);
164 /* it's an enum value */
165 simpletype = sig->params [i - 1]->data.klass->enum_basetype->type;
170 x86_alu_reg_imm (p, X86_SUB, X86_ESP, 8);
171 x86_fld_membase (p, X86_EDX, arg_pos, TRUE);
172 x86_fst_membase (p, X86_ESP, 0, TRUE, TRUE);
174 case MONO_TYPE_STRING:
176 * If it is an internalcall we assume it's the object we want.
177 * Yet another reason why MONO_TYPE_STRING should not be used to indicate char*.
179 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
180 x86_push_membase (p, X86_EDX, arg_pos);
183 /*if (frame->method->flags & PINVOKE_ATTRIBUTE_CHAR_SET_ANSI*/
184 x86_push_membase (p, X86_EDX, arg_pos);
185 x86_mov_reg_imm (p, X86_EDX, mono_string_to_utf8);
186 x86_call_reg (p, X86_EDX);
187 x86_alu_reg_imm (p, X86_ADD, X86_ESP, 4);
188 x86_push_reg (p, X86_EAX);
190 * Store the pointer in a local we'll free later.
193 x86_mov_membase_reg (p, X86_EBP, LOC_POS * stringp, X86_EAX, 4);
195 * we didn't save the reg: restore it here.
198 x86_mov_reg_membase (p, X86_EDX, X86_EBP, ARGP_POS, 4);
201 x86_push_membase (p, X86_EDX, arg_pos + 4);
202 x86_push_membase (p, X86_EDX, arg_pos);
205 g_error ("Can't trampoline 0x%x", sig->params [i - 1]->type);
210 if (sig->call_convention != MONO_CALL_THISCALL) {
211 x86_mov_reg_membase (p, X86_EDX, X86_EBP, THIS_POS, 4);
212 x86_push_reg (p, X86_EDX);
214 x86_mov_reg_membase (p, X86_ECX, X86_EBP, THIS_POS, 4);
219 * Insert call to function
221 x86_mov_reg_membase (p, X86_EDX, X86_EBP, FUNC_ADDR_POS, 4);
222 x86_call_reg (p, X86_EDX);
226 * Small integer and pointer values are in EAX.
227 * Long integers are in EAX:EDX.
228 * FP values are on the FP stack.
230 if (sig->ret->byref) {
231 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
232 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
234 simpletype = sig->ret->type;
236 switch (simpletype) {
237 case MONO_TYPE_BOOLEAN:
240 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
241 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 1);
247 case MONO_TYPE_CLASS:
248 case MONO_TYPE_OBJECT:
249 case MONO_TYPE_STRING: /* this is going to cause large pains... */
250 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
251 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
254 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
255 x86_fst_membase (p, X86_ECX, 0, FALSE, TRUE);
258 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
259 x86_fst_membase (p, X86_ECX, 0, TRUE, TRUE);
262 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
263 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
264 x86_mov_membase_reg (p, X86_ECX, 4, X86_EDX, 4);
266 case MONO_TYPE_VALUETYPE:
267 if (sig->ret->data.klass->enumtype) {
268 simpletype = sig->ret->data.klass->enum_basetype->type;
274 g_error ("Can't handle as return value 0x%x", sig->ret->type);
279 * free the allocated strings.
281 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)) {
283 x86_mov_reg_imm (p, X86_EDX, g_free);
284 for (i = 1; i <= local_size; ++i) {
285 x86_push_membase (p, X86_EBP, LOC_POS * i);
286 x86_call_reg (p, X86_EDX);
295 return g_memdup (code_buffer, p - code_buffer);
298 #define MINV_POS (- sizeof (MonoInvocation))
299 #define STACK_POS (MINV_POS - sizeof (stackval) * sig->param_count)
301 #define TYPE_OFFSET (G_STRUCT_OFFSET (stackval, type))
304 * Returns a pointer to a native function that can be used to
305 * call the specified method.
306 * The function created will receive the arguments according
307 * to the call convention specified in the method.
308 * This function works by creating a MonoInvocation structure,
309 * filling the fields in and calling ves_exec_method on it.
310 * Still need to figure out how to handle the exception stuff
311 * across the managed/unmanaged boundary.
314 mono_create_method_pointer (MonoMethod *method)
316 MonoMethodSignature *sig;
317 unsigned char *p, *code_buffer;
319 gint32 stackval_pos, arg_pos = 8;
323 * If it is a static P/Invoke method, we can just return the pointer
324 * to the method implementation.
326 sig = method->signature;
328 code_buffer = p = alloca (512); /* FIXME: check for overflows... */
330 local_size = sizeof (MonoInvocation) + sizeof (stackval) * (sig->param_count + 1);
331 stackval_pos = -local_size;
334 * Standard function prolog with magic trick.
336 x86_jump_code (p, code_buffer + 8);
341 x86_push_reg (p, X86_EBP);
342 x86_mov_reg_reg (p, X86_EBP, X86_ESP, 4);
343 x86_alu_reg_imm (p, X86_SUB, X86_ESP, local_size);
346 * Initialize MonoInvocation fields, first the ones known now.
348 x86_mov_reg_imm (p, X86_EAX, 0);
349 x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex)), X86_EAX, 4);
350 x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex_handler)), X86_EAX, 4);
351 x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, child)), X86_EAX, 4);
352 x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, parent)), X86_EAX, 4);
354 * Set the method pointer.
356 x86_mov_membase_imm (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, method)), (int)method, 4);
362 if (sig->call_convention != MONO_CALL_THISCALL) {
364 * Grab it from the stack, otherwise it's already in ECX.
366 x86_mov_reg_membase (p, X86_ECX, X86_EBP, OBJ_POS, 4);
369 x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, obj)), X86_ECX, 4);
372 * Handle the arguments. stackval_pos is the posset of the stackval array from EBP.
373 * arg_pos is the offset from EBP to the incoming arg on the stack.
374 * We just call stackval_from_data to handle all the (nasty) issues....
376 for (i = 0; i < sig->param_count; ++i) {
377 x86_mov_reg_imm (p, X86_ECX, stackval_from_data);
378 x86_lea_membase (p, X86_EDX, X86_EBP, arg_pos);
379 x86_lea_membase (p, X86_EAX, X86_EBP, stackval_pos);
380 x86_push_reg (p, X86_EDX);
381 x86_push_reg (p, X86_EAX);
382 x86_push_imm (p, sig->params [i]);
383 x86_call_reg (p, X86_ECX);
384 x86_alu_reg_imm (p, X86_SUB, X86_ESP, 12);
385 stackval_pos += sizeof (stackval);
387 if (!sig->params [i]->byref) {
388 switch (sig->params [i]->type) {
393 case MONO_TYPE_VALUETYPE:
394 g_assert_not_reached (); /* Not implemented yet. */
402 * Handle the return value storage area.
404 x86_lea_membase (p, X86_EAX, X86_EBP, stackval_pos);
405 x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, retval)), X86_EAX, 4);
410 x86_lea_membase (p, X86_EAX, X86_EBP, MINV_POS);
411 x86_push_reg (p, X86_EAX);
412 x86_mov_reg_imm (p, X86_EDX, ves_exec_method);
413 x86_call_reg (p, X86_EDX);
416 * Move the return value to the proper place.
418 x86_lea_membase (p, X86_EAX, X86_EBP, stackval_pos);
419 if (sig->ret->byref) {
420 x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 4);
422 switch (sig->ret->type) {
425 case MONO_TYPE_BOOLEAN:
426 x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 1);
432 case MONO_TYPE_OBJECT:
433 case MONO_TYPE_STRING:
434 case MONO_TYPE_CLASS:
435 x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 4);
438 x86_mov_reg_membase (p, X86_EDX, X86_EAX, 4, 4);
439 x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 4);
442 x86_fld_membase (p, X86_EAX, 0, TRUE);
445 g_error ("Type 0x%x not handled yet in thunk creation", sig->ret->type);
456 return g_memdup (code_buffer, p - code_buffer);