static void emit_branch(REgg *egg, char *b, char *g, char *e, char *n, int sz, const char *dst) { char *p, str[64]; char *arg = NULL; char *op = "beq"; /* NOTE that jb/ja are inverted to fit cmp opcode */ if (b) { *b = '\0'; op = e?"bge":"bgt"; arg = b+1; } else if (g) { *g = '\0'; op = e?"ble":"blt"; arg = g+1; } if (arg == NULL) { if (e) { arg = e+1; op = "bne"; } else { arg = "0"; op = n?"bne":"beq"; } } if (*arg=='=') arg++; /* for <=, >=, ... */ 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); }
static void emit_mathop(REgg *egg, int ch, int vs, int type, const char *eq, const char *p) { char *op; switch(ch) { case '^': op = "xor"; break; case '&': op = "and"; break; case '|': op = "or"; break; case '-': op = "sub"; break; case '+': op = "add"; break; case '*': op = "mul"; break; case '/': op = "div"; break; default: op = "mov"; break; } if (attsyntax) { if (eq == NULL) eq = "%"R_AX; if (p == NULL) p = "%"R_AX; r_egg_printf (egg, " %s%c %c%s, %s\n", op, vs, type, eq, p); } else { if (eq == NULL) eq = R_AX; if (p == NULL) p = R_AX; // TODO: #if 0 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 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 int parsedatachar(REgg *egg, char c) { static int inlinectr = 0; char *str; int i, j; if (!dstval) { return 0; } /* skip until '{' */ if (c == '{') { /* XXX: repeated code!! */ rcc_context (egg, 1); if (++inlinectr==1) return (ndstval = 0); } else if (inlinectr == 0) { /* capture value between parenthesis foo@data(NNN) { ... } */ if (c==')') { stackframe = atoi (dstval); ndstval = 0; } else { dstval[ndstval++] = c; } return 0; } /* capture body */ if (c == '}') { /* XXX: repeated code!! */ if (CTX< 2) { inlinectr = 0; rcc_context (egg, -1); slurp = 0; mode = NORMAL; /* register */ if (dstval != NULL && dstvar != NULL) { dstval[ndstval]='\0'; egg->remit->comment (egg, "data (%s)(%s)size=(%d)\n", dstvar, dstval, stackframe); r_egg_printf (egg, ".data\n"); for (str=dstval; is_space (*str); str++); j = (stackframe)? stackframe: 1; /* emit label */ r_egg_printf (egg, "%s:\n", dstvar); for (i=1; i<=j; i++) { if (*str=='"') r_egg_printf (egg, ".ascii %s%s\n", dstval, (i==j)?"\"\\x00\"":""); else r_egg_printf (egg, ".long %s\n", dstval); } r_egg_printf (egg, ".text\n"); R_FREE (dstvar); R_FREE (dstval); ndstval = 0; CTX = 0; return 1; } } } dstval[ndstval++] = c; return 0; }
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); if (attsyntax) r_egg_printf (egg, " /* %s */\n", buf); else r_egg_printf (egg, "# %s\n", buf); va_end (ap); }
static void emit_arg (REgg *egg, int xs, int num, const char *str) { int d = atoi (str); if (!attsyntax && (*str=='$')) str = str +1; switch (xs) { case 0: r_egg_printf (egg, " push %s\n", str); break; case '*': if (attsyntax) r_egg_printf (egg, " push (%s)\n", str); else r_egg_printf (egg, " push [%s]\n", str); break; case '&': if (attsyntax) { if (d != 0) r_egg_printf (egg, " addl $%d, %%"R_BP"\n", d); r_egg_printf (egg, " pushl %%"R_BP"\n"); if (d != 0) r_egg_printf (egg, " subl $%d, %%"R_BP"\n", d); } else { if (d != 0) r_egg_printf (egg, " add "R_BP", %d\n", d); r_egg_printf (egg, " push "R_BP"\n"); if (d != 0) r_egg_printf (egg, " sub "R_BP", %d\n", d); } break; } }
static void emit_branch(REgg *egg, char *b, char *g, char *e, char *n, int sz, const char *dst) { char *p, str[64]; char *arg = NULL; char *op = "jz"; int signed_value = 1; // XXX: add support for signed/unsigned variables /* NOTE that jb/ja are inverted to fit cmp opcode */ if (b) { *b = '\0'; if (signed_value) { if (e) op = "jge"; else op = "jg"; } else { if (e) op = "jae"; else op = "ja"; } arg = b+1; } else if (g) { *g = '\0'; if (signed_value) { if (e) op = "jle"; else op = "jl"; } else { if (e) op = "jbe"; else op = "jb"; } arg = g+1; } if (arg == NULL) { if (e) { arg = e+1; op = "jne"; } else { arg = attsyntax? "$0": "0"; if (n) op = "jnz"; else op ="jz"; } } if (*arg=='=') arg++; /* for <=, >=, ... */ p = r_egg_mkvar (egg, str, arg, 0); if (attsyntax) { r_egg_printf (egg, " pop %%"R_AX"\n"); /* TODO: add support for more than one arg get arg0 */ r_egg_printf (egg, " cmp%c %s, %%"R_AX"\n", sz, p); } else { r_egg_printf (egg, " pop "R_AX"\n"); /* TODO: add support for more than one arg get arg0 */ r_egg_printf (egg, " cmp "R_AX", %s\n", p); } // if (context>0) free (p); r_egg_printf (egg, " %s %s\n", op, dst); }
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<lastarg;i++) { r_egg_printf (egg, " ldr r%d, [%s]\n", lastarg-1-i, lastargs[i]); lastargs[i][0] = 0; } if (atr) { r_egg_printf (egg, " ldr r0, %s", str); r_egg_printf (egg, " blx r0\n"); } else r_egg_printf (egg, " bl %s\n", str); }
static void emit_frame_end (REgg *egg, int sz, int ctx) { if (sz>0) { if (attsyntax) { r_egg_printf (egg, " add $%d, %%"R_SP"\n", sz); r_egg_printf (egg, " pop %%"R_BP"\n"); } else { r_egg_printf (egg, " add "R_SP", %d\n", sz); r_egg_printf (egg, " pop "R_BP"\n"); } } if (ctx>0) r_egg_printf (egg, " ret\n"); }
static void emit_frame (REgg *egg, int sz) { if (sz<1) return; if (attsyntax) r_egg_printf (egg, " push %%"R_BP"\n" " mov %%"R_SP", %%"R_BP"\n" " sub $%d, %%"R_SP"\n", sz); else r_egg_printf (egg, " push "R_BP"\n" " mov "R_BP", "R_SP"\n" " sub "R_SP", %d\n", sz); }
static void emit_load_ptr(REgg *egg, const char *dst) { int d = atoi (dst); if (d == 0) { // hack to handle stackvarptrz char *p = strchr (dst, '+'); if (p) d = atoi (p+1); } //eprintf ("emit_load_ptr: HACK\n"); // XXX: 32/64bit care //r_egg_printf (egg, "# DELTA IS (%s)\n", dst); if (attsyntax) r_egg_printf (egg, " leal %d(%%"R_BP"), %%"R_AX"\n", d); else r_egg_printf (egg, " lea "R_AX", ["R_BP"+%d]\n", d); //r_egg_printf (egg, " movl %%"R_BP", %%"R_AX"\n"); //r_egg_printf (egg, " addl $%d, %%"R_AX"\n", d); }
static void emit_syscall_args(REgg *egg, int nargs) { int j, k; for (j=0; j<nargs; j++) { k = j*R_SZ; if (attsyntax) r_egg_printf (egg, " mov %d(%%"R_SP"), %%%s\n", k, regs[j+1]); else { if (k>0) r_egg_printf (egg, " mov %s, ["R_SP"+%d]\n", regs[j+1], k); else if (k<0) r_egg_printf (egg, " mov %s, ["R_SP"%d]\n", regs[j+1], k); else r_egg_printf (egg, " mov %s, ["R_SP"]\n", regs[j+1]); } } }
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, #%c%d]\n", regs[j+1], k>0?'+':' ', k); } }
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-8; 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+16); { 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_arg (REgg *egg, int xs, int num, const char *str) { int d = atoi (str); if (!attsyntax && (*str=='$')) str++; lastarg = num; switch (xs) { case 0: if (strchr (str, ',')) { //r_egg_printf (egg, ". str r0, [%s]\n", str); strncpy (lastargs[num-1], str, sizeof(lastargs[0])-1); } else { if (!atoi (str)) eprintf ("WARNING: probably a bug?\n"); r_egg_printf (egg, " mov r0, $%s\n", str); snprintf (lastargs[num-1], sizeof (lastargs[0]), "fp, $-%d", 8+(num*4)); r_egg_printf (egg, " str r0, [%s]\n", lastargs[num-1]); } break; case '*': r_egg_printf (egg, " push {%s}\n", str); break; case '&': if (d) r_egg_printf (egg, " add "R_BP", %d\n", d); r_egg_printf (egg, " push {"R_BP"}\n"); if (d) r_egg_printf (egg, " sub "R_BP", %d\n", d); break; } }
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_while_end (REgg *egg, const char *labelback) { #if 0 if (attsyntax) { r_egg_printf (egg, " pop %%"R_AX"\n"); r_egg_printf (egg, " cmp $0, %%"R_AX"\n"); // XXX MUST SUPPORT != 0 COMPARE HERE r_egg_printf (egg, " jnz %s\n", labelback); } else { #endif r_egg_printf (egg, " pop "R_AX"\n"); r_egg_printf (egg, " test "R_AX", "R_AX"\n"); // XXX MUST SUPPORT != 0 COMPARE HERE r_egg_printf (egg, " jnz %s\n", labelback); // } } // XXX: this is wrong static void emit_get_var (REgg *egg, int type, char *out, int idx) { switch (type) { case 0: /* variable */ if (idx>0) sprintf (out, "["R_BP"+%d]", idx); else if (idx<0) sprintf (out, "["R_BP"%d]", idx); else strcpy (out, "["R_BP"]"); break; case 1: /* argument */ // OMG WE CANT stuff found in relative address in stack in the stack eprintf ("WARNING: Using stack vars in naked functions\n"); idx = 8; // HACK to make arg0, arg4, ... work if (idx>0) sprintf (out, "["R_SP"+%d]", idx); else if (idx<0) sprintf (out, "["R_SP"%d]", idx); else strcpy (out, "["R_SP"]"); break; case 2: if (idx>0) sprintf (out, "["R_BP"+%d]", idx); else if (idx<0) sprintf (out, "["R_BP"%d]", idx); else strcpy (out, "["R_BP"]"); break; } } static void emit_trap (REgg *egg) { r_egg_printf (egg, " int3\n"); }
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_restore_stack (REgg *egg, int size) { if (attsyntax) r_egg_printf (egg, " add $%d, %%"R_SP" /* args */\n", size); else r_egg_printf (egg, " add "R_SP", %d\n", size); }
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_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_init (REgg *egg) { // TODO: add 'andb rsp, 0xf0' if (attsyntax) r_egg_printf (egg, "mov %esp, %ebp\n"); else r_egg_printf (egg, "mov ebp, esp\n"); }
static void emit_load(REgg *egg, const char *dst, int sz) { if (attsyntax) { switch (sz) { case 'l': r_egg_printf (egg, " movl %s, %%"R_AX"\n", dst); r_egg_printf (egg, " movl (%%"R_AX"), %%"R_AX"\n"); case 'b': r_egg_printf (egg, " movl %s, %%"R_AX"\n", dst); r_egg_printf (egg, " movzb (%%"R_AX"), %%"R_AX"\n"); break; default: // TODO: unhandled?!? r_egg_printf (egg, " mov%c %s, %%"R_AX"\n", sz, dst); r_egg_printf (egg, " mov%c (%%"R_AX"), %%"R_AX"\n", sz); } } else { switch (sz) { case 'l': r_egg_printf (egg, " mov "R_AX", %s\n", dst); r_egg_printf (egg, " mov "R_AX", ["R_AX"]\n"); 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_load_ptr(REgg *egg, const char *dst) { r_egg_printf (egg, " ldr r0, [fp, %d]\n", atoi (dst)); }
static void emit_trap (REgg *egg) { r_egg_printf (egg, " svc 3\n"); }
static void rcc_fun(REgg *egg, const char *str) { char *ptr, *ptr2; REggEmit *e = egg->remit; str = skipspaces (str); if (CTX) { ptr = strchr (str, '='); if (ptr) { *ptr++ = '\0'; free (dstvar); dstvar = strdup (skipspaces (str)); ptr2 = (char *)skipspaces (ptr); if (*ptr2) rcc_set_callname (skipspaces (ptr)); } else { str = skipspaces (str); rcc_set_callname (skipspaces (str)); egg->remit->comment (egg, "rcc_fun %d (%s)", CTX, callname); } } else { ptr = strchr (str, '@'); if (ptr) { *ptr++ = '\0'; mode = NORMAL; if (strstr (ptr, "env")) { //eprintf ("SETENV (%s)\n", str); free (setenviron); setenviron = strdup (skipspaces (str)); slurp = 0; } else if (strstr (ptr, "fastcall")) { /* TODO : not yet implemented */ } else if (strstr (ptr, "syscall")) { if (*str) { mode = SYSCALL; dstvar = strdup (skipspaces (str)); } else { mode = INLINE; free (syscallbody); syscallbody = malloc (4096); // XXX hardcoded size dstval = syscallbody; R_FREE (dstvar); ndstval = 0; *syscallbody = '\0'; } } else if (strstr (ptr, "include")) { free (includefile); includefile = strdup (skipspaces (str)); slurp = 0; } else if (strstr (ptr, "alias")) { mode = ALIAS; dstvar = strdup (skipspaces (str)); } else if (strstr (ptr, "data")) { mode = DATA; ndstval = 0; dstvar = strdup (skipspaces (str)); dstval = malloc (4096); } else if (strstr (ptr, "naked")) { mode = NAKED; free (dstvar); dstvar = strdup (skipspaces (str)); dstval = malloc (4096); ndstval = 0; r_egg_printf (egg, "%s:\n", str); } else if (strstr (ptr, "inline")) { mode = INLINE; free (dstvar); dstvar = strdup (skipspaces (str)); dstval = malloc (4096); ndstval = 0; } else { // naked label if (*ptr) r_egg_printf (egg, "\n.%s %s\n", ptr, str); r_egg_printf (egg, "%s:\n", str); } } else { //e->jmp (egg, ctxpush[context], 0); if (CTX>0) { // WTF? eprintf ("LABEL %d\n", CTX); r_egg_printf (egg, "\n%s:\n", str); } else { if (!strcmp (str, "goto")) { mode = GOTO; } else { // call() // or maybe jmp? e->call (egg, str, 0); } } } } }
static void emit_get_result(REgg *egg, const char *ocn) { r_egg_printf (egg, " mov %s, r0\n", ocn); }
R_API int r_egg_lang_parsechar(REgg *egg, char c) { REggEmit *e = egg->remit; char *ptr, str[64], *tmp_ptr = NULL; if (c=='\n') { line++; elem_n = 0; } //eprintf ("CH %c\n", c); /* comments */ if (skipline) { if (c != '\n') { oc = c; return 0; } skipline = 0; } if (mode == DATA) return parsedatachar (egg, c); if (mode == INLINE) return parseinlinechar (egg, c); /* quotes */ if (quoteline) { if (c != quoteline) { if (quotelinevar == 1) { if (c == '`') { elem[elem_n] = 0; elem_n = 0; tmp_ptr = r_egg_mkvar (egg, str, elem, 0); r_egg_printf (egg, "%s", tmp_ptr); free (tmp_ptr); quotelinevar = 0; } else elem[elem_n++] = c; } else { if (c == '`') { elem_n = 0; quotelinevar = 1; } else r_egg_printf (egg, "%c", c); } oc = c; return 0; } else { r_egg_printf (egg, "\n"); quoteline = 0; } } if (commentmode) { if (c=='/' && oc == '*') commentmode = 0; oc = c; return 0; } else if (c=='*' && oc == '/') commentmode = 1; if (slurp) { if (slurp != '"' && c == slurpin) exit (eprintf ( "%s:%d Nesting of expressions not yet supported\n", file, line)); if (c == slurp && oc != '\\') { slurp = 0; elem[elem_n] = '\0'; if (elem_n > 0) rcc_element (egg, elem); else e->frame (egg, 0); elem_n = 0; } else elem[elem_n++] = c; elem[elem_n] = '\0'; } else { switch (c) { case ';': rcc_next (egg); break; case '"': slurp = '"'; break; case '(': slurpin = '('; slurp = ')'; break; case '{': if (CTX>0) { // r_egg_printf (egg, " %s:\n", get_frame_label (0)); r_egg_printf (egg, " __begin_%d_%d_%d:\n", nfunctions, CTX, nestedi[CTX]); //%s:\n", get_frame_label (0)); } rcc_context (egg, 1); break; case '}': endframe = nested[CTX-1]; if (endframe) { // XXX: use endframe[context] r_egg_printf (egg, "%s\n", endframe); // R_FREE (endframe); } if (CTX>0) { if (nestede[CTX]) { r_egg_printf (egg, "%s:\n", nestede[CTX]); //nestede[CTX] = NULL; } else { r_egg_printf (egg, " __end_%d_%d_%d:\n", nfunctions, CTX, nestedi[CTX-1]); //get_end_frame_label (egg)); } nbrackets++; } rcc_context (egg, -1); if (CTX== 0) { nbrackets = 0; nfunctions++; } break; case ':': if (oc == '\n' || oc == '}') quoteline = '\n'; else elem[elem_n++] = c; break; case '#': if (oc == '\n') skipline = 1; break; case '/': if (oc == '/') skipline = 1; else elem[elem_n++] = c; break; default: elem[elem_n++] = c; } if (slurp) { if (elem_n) { ptr = elem; elem[elem_n] = '\0'; while (is_space (*ptr)) ptr++; rcc_fun (egg, ptr); } elem_n = 0; } } if (c!='\t' && c!=' ') oc = c; return 0; }
static void emit_while_end (REgg *egg, const char *labelback) { r_egg_printf (egg, " pop "R_AX"\n" " cmp "R_AX", "R_AX"\n" // XXX MUST SUPPORT != 0 COMPARE HERE " beq %s\n", labelback); }