2013-09-13 22:51:42 +00:00
|
|
|
|
/* pancake // nopcode.org 2010-2013 -- emit module for rcc */
|
2011-07-26 23:16:18 +00:00
|
|
|
|
|
|
|
|
|
#include <r_egg.h>
|
2013-12-05 20:42:56 +00:00
|
|
|
|
#include <r_types.h>
|
2011-07-26 23:16:18 +00:00
|
|
|
|
|
|
|
|
|
/* hardcoded */
|
|
|
|
|
#define attsyntax 0
|
|
|
|
|
|
|
|
|
|
#ifdef ARCH_X86_64
|
|
|
|
|
# define EMIT_NAME emit_x64
|
|
|
|
|
# define R_ARCH "x64"
|
|
|
|
|
# define R_SZ 8
|
|
|
|
|
# define R_SP "rsp"
|
|
|
|
|
# define R_BP "rbp"
|
|
|
|
|
# define R_AX "rax"
|
2013-12-05 20:42:56 +00:00
|
|
|
|
# define SYSCALL_ATT "syscall"
|
|
|
|
|
# define SYSCALL_INTEL "syscall"
|
2017-09-27 09:29:15 +00:00
|
|
|
|
# define R_REG_AR_OFF 1
|
|
|
|
|
static char *regs[] = { "rax", "rdi", "rsi", "rdx", "r10", "r8", "r9" };
|
2011-07-26 23:16:18 +00:00
|
|
|
|
#else
|
|
|
|
|
# define EMIT_NAME emit_x86
|
|
|
|
|
# define R_ARCH "x86"
|
|
|
|
|
# define R_SZ 4
|
|
|
|
|
# define R_SP "esp"
|
|
|
|
|
# define R_BP "ebp"
|
|
|
|
|
# define R_AX "eax"
|
2013-12-05 20:42:56 +00:00
|
|
|
|
# define SYSCALL_ATT "int $0x80"
|
|
|
|
|
# define SYSCALL_INTEL "int 0x80"
|
2017-09-27 09:29:15 +00:00
|
|
|
|
# define R_REG_AR_OFF 0
|
2017-09-29 11:05:58 +00:00
|
|
|
|
static char *regs[] = { "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp" };
|
2011-07-26 23:16:18 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
2017-09-27 09:29:15 +00:00
|
|
|
|
# define R_NGP (sizeof (regs)/sizeof (char *))
|
2011-07-26 23:16:18 +00:00
|
|
|
|
|
2021-12-21 18:52:17 +00:00
|
|
|
|
static void emit_init(REgg *egg) {
|
2011-08-11 15:41:24 +00:00
|
|
|
|
// TODO: add 'andb rsp, 0xf0'
|
2018-09-13 08:17:26 +00:00
|
|
|
|
if (attsyntax) {
|
|
|
|
|
r_egg_printf (egg, "mov %%" R_SP ", %%" R_BP "\n");
|
|
|
|
|
} else {
|
|
|
|
|
r_egg_printf (egg, "mov " R_BP ", " R_SP "\n");
|
|
|
|
|
}
|
2011-08-10 09:24:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-12-21 18:52:17 +00:00
|
|
|
|
static char *emit_syscall(REgg *egg, int nargs) {
|
2011-08-10 09:24:15 +00:00
|
|
|
|
char p[512];
|
2018-09-13 08:17:26 +00:00
|
|
|
|
if (attsyntax) {
|
|
|
|
|
return strdup (": mov $`.arg`, %" R_AX "\n: " SYSCALL_ATT "\n");
|
|
|
|
|
}
|
2011-08-10 09:24:15 +00:00
|
|
|
|
switch (egg->os) {
|
|
|
|
|
case R_EGG_OS_LINUX:
|
2013-12-05 20:42:56 +00:00
|
|
|
|
strcpy (p, "\n : mov "R_AX", `.arg`\n : "SYSCALL_INTEL "\n");
|
2011-08-10 09:24:15 +00:00
|
|
|
|
break;
|
|
|
|
|
case R_EGG_OS_OSX:
|
|
|
|
|
case R_EGG_OS_MACOS:
|
|
|
|
|
case R_EGG_OS_DARWIN:
|
2013-09-14 00:42:02 +00:00
|
|
|
|
#if ARCH_X86_64
|
|
|
|
|
snprintf (p, sizeof (p), "\n"
|
|
|
|
|
" : mov rax, `.arg`\n"
|
|
|
|
|
" : syscall\n");
|
|
|
|
|
#else
|
|
|
|
|
snprintf (p, sizeof (p), "\n"
|
|
|
|
|
" : mov eax, `.arg`\n"
|
|
|
|
|
" : push eax\n"
|
|
|
|
|
" : int 0x80\n"
|
|
|
|
|
" : add esp, %d\n",
|
2011-08-10 09:24:15 +00:00
|
|
|
|
4); //(nargs+2)*(egg->bits/8));
|
2013-09-14 00:42:02 +00:00
|
|
|
|
#endif
|
2011-08-10 09:24:15 +00:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
return strdup (p);
|
2011-07-26 23:16:18 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-12-21 18:52:17 +00:00
|
|
|
|
static void emit_frame(REgg *egg, int sz) {
|
2018-09-13 08:17:26 +00:00
|
|
|
|
if (sz < 1) {
|
2011-08-10 09:24:15 +00:00
|
|
|
|
return;
|
2018-09-13 08:17:26 +00:00
|
|
|
|
}
|
|
|
|
|
if (attsyntax) {
|
2014-04-30 00:16:48 +00:00
|
|
|
|
r_egg_printf (egg,
|
2011-08-10 09:24:15 +00:00
|
|
|
|
" push %%"R_BP"\n"
|
|
|
|
|
" mov %%"R_SP", %%"R_BP"\n"
|
|
|
|
|
" sub $%d, %%"R_SP"\n", sz);
|
2018-09-13 08:17:26 +00:00
|
|
|
|
} else {
|
|
|
|
|
r_egg_printf (egg,
|
|
|
|
|
" push " R_BP "\n"
|
|
|
|
|
" mov " R_BP ", " R_SP "\n"
|
|
|
|
|
" sub " R_SP ", %d\n",
|
|
|
|
|
sz);
|
|
|
|
|
}
|
2011-07-26 23:16:18 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-12-21 18:52:17 +00:00
|
|
|
|
static void emit_frame_end(REgg *egg, int sz, int ctx) {
|
2011-07-26 23:16:18 +00:00
|
|
|
|
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");
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-09-13 08:17:26 +00:00
|
|
|
|
if (ctx > 0) {
|
2011-07-26 23:16:18 +00:00
|
|
|
|
r_egg_printf (egg, " ret\n");
|
2018-09-13 08:17:26 +00:00
|
|
|
|
}
|
2011-07-26 23:16:18 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
2018-09-13 08:17:26 +00:00
|
|
|
|
if (attsyntax) {
|
|
|
|
|
r_egg_printf (egg, " /* %s */\n", buf);
|
|
|
|
|
} else {
|
|
|
|
|
r_egg_printf (egg, "# %s\n", buf);
|
|
|
|
|
}
|
2011-07-26 23:16:18 +00:00
|
|
|
|
va_end (ap);
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-21 18:52:17 +00:00
|
|
|
|
static void emit_equ(REgg *egg, const char *key, const char *value) {
|
2011-07-26 23:16:18 +00:00
|
|
|
|
r_egg_printf (egg, ".equ %s,%s\n", key, value);
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-15 14:59:51 +00:00
|
|
|
|
static const char *getreg(int i) {
|
2017-09-27 09:29:15 +00:00
|
|
|
|
if (i < 0 || i >= R_NGP) {
|
2017-09-15 14:59:51 +00:00
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
return regs[i];
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-26 23:16:18 +00:00
|
|
|
|
static void emit_syscall_args(REgg *egg, int nargs) {
|
|
|
|
|
int j, k;
|
2017-09-15 14:59:51 +00:00
|
|
|
|
for (j = 0; j < nargs; j++) {
|
|
|
|
|
k = j * R_SZ;
|
|
|
|
|
const char *reg = getreg (j + 1);
|
|
|
|
|
if (!reg) {
|
2022-08-01 07:56:51 +00:00
|
|
|
|
R_LOG_ERROR ("Cannot find gpr %d", j + 1);
|
2017-09-15 14:59:51 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (attsyntax) {
|
|
|
|
|
r_egg_printf (egg, " mov %d(%%"R_SP"), %%%s\n", k, reg);
|
|
|
|
|
} else {
|
|
|
|
|
if (k > 0) {
|
|
|
|
|
r_egg_printf (egg, " mov %s, ["R_SP"+%d]\n", reg, k);
|
|
|
|
|
} else if (k < 0) {
|
|
|
|
|
r_egg_printf (egg, " mov %s, ["R_SP"%d]\n", reg, k);
|
|
|
|
|
} else {
|
2019-12-13 17:25:19 +00:00
|
|
|
|
r_egg_printf (egg, " mov %s, ["R_SP"]\n", reg);
|
2017-09-15 14:59:51 +00:00
|
|
|
|
}
|
2011-08-07 22:46:04 +00:00
|
|
|
|
}
|
2011-07-26 23:16:18 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-10 09:24:15 +00:00
|
|
|
|
static void emit_string(REgg *egg, const char *dstvar, const char *str, int j) {
|
2018-05-13 01:59:37 +00:00
|
|
|
|
char *p, str2[64];
|
|
|
|
|
int i, oj = j;
|
2011-09-21 17:51:09 +00:00
|
|
|
|
|
2018-05-13 01:59:37 +00:00
|
|
|
|
int len = strlen (str);
|
|
|
|
|
char *s = calloc (1, len + 8);
|
|
|
|
|
if (!s) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2011-09-21 17:51:09 +00:00
|
|
|
|
memcpy (s, str, len);
|
2018-05-13 01:59:37 +00:00
|
|
|
|
memset (s + len, 0, 4);
|
2011-09-21 17:51:09 +00:00
|
|
|
|
|
2013-12-05 20:42:56 +00:00
|
|
|
|
/* XXX: Hack: Adjust offset in R_BP correctly for 64b addresses */
|
2018-08-30 11:16:50 +00:00
|
|
|
|
#define BPOFF (R_SZ-4)
|
2013-12-05 20:42:56 +00:00
|
|
|
|
#define M32(x) (unsigned int)((x) & 0xffffffff)
|
2022-08-18 12:37:29 +00:00
|
|
|
|
/* XXX: Assumes sizeof (ut32) == 4 */
|
2022-08-18 00:22:17 +00:00
|
|
|
|
for (i = 4; i <= oj; i += 4) {
|
2013-12-05 20:42:56 +00:00
|
|
|
|
/* XXX endian issues (non-portable asm) */
|
2022-08-18 00:22:17 +00:00
|
|
|
|
ut32 *n = (ut32 *)(s + i - 4);
|
2013-12-05 20:42:56 +00:00
|
|
|
|
p = r_egg_mkvar (egg, str2, dstvar, i+BPOFF);
|
2018-09-13 08:17:26 +00:00
|
|
|
|
if (attsyntax) {
|
|
|
|
|
r_egg_printf (egg, " movl $0x%x, %s\n", M32 (*n), p);
|
|
|
|
|
} else {
|
|
|
|
|
r_egg_printf (egg, " mov dword %s, 0x%x\n", p, M32 (*n));
|
|
|
|
|
}
|
2014-05-03 12:19:23 +00:00
|
|
|
|
free (p);
|
2011-08-09 09:06:50 +00:00
|
|
|
|
j -= 4;
|
|
|
|
|
}
|
2013-12-05 20:42:56 +00:00
|
|
|
|
#undef M32
|
2014-05-03 12:19:23 +00:00
|
|
|
|
|
2011-08-10 09:24:15 +00:00
|
|
|
|
/* zero */
|
2013-12-05 20:42:56 +00:00
|
|
|
|
p = r_egg_mkvar (egg, str2, dstvar, i+BPOFF);
|
2018-09-13 08:17:26 +00:00
|
|
|
|
if (attsyntax) {
|
|
|
|
|
r_egg_printf (egg, " movl $0, %s\n", p);
|
|
|
|
|
} else {
|
|
|
|
|
r_egg_printf (egg, " mov dword %s, 0\n", p);
|
|
|
|
|
}
|
2014-05-03 12:19:23 +00:00
|
|
|
|
free (p);
|
2011-08-10 09:24:15 +00:00
|
|
|
|
|
|
|
|
|
/* store pointer */
|
2013-12-05 20:42:56 +00:00
|
|
|
|
p = r_egg_mkvar (egg, str2, dstvar, j+4+BPOFF);
|
2018-09-13 08:17:26 +00:00
|
|
|
|
if (attsyntax) {
|
|
|
|
|
r_egg_printf (egg, " lea %s, %%" R_AX "\n", p);
|
|
|
|
|
} else {
|
|
|
|
|
r_egg_printf (egg, " lea " R_AX ", %s\n", p);
|
|
|
|
|
}
|
2014-05-03 12:19:23 +00:00
|
|
|
|
free (p);
|
|
|
|
|
|
2011-08-09 09:06:50 +00:00
|
|
|
|
p = r_egg_mkvar (egg, str2, dstvar, 0);
|
2018-09-13 08:17:26 +00:00
|
|
|
|
if (attsyntax) {
|
|
|
|
|
r_egg_printf (egg, " mov %%" R_AX ", %s\n", p);
|
|
|
|
|
} else {
|
|
|
|
|
r_egg_printf (egg, " mov %s, " R_AX "\n", p);
|
|
|
|
|
}
|
2014-05-03 12:19:23 +00:00
|
|
|
|
free (p);
|
|
|
|
|
|
2013-12-05 20:42:56 +00:00
|
|
|
|
#undef BPOFF
|
2011-08-09 09:06:50 +00:00
|
|
|
|
#if 0
|
2011-07-26 23:16:18 +00:00
|
|
|
|
char *p, str2[64];
|
|
|
|
|
int i, oj = j;
|
2022-08-18 00:22:17 +00:00
|
|
|
|
for (i = 0; i < oj; i += 4) {
|
2011-07-26 23:16:18 +00:00
|
|
|
|
/* 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);
|
2011-08-09 09:06:50 +00:00
|
|
|
|
#endif
|
2011-09-21 17:51:09 +00:00
|
|
|
|
free (s);
|
2011-07-26 23:16:18 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void emit_call(REgg *egg, const char *str, int atr) {
|
|
|
|
|
if (atr) {
|
2018-09-13 08:17:26 +00:00
|
|
|
|
if (attsyntax) {
|
|
|
|
|
r_egg_printf (egg, " call *%s\n", str);
|
|
|
|
|
} else {
|
|
|
|
|
r_egg_printf (egg, " call [%s]\n", str);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
r_egg_printf (egg, " call %s\n", str);
|
|
|
|
|
}
|
2011-07-26 23:16:18 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-09-19 00:39:33 +00:00
|
|
|
|
static void emit_jmp(REgg *egg, const char *str, int atr) {
|
2017-09-30 16:41:29 +00:00
|
|
|
|
if (str) {
|
|
|
|
|
if (atr) {
|
2018-09-13 08:17:26 +00:00
|
|
|
|
if (attsyntax) {
|
|
|
|
|
r_egg_printf (egg, " jmp *%s\n", str);
|
|
|
|
|
} else {
|
|
|
|
|
r_egg_printf (egg, " jmp [%s]\n", str);
|
|
|
|
|
}
|
2017-09-30 16:41:29 +00:00
|
|
|
|
} else {
|
|
|
|
|
r_egg_printf (egg, " jmp %s\n", str);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2019-06-20 04:45:00 +00:00
|
|
|
|
eprintf ("Jump without destination\n");
|
2017-09-30 16:41:29 +00:00
|
|
|
|
}
|
2011-09-19 00:39:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-12-21 18:52:17 +00:00
|
|
|
|
static void emit_arg(REgg *egg, int xs, int num, const char *str) {
|
2011-07-26 23:16:18 +00:00
|
|
|
|
int d = atoi (str);
|
2018-09-13 08:17:26 +00:00
|
|
|
|
if (!attsyntax && (*str == '$')) {
|
|
|
|
|
str = str + 1;
|
|
|
|
|
}
|
2011-07-26 23:16:18 +00:00
|
|
|
|
switch (xs) {
|
|
|
|
|
case 0:
|
2017-09-27 09:29:15 +00:00
|
|
|
|
#ifdef ARCH_X86_64
|
|
|
|
|
/* push imm64 instruction not exist, it´s translated to:
|
2019-08-06 04:32:50 +00:00
|
|
|
|
mov rax, 0x0102030405060708
|
2017-09-27 09:29:15 +00:00
|
|
|
|
push rax
|
|
|
|
|
*/
|
|
|
|
|
if (attsyntax) {
|
|
|
|
|
r_egg_printf (egg, " mov %s, %%"R_AX "\n", str);
|
|
|
|
|
r_egg_printf (egg, " push %%"R_AX "\n");
|
|
|
|
|
} else {
|
|
|
|
|
r_egg_printf (egg, " mov "R_AX ", %s\n", str);
|
|
|
|
|
r_egg_printf (egg, " push "R_AX "\n");
|
|
|
|
|
}
|
|
|
|
|
#else
|
2011-07-26 23:16:18 +00:00
|
|
|
|
r_egg_printf (egg, " push %s\n", str);
|
2017-09-27 09:29:15 +00:00
|
|
|
|
#endif
|
2011-07-26 23:16:18 +00:00
|
|
|
|
break;
|
|
|
|
|
case '*':
|
2018-09-13 08:17:26 +00:00
|
|
|
|
if (attsyntax) {
|
|
|
|
|
r_egg_printf (egg, " push (%s)\n", str);
|
|
|
|
|
} else {
|
|
|
|
|
r_egg_printf (egg, " push [%s]\n", str);
|
|
|
|
|
}
|
2011-07-26 23:16:18 +00:00
|
|
|
|
break;
|
|
|
|
|
case '&':
|
|
|
|
|
if (attsyntax) {
|
2018-09-13 08:17:26 +00:00
|
|
|
|
if (d != 0) {
|
|
|
|
|
r_egg_printf (egg, " addl $%d, %%" R_BP "\n", d);
|
|
|
|
|
}
|
2011-07-26 23:16:18 +00:00
|
|
|
|
r_egg_printf (egg, " pushl %%"R_BP"\n");
|
2018-09-13 08:17:26 +00:00
|
|
|
|
if (d != 0) {
|
|
|
|
|
r_egg_printf (egg, " subl $%d, %%" R_BP "\n", d);
|
|
|
|
|
}
|
2011-07-26 23:16:18 +00:00
|
|
|
|
} else {
|
2018-09-13 08:17:26 +00:00
|
|
|
|
if (d != 0) {
|
|
|
|
|
r_egg_printf (egg, " add " R_BP ", %d\n", d);
|
|
|
|
|
}
|
2011-07-26 23:16:18 +00:00
|
|
|
|
r_egg_printf (egg, " push "R_BP"\n");
|
2018-09-13 08:17:26 +00:00
|
|
|
|
if (d != 0) {
|
|
|
|
|
r_egg_printf (egg, " sub " R_BP ", %d\n", d);
|
|
|
|
|
}
|
2011-07-26 23:16:18 +00:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void emit_get_result(REgg *egg, const char *ocn) {
|
2018-09-13 08:17:26 +00:00
|
|
|
|
if (attsyntax) {
|
|
|
|
|
r_egg_printf (egg, " mov %%" R_AX ", %s\n", ocn);
|
|
|
|
|
} else {
|
|
|
|
|
r_egg_printf (egg, " mov %s, " R_AX "\n", ocn);
|
|
|
|
|
}
|
2011-07-26 23:16:18 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-12-21 18:52:17 +00:00
|
|
|
|
static void emit_restore_stack(REgg *egg, int size) {
|
2018-09-13 08:17:26 +00:00
|
|
|
|
if (attsyntax) {
|
|
|
|
|
r_egg_printf (egg, " add $%d, %%" R_SP " /* args */\n", size);
|
|
|
|
|
} else {
|
|
|
|
|
r_egg_printf (egg, " add " R_SP ", %d\n", size);
|
|
|
|
|
}
|
2011-07-26 23:16:18 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-12-21 18:52:17 +00:00
|
|
|
|
static void emit_get_while_end(REgg *egg, char *str, const char *ctxpush, const char *label) {
|
2011-10-24 02:35:42 +00:00
|
|
|
|
sprintf (str, " push %s\n jmp %s\n", ctxpush, label);
|
2011-07-26 23:16:18 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-12-21 18:52:17 +00:00
|
|
|
|
static void emit_while_end(REgg *egg, const char *labelback) {
|
2011-08-09 09:06:50 +00:00
|
|
|
|
#if 0
|
2011-07-26 23:16:18 +00:00
|
|
|
|
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 {
|
2011-08-09 09:06:50 +00:00
|
|
|
|
#endif
|
2011-07-26 23:16:18 +00:00
|
|
|
|
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);
|
2011-08-09 09:06:50 +00:00
|
|
|
|
// }
|
2011-07-26 23:16:18 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-10-24 02:35:42 +00:00
|
|
|
|
// XXX: this is wrong
|
2021-12-21 18:52:17 +00:00
|
|
|
|
static void emit_get_var(REgg *egg, int type, char *out, int idx) {
|
2011-09-21 17:51:09 +00:00
|
|
|
|
switch (type) {
|
|
|
|
|
case 0: /* variable */
|
2018-09-13 08:17:26 +00:00
|
|
|
|
if (idx > 0) {
|
|
|
|
|
sprintf (out, "[" R_BP "+%d]", idx);
|
|
|
|
|
} else if (idx < 0) {
|
|
|
|
|
sprintf (out, "[" R_BP "%d]", idx);
|
|
|
|
|
} else {
|
|
|
|
|
strcpy (out, "[" R_BP "]");
|
|
|
|
|
}
|
2011-09-21 17:51:09 +00:00
|
|
|
|
break;
|
|
|
|
|
case 1: /* argument */
|
2019-06-20 04:45:00 +00:00
|
|
|
|
// OMG WE CAN'T stuff found in relative address in stack in the stack
|
2022-06-28 00:49:42 +00:00
|
|
|
|
R_LOG_WARN ("Using stack vars in naked functions");
|
2011-10-24 08:59:27 +00:00
|
|
|
|
idx = 8; // HACK to make arg0, arg4, ... work
|
2018-09-13 08:17:26 +00:00
|
|
|
|
if (idx > 0) {
|
|
|
|
|
sprintf (out, "[" R_SP "+%d]", idx);
|
|
|
|
|
} else if (idx < 0) {
|
|
|
|
|
sprintf (out, "[" R_SP "%d]", idx);
|
|
|
|
|
} else {
|
|
|
|
|
strcpy (out, "[" R_SP "]");
|
|
|
|
|
}
|
2011-09-21 17:51:09 +00:00
|
|
|
|
break;
|
2011-10-24 02:35:42 +00:00
|
|
|
|
case 2:
|
2018-09-13 08:17:26 +00:00
|
|
|
|
if (idx > 0) {
|
|
|
|
|
sprintf (out, "[" R_BP "+%d]", idx);
|
|
|
|
|
} else if (idx < 0) {
|
|
|
|
|
sprintf (out, "[" R_BP "%d]", idx);
|
|
|
|
|
} else {
|
|
|
|
|
strcpy (out, "[" R_BP "]");
|
|
|
|
|
}
|
2011-10-24 02:35:42 +00:00
|
|
|
|
break;
|
2011-07-26 23:16:18 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-21 18:52:17 +00:00
|
|
|
|
static void emit_trap(REgg *egg) {
|
2011-07-26 23:16:18 +00:00
|
|
|
|
r_egg_printf (egg, " int3\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void emit_load_ptr(REgg *egg, const char *dst) {
|
|
|
|
|
int d = atoi (dst);
|
2011-10-24 08:59:27 +00:00
|
|
|
|
if (d == 0) { // hack to handle stackvarptrz
|
|
|
|
|
char *p = strchr (dst, '+');
|
2018-09-13 08:17:26 +00:00
|
|
|
|
if (p) {
|
|
|
|
|
d = atoi (p + 1);
|
|
|
|
|
}
|
2011-10-24 08:59:27 +00:00
|
|
|
|
}
|
2011-07-26 23:16:18 +00:00
|
|
|
|
//eprintf ("emit_load_ptr: HACK\n");
|
|
|
|
|
// XXX: 32/64bit care
|
2011-10-24 08:59:27 +00:00
|
|
|
|
//r_egg_printf (egg, "# DELTA IS (%s)\n", dst);
|
2017-09-15 14:59:51 +00:00
|
|
|
|
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);
|
|
|
|
|
}
|
2011-07-26 23:16:18 +00:00
|
|
|
|
//r_egg_printf (egg, " movl %%"R_BP", %%"R_AX"\n");
|
|
|
|
|
//r_egg_printf (egg, " addl $%d, %%"R_AX"\n", d);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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";
|
2011-08-13 15:23:24 +00:00
|
|
|
|
int signed_value = 1; // XXX: add support for signed/unsigned variables
|
2011-07-26 23:16:18 +00:00
|
|
|
|
/* NOTE that jb/ja are inverted to fit cmp opcode */
|
|
|
|
|
if (b) {
|
|
|
|
|
*b = '\0';
|
2011-08-13 15:23:24 +00:00
|
|
|
|
if (signed_value) {
|
2017-09-15 14:59:51 +00:00
|
|
|
|
op = e? "jge": "jg";
|
2011-08-13 15:23:24 +00:00
|
|
|
|
} else {
|
2017-09-15 14:59:51 +00:00
|
|
|
|
op = e? "jae": "ja";
|
2011-08-13 15:23:24 +00:00
|
|
|
|
}
|
2011-07-26 23:16:18 +00:00
|
|
|
|
arg = b+1;
|
2022-08-18 16:35:22 +00:00
|
|
|
|
} else if (g) {
|
2011-07-26 23:16:18 +00:00
|
|
|
|
*g = '\0';
|
2011-08-13 15:23:24 +00:00
|
|
|
|
if (signed_value) {
|
2017-09-15 14:59:51 +00:00
|
|
|
|
op = e? "jle": "jl";
|
2011-08-13 15:23:24 +00:00
|
|
|
|
} else {
|
2017-09-15 14:59:51 +00:00
|
|
|
|
op = e? "jbe": "jb";
|
2011-08-13 15:23:24 +00:00
|
|
|
|
}
|
2017-09-15 14:59:51 +00:00
|
|
|
|
arg = g + 1;
|
2011-07-26 23:16:18 +00:00
|
|
|
|
}
|
2016-09-19 12:44:47 +00:00
|
|
|
|
if (!arg) {
|
2011-07-26 23:16:18 +00:00
|
|
|
|
if (e) {
|
|
|
|
|
arg = e+1;
|
|
|
|
|
op = "jne";
|
|
|
|
|
} else {
|
2011-08-09 09:06:50 +00:00
|
|
|
|
arg = attsyntax? "$0": "0";
|
2018-09-13 08:17:26 +00:00
|
|
|
|
if (n) {
|
|
|
|
|
op = "jnz";
|
|
|
|
|
} else {
|
|
|
|
|
op = "jz";
|
|
|
|
|
}
|
2011-07-26 23:16:18 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-13 08:17:26 +00:00
|
|
|
|
if (*arg == '=') {
|
|
|
|
|
arg++; /* for <=, >=, ... */
|
|
|
|
|
}
|
2011-07-26 23:16:18 +00:00
|
|
|
|
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 */
|
2011-08-09 09:06:50 +00:00
|
|
|
|
r_egg_printf (egg, " cmp "R_AX", %s\n", p);
|
2011-07-26 23:16:18 +00:00
|
|
|
|
}
|
|
|
|
|
// if (context>0)
|
2014-04-30 00:16:48 +00:00
|
|
|
|
free (p);
|
2011-07-26 23:16:18 +00:00
|
|
|
|
r_egg_printf (egg, " %s %s\n", op, dst);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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");
|
2016-10-26 21:46:41 +00:00
|
|
|
|
break;
|
2011-07-26 23:16:18 +00:00
|
|
|
|
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");
|
2016-10-26 21:46:41 +00:00
|
|
|
|
break;
|
2011-07-26 23:16:18 +00:00
|
|
|
|
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 = "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) {
|
2018-09-13 08:17:26 +00:00
|
|
|
|
if (!eq) {
|
|
|
|
|
eq = "%" R_AX;
|
|
|
|
|
}
|
|
|
|
|
if (!p) {
|
|
|
|
|
p = "%" R_AX;
|
|
|
|
|
}
|
2011-07-26 23:16:18 +00:00
|
|
|
|
r_egg_printf (egg, " %s%c %c%s, %s\n", op, vs, type, eq, p);
|
|
|
|
|
} else {
|
2018-09-13 08:17:26 +00:00
|
|
|
|
if (!eq) {
|
|
|
|
|
eq = R_AX;
|
|
|
|
|
}
|
|
|
|
|
if (!p) {
|
|
|
|
|
p = R_AX;
|
|
|
|
|
}
|
|
|
|
|
// TODO:
|
2011-08-07 22:46:04 +00:00
|
|
|
|
#if 0
|
2011-07-26 23:16:18 +00:00
|
|
|
|
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);
|
2011-08-07 22:46:04 +00:00
|
|
|
|
#endif
|
2018-09-13 08:17:26 +00:00
|
|
|
|
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);
|
|
|
|
|
}
|
2011-07-26 23:16:18 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const char* emit_regs(REgg *egg, int idx) {
|
|
|
|
|
return regs[idx%R_NGP];
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-21 18:52:17 +00:00
|
|
|
|
static void emit_get_ar(REgg *egg, char *out, int idx) {
|
2017-09-27 09:29:15 +00:00
|
|
|
|
const char *reg = emit_regs (egg, R_REG_AR_OFF + idx);
|
|
|
|
|
|
2018-09-13 08:17:26 +00:00
|
|
|
|
if (reg) {
|
|
|
|
|
strcpy (out, reg);
|
|
|
|
|
}
|
2017-09-27 09:29:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-07-26 23:16:18 +00:00
|
|
|
|
REggEmit EMIT_NAME = {
|
2011-09-19 00:39:33 +00:00
|
|
|
|
.retvar = R_AX,
|
2011-07-26 23:16:18 +00:00
|
|
|
|
.arch = R_ARCH,
|
|
|
|
|
.size = R_SZ,
|
2011-08-10 09:24:15 +00:00
|
|
|
|
.init = emit_init,
|
2011-09-19 00:39:33 +00:00
|
|
|
|
.jmp = emit_jmp,
|
2011-07-26 23:16:18 +00:00
|
|
|
|
.call = emit_call,
|
|
|
|
|
.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,
|
2011-08-10 09:24:15 +00:00
|
|
|
|
.set_string = emit_string,
|
2017-09-27 09:29:15 +00:00
|
|
|
|
.get_ar = emit_get_ar,
|
2011-07-26 23:16:18 +00:00
|
|
|
|
.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,
|
|
|
|
|
};
|