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 rcc_pusharg(REgg *egg, char *str) { REggEmit *e = egg->emit; char buf[64], *p = r_egg_mkvar (egg, buf, str, 0); if (!p) return; // TODO: free (ctxpush[context]); ctxpush[context] = strdup (p); // INDEX IT WITH NARGS OR CONTEXT?!? nargs++; if (pushargs) e->push_arg (egg, varxs, nargs, p); //ctxpush[context+nbrackets] = strdup(str); // use nargs??? (in callname) }
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_string(REgg *egg, const char *dstvar, const char *str, int j) { char *p, *s, str2[64]; int i, len, oj = j; len = strlen (str); s = malloc (len+4); memcpy (s, str, len); memset (s+len, 0, 4); for (i=4; i<=oj; i+=4) { /* XXX endian and 32/64bit issues */ int *n = (int *)(s+i-4); p = r_egg_mkvar (egg, str2, dstvar, i); if (attsyntax) r_egg_printf (egg, " movl $0x%x, %s\n", *n, p); else r_egg_printf (egg, " mov %s, 0x%x\n", p, *n); j -= 4; } /* zero */ p = r_egg_mkvar (egg, str2, dstvar, i); if (attsyntax) r_egg_printf (egg, " movl $0, %s\n", p); else r_egg_printf (egg, " mov %s, 0\n", p); /* store pointer */ p = r_egg_mkvar (egg, str2, dstvar, j+4); if (attsyntax) r_egg_printf (egg, " lea %s, %%"R_AX"\n", p); else r_egg_printf (egg, " lea "R_AX", %s\n", p); p = r_egg_mkvar (egg, str2, dstvar, 0); if (attsyntax) r_egg_printf (egg, " mov %%"R_AX", %s\n", p); else r_egg_printf (egg, " mov %s, "R_AX"\n", p); #if 0 char *p, str2[64]; int i, oj = j; for (i=0; i<oj; i+=4) { /* XXX endian and 32/64bit issues */ int *n = (int *)(str+i); p = r_egg_mkvar (egg, str2, dstvar, j); if (attsyntax) r_egg_printf (egg, " movl $0x%x, %s\n", *n, p); else r_egg_printf (egg, " mov %s, 0x%x\n", p, *n); j -= 4; } p = r_egg_mkvar (egg, str2, dstvar, oj); if (attsyntax) r_egg_printf (egg, " lea %s, %%"R_AX"\n", p); else r_egg_printf (egg, " lea "R_AX", %s\n", p); p = r_egg_mkvar (egg, str2, dstvar, 0); if (attsyntax) r_egg_printf (egg, " mov %%"R_AX", %s\n", p); else r_egg_printf (egg, " mov %s, "R_AX"\n", p); #endif free (s); }
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); } }
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; }
/* TODO: split this function into several ones..quite long fun */ static void rcc_next(REgg *egg) { const char *ocn; REggEmit *e = egg->remit; char *str = NULL, *p, *ptr, buf[64]; int i; if (setenviron) { elem[elem_n - 1] = 0; r_sys_setenv (setenviron, elem); R_FREE (setenviron); return; } if (includefile) { char *p, *q, *path; // TODO: add support for directories elem[elem_n-1] = 0; path = find_include (elem, includefile); if (!path) { eprintf ("Cannot find include file '%s'\n", elem); return; } free (includefile); includefile = NULL; rcc_reset_callname (); p = q = r_file_slurp (path, NULL); if (p) { int oline = ++line; elem[0] = 0; // TODO: this must be a separate function elem_n = 0; line = 0; for (; *p; p++) r_egg_lang_parsechar (egg, *p); free (q); line = oline; } else { eprintf ("Cannot find '%s'\n", path); } free (path); return; } docall = 1; if (callname) { if (!strcmp (callname, "goto")) { if (nargs != 1) { eprintf ("Invalid number of arguments for goto()\n"); return; } e->jmp (egg, ctxpush[CTX], 0); rcc_reset_callname (); return; } if (!strcmp (callname, "break")) { e->trap (egg); rcc_reset_callname (); return; } ptr = strchr (callname, '='); if (ptr) { *ptr = '\0'; //ocn = ptr+1; // what is the point of this? } ocn = skipspaces (callname); if (!ocn) return; str = r_egg_mkvar (egg, buf, ocn, 0); if (!str) { eprintf ("Cannot mkvar\n"); return; } if (*ocn=='.') e->call (egg, str, 1); if (!strcmp (str, "while")) { char var[128]; if (lastctxdelta >= 0) exit (eprintf ("ERROR: Unsupported while syntax\n")); sprintf (var, "__begin_%d_%d_%d\n", nfunctions, CTX, nestedi[CTX-1]); e->while_end (egg, var); //get_frame_label (1)); #if 0 eprintf ("------------------------------------------ lastctx: %d\n", lastctxdelta); // TODO: the pushvar is required for the if(){}while(); constructions //char *pushvar = ctxpush[context+nbrackets-1]; /* TODO: support to compare more than one expression (LOGICAL OR) */ rcc_printf (" pop %%eax\n"); rcc_printf (" cmp $0, %%eax\n"); // XXX MUST SUPPORT != 0 COMPARE HERE /* TODO : Simplify!! */ //if (pushvar) // printf(" push %s /* wihle push */\n", pushvar); if (lastctxdelta<0) rcc_printf (" jnz %s\n", get_frame_label (1)); else rcc_printf (" jnz %s\n", get_frame_label (0)); //if (pushvar) // printf(" pop %%"R_AX" /* while pop */\n"); #endif nargs = 0; } else { for (i = 0; i < nsyscalls; i++) { if (!strcmp (str, syscalls[i].name)) { p = syscallbody; e->comment (egg, "set syscall args"); e->syscall_args (egg, nargs); docall = 0; e->comment (egg, "syscall"); r_egg_lang_parsechar (egg, '\n'); /* FIX parsing issue */ if (p) { for (; *p; p++) r_egg_lang_parsechar (egg, *p); } else { char *q, *s = e->syscall (egg, nargs); if (s) { for (q=s; *q; q++) r_egg_lang_parsechar (egg, *q); free (s); } else eprintf ("Cannot get @syscall payload\n"); } docall = 0; break; } } if (docall) for (i = 0; i < ninlines; i++) { if (!strcmp (str, inlines[i].name)) { p = inlines[i].body; docall = 0; e->comment (egg, "inline"); r_egg_lang_parsechar (egg, '\n'); /* FIX parsing issue */ for (; *p; p++) r_egg_lang_parsechar (egg, *p); docall = 0; break; } } if (docall) { e->comment (egg, "call in mode %d", mode); e->call (egg, str, 0); } } if (nargs > 0) e->restore_stack (egg, nargs*e->size); if (ocn) { // Used to call .var0() /* XXX: Probably buggy and wrong */ *buf = 0; free (str); str = r_egg_mkvar (egg, buf, ocn, 0); if (*buf) e->get_result (egg, buf); //else { eprintf("external symbol %s\n", ocn); } } /* store result of call */ if (dstvar) { if (mode != NAKED) { *buf = 0; free (str); str = r_egg_mkvar (egg, buf, dstvar, 0); if (*buf == 0) eprintf ("Cannot resolve variable '%s'\n", dstvar); else e->get_result (egg, buf); } R_FREE (dstvar); } rcc_reset_callname (); } else { int vs = 'l'; char type, *eq, *ptr = elem; elem[elem_n] = '\0'; ptr = (char*)skipspaces (ptr); if (*ptr) { eq = strchr (ptr, '='); if (eq) { char str2[64], *p, ch = *(eq-1); *eq = '\0'; eq = (char*) skipspaces (eq+1); p = r_egg_mkvar (egg, str2, ptr, 0); vs = varsize; if (is_var (eq)) { eq = r_egg_mkvar (egg, buf, eq, 0); if (varxs=='*') e->load (egg, eq, varsize); else /* XXX this is a hack .. must be integrated with pusharg */ if (varxs=='&') e->load_ptr (egg, eq); if (eq) { free (eq); eq = NULL; } type = ' '; } else type = '$'; vs = 'l'; // XXX: add support for != 'l' size e->mathop (egg, ch, vs, type, eq, p); free(p); } else { if (!strcmp (ptr, "break")) { // handle 'break;' e->trap (egg); rcc_reset_callname (); } else { e->mathop (egg, '=', vs, '$', ptr, NULL); } } } } free (str); }
R_API char *r_egg_mkvar(REgg *egg, char *out, const char *_str, int delta) { int i, idx, len, qi; char *oldstr = NULL, *str = NULL, foo[32], *q, *ret = NULL; delta += stackfixed; // XXX can be problematic if (!_str) return NULL; /* fix segfault, but not badparsing */ /* XXX memory leak */ ret = str = oldstr = strdup (skipspaces (_str)); //if (num || str[0]=='0') { sprintf(out, "$%d", num); ret = out; } if ( (q = strchr (str, ':')) ) { *q = '\0'; qi = atoi (q+1); varsize = (qi==1)? 'b': 'l'; } else varsize='l'; if (*str == '*' || *str == '&') { varxs = *str; str++; } else varxs = 0; if (str[0] == '.') { REggEmit *e = egg->remit; idx = atoi (str+4) + delta + e->size; if (!strncmp (str+1, "ret", 3)) { strcpy (out, e->retvar); } else if (!strncmp (str+1, "fix", 3)) { e->get_var (egg, 0, out, idx-stackfixed); //sprintf(out, "%d(%%"R_BP")", -(atoi(str+4)+delta+R_SZ-stackfixed)); } else if (!strncmp (str+1, "var", 3)) { e->get_var (egg, 0, out, idx); //sprintf(out, "%d(%%"R_BP")", -(atoi(str+4)+delta+R_SZ)); } else if (!strncmp (str+1, "arg", 3)) { if (str[4]) { if (stackframe == 0) { e->get_var (egg, 1, out, 4); //idx-4); } else { e->get_var (egg, 2, out, idx+4); } } else { /* TODO: return size of syscall */ if (callname) { for (i=0; i<nsyscalls; i++) if (!strcmp (syscalls[i].name, callname)) { free (oldstr); return strdup(syscalls[i].arg); } eprintf ("Unknown arg for syscall '%s'\n", callname); } else eprintf ("NO CALLNAME '%s'\n", callname); } } else if (!strncmp (str+1, "reg", 3)) { // XXX: can overflow if out is small if (attsyntax) snprintf (out, 32, "%%%s", e->regs (egg, atoi (str+4))); else snprintf (out, 32, "%s", e->regs (egg, atoi (str+4))); } else { out = str; /* TODO: show error, invalid var name? */ eprintf ("Something is really wrong\n"); } ret = strdup(out); free (oldstr); } else if (*str=='"' || *str=='\'') { int mustfilter = *str=='"'; /* TODO: check for room in stackfixed area */ str++; len = strlen (str)-1; if (!stackfixed || stackfixed <len) eprintf ("WARNING: No room in the static stackframe! (%d must be %d)\n", stackfixed, len); str[len]='\0'; snprintf (foo, sizeof (foo)-1, ".fix%d", nargs*16); /* XXX FIX DELTA !!!1 */ free(dstvar); dstvar = strdup (skipspaces (foo)); rcc_pushstr (egg, str, mustfilter); ret = r_egg_mkvar (egg, out, foo, 0); free (oldstr); } return ret; }
static void emit_string(REgg *egg, const char *dstvar, const char *str, int j) { char *p, *s, str2[64]; int i, len, oj = j; len = strlen (str); s = malloc (len+4); if (!s) return; memcpy (s, str, len); memset (s+len, 0, 4); /* XXX: Hack: Adjust offset in R_BP correctly for 64b addresses */ #define BPOFF R_SZ-4 #define M32(x) (unsigned int)((x) & 0xffffffff) /* XXX: Assumes sizeof(ut32) == 4 */ for (i=4; i<=oj; i+=4) { /* XXX endian issues (non-portable asm) */ ut32 *n = (ut32 *)(s+i-4); p = r_egg_mkvar (egg, str2, dstvar, i+BPOFF); if (attsyntax) r_egg_printf (egg, " movl $0x%x, %s\n", M32(*n), p); else r_egg_printf (egg, " mov %s, 0x%x\n", p, M32(*n)); free (p); j -= 4; } #undef M32 /* zero */ p = r_egg_mkvar (egg, str2, dstvar, i+BPOFF); if (attsyntax) r_egg_printf (egg, " movl $0, %s\n", p); else r_egg_printf (egg, " mov %s, 0\n", p); free (p); /* store pointer */ p = r_egg_mkvar (egg, str2, dstvar, j+4+BPOFF); if (attsyntax) r_egg_printf (egg, " lea %s, %%"R_AX"\n", p); else r_egg_printf (egg, " lea "R_AX", %s\n", p); free (p); p = r_egg_mkvar (egg, str2, dstvar, 0); if (attsyntax) r_egg_printf (egg, " mov %%"R_AX", %s\n", p); else r_egg_printf (egg, " mov %s, "R_AX"\n", p); free (p); #undef BPOFF #if 0 char *p, str2[64]; int i, oj = j; for (i=0; i<oj; i+=4) { /* XXX endian and 32/64bit issues */ int *n = (int *)(str+i); p = r_egg_mkvar (egg, str2, dstvar, j); if (attsyntax) r_egg_printf (egg, " movl $0x%x, %s\n", *n, p); else r_egg_printf (egg, " mov %s, 0x%x\n", p, *n); j -= 4; } p = r_egg_mkvar (egg, str2, dstvar, oj); if (attsyntax) r_egg_printf (egg, " lea %s, %%"R_AX"\n", p); else r_egg_printf (egg, " lea "R_AX", %s\n", p); p = r_egg_mkvar (egg, str2, dstvar, 0); if (attsyntax) r_egg_printf (egg, " mov %%"R_AX", %s\n", p); else r_egg_printf (egg, " mov %s, "R_AX"\n", p); #endif free (s); }