/* pancake // nopcode.org 2010-2011 -- arm emiter */ #include #define attsyntax 0 #define EMIT_NAME emit_arm #define R_ARCH "arm" #define R_SZ 8 #define R_SP "sp" #define R_BP "fp" #define R_AX "r7" #define R_GP { "r0", "r1", "r2", "r3", "r4" } #define R_TMP "r9" #define R_NGP 5 // no attsyntax for arm static char *regs[] = R_GP; static int lastarg = 0; static char lastargs[16][32]; static void emit_init (REgg *egg) { /* TODO */ } static char *emit_syscall (REgg *egg, int num) { int svc = 0; switch (egg->os) { case R_EGG_OS_DARWIN: case R_EGG_OS_OSX: case R_EGG_OS_IOS: case R_EGG_OS_MACOS: svc = 0x80; break; case R_EGG_OS_WATCHOS: svc = 0x8000; break; case R_EGG_OS_LINUX: svc = 0; break; } return r_str_newf (": mov "R_AX", `.arg`\n: svc 0x%x\n", svc); } static void emit_frame (REgg *egg, int sz) { r_egg_printf (egg, " push {fp,lr}\n"); if (sz>0) r_egg_printf (egg, //" mov "R_BP", "R_SP"\n" " add fp, sp, $4\n" // size of arguments " sub sp, %d\n", sz); // size of stackframe 8, 16, .. } static void emit_frame_end (REgg *egg, int sz, int ctx) { if (sz>0) r_egg_printf (egg, " add sp, fp, %d\n", sz); if (ctx>0) r_egg_printf (egg, " pop {fp,pc}\n"); } static void emit_comment(REgg *egg, const char *fmt, ...) { va_list ap; char buf[1024]; va_start (ap, fmt); vsnprintf (buf, sizeof (buf), fmt, ap); r_egg_printf (egg, "# %s\n", buf); va_end (ap); } static void emit_equ (REgg *egg, const char *key, const char *value) { r_egg_printf (egg, ".equ %s, %s\n", key, value); } static void emit_syscall_args(REgg *egg, int nargs) { int j, k; for (j = 0; j < nargs; j++) { k = j * R_SZ; r_egg_printf (egg, " ldr %s, [sp, %d]\n", regs[j+1], k?k+4:k+8); } } static void emit_set_string(REgg *egg, const char *dstvar, const char *str, int j) { int rest, off = 0; off = strlen (str)+1; rest = (off%4); if (rest) rest = 4 - rest; off += rest - 4; r_egg_printf (egg, " add pc, %d\n", (off)); // XXX: does not handle \n and so on.. must use r_util r_egg_printf (egg, ".string \"%s\"\n", str); if (rest) r_egg_printf (egg, ".fill %d, 1, 0\n", (rest)); r_egg_printf (egg, " sub r0, pc, %d\n", off+12); { char str[32], *p = r_egg_mkvar (egg, str, dstvar, 0); //r_egg_printf (egg, "DSTVAR=%s --> %s\n", dstvar, p); r_egg_printf (egg, " str r0, [%s]\n", p); free (p); } } static void emit_jmp(REgg *egg, const char *str, int atr) { if (atr) { r_egg_printf (egg, " ldr r0, %s", str); r_egg_printf (egg, " bx r0\n"); } else r_egg_printf (egg, " b %s\n", str); } static void emit_call(REgg *egg, const char *str, int atr) { int i; //r_egg_printf (egg, " ARGS=%d CALL(%s,%d)\n", lastarg, str, atr); for (i=0;i=, ... */ p = r_egg_mkvar (egg, str, arg, 0); r_egg_printf (egg, " pop "R_AX"\n"); /* TODO: add support for more than one arg get arg0 */ r_egg_printf (egg, " cmp %s, "R_AX"\n", p); // if (context>0) r_egg_printf (egg, " %s %s\n", op, dst); free (p); } static void emit_load(REgg *egg, const char *dst, int sz) { switch (sz) { case 'l': r_egg_printf (egg, " mov "R_AX", %s\n", dst); r_egg_printf (egg, " mov "R_AX", ["R_AX"]\n"); break; case 'b': r_egg_printf (egg, " mov "R_AX", %s\n", dst); r_egg_printf (egg, " movz "R_AX", ["R_AX"]\n"); break; default: // TODO: unhandled?!? r_egg_printf (egg, " mov "R_AX", %s\n", dst); r_egg_printf (egg, " mov "R_AX", ["R_AX"]\n"); } } static void emit_mathop(REgg *egg, int ch, int vs, int type, const char *eq, const char *p) { char *op; switch (ch) { case '^': op = "eor"; break; case '&': op = "and"; break; case '|': op = "orr"; break; case '-': op = "sub"; break; case '+': op = "add"; break; case '*': op = "mul"; break; case '/': op = "div"; break; default: op = "mov"; break; } if (eq == NULL) eq = R_AX; if (p == NULL) p = R_AX; #if 0 // TODO: eprintf ("TYPE = %c\n", type); eprintf (" %s%c %c%s, %s\n", op, vs, type, eq, p); eprintf (" %s %s, [%s]\n", op, p, eq); #endif if (type == '*') r_egg_printf (egg, " %s %s, [%s]\n", op, p, eq); else r_egg_printf (egg, " %s %s, %s\n", op, p, eq); } static const char* emit_regs(REgg *egg, int idx) { return regs[idx%R_NGP]; } REggEmit EMIT_NAME = { .arch = R_ARCH, .size = R_SZ, .jmp = emit_jmp, .call = emit_call, .init = emit_init, .equ = emit_equ, .regs = emit_regs, //.sc = emit_sc, .trap = emit_trap, .frame = emit_frame, .frame_end = emit_frame_end, .comment = emit_comment, .push_arg = emit_arg, .restore_stack = emit_restore_stack, .get_result = emit_get_result, .syscall_args = emit_syscall_args, .set_string = emit_set_string, .get_var = emit_get_var, .while_end = emit_while_end, .get_while_end = emit_get_while_end, .branch = emit_branch, .load = emit_load, .load_ptr = emit_load_ptr, .mathop = emit_mathop, .syscall = emit_syscall, };