1 /* pancake // nopcode.org 2010-2013 -- emit module for rcc */
2
3 #include <r_egg.h>
4 #include <r_types.h>
5
6 /* hardcoded */
7 #define attsyntax 0
8
9 #ifdef ARCH_X86_64
10 # define EMIT_NAME emit_x64
11 # define R_ARCH "x64"
12 # define R_SZ 8
13 # define R_SP "rsp"
14 # define R_BP "rbp"
15 # define R_AX "rax"
16 # define SYSCALL_ATT "syscall"
17 # define SYSCALL_INTEL "syscall"
18 # define R_REG_AR_OFF 1
19 static char *regs[] = { "rax", "rdi", "rsi", "rdx", "r10", "r8", "r9" };
20 #else
21 # define EMIT_NAME emit_x86
22 # define R_ARCH "x86"
23 # define R_SZ 4
24 # define R_SP "esp"
25 # define R_BP "ebp"
26 # define R_AX "eax"
27 # define SYSCALL_ATT "int $0x80"
28 # define SYSCALL_INTEL "int 0x80"
29 # define R_REG_AR_OFF 0
30 static char *regs[] = { "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp" };
31 #endif
32
33 # define R_NGP (sizeof (regs)/sizeof (char *))
34
emit_init(REgg * egg)35 static void emit_init (REgg *egg) {
36 // TODO: add 'andb rsp, 0xf0'
37 if (attsyntax) {
38 r_egg_printf (egg, "mov %%" R_SP ", %%" R_BP "\n");
39 } else {
40 r_egg_printf (egg, "mov " R_BP ", " R_SP "\n");
41 }
42 }
43
emit_syscall(REgg * egg,int nargs)44 static char *emit_syscall (REgg *egg, int nargs) {
45 char p[512];
46 if (attsyntax) {
47 return strdup (": mov $`.arg`, %" R_AX "\n: " SYSCALL_ATT "\n");
48 }
49 switch (egg->os) {
50 case R_EGG_OS_LINUX:
51 strcpy (p, "\n : mov "R_AX", `.arg`\n : "SYSCALL_INTEL "\n");
52 break;
53 case R_EGG_OS_OSX:
54 case R_EGG_OS_MACOS:
55 case R_EGG_OS_DARWIN:
56 #if ARCH_X86_64
57 snprintf (p, sizeof (p), "\n"
58 " : mov rax, `.arg`\n"
59 " : syscall\n");
60 #else
61 snprintf (p, sizeof (p), "\n"
62 " : mov eax, `.arg`\n"
63 " : push eax\n"
64 " : int 0x80\n"
65 " : add esp, %d\n",
66 4); //(nargs+2)*(egg->bits/8));
67 #endif
68 break;
69 default:
70 return NULL;
71 }
72 return strdup (p);
73 }
74
emit_frame(REgg * egg,int sz)75 static void emit_frame (REgg *egg, int sz) {
76 if (sz < 1) {
77 return;
78 }
79 if (attsyntax) {
80 r_egg_printf (egg,
81 " push %%"R_BP"\n"
82 " mov %%"R_SP", %%"R_BP"\n"
83 " sub $%d, %%"R_SP"\n", sz);
84 } else {
85 r_egg_printf (egg,
86 " push " R_BP "\n"
87 " mov " R_BP ", " R_SP "\n"
88 " sub " R_SP ", %d\n",
89 sz);
90 }
91 }
92
emit_frame_end(REgg * egg,int sz,int ctx)93 static void emit_frame_end (REgg *egg, int sz, int ctx) {
94 if (sz>0) {
95 if (attsyntax) {
96 r_egg_printf (egg, " add $%d, %%"R_SP"\n", sz);
97 r_egg_printf (egg, " pop %%"R_BP"\n");
98 } else {
99 r_egg_printf (egg, " add "R_SP", %d\n", sz);
100 r_egg_printf (egg, " pop "R_BP"\n");
101 }
102 }
103 if (ctx > 0) {
104 r_egg_printf (egg, " ret\n");
105 }
106 }
107
emit_comment(REgg * egg,const char * fmt,...)108 static void emit_comment(REgg *egg, const char *fmt, ...) {
109 va_list ap;
110 char buf[1024];
111 va_start (ap, fmt);
112 vsnprintf (buf, sizeof (buf), fmt, ap);
113 if (attsyntax) {
114 r_egg_printf (egg, " /* %s */\n", buf);
115 } else {
116 r_egg_printf (egg, "# %s\n", buf);
117 }
118 va_end (ap);
119 }
120
emit_equ(REgg * egg,const char * key,const char * value)121 static void emit_equ (REgg *egg, const char *key, const char *value) {
122 r_egg_printf (egg, ".equ %s,%s\n", key, value);
123 }
124
getreg(int i)125 static const char *getreg(int i) {
126 if (i < 0 || i >= R_NGP) {
127 return NULL;
128 }
129 return regs[i];
130 }
131
emit_syscall_args(REgg * egg,int nargs)132 static void emit_syscall_args(REgg *egg, int nargs) {
133 int j, k;
134 for (j = 0; j < nargs; j++) {
135 k = j * R_SZ;
136 const char *reg = getreg (j + 1);
137 if (!reg) {
138 eprintf ("Cannot find gpr %d\n", j + 1);
139 break;
140 }
141 if (attsyntax) {
142 r_egg_printf (egg, " mov %d(%%"R_SP"), %%%s\n", k, reg);
143 } else {
144 if (k > 0) {
145 r_egg_printf (egg, " mov %s, ["R_SP"+%d]\n", reg, k);
146 } else if (k < 0) {
147 r_egg_printf (egg, " mov %s, ["R_SP"%d]\n", reg, k);
148 } else {
149 r_egg_printf (egg, " mov %s, ["R_SP"]\n", reg);
150 }
151 }
152 }
153 }
154
emit_string(REgg * egg,const char * dstvar,const char * str,int j)155 static void emit_string(REgg *egg, const char *dstvar, const char *str, int j) {
156 char *p, str2[64];
157 int i, oj = j;
158
159 int len = strlen (str);
160 char *s = calloc (1, len + 8);
161 if (!s) {
162 return;
163 }
164 memcpy (s, str, len);
165 memset (s + len, 0, 4);
166
167 /* XXX: Hack: Adjust offset in R_BP correctly for 64b addresses */
168 #define BPOFF (R_SZ-4)
169 #define M32(x) (unsigned int)((x) & 0xffffffff)
170 /* XXX: Assumes sizeof(ut32) == 4 */
171 for (i=4; i<=oj; i+=4) {
172 /* XXX endian issues (non-portable asm) */
173 ut32 *n = (ut32 *)(s+i-4);
174 p = r_egg_mkvar (egg, str2, dstvar, i+BPOFF);
175 if (attsyntax) {
176 r_egg_printf (egg, " movl $0x%x, %s\n", M32 (*n), p);
177 } else {
178 r_egg_printf (egg, " mov dword %s, 0x%x\n", p, M32 (*n));
179 }
180 free (p);
181 j -= 4;
182 }
183 #undef M32
184
185 /* zero */
186 p = r_egg_mkvar (egg, str2, dstvar, i+BPOFF);
187 if (attsyntax) {
188 r_egg_printf (egg, " movl $0, %s\n", p);
189 } else {
190 r_egg_printf (egg, " mov dword %s, 0\n", p);
191 }
192 free (p);
193
194 /* store pointer */
195 p = r_egg_mkvar (egg, str2, dstvar, j+4+BPOFF);
196 if (attsyntax) {
197 r_egg_printf (egg, " lea %s, %%" R_AX "\n", p);
198 } else {
199 r_egg_printf (egg, " lea " R_AX ", %s\n", p);
200 }
201 free (p);
202
203 p = r_egg_mkvar (egg, str2, dstvar, 0);
204 if (attsyntax) {
205 r_egg_printf (egg, " mov %%" R_AX ", %s\n", p);
206 } else {
207 r_egg_printf (egg, " mov %s, " R_AX "\n", p);
208 }
209 free (p);
210
211 #undef BPOFF
212 #if 0
213 char *p, str2[64];
214 int i, oj = j;
215 for (i=0; i<oj; i+=4) {
216 /* XXX endian and 32/64bit issues */
217 int *n = (int *)(str+i);
218 p = r_egg_mkvar (egg, str2, dstvar, j);
219 if (attsyntax) r_egg_printf (egg, " movl $0x%x, %s\n", *n, p);
220 else r_egg_printf (egg, " mov %s, 0x%x\n", p, *n);
221 j -= 4;
222 }
223 p = r_egg_mkvar (egg, str2, dstvar, oj);
224 if (attsyntax) r_egg_printf (egg, " lea %s, %%"R_AX"\n", p);
225 else r_egg_printf (egg, " lea "R_AX", %s\n", p);
226 p = r_egg_mkvar (egg, str2, dstvar, 0);
227 if (attsyntax) r_egg_printf (egg, " mov %%"R_AX", %s\n", p);
228 else r_egg_printf (egg, " mov %s, "R_AX"\n", p);
229 #endif
230 free (s);
231 }
232
emit_call(REgg * egg,const char * str,int atr)233 static void emit_call(REgg *egg, const char *str, int atr) {
234 if (atr) {
235 if (attsyntax) {
236 r_egg_printf (egg, " call *%s\n", str);
237 } else {
238 r_egg_printf (egg, " call [%s]\n", str);
239 }
240 } else {
241 r_egg_printf (egg, " call %s\n", str);
242 }
243 }
244
emit_jmp(REgg * egg,const char * str,int atr)245 static void emit_jmp(REgg *egg, const char *str, int atr) {
246 if (str) {
247 if (atr) {
248 if (attsyntax) {
249 r_egg_printf (egg, " jmp *%s\n", str);
250 } else {
251 r_egg_printf (egg, " jmp [%s]\n", str);
252 }
253 } else {
254 r_egg_printf (egg, " jmp %s\n", str);
255 }
256 } else {
257 eprintf ("Jump without destination\n");
258 }
259 }
260
emit_arg(REgg * egg,int xs,int num,const char * str)261 static void emit_arg (REgg *egg, int xs, int num, const char *str) {
262 int d = atoi (str);
263 if (!attsyntax && (*str == '$')) {
264 str = str + 1;
265 }
266 switch (xs) {
267 case 0:
268 #ifdef ARCH_X86_64
269 /* push imm64 instruction not exist, it´s translated to:
270 mov rax, 0x0102030405060708
271 push rax
272 */
273 if (attsyntax) {
274 r_egg_printf (egg, " mov %s, %%"R_AX "\n", str);
275 r_egg_printf (egg, " push %%"R_AX "\n");
276 } else {
277 r_egg_printf (egg, " mov "R_AX ", %s\n", str);
278 r_egg_printf (egg, " push "R_AX "\n");
279 }
280 #else
281 r_egg_printf (egg, " push %s\n", str);
282 #endif
283 break;
284 case '*':
285 if (attsyntax) {
286 r_egg_printf (egg, " push (%s)\n", str);
287 } else {
288 r_egg_printf (egg, " push [%s]\n", str);
289 }
290 break;
291 case '&':
292 if (attsyntax) {
293 if (d != 0) {
294 r_egg_printf (egg, " addl $%d, %%" R_BP "\n", d);
295 }
296 r_egg_printf (egg, " pushl %%"R_BP"\n");
297 if (d != 0) {
298 r_egg_printf (egg, " subl $%d, %%" R_BP "\n", d);
299 }
300 } else {
301 if (d != 0) {
302 r_egg_printf (egg, " add " R_BP ", %d\n", d);
303 }
304 r_egg_printf (egg, " push "R_BP"\n");
305 if (d != 0) {
306 r_egg_printf (egg, " sub " R_BP ", %d\n", d);
307 }
308 }
309 break;
310 }
311 }
312
emit_get_result(REgg * egg,const char * ocn)313 static void emit_get_result(REgg *egg, const char *ocn) {
314 if (attsyntax) {
315 r_egg_printf (egg, " mov %%" R_AX ", %s\n", ocn);
316 } else {
317 r_egg_printf (egg, " mov %s, " R_AX "\n", ocn);
318 }
319 }
320
emit_restore_stack(REgg * egg,int size)321 static void emit_restore_stack (REgg *egg, int size) {
322 if (attsyntax) {
323 r_egg_printf (egg, " add $%d, %%" R_SP " /* args */\n", size);
324 } else {
325 r_egg_printf (egg, " add " R_SP ", %d\n", size);
326 }
327 }
328
emit_get_while_end(REgg * egg,char * str,const char * ctxpush,const char * label)329 static void emit_get_while_end (REgg *egg, char *str, const char *ctxpush, const char *label) {
330 sprintf (str, " push %s\n jmp %s\n", ctxpush, label);
331 }
332
emit_while_end(REgg * egg,const char * labelback)333 static void emit_while_end (REgg *egg, const char *labelback) {
334 #if 0
335 if (attsyntax) {
336 r_egg_printf (egg, " pop %%"R_AX"\n");
337 r_egg_printf (egg, " cmp $0, %%"R_AX"\n"); // XXX MUST SUPPORT != 0 COMPARE HERE
338 r_egg_printf (egg, " jnz %s\n", labelback);
339 } else {
340 #endif
341 r_egg_printf (egg, " pop "R_AX"\n");
342 r_egg_printf (egg, " test "R_AX", "R_AX"\n"); // XXX MUST SUPPORT != 0 COMPARE HERE
343 r_egg_printf (egg, " jnz %s\n", labelback);
344 // }
345 }
346
347 // XXX: this is wrong
348 static void emit_get_var (REgg *egg, int type, char *out, int idx) {
349 switch (type) {
350 case 0: /* variable */
351 if (idx > 0) {
352 sprintf (out, "[" R_BP "+%d]", idx);
353 } else if (idx < 0) {
354 sprintf (out, "[" R_BP "%d]", idx);
355 } else {
356 strcpy (out, "[" R_BP "]");
357 }
358 break;
359 case 1: /* argument */
360 // OMG WE CAN'T stuff found in relative address in stack in the stack
361 eprintf ("WARNING: Using stack vars in naked functions\n");
362 idx = 8; // HACK to make arg0, arg4, ... work
363 if (idx > 0) {
364 sprintf (out, "[" R_SP "+%d]", idx);
365 } else if (idx < 0) {
366 sprintf (out, "[" R_SP "%d]", idx);
367 } else {
368 strcpy (out, "[" R_SP "]");
369 }
370 break;
371 case 2:
372 if (idx > 0) {
373 sprintf (out, "[" R_BP "+%d]", idx);
374 } else if (idx < 0) {
375 sprintf (out, "[" R_BP "%d]", idx);
376 } else {
377 strcpy (out, "[" R_BP "]");
378 }
379 break;
380 }
381 }
382
383 static void emit_trap (REgg *egg) {
384 r_egg_printf (egg, " int3\n");
385 }
386
387 static void emit_load_ptr(REgg *egg, const char *dst) {
388 int d = atoi (dst);
389 if (d == 0) { // hack to handle stackvarptrz
390 char *p = strchr (dst, '+');
391 if (p) {
392 d = atoi (p + 1);
393 }
394 }
395 //eprintf ("emit_load_ptr: HACK\n");
396 // XXX: 32/64bit care
397 //r_egg_printf (egg, "# DELTA IS (%s)\n", dst);
398 if (attsyntax) {
399 r_egg_printf (egg, " leal %d(%%"R_BP"), %%"R_AX"\n", d);
400 } else {
401 r_egg_printf (egg, " lea "R_AX", ["R_BP"+%d]\n", d);
402 }
403 //r_egg_printf (egg, " movl %%"R_BP", %%"R_AX"\n");
404 //r_egg_printf (egg, " addl $%d, %%"R_AX"\n", d);
405 }
406
407 static void emit_branch(REgg *egg, char *b, char *g, char *e, char *n, int sz, const char *dst) {
408 char *p, str[64];
409 char *arg = NULL;
410 char *op = "jz";
411 int signed_value = 1; // XXX: add support for signed/unsigned variables
412 /* NOTE that jb/ja are inverted to fit cmp opcode */
413 if (b) {
414 *b = '\0';
415 if (signed_value) {
416 op = e? "jge": "jg";
417 } else {
418 op = e? "jae": "ja";
419 }
420 arg = b+1;
421 } else
422 if (g) {
423 *g = '\0';
424 if (signed_value) {
425 op = e? "jle": "jl";
426 } else {
427 op = e? "jbe": "jb";
428 }
429 arg = g + 1;
430 }
431 if (!arg) {
432 if (e) {
433 arg = e+1;
434 op = "jne";
435 } else {
436 arg = attsyntax? "$0": "0";
437 if (n) {
438 op = "jnz";
439 } else {
440 op = "jz";
441 }
442 }
443 }
444
445 if (*arg == '=') {
446 arg++; /* for <=, >=, ... */
447 }
448 p = r_egg_mkvar (egg, str, arg, 0);
449 if (attsyntax) {
450 r_egg_printf (egg, " pop %%"R_AX"\n"); /* TODO: add support for more than one arg get arg0 */
451 r_egg_printf (egg, " cmp%c %s, %%"R_AX"\n", sz, p);
452 } else {
453 r_egg_printf (egg, " pop "R_AX"\n"); /* TODO: add support for more than one arg get arg0 */
454 r_egg_printf (egg, " cmp "R_AX", %s\n", p);
455 }
456 // if (context>0)
457 free (p);
458 r_egg_printf (egg, " %s %s\n", op, dst);
459 }
460
461 static void emit_load(REgg *egg, const char *dst, int sz) {
462 if (attsyntax) {
463 switch (sz) {
464 case 'l':
465 r_egg_printf (egg, " movl %s, %%"R_AX"\n", dst);
466 r_egg_printf (egg, " movl (%%"R_AX"), %%"R_AX"\n");
467 break;
468 case 'b':
469 r_egg_printf (egg, " movl %s, %%"R_AX"\n", dst);
470 r_egg_printf (egg, " movzb (%%"R_AX"), %%"R_AX"\n");
471 break;
472 default:
473 // TODO: unhandled?!?
474 r_egg_printf (egg, " mov%c %s, %%"R_AX"\n", sz, dst);
475 r_egg_printf (egg, " mov%c (%%"R_AX"), %%"R_AX"\n", sz);
476 }
477 } else {
478 switch (sz) {
479 case 'l':
480 r_egg_printf (egg, " mov "R_AX", %s\n", dst);
481 r_egg_printf (egg, " mov "R_AX", ["R_AX"]\n");
482 break;
483 case 'b':
484 r_egg_printf (egg, " mov "R_AX", %s\n", dst);
485 r_egg_printf (egg, " movz "R_AX", ["R_AX"]\n");
486 break;
487 default:
488 // TODO: unhandled?!?
489 r_egg_printf (egg, " mov "R_AX", %s\n", dst);
490 r_egg_printf (egg, " mov "R_AX", ["R_AX"]\n");
491 }
492 }
493 }
494
495 static void emit_mathop(REgg *egg, int ch, int vs, int type, const char *eq, const char *p) {
496 char *op;
497 switch(ch) {
498 case '^': op = "xor"; break;
499 case '&': op = "and"; break;
500 case '|': op = "or"; break;
501 case '-': op = "sub"; break;
502 case '+': op = "add"; break;
503 case '*': op = "mul"; break;
504 case '/': op = "div"; break;
505 default: op = "mov"; break;
506 }
507 if (attsyntax) {
508 if (!eq) {
509 eq = "%" R_AX;
510 }
511 if (!p) {
512 p = "%" R_AX;
513 }
514 r_egg_printf (egg, " %s%c %c%s, %s\n", op, vs, type, eq, p);
515 } else {
516 if (!eq) {
517 eq = R_AX;
518 }
519 if (!p) {
520 p = R_AX;
521 }
522 // TODO:
523 #if 0
524 eprintf ("TYPE = %c\n", type);
525 eprintf (" %s%c %c%s, %s\n", op, vs, type, eq, p);
526 eprintf (" %s %s, [%s]\n", op, p, eq);
527 #endif
528 if (type == '*') {
529 r_egg_printf (egg, " %s %s, [%s]\n", op, p, eq);
530 } else {
531 r_egg_printf (egg, " %s %s, %s\n", op, p, eq);
532 }
533 }
534 }
535
536 static const char* emit_regs(REgg *egg, int idx) {
537 return regs[idx%R_NGP];
538 }
539
540 static void emit_get_ar (REgg *egg, char *out, int idx) {
541 const char *reg = emit_regs (egg, R_REG_AR_OFF + idx);
542
543 if (reg) {
544 strcpy (out, reg);
545 }
546 }
547
548 REggEmit EMIT_NAME = {
549 .retvar = R_AX,
550 .arch = R_ARCH,
551 .size = R_SZ,
552 .init = emit_init,
553 .jmp = emit_jmp,
554 .call = emit_call,
555 .equ = emit_equ,
556 .regs = emit_regs,
557 //.sc = emit_sc,
558 .trap = emit_trap,
559 .frame = emit_frame,
560 .frame_end = emit_frame_end,
561 .comment = emit_comment,
562 .push_arg = emit_arg,
563 .restore_stack = emit_restore_stack,
564 .get_result = emit_get_result,
565 .syscall_args = emit_syscall_args,
566 .set_string = emit_string,
567 .get_ar = emit_get_ar,
568 .get_var = emit_get_var,
569 .while_end = emit_while_end,
570 .get_while_end = emit_get_while_end,
571 .branch = emit_branch,
572 .load = emit_load,
573 .load_ptr = emit_load_ptr,
574 .mathop = emit_mathop,
575 .syscall = emit_syscall,
576 };
577