2 * Create trampolines to invoke arbitrary functions.
4 * Copyright (C) Ximian Inc.
6 * Author: Paolo Molaro (lupus@ximian.com)
11 #include "x86-codegen.h"
12 #include "mono/metadata/class.h"
13 #include "mono/interpreter/interp.h"
16 * The resulting function takes the form:
17 * void func (void (*callme)(), void *retval, void *this_obj, stackval *arguments);
19 #define FUNC_ADDR_POS 8
25 #define ARG_SIZE sizeof (stackval)
28 mono_get_ansi_string (MonoObject *o)
30 MonoStringObject *s = (MonoStringObject *)o;
39 vector = s->c_str->vector;
41 g_assert (vector != NULL);
43 as = g_malloc (s->length + 1);
45 /* fixme: replace with a real unicode/ansi conversion */
46 for (i = 0; i < s->length; i++) {
47 as [i] = vector [i*2];
56 mono_create_trampoline (MonoMethod *method)
58 MonoMethodSignature *sig;
59 unsigned char *p, *code_buffer;
60 guint32 local_size = 0, stack_size = 0, code_size = 30;
64 sig = method->signature;
67 stack_size += sizeof (gpointer);
71 for (i = 0; i < sig->param_count; ++i) {
72 if (sig->params [i]->byref) {
73 stack_size += sizeof (gpointer);
74 code_size += i < 10 ? 5 : 8;
77 switch (sig->params [i]->type) {
78 case MONO_TYPE_BOOLEAN:
90 case MONO_TYPE_SZARRAY:
92 case MONO_TYPE_OBJECT:
94 code_size += i < 10 ? 5 : 8;
96 case MONO_TYPE_STRING:
103 code_size += i < 10 ? 5 : 8;
107 code_size += i < 10 ? 7 : 10;
110 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
114 * FIXME: take into account large return values.
117 code_buffer = p = alloca (code_size);
120 * Standard function prolog.
122 x86_push_reg (p, X86_EBP);
123 x86_mov_reg_reg (p, X86_EBP, X86_ESP, 4);
125 * We store some local vars here to handle string pointers.
126 * and align to 16 byte boundary...
129 x86_alu_reg_imm (p, X86_SUB, X86_ESP, local_size * 4);
130 stack_size = (stack_size * local_size * 4) % 16;
132 stack_size = stack_size % 16;
134 x86_alu_reg_imm (p, X86_SUB, X86_ESP, stack_size);
137 * EDX has the pointer to the args.
139 x86_mov_reg_membase (p, X86_EDX, X86_EBP, ARGP_POS, 4);
142 * Push arguments in reverse order.
145 for (i = sig->param_count; i; --i) {
146 arg_pos = ARG_SIZE * (i - 1);
147 if (sig->params [i - 1]->byref) {
148 x86_push_membase (p, X86_EDX, arg_pos);
151 switch (sig->params [i - 1]->type) {
161 case MONO_TYPE_SZARRAY:
162 case MONO_TYPE_CLASS:
163 case MONO_TYPE_OBJECT:
165 x86_push_membase (p, X86_EDX, arg_pos);
168 x86_alu_reg_imm (p, X86_SUB, X86_ESP, 8);
169 x86_fld_membase (p, X86_EDX, arg_pos, TRUE);
170 x86_fst_membase (p, X86_ESP, 0, TRUE, TRUE);
172 case MONO_TYPE_STRING:
173 /*if (frame->method->flags & PINVOKE_ATTRIBUTE_CHAR_SET_ANSI*/
174 x86_push_membase (p, X86_EDX, arg_pos);
175 x86_mov_reg_imm (p, X86_EDX, mono_get_ansi_string);
176 x86_call_reg (p, X86_EDX);
177 x86_alu_reg_imm (p, X86_SUB, X86_ESP, 4);
178 x86_push_reg (p, X86_EAX);
180 * Store the pointer in a local we'll free later.
183 x86_mov_membase_reg (p, X86_EBP, LOC_POS * stringp, X86_EAX, 4);
185 * we didn't save the reg: restore it here.
187 x86_mov_reg_membase (p, X86_EDX, X86_EBP, ARGP_POS, 4);
190 x86_push_membase (p, X86_EDX, arg_pos + 4);
191 x86_push_membase (p, X86_EDX, arg_pos);
193 case MONO_TYPE_BOOLEAN:
196 g_error ("Can't trampoline 0x%x", sig->params [i - 1]->type);
201 if (sig->call_convention != MONO_CALL_THISCALL) {
202 x86_mov_reg_membase (p, X86_EDX, X86_EBP, THIS_POS, 4);
203 x86_push_reg (p, X86_EDX);
205 x86_mov_reg_membase (p, X86_ECX, X86_EBP, THIS_POS, 4);
210 * Insert call to function
212 x86_mov_reg_membase (p, X86_EDX, X86_EBP, FUNC_ADDR_POS, 4);
213 x86_call_reg (p, X86_EDX);
217 * Small integer and pointer values are in EAX.
218 * Long integers are in EAX:EDX.
219 * FP values are on the FP stack.
221 if (sig->ret->byref) {
222 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
223 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
225 switch (sig->ret->type) {
230 case MONO_TYPE_OBJECT:
231 case MONO_TYPE_STRING: /* this is going to cause large pains... */
232 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
233 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
236 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
237 x86_fst_membase (p, X86_ECX, 0, FALSE, TRUE);
240 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
241 x86_fst_membase (p, X86_ECX, 0, TRUE, TRUE);
244 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
245 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
246 x86_mov_membase_reg (p, X86_ECX, 4, X86_EDX, 4);
251 g_error ("Can't handle as return value 0x%x", sig->ret->type);
256 * free the allocated strings.
259 x86_mov_reg_imm (p, X86_EDX, g_free);
260 for (i = 1; i <= local_size; ++i) {
261 x86_push_membase (p, X86_EBP, LOC_POS * i);
262 x86_call_reg (p, X86_EDX);
270 return g_memdup (code_buffer, p - code_buffer);
273 #define MINV_POS (- sizeof (MonoInvocation))
274 #define STACK_POS (MINV_POS - sizeof (stackval) * sig->param_count)
276 #define TYPE_OFFSET (G_STRUCT_OFFSET (stackval, type))
279 * Returns a pointer to a native function that can be used to
280 * call the specified method.
281 * The function created will receive the arguments according
282 * to the call convention specified in the method.
283 * This function works by creating a MonoInvocation structure,
284 * filling the fields in and calling ves_exec_method on it.
285 * Still need to figure out how to handle the exception stuff
286 * across the managed/unmanaged boundary.
289 mono_create_method_pointer (MonoMethod *method)
291 MonoMethodSignature *sig;
292 unsigned char *p, *code_buffer;
294 gint32 stackval_pos, arg_pos = 8;
298 * If it is a static P/Invoke method, we can just return the pointer
299 * to the method implementation.
301 sig = method->signature;
303 code_buffer = p = alloca (512); /* FIXME: check for overflows... */
305 local_size = sizeof (MonoInvocation) + sizeof (stackval) * (sig->param_count + 1);
306 stackval_pos = -local_size;
309 * Standard function prolog with magic trick.
311 x86_jump_code (p, code_buffer + 8);
316 x86_push_reg (p, X86_EBP);
317 x86_mov_reg_reg (p, X86_EBP, X86_ESP, 4);
318 x86_alu_reg_imm (p, X86_SUB, X86_ESP, local_size);
321 * Initialize MonoInvocation fields, first the ones known now.
323 x86_mov_reg_imm (p, X86_EAX, 0);
324 x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex)), X86_EAX, 4);
325 x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex_handler)), X86_EAX, 4);
326 x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, child)), X86_EAX, 4);
327 x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, parent)), X86_EAX, 4);
329 * Set the method pointer.
331 x86_mov_membase_imm (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, method)), (int)method, 4);
337 if (sig->call_convention != MONO_CALL_THISCALL) {
339 * Grab it from the stack, otherwise it's already in ECX.
341 x86_mov_reg_membase (p, X86_ECX, X86_EBP, OBJ_POS, 4);
344 x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, obj)), X86_ECX, 4);
347 * Handle the arguments. stackval_pos is the posset of the stackval array from EBP.
348 * arg_pos is the offset from EBP to the incoming arg on the stack.
349 * We just call stackval_from_data to handle all the (nasty) issues....
351 for (i = 0; i < sig->param_count; ++i) {
352 x86_mov_reg_imm (p, X86_ECX, stackval_from_data);
353 x86_lea_membase (p, X86_EDX, X86_EBP, arg_pos);
354 x86_lea_membase (p, X86_EAX, X86_EBP, stackval_pos);
355 x86_push_reg (p, X86_EDX);
356 x86_push_reg (p, X86_EAX);
357 x86_push_imm (p, sig->params [i]);
358 x86_call_reg (p, X86_ECX);
359 x86_alu_reg_imm (p, X86_SUB, X86_ESP, 12);
360 stackval_pos += sizeof (stackval);
362 if (!sig->params [i]->byref) {
363 switch (sig->params [i]->type) {
368 case MONO_TYPE_VALUETYPE:
369 g_assert_not_reached (); /* Not implemented yet. */
377 * Handle the return value storage area.
379 x86_lea_membase (p, X86_EAX, X86_EBP, stackval_pos);
380 x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, retval)), X86_EAX, 4);
385 x86_lea_membase (p, X86_EAX, X86_EBP, MINV_POS);
386 x86_push_reg (p, X86_EAX);
387 x86_mov_reg_imm (p, X86_EDX, ves_exec_method);
388 x86_call_reg (p, X86_EDX);
391 * Move the return value to the proper place.
393 x86_lea_membase (p, X86_EAX, X86_EBP, stackval_pos);
394 if (sig->ret->byref) {
395 x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 4);
397 switch (sig->ret->type) {
404 case MONO_TYPE_OBJECT:
405 case MONO_TYPE_STRING:
406 x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 4);
409 x86_mov_reg_membase (p, X86_EDX, X86_EAX, 4, 4);
410 x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 4);
413 x86_fld_membase (p, X86_EAX, 0, TRUE);
416 g_error ("Type 0x%x not handled yet in thunk creation", sig->ret->type);
427 return g_memdup (code_buffer, p - code_buffer);