2 * Create trampolines to invoke arbitrary functions.
4 * Copyright (C) Radek Doulik
10 #include "ppc-codegen.h"
11 #include "mono/metadata/class.h"
12 #include "mono/metadata/tabledefs.h"
13 #include "mono/interpreter/interp.h"
17 #include <limits.h> /* for PAGESIZE */
24 fake_func (gdouble (*callme)(), stackval *retval, void *this_obj, stackval *arguments)
26 guint32 i = 0xc002becd;
28 callme = (gpointer) 0x100fabcd;
30 *(gpointer*)retval = (gpointer)(*callme) (arguments [0].data.p, arguments [1].data.p, arguments [2].data.p);
31 *(gdouble*) retval = (gdouble)(*callme) (arguments [0].data.f);
34 #define MIN_CACHE_LINE 8
37 flush_icache (guint8 *code, guint size)
43 for (i = 0; i < size; i += MIN_CACHE_LINE, p += MIN_CACHE_LINE) {
44 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
48 for (i = 0; i < size; i += MIN_CACHE_LINE, p += MIN_CACHE_LINE) {
49 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
55 #define NOT_IMPLEMENTED(x) \
56 g_error ("FIXME: %s is not yet implemented. (trampoline)", x);
61 #define MINIMAL_STACK_SIZE 4
63 #define GENERAL_REGS 8
66 add_general (guint *gr, guint *stack_size, guint *code_size, gboolean simple)
69 if (*gr >= GENERAL_REGS) {
71 *code_size += 8; /* load from stack, save on stack */
73 *code_size += 4; /* load from stack */
76 if (*gr >= GENERAL_REGS - 1) {
77 *stack_size += 8 + (*stack_size % 8);
78 *code_size += 16; /* 2x load from stack, save to stack */
80 *code_size += 16; /* 2x load from stack */
88 calculate_sizes (MonoMethod *method, guint *stack_size, guint *code_size, guint *strings, gint runtime)
90 MonoMethodSignature *sig;
95 *stack_size = MINIMAL_STACK_SIZE*4;
96 *code_size = (PROLOG_INS + CALL_INS + EPILOG_INS)*4;
99 sig = method->signature;
101 add_general (&gr, stack_size, code_size, TRUE);
104 for (i = 0; i < sig->param_count; ++i) {
105 if (sig->params [i]->byref) {
106 add_general (&gr, stack_size, code_size, TRUE);
109 simpletype = sig->params [i]->type;
111 switch (simpletype) {
112 case MONO_TYPE_BOOLEAN:
123 case MONO_TYPE_SZARRAY:
124 case MONO_TYPE_CLASS:
125 case MONO_TYPE_OBJECT:
126 add_general (&gr, stack_size, code_size, TRUE);
128 case MONO_TYPE_VALUETYPE:
129 if (sig->params [i]->data.klass->enumtype) {
130 simpletype = sig->params [i]->data.klass->enum_basetype->type;
133 if (mono_class_value_size (sig->params [i]->data.klass, NULL) != 4)
134 g_error ("can only marshal enums, not generic structures (size: %d)",
135 mono_class_value_size (sig->params [i]->data.klass, NULL));
136 add_general (&gr, stack_size, code_size, TRUE);
139 case MONO_TYPE_STRING:
140 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || runtime) {
141 add_general (&gr, stack_size, code_size, TRUE);
149 add_general (&gr, stack_size, code_size, FALSE);
157 NOT_IMPLEMENTED ("R8 arg");
161 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
165 if (sig->ret->byref) {
168 simpletype = sig->ret->type;
170 switch (simpletype) {
171 case MONO_TYPE_BOOLEAN:
178 case MONO_TYPE_CLASS:
179 case MONO_TYPE_OBJECT:
182 case MONO_TYPE_SZARRAY:
183 case MONO_TYPE_ARRAY:
184 case MONO_TYPE_STRING:
190 case MONO_TYPE_VALUETYPE:
191 if (sig->ret->data.klass->enumtype) {
192 simpletype = sig->ret->data.klass->enum_basetype->type;
195 NOT_IMPLEMENTED ("valuetype");
200 g_error ("Can't handle as return value 0x%x", sig->ret->type);
205 /* space to keep parameters and prepared strings */
213 /* align stack size to 16 */
214 printf (" stack size: %d (%d)\n code size: %d\n", (*stack_size + 15) & ~15, *stack_size, *code_size);
215 *stack_size = (*stack_size + 15) & ~15;
219 static inline guint8 *
220 emit_prolog (guint8 *p, MonoMethod *method, guint stack_size, guint strings)
222 /* function prolog */
223 ppc_stwu (p, ppc_r1, -stack_size, ppc_r1); /* sp <--- sp - stack_size, sp[0] <---- sp save sp, alloc stack */
224 ppc_mflr (p, ppc_r0); /* r0 <--- LR */
225 ppc_stw (p, ppc_r31, stack_size - 4, ppc_r1); /* sp[+4] <--- r31 save r31 */
226 ppc_stw (p, ppc_r0, stack_size + 4, ppc_r1); /* sp[-4] <--- LR save return address for "callme" */
227 ppc_mr (p, ppc_r31, ppc_r1); /* r31 <--- sp */
229 /* handle our parameters */
231 ppc_stw (p, ppc_r30, 16, ppc_r1);
232 ppc_stw (p, ppc_r29, 20, ppc_r1);
233 if (method->signature->hasthis) {
234 ppc_stw (p, ppc_r28, 24, ppc_r1);
236 ppc_mr (p, ppc_r30, ppc_r6); /* args */
237 ppc_mr (p, ppc_r29, ppc_r3); /* callme */
238 if (method->signature->hasthis) {
239 ppc_mr (p, ppc_r28, ppc_r5); /* this */
242 ppc_mr (p, ppc_r12, ppc_r6); /* keep "arguments" in register */
243 ppc_mr (p, ppc_r0, ppc_r3); /* keep "callme" in register */
245 ppc_stw (p, ppc_r4, 8, ppc_r31); /* preserve "retval", sp[+8] */
250 #define ARG_BASE strings ? ppc_r30 : ppc_r12
251 #define SAVE_4_IN_GENERIC_REGISTER \
252 if (gr < GENERAL_REGS) { \
253 ppc_lwz (p, ppc_r3 + gr, i*16, ARG_BASE); \
256 NOT_IMPLEMENTED("save on stack"); \
259 inline static guint8*
260 emit_save_parameters (guint8 *p, MonoMethod *method, guint strings, gint runtime)
262 MonoMethodSignature *sig;
263 guint i, fr, gr, act_strs;
268 sig = method->signature;
271 for (i = 0; i < sig->param_count; ++i) {
272 if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_STRING) {
273 ppc_lis (p, ppc_r0, (guint32) mono_string_to_utf8 >> 16);
274 ppc_lwz (p, ppc_r3, i*16, ppc_r30);
275 ppc_ori (p, ppc_r0, ppc_r0, (guint32) mono_string_to_utf8 & 0xffff);
276 ppc_mtlr (p, ppc_r0);
278 ppc_stw (p, ppc_r3, 24 + act_strs, ppc_r31);
285 ppc_mr (p, ppc_r3, ppc_r5);
290 for (i = 0; i < sig->param_count; ++i) {
291 if (sig->params [i]->byref) {
292 SAVE_4_IN_GENERIC_REGISTER;
295 simpletype = sig->params [i]->type;
297 switch (simpletype) {
298 case MONO_TYPE_BOOLEAN:
309 case MONO_TYPE_SZARRAY:
310 case MONO_TYPE_CLASS:
311 case MONO_TYPE_OBJECT:
312 SAVE_4_IN_GENERIC_REGISTER;
314 case MONO_TYPE_VALUETYPE:
315 if (sig->params [i]->data.klass->enumtype) {
316 simpletype = sig->params [i]->data.klass->enum_basetype->type;
319 if (mono_class_value_size (sig->params [i]->data.klass, NULL) != 4)
320 g_error ("can only marshal enums, not generic structures (size: %d)",
321 mono_class_value_size (sig->params [i]->data.klass, NULL));
322 if (gr < GENERAL_REGS) {
323 ppc_lwz (p, ppc_r3 + gr, i*16, ARG_BASE);
324 ppc_lwz (p, ppc_r3 + gr, 0, ppc_r3 + gr);
327 NOT_IMPLEMENTED ("save value type on stack");
330 case MONO_TYPE_STRING:
331 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || runtime) {
332 SAVE_4_IN_GENERIC_REGISTER;
335 ppc_lwz (p, ppc_r3 + gr, 24 + act_strs * 4, ppc_r31);
339 NOT_IMPLEMENTED ("string on stack");
344 g_warning ("check endianess");
345 ppc_lwz (p, ppc_r3 + gr, i*16, ARG_BASE);
347 ppc_lwz (p, ppc_r3 + gr, i*17, ARG_BASE);
350 NOT_IMPLEMENTED ("i8 on stack");
355 ppc_lfs (p, ppc_f1 + fr, i*16, ARG_BASE);
358 NOT_IMPLEMENTED ("r4 on stack");
363 ppc_lfd (p, ppc_f1 + fr, i*16, ARG_BASE);
366 NOT_IMPLEMENTED ("r8 on stack");
370 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
377 static inline guint8 *
378 alloc_code_memory (guint code_size)
383 p = g_malloc (code_size + PAGESIZE - 1);
385 /* Align to a multiple of PAGESIZE, assumed to be a power of two */
386 p = (char *)(((int) p + PAGESIZE-1) & ~(PAGESIZE-1));
388 p = g_malloc (code_size);
390 printf (" align: %p (%d)\n", p, (guint)p % 4);
395 static inline guint8 *
396 emit_call_and_store_retval (guint8 *p, MonoMethod *method, guint strings)
398 MonoMethodSignature *sig = method->signature;
402 ppc_mtlr (p, strings ? ppc_r29 : ppc_r0);
405 /* get return value */
406 if (sig->ret->byref) {
407 ppc_lwz (p, ppc_r9, 8, ppc_r31); /* load "retval" address */
408 ppc_stw (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */
410 simpletype = sig->ret->type;
412 switch (simpletype) {
413 case MONO_TYPE_BOOLEAN:
416 ppc_lwz (p, ppc_r9, 8, ppc_r31); /* load "retval" address */
417 ppc_stb (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */
423 case MONO_TYPE_CLASS:
424 case MONO_TYPE_OBJECT:
425 case MONO_TYPE_SZARRAY:
426 case MONO_TYPE_ARRAY:
427 case MONO_TYPE_STRING:
428 ppc_lwz (p, ppc_r9, 8, ppc_r31); /* load "retval" address */
429 ppc_stw (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */
432 ppc_lwz (p, ppc_r9, 8, ppc_r31); /* load "retval" address */
433 ppc_stfs (p, ppc_f1, 0, ppc_r9); /* save return value (f1) to "retval" */
436 ppc_lwz (p, ppc_r9, 8, ppc_r31); /* load "retval" address */
437 ppc_stfd (p, ppc_f1, 0, ppc_r9); /* save return value (f1) to "retval" */
440 g_warning ("check endianess");
441 ppc_lwz (p, ppc_r9, 8, ppc_r31); /* load "retval" address */
442 ppc_stw (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */
443 ppc_stw (p, ppc_r4, 4, ppc_r9); /* save return value (r3) to "retval" */
445 case MONO_TYPE_VALUETYPE:
446 if (sig->ret->data.klass->enumtype) {
447 simpletype = sig->ret->data.klass->enum_basetype->type;
450 NOT_IMPLEMENTED ("retval valuetype");
455 g_error ("Can't handle as return value 0x%x", sig->ret->type);
462 static inline guint8 *
463 emit_epilog (guint8 *p, MonoMethod *method, guint strings)
466 MonoMethodSignature *sig = method->signature;
469 /* free allocated memory */
471 for (i = 0; i < sig->param_count; ++i) {
472 if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_STRING) {
473 ppc_lis (p, ppc_r0, (guint32) g_free >> 16);
474 ppc_lwz (p, ppc_r3, 24 + act_strs, ppc_r31);
475 ppc_ori (p, ppc_r0, ppc_r0, (guint32) g_free & 0xffff);
476 ppc_mtlr (p, ppc_r0);
482 /* restore volatile registers */
483 ppc_lwz (p, ppc_r30, 16, ppc_r1);
484 ppc_lwz (p, ppc_r29, 20, ppc_r1);
485 if (method->signature->hasthis) {
486 ppc_lwz (p, ppc_r28, 24, ppc_r1);
490 /* function epilog */
491 ppc_lwz (p, ppc_r11, 0, ppc_r1); /* r11 <--- sp[0] load backchain from caller's function */
492 ppc_lwz (p, ppc_r0, 4, ppc_r11); /* r0 <--- r11[4] load return address */
493 ppc_mtlr (p, ppc_r0); /* LR <--- r0 set return address */
494 ppc_lwz (p, ppc_r31, -4, ppc_r11); /* r31 <--- r11[-4] restore r31 */
495 ppc_mr (p, ppc_r1, ppc_r11); /* sp <--- r11 restore stack */
496 ppc_blr (p); /* return */
502 mono_create_trampoline (MonoMethod *method, int runtime)
504 guint8 *p, *code_buffer;
505 guint stack_size, code_size, strings;
507 printf ("\nPInvoke [start emiting] %s\n", method->name);
508 calculate_sizes (method, &stack_size, &code_size, &strings, runtime);
510 p = code_buffer = alloc_code_memory (code_size);
511 p = emit_prolog (p, method, stack_size, strings);
512 p = emit_save_parameters (p, method, strings, runtime);
513 p = emit_call_and_store_retval (p, method, strings);
514 p = emit_epilog (p, method, strings);
518 printf (".text\n.align 4\n.globl main\n.type main,@function\nmain:\n");
519 for (cp = code_buffer; cp < p; cp++) {
520 printf (".byte 0x%x\n", *cp);
525 if (mprotect (code_buffer, 1024, PROT_READ | PROT_WRITE | PROT_EXEC)) {
526 g_error ("Cannot mprotect trampoline\n");
530 printf ("emited code size: %d\n", p - code_buffer);
531 flush_icache (code_buffer, p - code_buffer);
533 printf ("PInvoke [end emiting]\n");
535 return (MonoPIFunc) code_buffer;
536 /* return fake_func; */
540 #define MINV_POS (- sizeof (MonoInvocation))
541 #define STACK_POS (MINV_POS - sizeof (stackval) * sig->param_count)
543 #define TYPE_OFFSET (G_STRUCT_OFFSET (stackval, type))
546 * Returns a pointer to a native function that can be used to
547 * call the specified method.
548 * The function created will receive the arguments according
549 * to the call convention specified in the method.
550 * This function works by creating a MonoInvocation structure,
551 * filling the fields in and calling ves_exec_method on it.
552 * Still need to figure out how to handle the exception stuff
553 * across the managed/unmanaged boundary.
556 mono_create_method_pointer (MonoMethod *method)