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