more ops, fixes, refactoring
[ia32rtools.git] / tools / translate.c
CommitLineData
c36e914d 1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4
5#include "my_assert.h"
6#include "my_str.h"
7
8#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
9#define IS(w, y) !strcmp(w, y)
10
11#include "protoparse.h"
12
13const char *asmfn;
14static int asmln;
15
16#define awarn(fmt, ...) \
17 printf("warning:%s:%d: " fmt, asmfn, asmln, ##__VA_ARGS__)
18#define aerr(fmt, ...) do { \
19 printf("error:%s:%d: " fmt, asmfn, asmln, ##__VA_ARGS__); \
20 exit(1); \
21} while (0)
22
69a3cdfc 23enum op_flags {
24 OPF_RMD = (1 << 0), /* removed or optimized out */
25 OPF_DATA = (1 << 1), /* data processing - writes to dst opr */
26 OPF_FLAGS = (1 << 2), /* sets flags */
27 OPF_JMP = (1 << 3), /* branches, ret and call */
28 OPF_CC = (1 << 4), /* uses flags */
c36e914d 29};
30
31enum op_op {
32 OP_INVAL,
33 OP_PUSH,
34 OP_POP,
35 OP_MOV,
850c9265 36 OP_LEA,
37 OP_MOVZX,
38 OP_MOVSX,
39 OP_NOT,
5101a5f9 40 OP_CDQ,
c36e914d 41 OP_RET,
42 OP_ADD,
91977a1c 43 OP_SUB,
850c9265 44 OP_AND,
45 OP_OR,
46 OP_XOR,
47 OP_SHL,
48 OP_SHR,
49 OP_SAR,
69a3cdfc 50 OP_ADC,
850c9265 51 OP_SBB,
52 OP_INC,
53 OP_DEC,
5101a5f9 54 OP_NEG,
850c9265 55 OP_MUL,
56 OP_IMUL,
5101a5f9 57 OP_DIV,
58 OP_IDIV,
c36e914d 59 OP_TEST,
60 OP_CMP,
61 OP_CALL,
62 OP_JMP,
63 OP_JO,
64 OP_JNO,
65 OP_JC,
66 OP_JNC,
67 OP_JZ,
68 OP_JNZ,
69 OP_JBE,
70 OP_JA,
71 OP_JS,
72 OP_JNS,
73 OP_JP,
74 OP_JNP,
75 OP_JL,
76 OP_JGE,
77 OP_JLE,
78 OP_JG,
79};
80
81enum opr_type {
82 OPT_UNSPEC,
83 OPT_REG,
84 OPT_REGMEM,
85 OPT_LABEL,
850c9265 86 OPT_OFFSET,
c36e914d 87 OPT_CONST,
88};
89
90enum opr_lenmod {
91977a1c 91 OPLM_UNSPEC,
92 OPLM_BYTE,
93 OPLM_WORD,
94 OPLM_DWORD,
c36e914d 95};
96
850c9265 97#define MAX_OPERANDS 3
c36e914d 98
99struct parsed_opr {
91977a1c 100 enum opr_type type;
101 enum opr_lenmod lmod;
102 int reg;
103 unsigned int val;
104 char name[256];
c36e914d 105};
106
107struct parsed_op {
91977a1c 108 enum op_op op;
109 struct parsed_opr operand[MAX_OPERANDS];
69a3cdfc 110 unsigned int flags;
91977a1c 111 int operand_cnt;
69a3cdfc 112 int regmask_src; // all referensed regs
113 int regmask_dst;
114 int pfomask; // parsed_flag_op that can't be delayed
91977a1c 115 void *datap;
116};
117
69a3cdfc 118// datap:
119// OP_PUSH - arg number if arg is altered before call
120// OP_CALL - ptr to parsed_proto
121// (OPF_CC) - point to corresponding (OPF_FLAGS)
122
91977a1c 123struct parsed_equ {
124 char name[64];
125 enum opr_lenmod lmod;
126 int offset;
c36e914d 127};
128
129#define MAX_OPS 1024
130
131static struct parsed_op ops[MAX_OPS];
91977a1c 132static struct parsed_equ *g_eqs;
133static int g_eqcnt;
134static char g_labels[MAX_OPS][32];
135static struct parsed_proto g_func_pp;
136static char g_func[256];
137static char g_comment[256];
138static int g_bp_frame;
139static int g_bp_stack;
140#define ferr(op_, fmt, ...) do { \
850c9265 141 printf("error:%s:#%ld: '%s': " fmt, g_func, (op_) - ops, \
142 dump_op(op_), ##__VA_ARGS__); \
91977a1c 143 exit(1); \
144} while (0)
145
146#define MAX_REGS 8
147
148const char *regs_r32[] = { "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp" };
149const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
150const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
151const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
152
153enum x86_regs { xUNSPEC = -1, xAX, xBX, xCX, xDX, xSI, xDI, xBP, xSP };
154
69a3cdfc 155// possible basic comparison types (without inversion)
156enum parsed_flag_op {
157 PFO_O, // 0 OF=1
158 PFO_C, // 2 CF=1
159 PFO_Z, // 4 ZF=1
160 PFO_BE, // 6 CF=1||ZF=1
161 PFO_S, // 8 SF=1
162 PFO_P, // a PF=1
163 PFO_L, // c SF!=OF
164 PFO_LE, // e ZF=1||SF!=OF
165};
166
167static const char *parsed_flag_op_names[] = {
168 "o", "c", "z", "be", "s", "p", "l", "le"
169};
170
91977a1c 171static int char_array_i(const char *array[], size_t len, const char *s)
172{
173 int i;
c36e914d 174
91977a1c 175 for (i = 0; i < len; i++)
176 if (IS(s, array[i]))
177 return i;
c36e914d 178
91977a1c 179 return -1;
180}
181
5101a5f9 182static void printf_number(char *buf, size_t buf_size, long number)
91977a1c 183{
5101a5f9 184 // output in C-friendly form
185 snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
186}
91977a1c 187
5101a5f9 188static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
189{
190 int reg;
91977a1c 191
5101a5f9 192 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
193 if (reg >= 0) {
194 *reg_lmod = OPLM_DWORD;
195 return reg;
91977a1c 196 }
5101a5f9 197 reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
198 if (reg >= 0) {
199 *reg_lmod = OPLM_WORD;
200 return reg;
201 }
202 reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
203 if (reg >= 0) {
204 *reg_lmod = OPLM_BYTE;
205 return reg;
206 }
207 reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
208 if (reg >= 0) {
209 *reg_lmod = OPLM_BYTE;
210 return reg;
850c9265 211 }
212
213 return -1;
91977a1c 214}
215
216static long parse_number(const char *number)
217{
218 int len = strlen(number);
219 const char *p = number;
220 char *endp = NULL;
221 int neg = 0;
222 int bad;
223 long ret;
224
225 if (*p == '-') {
226 neg = 1;
227 p++;
228 }
229 if (len > 1 && *p == '0')
230 p++;
231 if (number[len - 1] == 'h') {
232 ret = strtol(p, &endp, 16);
233 bad = (*endp != 'h');
234 }
235 else {
236 ret = strtol(p, &endp, 10);
237 bad = (*endp != 0);
238 }
239 if (bad)
240 aerr("number parsing failed\n");
241 if (neg)
242 ret = -ret;
243 return ret;
244}
245
5101a5f9 246static int parse_indmode(char *name, int *regmask, int need_c_cvt)
247{
248 enum opr_lenmod lmod;
249 char cvtbuf[256];
250 char *d = cvtbuf;
251 char *s = name;
252 char w[64];
253 long number;
254 int reg;
255 int c = 0;
256
257 *d = 0;
258
259 while (*s != 0) {
260 d += strlen(d);
261 while (my_isblank(*s))
262 s++;
263 for (; my_issep(*s); d++, s++)
264 *d = *s;
265 while (my_isblank(*s))
266 s++;
267 *d = 0;
268
269 s = next_idt(w, sizeof(w), s);
270 if (w[0] == 0)
271 break;
272 c++;
273
274 reg = parse_reg(&lmod, w);
275 if (reg >= 0) {
276 *regmask |= 1 << reg;
277 goto pass;
278 }
279
280 if ('0' <= w[0] && w[0] <= '9') {
281 number = parse_number(w);
282 printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
283 continue;
284 }
285
286 // probably some label/identifier - pass
287
288pass:
289 snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
290 }
291
292 if (need_c_cvt)
293 strcpy(name, cvtbuf);
294
295 return c;
296}
297
850c9265 298static int guess_lmod_from_name(struct parsed_opr *opr)
299{
300 if (!strncmp(opr->name, "dword_", 6)) {
301 opr->lmod = OPLM_DWORD;
302 return 1;
303 }
304 if (!strncmp(opr->name, "word_", 5)) {
305 opr->lmod = OPLM_WORD;
306 return 1;
307 }
308 if (!strncmp(opr->name, "byte_", 5)) {
309 opr->lmod = OPLM_BYTE;
310 return 1;
311 }
312 return 0;
313}
314
5101a5f9 315static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
316 int *regmask)
317{
318 opr->type = OPT_REG;
319 opr->reg = reg;
320 opr->lmod = lmod;
321 *regmask |= 1 << reg;
322}
323
69a3cdfc 324static int parse_operand(struct parsed_opr *opr,
325 int *regmask, int *regmask_indirect,
326 char words[16][256], int wordc, int w, unsigned int op_flags)
c36e914d 327{
850c9265 328 enum opr_lenmod tmplmod;
850c9265 329 int ret, len;
5101a5f9 330 long number;
850c9265 331 int i;
c36e914d 332
333 if (w >= wordc)
334 aerr("parse_operand w %d, wordc %d\n", w, wordc);
335
91977a1c 336 opr->reg = xUNSPEC;
337
c36e914d 338 for (i = w; i < wordc; i++) {
339 len = strlen(words[i]);
340 if (words[i][len - 1] == ',') {
341 words[i][len - 1] = 0;
342 wordc = i + 1;
343 break;
344 }
345 }
346
69a3cdfc 347 if (op_flags & OPF_JMP) {
c36e914d 348 const char *label;
349
350 if (wordc - w == 3 && IS(words[w + 1], "ptr"))
351 label = words[w + 2];
352 else if (wordc - w == 2 && IS(words[w], "short"))
353 label = words[w + 1];
354 else if (wordc - w == 1)
355 label = words[w];
356 else
357 aerr("jump parse error");
358
359 opr->type = OPT_LABEL;
360 strcpy(opr->name, label);
361 return wordc;
362 }
363
364 if (wordc - w >= 3) {
365 if (IS(words[w + 1], "ptr")) {
366 if (IS(words[w], "dword"))
91977a1c 367 opr->lmod = OPLM_DWORD;
c36e914d 368 else if (IS(words[w], "word"))
91977a1c 369 opr->lmod = OPLM_WORD;
c36e914d 370 else if (IS(words[w], "byte"))
91977a1c 371 opr->lmod = OPLM_BYTE;
c36e914d 372 else
373 aerr("type parsing failed\n");
374 w += 2;
375 }
376 }
377
378 if (wordc - w == 2 && IS(words[w], "offset")) {
850c9265 379 opr->type = OPT_OFFSET;
c36e914d 380 strcpy(opr->name, words[w + 1]);
381 return wordc;
382 }
383
850c9265 384 if (wordc - w != 1)
385 aerr("parse_operand 1 word expected\n");
c36e914d 386
850c9265 387 strcpy(opr->name, words[w]);
c36e914d 388
850c9265 389 if (words[w][0] == '[') {
390 opr->type = OPT_REGMEM;
391 ret = sscanf(words[w], "[%[^]]]", opr->name);
392 if (ret != 1)
393 aerr("[] parse failure\n");
394 // only need the regmask
5101a5f9 395 parse_indmode(opr->name, regmask_indirect, 1);
850c9265 396 return wordc;
397 }
398 else if (strchr(words[w], '[')) {
399 // label[reg] form
400 opr->type = OPT_REGMEM;
401 if (opr->lmod == OPLM_UNSPEC)
402 guess_lmod_from_name(opr);
5101a5f9 403 parse_indmode(strchr(words[w], '['), regmask_indirect, 0);
850c9265 404 return wordc;
405 }
406 else if (('0' <= words[w][0] && words[w][0] <= '9')
407 || words[w][0] == '-')
408 {
5101a5f9 409 number = parse_number(words[w]);
91977a1c 410 opr->type = OPT_CONST;
5101a5f9 411 opr->val = number;
412 printf_number(opr->name, sizeof(opr->name), number);
91977a1c 413 return wordc;
850c9265 414 }
c36e914d 415
5101a5f9 416 ret = parse_reg(&tmplmod, opr->name);
417 if (ret >= 0) {
418 setup_reg_opr(opr, ret, tmplmod, regmask);
850c9265 419 return wordc;
420 }
421
422 // most likely var in data segment
423 opr->type = OPT_LABEL;
424 if (opr->lmod == OPLM_UNSPEC)
425 guess_lmod_from_name(opr);
426 if (opr->lmod != OPLM_UNSPEC)
427 return wordc;
91977a1c 428
850c9265 429 // TODO: scan data seg to determine type?
430 return wordc;
c36e914d 431}
432
433static const struct {
850c9265 434 const char *name;
435 enum op_op op;
69a3cdfc 436 unsigned int minopr;
437 unsigned int maxopr;
438 unsigned int flags;
c36e914d 439} op_table[] = {
69a3cdfc 440 { "push", OP_PUSH, 1, 1, 0 },
441 { "pop", OP_POP, 1, 1, OPF_DATA },
442 { "mov" , OP_MOV, 2, 2, OPF_DATA },
443 { "lea", OP_LEA, 2, 2, OPF_DATA },
444 { "movzx",OP_MOVZX, 2, 2, OPF_DATA },
445 { "movsx",OP_MOVSX, 2, 2, OPF_DATA },
446 { "not", OP_NOT, 1, 1, OPF_DATA },
5101a5f9 447 { "cdq", OP_CDQ, 0, 0, OPF_DATA },
69a3cdfc 448 { "add", OP_ADD, 2, 2, OPF_DATA|OPF_FLAGS },
449 { "sub", OP_SUB, 2, 2, OPF_DATA|OPF_FLAGS },
450 { "and", OP_AND, 2, 2, OPF_DATA|OPF_FLAGS },
451 { "or", OP_OR, 2, 2, OPF_DATA|OPF_FLAGS },
452 { "xor", OP_XOR, 2, 2, OPF_DATA|OPF_FLAGS },
453 { "shl", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
454 { "shr", OP_SHR, 2, 2, OPF_DATA|OPF_FLAGS },
455 { "sal", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
456 { "sar", OP_SAR, 2, 2, OPF_DATA|OPF_FLAGS },
5101a5f9 457 { "adc", OP_ADC, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC },
69a3cdfc 458 { "sbb", OP_SBB, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC },
459 { "inc", OP_INC, 1, 1, OPF_DATA|OPF_FLAGS },
460 { "dec", OP_DEC, 1, 1, OPF_DATA|OPF_FLAGS },
5101a5f9 461 { "neg", OP_NEG, 1, 1, OPF_DATA|OPF_FLAGS },
462 { "mul", OP_MUL, 1, 1, OPF_DATA|OPF_FLAGS },
69a3cdfc 463 { "imul", OP_IMUL, 1, 3, OPF_DATA|OPF_FLAGS },
5101a5f9 464 { "div", OP_DIV, 1, 1, OPF_DATA|OPF_FLAGS },
465 { "idiv", OP_IDIV, 1, 1, OPF_DATA|OPF_FLAGS },
69a3cdfc 466 { "test", OP_TEST, 2, 2, OPF_FLAGS },
467 { "cmp", OP_CMP, 2, 2, OPF_FLAGS },
468 { "retn", OP_RET, 0, 1, OPF_JMP },
469 { "call", OP_CALL, 1, 1, OPF_JMP },
470 { "jmp", OP_JMP, 1, 1, OPF_JMP },
471 { "jo", OP_JO, 1, 1, OPF_JMP|OPF_CC }, // 70 OF=1
472 { "jno", OP_JNO, 1, 1, OPF_JMP|OPF_CC }, // 71 OF=0
473 { "jc", OP_JC, 1, 1, OPF_JMP|OPF_CC }, // 72 CF=1
474 { "jb", OP_JC, 1, 1, OPF_JMP|OPF_CC }, // 72
475 { "jnc", OP_JNC, 1, 1, OPF_JMP|OPF_CC }, // 73 CF=0
476 { "jae", OP_JNC, 1, 1, OPF_JMP|OPF_CC }, // 73
477 { "jz", OP_JZ, 1, 1, OPF_JMP|OPF_CC }, // 74 ZF=1
478 { "je", OP_JZ, 1, 1, OPF_JMP|OPF_CC }, // 74
479 { "jnz", OP_JNZ, 1, 1, OPF_JMP|OPF_CC }, // 75 ZF=0
480 { "jne", OP_JNZ, 1, 1, OPF_JMP|OPF_CC }, // 75
481 { "jbe", OP_JBE, 1, 1, OPF_JMP|OPF_CC }, // 76 CF=1 || ZF=1
482 { "jna", OP_JBE, 1, 1, OPF_JMP|OPF_CC }, // 76
483 { "ja", OP_JA, 1, 1, OPF_JMP|OPF_CC }, // 77 CF=0 && ZF=0
484 { "jnbe", OP_JA, 1, 1, OPF_JMP|OPF_CC }, // 77
485 { "js", OP_JS, 1, 1, OPF_JMP|OPF_CC }, // 78 SF=1
486 { "jns", OP_JNS, 1, 1, OPF_JMP|OPF_CC }, // 79 SF=0
487 { "jp", OP_JP, 1, 1, OPF_JMP|OPF_CC }, // 7a PF=1
488 { "jpe", OP_JP, 1, 1, OPF_JMP|OPF_CC }, // 7a
489 { "jnp", OP_JNP, 1, 1, OPF_JMP|OPF_CC }, // 7b PF=0
490 { "jpo", OP_JNP, 1, 1, OPF_JMP|OPF_CC }, // 7b
491 { "jl", OP_JL, 1, 1, OPF_JMP|OPF_CC }, // 7c SF!=OF
492 { "jnge", OP_JL, 1, 1, OPF_JMP|OPF_CC }, // 7c
493 { "jge", OP_JGE, 1, 1, OPF_JMP|OPF_CC }, // 7d SF=OF
494 { "jnl", OP_JGE, 1, 1, OPF_JMP|OPF_CC }, // 7d
495 { "jle", OP_JLE, 1, 1, OPF_JMP|OPF_CC }, // 7e ZF=1 || SF!=OF
496 { "jng", OP_JLE, 1, 1, OPF_JMP|OPF_CC }, // 7e
497 { "jg", OP_JG, 1, 1, OPF_JMP|OPF_CC }, // 7f ZF=0 && SF=OF
498 { "jnle", OP_JG, 1, 1, OPF_JMP|OPF_CC }, // 7f
5101a5f9 499 { "seto", OP_JO, 1, 1, OPF_DATA|OPF_CC },
500 { "setno", OP_JNO, 1, 1, OPF_DATA|OPF_CC },
501 { "setc", OP_JC, 1, 1, OPF_DATA|OPF_CC },
502 { "setb", OP_JC, 1, 1, OPF_DATA|OPF_CC },
503 { "setnc", OP_JNC, 1, 1, OPF_DATA|OPF_CC },
504 { "setae", OP_JNC, 1, 1, OPF_DATA|OPF_CC },
505 { "setz", OP_JZ, 1, 1, OPF_DATA|OPF_CC },
506 { "sete", OP_JZ, 1, 1, OPF_DATA|OPF_CC },
507 { "setnz", OP_JNZ, 1, 1, OPF_DATA|OPF_CC },
508 { "setne", OP_JNZ, 1, 1, OPF_DATA|OPF_CC },
509 { "setbe", OP_JBE, 1, 1, OPF_DATA|OPF_CC },
510 { "setna", OP_JBE, 1, 1, OPF_DATA|OPF_CC },
511 { "seta", OP_JA, 1, 1, OPF_DATA|OPF_CC },
512 { "setnbe", OP_JA, 1, 1, OPF_DATA|OPF_CC },
513 { "sets", OP_JS, 1, 1, OPF_DATA|OPF_CC },
514 { "setns", OP_JNS, 1, 1, OPF_DATA|OPF_CC },
515 { "setp", OP_JP, 1, 1, OPF_DATA|OPF_CC },
516 { "setpe", OP_JP, 1, 1, OPF_DATA|OPF_CC },
517 { "setnp", OP_JNP, 1, 1, OPF_DATA|OPF_CC },
518 { "setpo", OP_JNP, 1, 1, OPF_DATA|OPF_CC },
519 { "setl", OP_JL, 1, 1, OPF_DATA|OPF_CC },
520 { "setnge", OP_JL, 1, 1, OPF_DATA|OPF_CC },
521 { "setge", OP_JGE, 1, 1, OPF_DATA|OPF_CC },
522 { "setnl", OP_JGE, 1, 1, OPF_DATA|OPF_CC },
523 { "setle", OP_JLE, 1, 1, OPF_DATA|OPF_CC },
524 { "setng", OP_JLE, 1, 1, OPF_DATA|OPF_CC },
525 { "setg", OP_JG, 1, 1, OPF_DATA|OPF_CC },
526 { "setnle", OP_JG, 1, 1, OPF_DATA|OPF_CC },
69a3cdfc 527};
c36e914d 528
529static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
530{
69a3cdfc 531 int regmask_ind;
532 int regmask;
91977a1c 533 int opr = 0;
534 int w = 1;
535 int i;
c36e914d 536
91977a1c 537 for (i = 0; i < ARRAY_SIZE(op_table); i++) {
69a3cdfc 538 if (IS(words[0], op_table[i].name))
539 break;
540 }
c36e914d 541
69a3cdfc 542 if (i == ARRAY_SIZE(op_table))
543 aerr("unhandled op: '%s'\n", words[0]);
c36e914d 544
69a3cdfc 545 op->op = op_table[i].op;
546 op->flags = op_table[i].flags;
547 op->regmask_src = op->regmask_dst = 0;
548
549 for (opr = 0; opr < op_table[i].minopr; opr++) {
550 regmask = regmask_ind = 0;
551 w = parse_operand(&op->operand[opr], &regmask, &regmask_ind,
552 words, wordc, w, op->flags);
553
554 if (opr == 0 && (op->flags & OPF_DATA))
555 op->regmask_dst = regmask;
556 // for now, mark dst as src too
557 op->regmask_src |= regmask | regmask_ind;
558 }
c36e914d 559
69a3cdfc 560 for (; w < wordc && opr < op_table[i].maxopr; opr++) {
561 w = parse_operand(&op->operand[opr],
562 &op->regmask_src, &op->regmask_src,
563 words, wordc, w, op->flags);
91977a1c 564 }
c36e914d 565
91977a1c 566 if (w < wordc)
567 aerr("parse_op %s incomplete: %d/%d\n",
568 words[0], w, wordc);
5101a5f9 569
570 // special cases
571 op->operand_cnt = opr;
572 if (!strncmp(op_table[i].name, "set", 3))
573 op->operand[0].lmod = OPLM_BYTE;
574
575 // ops with implicit argumets
576 switch (op->op) {
577 case OP_CDQ:
578 op->operand_cnt = 2;
579 setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
580 setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
581 break;
582
583 case OP_IMUL:
584 if (op->operand_cnt != 1)
585 break;
586 // fallthrough
587 case OP_MUL:
588 // singleop mul
589 op->regmask_dst = (1 << xDX) | (1 << xAX);
590 op->regmask_src |= (1 << xAX);
591 if (op->operand[0].lmod == OPLM_UNSPEC)
592 op->operand[0].lmod = OPLM_DWORD;
593 break;
594
595 case OP_DIV:
596 case OP_IDIV:
597 // we could set up operands for edx:eax, but there is no real need to
598 // (see is_opr_modified())
599 regmask = (1 << xDX) | (1 << xAX);
600 op->regmask_dst = regmask;
601 op->regmask_src |= regmask;
602 if (op->operand[0].lmod == OPLM_UNSPEC)
603 op->operand[0].lmod = OPLM_DWORD;
604 break;
605
606 case OP_SHL:
607 case OP_SHR:
608 case OP_SAR:
609 if (op->operand[1].lmod == OPLM_UNSPEC)
610 op->operand[1].lmod = OPLM_BYTE;
611 break;
612
613 default:
614 break;
615 }
c36e914d 616}
617
850c9265 618static const char *op_name(enum op_op op)
619{
620 int i;
621
622 for (i = 0; i < ARRAY_SIZE(op_table); i++)
623 if (op_table[i].op == op)
624 return op_table[i].name;
625
626 return "???";
627}
628
629// debug
630static const char *dump_op(struct parsed_op *po)
631{
632 static char out[128];
633 char *p = out;
634 int i;
635
636 snprintf(out, sizeof(out), "%s", op_name(po->op));
637 for (i = 0; i < po->operand_cnt; i++) {
638 p += strlen(p);
639 if (i > 0)
640 *p++ = ',';
641 snprintf(p, sizeof(out) - (p - out),
642 po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
643 po->operand[i].name);
644 }
645
646 return out;
647}
648
91977a1c 649static const char *opr_name(struct parsed_op *po, int opr_num)
c36e914d 650{
91977a1c 651 if (opr_num >= po->operand_cnt)
652 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
653 return po->operand[opr_num].name;
c36e914d 654}
655
91977a1c 656static unsigned int opr_const(struct parsed_op *po, int opr_num)
c36e914d 657{
91977a1c 658 if (opr_num >= po->operand_cnt)
659 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
660 if (po->operand[opr_num].type != OPT_CONST)
661 ferr(po, "opr %d: const expected\n", opr_num);
662 return po->operand[opr_num].val;
663}
c36e914d 664
91977a1c 665static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
666{
667 if ((unsigned int)popr->reg >= MAX_REGS)
668 ferr(po, "invalid reg: %d\n", popr->reg);
669 return regs_r32[popr->reg];
670}
c36e914d 671
850c9265 672static struct parsed_equ *equ_find(struct parsed_op *po, const char *name)
91977a1c 673{
850c9265 674 int i;
675
676 for (i = 0; i < g_eqcnt; i++)
677 if (IS(g_eqs[i].name, name))
678 break;
679 if (i >= g_eqcnt)
680 ferr(po, "unresolved equ name: '%s'\n", name);
681
682 return &g_eqs[i];
683}
684
685static void bg_frame_access(struct parsed_op *po, enum opr_lenmod lmod,
686 char *buf, size_t buf_size, const char *bp_arg,
687 int is_src, int is_lea)
688{
689 const char *prefix = "";
91977a1c 690 struct parsed_equ *eq;
691 int i, arg_i, arg_s;
850c9265 692 int sf_ofs;
91977a1c 693
694 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
695
850c9265 696 eq = equ_find(po, bp_arg);
91977a1c 697
698 if (eq->offset >= 0) {
699 arg_i = eq->offset / 4 - 2;
700 if (arg_i < 0 || arg_i >= g_func_pp.argc_stack)
701 ferr(po, "offset %d doesn't map to any arg\n", eq->offset);
702
703 for (i = arg_s = 0; i < g_func_pp.argc; i++) {
704 if (g_func_pp.arg[i].reg != NULL)
705 continue;
706 if (arg_s == arg_i)
707 break;
708 arg_s++;
709 }
710 if (i == g_func_pp.argc)
711 ferr(po, "arg %d not in prototype?\n", arg_i);
850c9265 712 if (is_lea)
713 ferr(po, "lea to arg?\n");
714
91977a1c 715 snprintf(buf, buf_size, "%sa%d", is_src ? "(u32)" : "", i + 1);
716 }
717 else {
718 if (g_bp_stack == 0)
719 ferr(po, "bp_stack access after it was not detected\n");
850c9265 720
721 sf_ofs = g_bp_stack + eq->offset;
722 if (sf_ofs < 0)
723 ferr(po, "bp_stack offset %d/%d\n", eq->offset, g_bp_stack);
724
725 if (is_lea)
726 prefix = "&";
727
728 switch (lmod)
729 {
730 case OPLM_BYTE:
731 snprintf(buf, buf_size, "%ssf.b[%d]", prefix, sf_ofs);
732 break;
733 case OPLM_WORD:
734 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
735 break;
736 case OPLM_DWORD:
737 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
738 break;
739 default:
740 ferr(po, "bp_stack bad lmod: %d\n", lmod);
741 }
91977a1c 742 }
743}
c36e914d 744
91977a1c 745static char *out_src_opr(char *buf, size_t buf_size,
850c9265 746 struct parsed_op *po, struct parsed_opr *popr, int is_lea)
91977a1c 747{
850c9265 748 const char *cast = "";
749 char tmp1[256], tmp2[256];
750 char expr[256];
751 int ret;
752
91977a1c 753 switch (popr->type) {
754 case OPT_REG:
850c9265 755 if (is_lea)
756 ferr(po, "lea from reg?\n");
757
91977a1c 758 switch (popr->lmod) {
759 case OPLM_DWORD:
760 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
761 break;
850c9265 762 case OPLM_WORD:
763 snprintf(buf, buf_size, "(u16)%s", opr_reg_p(po, popr));
764 break;
765 case OPLM_BYTE:
5101a5f9 766 if (popr->name[1] == 'h') // XXX..
767 snprintf(buf, buf_size, "(u8)(%s >> 8)", opr_reg_p(po, popr));
768 else
769 snprintf(buf, buf_size, "(u8)%s", opr_reg_p(po, popr));
850c9265 770 break;
91977a1c 771 default:
772 ferr(po, "invalid src lmod: %d\n", popr->lmod);
773 }
774 break;
850c9265 775
91977a1c 776 case OPT_REGMEM:
777 if (g_bp_frame && !strncmp(popr->name, "ebp+", 4)) {
850c9265 778 bg_frame_access(po, popr->lmod, buf, buf_size,
779 popr->name + 4, 1, is_lea);
91977a1c 780 break;
781 }
850c9265 782
783 strcpy(expr, popr->name);
784 if (strchr(expr, '[')) {
785 // special case: '[' can only be left for label[reg] form
786 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
787 if (ret != 2)
788 ferr(po, "parse failure for '%s'\n", expr);
789 snprintf(expr, sizeof(expr), "(u32)%s + %s", tmp1, tmp2);
790 }
791
792 // XXX: do we need more parsing?
793 if (is_lea) {
794 snprintf(buf, buf_size, "%s", expr);
795 break;
796 }
797
798 switch (popr->lmod) {
799 case OPLM_DWORD:
800 cast = "*(u32 *)";
801 break;
802 case OPLM_WORD:
803 cast = "*(u16 *)";
804 break;
805 case OPLM_BYTE:
806 cast = "*(u8 *)";
807 break;
808 default:
809 ferr(po, "invalid lmod: %d\n", popr->lmod);
810 }
811 snprintf(buf, buf_size, "%s(%s)", cast, expr);
91977a1c 812 break;
850c9265 813
91977a1c 814 case OPT_LABEL:
850c9265 815 if (is_lea)
816 snprintf(buf, buf_size, "(u32)&%s", popr->name);
817 else
818 snprintf(buf, buf_size, "%s", popr->name);
819 break;
820
821 case OPT_OFFSET:
822 if (is_lea)
823 ferr(po, "lea an offset?\n");
824 snprintf(buf, buf_size, "(u32)&%s", popr->name);
91977a1c 825 break;
850c9265 826
91977a1c 827 case OPT_CONST:
850c9265 828 if (is_lea)
829 ferr(po, "lea from const?\n");
830
5101a5f9 831 printf_number(buf, buf_size, popr->val);
91977a1c 832 break;
850c9265 833
91977a1c 834 default:
835 ferr(po, "invalid src type: %d\n", popr->type);
836 }
837
838 return buf;
839}
c36e914d 840
91977a1c 841static char *out_dst_opr(char *buf, size_t buf_size,
842 struct parsed_op *po, struct parsed_opr *popr)
843{
844 switch (popr->type) {
845 case OPT_REG:
846 switch (popr->lmod) {
847 case OPLM_DWORD:
848 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
849 break;
850c9265 850 case OPLM_WORD:
851 // ugh..
852 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
853 break;
854 case OPLM_BYTE:
855 // ugh..
5101a5f9 856 if (popr->name[1] == 'h') // XXX..
857 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
858 else
859 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
850c9265 860 break;
91977a1c 861 default:
862 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
863 }
864 break;
850c9265 865
866 case OPT_REGMEM:
867 if (g_bp_frame && !strncmp(popr->name, "ebp+", 4)) {
868 bg_frame_access(po, popr->lmod, buf, buf_size,
869 popr->name + 4, 0, 0);
870 break;
871 }
872
873 return out_src_opr(buf, buf_size, po, popr, 0);
874
91977a1c 875 default:
876 ferr(po, "invalid dst type: %d\n", popr->type);
877 }
878
879 return buf;
880}
c36e914d 881
69a3cdfc 882static const char *lmod_cast_u(struct parsed_op *po,
883 enum opr_lenmod lmod)
884{
885 switch (lmod) {
886 case OPLM_DWORD:
887 return "";
888 case OPLM_WORD:
889 return "(u16)";
890 case OPLM_BYTE:
891 return "(u8)";
892 default:
893 ferr(po, "invalid lmod: %d\n", lmod);
894 return "(_invalid_)";
895 }
896}
897
898static const char *lmod_cast_s(struct parsed_op *po,
899 enum opr_lenmod lmod)
900{
901 switch (lmod) {
902 case OPLM_DWORD:
903 return "(s32)";
904 case OPLM_WORD:
905 return "(s16)";
906 case OPLM_BYTE:
907 return "(s8)";
908 default:
909 ferr(po, "invalid lmod: %d\n", lmod);
910 return "(_invalid_)";
911 }
912}
913
5101a5f9 914static const char *lmod_cast(struct parsed_op *po,
915 enum opr_lenmod lmod, int is_signed)
916{
917 return is_signed ?
918 lmod_cast_s(po, lmod) :
919 lmod_cast_u(po, lmod);
920}
921
69a3cdfc 922static enum parsed_flag_op split_cond(struct parsed_op *po,
923 enum op_op op, int *is_neg)
91977a1c 924{
925 *is_neg = 0;
926
69a3cdfc 927 switch (op) {
928 case OP_JO:
929 return PFO_O;
930 case OP_JC:
931 return PFO_C;
932 case OP_JZ:
933 return PFO_Z;
934 case OP_JBE:
935 return PFO_BE;
936 case OP_JS:
937 return PFO_S;
938 case OP_JP:
939 return PFO_P;
940 case OP_JL:
941 return PFO_L;
942 case OP_JLE:
943 return PFO_LE;
944
91977a1c 945 case OP_JNO:
91977a1c 946 *is_neg = 1;
69a3cdfc 947 return PFO_O;
91977a1c 948 case OP_JNC:
91977a1c 949 *is_neg = 1;
69a3cdfc 950 return PFO_C;
91977a1c 951 case OP_JNZ:
91977a1c 952 *is_neg = 1;
69a3cdfc 953 return PFO_Z;
954 case OP_JA:
955 *is_neg = 1;
956 return PFO_BE;
91977a1c 957 case OP_JNS:
91977a1c 958 *is_neg = 1;
69a3cdfc 959 return PFO_S;
91977a1c 960 case OP_JNP:
91977a1c 961 *is_neg = 1;
69a3cdfc 962 return PFO_P;
850c9265 963 case OP_JGE:
850c9265 964 *is_neg = 1;
69a3cdfc 965 return PFO_L;
91977a1c 966 case OP_JG:
69a3cdfc 967 *is_neg = 1;
968 return PFO_LE;
969
970 case OP_ADC:
971 case OP_SBB:
972 return PFO_C;
973
91977a1c 974 default:
69a3cdfc 975 ferr(po, "split_cond: bad op %d\n", op);
976 return -1;
91977a1c 977 }
978}
c36e914d 979
91977a1c 980static void out_test_for_cc(char *buf, size_t buf_size,
69a3cdfc 981 struct parsed_op *po, enum parsed_flag_op pfo, int is_neg,
982 enum opr_lenmod lmod, const char *expr)
91977a1c 983{
69a3cdfc 984 const char *cast, *scast;
91977a1c 985
69a3cdfc 986 cast = lmod_cast_u(po, lmod);
987 scast = lmod_cast_s(po, lmod);
988
989 switch (pfo) {
990 case PFO_Z:
850c9265 991 snprintf(buf, buf_size, "(%s%s %s 0)",
992 cast, expr, is_neg ? "!=" : "==");
91977a1c 993 break;
850c9265 994
5101a5f9 995 case PFO_S:
996 case PFO_L: // SF!=OF; OF=0
997 snprintf(buf, buf_size, "(%s%s %s 0)",
998 scast, expr, is_neg ? ">=" : "<");
999 break;
1000
69a3cdfc 1001 case PFO_LE: // ZF=1||SF!=OF; OF=0 after test
1002 snprintf(buf, buf_size, "(%s%s %s 0)",
1003 scast, expr, is_neg ? ">" : "<=");
850c9265 1004 break;
1005
91977a1c 1006 default:
69a3cdfc 1007 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
91977a1c 1008 }
1009}
c36e914d 1010
850c9265 1011static void out_cmp_for_cc(char *buf, size_t buf_size,
69a3cdfc 1012 struct parsed_op *po, enum parsed_flag_op pfo, int is_neg,
1013 enum opr_lenmod lmod, const char *expr1, const char *expr2)
850c9265 1014{
69a3cdfc 1015 const char *cast, *scast;
850c9265 1016
69a3cdfc 1017 cast = lmod_cast_u(po, lmod);
1018 scast = lmod_cast_s(po, lmod);
850c9265 1019
69a3cdfc 1020 switch (pfo) {
5101a5f9 1021 case PFO_C:
1022 // note: must be unsigned compare
1023 snprintf(buf, buf_size, "(%s%s %s %s%s)",
1024 cast, expr1, is_neg ? ">=" : "<", cast, expr2);
1025 break;
1026
69a3cdfc 1027 case PFO_Z:
850c9265 1028 snprintf(buf, buf_size, "(%s%s %s %s%s)",
1029 cast, expr1, is_neg ? "!=" : "==", cast, expr2);
1030 break;
1031
5101a5f9 1032 case PFO_BE: // !a
850c9265 1033 // note: must be unsigned compare
1034 snprintf(buf, buf_size, "(%s%s %s %s%s)",
5101a5f9 1035 cast, expr1, is_neg ? ">" : "<=", cast, expr2);
1036 break;
1037
1038 // note: must be signed compare
1039 case PFO_S:
1040 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
1041 scast, expr1, expr2, is_neg ? ">=" : "<");
850c9265 1042 break;
1043
5101a5f9 1044 case PFO_L: // !ge
850c9265 1045 snprintf(buf, buf_size, "(%s%s %s %s%s)",
1046 scast, expr1, is_neg ? ">=" : "<", scast, expr2);
1047 break;
1048
5101a5f9 1049 case PFO_LE:
1050 snprintf(buf, buf_size, "(%s%s %s %s%s)",
1051 scast, expr1, is_neg ? ">" : "<=", scast, expr2);
1052 break;
1053
850c9265 1054 default:
69a3cdfc 1055 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
850c9265 1056 }
1057}
1058
69a3cdfc 1059static void out_cmp_test(char *buf, size_t buf_size,
1060 struct parsed_op *po, enum parsed_flag_op pfo, int is_neg)
1061{
1062 char buf1[256], buf2[256], buf3[256];
1063
1064 if (po->op == OP_TEST) {
1065 if (IS(opr_name(po, 0), opr_name(po, 1))) {
1066 out_src_opr(buf3, sizeof(buf3), po, &po->operand[0], 0);
1067 }
1068 else {
1069 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], 0);
1070 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0);
1071 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
1072 }
1073 out_test_for_cc(buf, buf_size, po, pfo, is_neg,
1074 po->operand[0].lmod, buf3);
1075 }
1076 else if (po->op == OP_CMP) {
1077 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0], 0);
1078 out_src_opr(buf3, sizeof(buf3), po, &po->operand[1], 0);
1079 out_cmp_for_cc(buf, buf_size, po, pfo, is_neg,
1080 po->operand[0].lmod, buf2, buf3);
1081 }
1082 else
1083 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
1084}
1085
850c9265 1086static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
91977a1c 1087 struct parsed_opr *popr2)
1088{
850c9265 1089 struct parsed_equ *eq;
1090
1091 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC) {
1092 // lmod could be specified by equ..
1093 if (!strncmp(popr1->name, "ebp+", 4)) {
1094 eq = equ_find(po, popr1->name + 4);
1095 popr1->lmod = eq->lmod;
1096 }
1097 if (!strncmp(popr2->name, "ebp+", 4)) {
1098 eq = equ_find(po, popr2->name + 4);
1099 popr2->lmod = eq->lmod;
1100 }
1101 }
1102
91977a1c 1103 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
1104 ferr(po, "missing lmod for both operands\n");
1105
1106 if (popr1->lmod == OPLM_UNSPEC)
1107 popr1->lmod = popr2->lmod;
1108 else if (popr2->lmod == OPLM_UNSPEC)
1109 popr2->lmod = popr1->lmod;
1110 else if (popr1->lmod != popr2->lmod)
1111 ferr(po, "conflicting lmods: %d vs %d\n", popr1->lmod, popr2->lmod);
1112}
c36e914d 1113
850c9265 1114static const char *op_to_c(struct parsed_op *po)
1115{
1116 switch (po->op)
1117 {
1118 case OP_ADD:
5101a5f9 1119 case OP_ADC:
850c9265 1120 return "+";
1121 case OP_SUB:
5101a5f9 1122 case OP_SBB:
850c9265 1123 return "-";
1124 case OP_AND:
1125 return "&";
1126 case OP_OR:
1127 return "|";
1128 case OP_XOR:
1129 return "^";
1130 case OP_SHL:
1131 return "<<";
1132 case OP_SHR:
1133 return ">>";
1134 case OP_MUL:
1135 case OP_IMUL:
1136 return "*";
1137 default:
1138 ferr(po, "op_to_c was supplied with %d\n", po->op);
1139 }
1140}
1141
1142static int scan_for_pop(int i, int opcnt, const char *reg)
1143{
1144 for (; i < opcnt; i++) {
69a3cdfc 1145 if (ops[i].flags & OPF_RMD)
850c9265 1146 continue;
1147
69a3cdfc 1148 if ((ops[i].flags & OPF_JMP) || g_labels[i][0] != 0)
850c9265 1149 return -1;
1150
1151 if (ops[i].op == OP_POP && ops[i].operand[0].type == OPT_REG
1152 && IS(ops[i].operand[0].name, reg))
1153 return i;
1154 }
1155
1156 return -1;
1157}
1158
69a3cdfc 1159// scan for pop starting from 'ret' op (all paths)
850c9265 1160static int scan_for_pop_ret(int i, int opcnt, const char *reg, int do_patch)
1161{
1162 int found = 0;
1163 int j;
1164
1165 for (; i < opcnt; i++) {
1166 if (ops[i].op != OP_RET)
1167 continue;
1168
1169 for (j = i - 1; j >= 0; j--) {
69a3cdfc 1170 if (ops[j].flags & OPF_RMD)
1171 continue;
1172 if (ops[j].flags & OPF_JMP)
850c9265 1173 return -1;
1174
1175 if (ops[j].op == OP_POP && ops[j].operand[0].type == OPT_REG
1176 && IS(ops[j].operand[0].name, reg))
1177 {
1178 found = 1;
1179 if (do_patch)
69a3cdfc 1180 ops[j].flags |= OPF_RMD;
850c9265 1181 break;
1182 }
1183
1184 if (g_labels[j][0] != 0)
1185 return -1;
1186 }
1187 }
1188
1189 return found ? 0 : -1;
1190}
1191
5101a5f9 1192// is operand 'opr modified' by parsed_op 'po'?
1193static int is_opr_modified(const struct parsed_opr *opr,
69a3cdfc 1194 const struct parsed_op *po)
1195{
1196 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
1197 return 0;
1198
1199 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG) {
1200 if (po->regmask_dst & (1 << opr->reg))
1201 return 1;
1202 else
1203 return 0;
1204 }
1205
1206 return IS(po->operand[0].name, opr->name);
1207}
1208
5101a5f9 1209// is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
1210static int is_any_opr_modified(const struct parsed_op *po_test,
1211 const struct parsed_op *po)
1212{
1213 int i;
1214
1215 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
1216 return 0;
1217
1218 if (po_test->regmask_src & po->regmask_dst)
1219 return 1;
1220
1221 for (i = 0; i < po_test->operand_cnt; i++)
1222 if (IS(po_test->operand[i].name, po->operand[0].name))
1223 return 1;
1224
1225 return 0;
1226}
1227
1228// scan for po_test operand modification in range given
1229static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt)
69a3cdfc 1230{
1231 for (; i < opcnt; i++) {
5101a5f9 1232 if (is_any_opr_modified(po_test, &ops[i]))
69a3cdfc 1233 return i;
1234 }
1235
1236 return -1;
1237}
1238
5101a5f9 1239static int scan_for_flag_set(int i)
69a3cdfc 1240{
1241 for (; i >= 0; i--) {
1242 if (ops[i].flags & OPF_FLAGS)
1243 return i;
1244
1245 if ((ops[i].flags & OPF_JMP) && !(ops[i].flags & OPF_CC))
1246 return -1;
1247 if (g_labels[i][0] != 0)
1248 return -1;
1249 }
1250
1251 return -1;
1252}
1253
5101a5f9 1254// scan back for cdq, if anything modifies edx, fail
1255static int scan_for_cdq_edx(int i)
1256{
1257 for (; i >= 0; i--) {
1258 if (ops[i].op == OP_CDQ)
1259 return i;
1260
1261 if (ops[i].regmask_dst & (1 << xDX))
1262 return -1;
1263 if (g_labels[i][0] != 0)
1264 return -1;
1265 }
1266
1267 return -1;
1268}
1269
91977a1c 1270static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
1271{
69a3cdfc 1272 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
850c9265 1273 struct parsed_opr *last_arith_dst = NULL;
91977a1c 1274 char buf1[256], buf2[256], buf3[256];
1275 struct parsed_proto *pp;
1276 const char *tmpname;
69a3cdfc 1277 int save_arg_vars = 0;
1278 int cmp_result_vars = 0;
91977a1c 1279 int had_decl = 0;
1280 int regmask_arg = 0;
1281 int regmask = 0;
1282 int no_output;
69a3cdfc 1283 int dummy;
91977a1c 1284 int arg;
1285 int i, j;
1286 int reg;
1287 int ret;
1288
1289 g_bp_frame = g_bp_stack = 0;
1290
1291 ret = proto_parse(fhdr, funcn, &g_func_pp);
1292 if (ret)
1293 ferr(ops, "proto_parse failed for '%s'\n", funcn);
1294
1295 fprintf(fout, "%s %s(", g_func_pp.ret_type, funcn);
1296 for (i = 0; i < g_func_pp.argc; i++) {
1297 if (i > 0)
1298 fprintf(fout, ", ");
1299 fprintf(fout, "%s a%d", g_func_pp.arg[i].type, i + 1);
1300 }
1301 fprintf(fout, ")\n{\n");
1302
1303 // pass1:
1304 // - handle ebp frame, remove ops related to it
1305 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
1306 && ops[1].op == OP_MOV
1307 && IS(opr_name(&ops[1], 0), "ebp")
1308 && IS(opr_name(&ops[1], 1), "esp"))
1309 {
1310 g_bp_frame = 1;
69a3cdfc 1311 ops[0].flags |= OPF_RMD;
1312 ops[1].flags |= OPF_RMD;
91977a1c 1313
1314 if (ops[2].op == OP_SUB && IS(opr_name(&ops[2], 0), "esp")) {
1315 g_bp_stack = opr_const(&ops[2], 1);
69a3cdfc 1316 ops[2].flags |= OPF_RMD;
91977a1c 1317 }
1318
1319 i = 2;
1320 do {
1321 for (; i < opcnt; i++)
1322 if (ops[i].op == OP_RET)
1323 break;
1324 if (ops[i - 1].op != OP_POP || !IS(opr_name(&ops[i - 1], 0), "ebp"))
1325 ferr(&ops[i - 1], "'pop ebp' expected\n");
69a3cdfc 1326 ops[i - 1].flags |= OPF_RMD;
91977a1c 1327
1328 if (g_bp_stack != 0) {
1329 if (ops[i - 2].op != OP_MOV
1330 || !IS(opr_name(&ops[i - 2], 0), "esp")
1331 || !IS(opr_name(&ops[i - 2], 1), "ebp"))
1332 {
1333 ferr(&ops[i - 2], "esp restore expected\n");
1334 }
69a3cdfc 1335 ops[i - 2].flags |= OPF_RMD;
91977a1c 1336 }
1337 i++;
1338 } while (i < opcnt);
1339 }
1340
1341 // pass2:
69a3cdfc 1342 // - find POPs for PUSHes, rm both
91977a1c 1343 // - scan for all used registers
69a3cdfc 1344 // - find flag set ops for their users
91977a1c 1345 // - process calls
1346 for (i = 0; i < opcnt; i++) {
69a3cdfc 1347 po = &ops[i];
1348 if (po->flags & OPF_RMD)
91977a1c 1349 continue;
850c9265 1350
69a3cdfc 1351 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG) {
1352 if (po->operand[0].reg < 0)
1353 ferr(po, "reg not set for push?\n");
1354 if (!(regmask & (1 << po->operand[0].reg))) { // reg save
1355 ret = scan_for_pop(i + 1, opcnt, po->operand[0].name);
850c9265 1356 if (ret >= 0) {
69a3cdfc 1357 po->flags |= OPF_RMD;
1358 ops[ret].flags |= OPF_RMD;
850c9265 1359 continue;
1360 }
69a3cdfc 1361 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].name, 0);
850c9265 1362 if (ret == 0) {
69a3cdfc 1363 po->flags |= OPF_RMD;
1364 scan_for_pop_ret(i + 1, opcnt, po->operand[0].name, 1);
850c9265 1365 continue;
1366 }
1367 }
1368 }
1369
69a3cdfc 1370 regmask |= po->regmask_src | po->regmask_dst;
91977a1c 1371
69a3cdfc 1372 if (po->flags & OPF_CC)
1373 {
5101a5f9 1374 ret = scan_for_flag_set(i - 1);
69a3cdfc 1375 if (ret < 0)
1376 ferr(po, "unable to trace flag setter\n");
1377
1378 tmp_op = &ops[ret]; // flag setter
5101a5f9 1379 ret = scan_for_mod(tmp_op, ret + 1, i);
1380 if (ret >= 0) {
1381 ret = 1 << split_cond(po, po->op, &dummy);
1382 tmp_op->pfomask |= ret;
1383 cmp_result_vars |= ret;
1384 po->datap = tmp_op;
69a3cdfc 1385 }
5101a5f9 1386
1387 if (po->op == OP_ADC || po->op == OP_SBB)
1388 cmp_result_vars |= 1 << PFO_C;
69a3cdfc 1389 }
1390 else if (po->op == OP_CALL)
1391 {
91977a1c 1392 pp = malloc(sizeof(*pp));
1393 my_assert_not(pp, NULL);
1394 tmpname = opr_name(&ops[i], 0);
1395 ret = proto_parse(fhdr, tmpname, pp);
1396 if (ret)
69a3cdfc 1397 ferr(po, "proto_parse failed for '%s'\n", tmpname);
91977a1c 1398
1399 for (arg = 0; arg < pp->argc; arg++)
1400 if (pp->arg[arg].reg == NULL)
1401 break;
1402
1403 for (j = i - 1; j >= 0 && arg < pp->argc; j--) {
69a3cdfc 1404 if (ops[j].flags & OPF_RMD)
91977a1c 1405 continue;
1406 if (ops[j].op != OP_PUSH)
1407 continue;
69a3cdfc 1408 if (g_labels[j + 1][0] != 0)
1409 ferr(po, "arg search interrupted by '%s'\n", g_labels[j + 1]);
91977a1c 1410
1411 pp->arg[arg].datap = &ops[j];
5101a5f9 1412 ret = scan_for_mod(&ops[j], j + 1, i);
69a3cdfc 1413 if (ret >= 0) {
1414 // mark this push as one that needs operand saving
1415 ops[j].datap = (void *)(long)(arg + 1);
1416 save_arg_vars |= 1 << arg;
1417 }
1418 else
1419 ops[j].flags |= OPF_RMD;
1420
1421 // next arg
91977a1c 1422 for (arg++; arg < pp->argc; arg++)
1423 if (pp->arg[arg].reg == NULL)
1424 break;
1425 }
1426 if (arg < pp->argc)
69a3cdfc 1427 ferr(po, "arg collect failed for '%s'\n", tmpname);
1428 po->datap = pp;
91977a1c 1429 }
1430 }
1431
850c9265 1432 // declare stack frame
1433 if (g_bp_stack)
1434 fprintf(fout, " union { u32 d[%d]; u16 w[%d]; u8 b[%d]; } sf;\n",
1435 (g_bp_stack + 3) / 4, (g_bp_stack + 1) / 2, g_bp_stack);
1436
91977a1c 1437 // instantiate arg-registers
1438 for (i = 0; i < g_func_pp.argc; i++) {
1439 if (g_func_pp.arg[i].reg != NULL) {
1440 reg = char_array_i(regs_r32,
1441 ARRAY_SIZE(regs_r32), g_func_pp.arg[i].reg);
1442 if (reg < 0)
1443 ferr(ops, "arg '%s' is not a reg?\n", g_func_pp.arg[i].reg);
1444
1445 regmask_arg |= 1 << reg;
1446 fprintf(fout, " u32 %s = (u32)a%d;\n",
850c9265 1447 g_func_pp.arg[i].reg, i + 1);
91977a1c 1448 had_decl = 1;
1449 }
1450 }
1451
1452 // instantiate other regs - special case for eax
1453 if (!((regmask | regmask_arg) & 1) && !IS(g_func_pp.ret_type, "void")) {
1454 fprintf(fout, " u32 eax = 0;\n");
1455 had_decl = 1;
1456 }
1457
1458 regmask &= ~regmask_arg;
1459 if (g_bp_frame)
1460 regmask &= ~(1 << xBP);
1461 if (regmask) {
1462 for (reg = 0; reg < 8; reg++) {
1463 if (regmask & (1 << reg)) {
1464 fprintf(fout, " u32 %s;\n", regs_r32[reg]);
1465 had_decl = 1;
1466 }
1467 }
1468 }
1469
69a3cdfc 1470 if (save_arg_vars) {
1471 for (reg = 0; reg < 32; reg++) {
1472 if (save_arg_vars & (1 << reg)) {
1473 fprintf(fout, " u32 s_a%d;\n", reg + 1);
1474 had_decl = 1;
1475 }
1476 }
1477 }
1478
1479 if (cmp_result_vars) {
1480 for (i = 0; i < 8; i++) {
1481 if (cmp_result_vars & (1 << i)) {
1482 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
1483 had_decl = 1;
1484 }
1485 }
1486 }
1487
91977a1c 1488 if (had_decl)
1489 fprintf(fout, "\n");
1490
1491 // output ops
69a3cdfc 1492 for (i = 0; i < opcnt; i++)
1493 {
91977a1c 1494 if (g_labels[i][0] != 0)
1495 fprintf(fout, "\n%s:\n", g_labels[i]);
1496
69a3cdfc 1497 po = &ops[i];
1498 if (po->flags & OPF_RMD)
91977a1c 1499 continue;
1500
1501 no_output = 0;
1502
91977a1c 1503 #define assert_operand_cnt(n_) \
850c9265 1504 if (po->operand_cnt != n_) \
1505 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
1506
69a3cdfc 1507 // conditional/flag using op?
1508 if (po->flags & OPF_CC)
850c9265 1509 {
69a3cdfc 1510 enum parsed_flag_op pfo;
1511 int is_neg = 0;
1512
1513 pfo = split_cond(po, po->op, &is_neg);
850c9265 1514
69a3cdfc 1515 // we go through all this trouble to avoid using parsed_flag_op,
1516 // which makes generated code much nicer
1517 if (delayed_flag_op != NULL)
850c9265 1518 {
69a3cdfc 1519 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op, pfo, is_neg);
91977a1c 1520 }
850c9265 1521 else if (last_arith_dst != NULL
69a3cdfc 1522 && (pfo == PFO_Z || pfo == PFO_S || pfo == PFO_P))
850c9265 1523 {
1524 out_src_opr(buf3, sizeof(buf3), po, last_arith_dst, 0);
69a3cdfc 1525 out_test_for_cc(buf1, sizeof(buf1), po, pfo, is_neg,
850c9265 1526 last_arith_dst->lmod, buf3);
1527 }
69a3cdfc 1528 else if (po->datap != NULL) {
1529 // use preprocessed results
1530 tmp_op = po->datap;
1531 if (!tmp_op || !(tmp_op->pfomask & (1 << pfo)))
1532 ferr(po, "not prepared for pfo %d\n", pfo);
1533
1534 // note: is_neg was not yet applied
1535 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
1536 is_neg ? "!" : "", parsed_flag_op_names[pfo]);
1537 }
1538 else {
1539 ferr(po, "all methods of finding comparison failed\n");
1540 }
850c9265 1541
69a3cdfc 1542 if (po->flags & OPF_JMP) {
850c9265 1543 fprintf(fout, " if %s\n", buf1);
1544 }
5101a5f9 1545 else if (po->op == OP_ADC || po->op == OP_SBB) {
1546 fprintf(fout, " cond_%s = %s;\n", parsed_flag_op_names[pfo], buf1);
850c9265 1547 }
5101a5f9 1548 else if (po->flags & OPF_DATA) { // SETcc
850c9265 1549 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
1550 fprintf(fout, " %s = %s;", buf2, buf1);
91977a1c 1551 }
69a3cdfc 1552 else {
1553 ferr(po, "unhandled conditional op\n");
1554 }
91977a1c 1555 }
1556
850c9265 1557 switch (po->op)
91977a1c 1558 {
1559 case OP_MOV:
1560 assert_operand_cnt(2);
850c9265 1561 propagate_lmod(po, &po->operand[0], &po->operand[1]);
1562 fprintf(fout, " %s = %s;",
1563 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
1564 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
1565 break;
1566
1567 case OP_LEA:
1568 assert_operand_cnt(2);
1569 propagate_lmod(po, &po->operand[0], &po->operand[1]);
1570 fprintf(fout, " %s = %s;",
1571 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
1572 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 1));
1573 break;
1574
1575 case OP_MOVZX:
1576 assert_operand_cnt(2);
91977a1c 1577 fprintf(fout, " %s = %s;",
850c9265 1578 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
1579 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
1580 break;
1581
1582 case OP_MOVSX:
1583 assert_operand_cnt(2);
1584 switch (po->operand[1].lmod) {
1585 case OPLM_BYTE:
1586 strcpy(buf3, "(s8)");
1587 break;
1588 case OPLM_WORD:
1589 strcpy(buf3, "(s16)");
1590 break;
1591 default:
1592 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
1593 }
1594 fprintf(fout, " %s = %s%s;",
1595 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
1596 buf3,
1597 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
1598 break;
1599
1600 case OP_NOT:
1601 assert_operand_cnt(1);
1602 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
1603 fprintf(fout, " %s = ~%s;", buf1, buf1);
1604 break;
1605
5101a5f9 1606 case OP_CDQ:
1607 assert_operand_cnt(2);
1608 fprintf(fout, " %s = (s32)%s >> 31;",
1609 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
1610 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
1611 strcpy(g_comment, "cdq");
1612 break;
1613
850c9265 1614 // arithmetic w/flags
1615 case OP_ADD:
1616 case OP_SUB:
1617 case OP_AND:
1618 case OP_OR:
5101a5f9 1619 propagate_lmod(po, &po->operand[0], &po->operand[1]);
1620 // fallthrough
850c9265 1621 case OP_SHL:
1622 case OP_SHR:
1623 dualop_arith:
1624 assert_operand_cnt(2);
850c9265 1625 fprintf(fout, " %s %s= %s;",
1626 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
1627 op_to_c(po),
1628 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
1629 last_arith_dst = &po->operand[0];
69a3cdfc 1630 delayed_flag_op = NULL;
850c9265 1631 break;
1632
5101a5f9 1633 case OP_XOR:
850c9265 1634 assert_operand_cnt(2);
1635 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5101a5f9 1636 if (IS(opr_name(po, 0), opr_name(po, 1))) {
1637 // special case for XOR
1638 fprintf(fout, " %s = 0;",
1639 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
1640 last_arith_dst = &po->operand[0];
1641 delayed_flag_op = NULL;
850c9265 1642 break;
850c9265 1643 }
5101a5f9 1644 goto dualop_arith;
1645
1646 case OP_SAR:
1647 assert_operand_cnt(2);
850c9265 1648 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5101a5f9 1649 fprintf(fout, " %s = %s%s >> %s;", buf1,
1650 lmod_cast_s(po, po->operand[0].lmod), buf1,
1651 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
850c9265 1652 last_arith_dst = &po->operand[0];
69a3cdfc 1653 delayed_flag_op = NULL;
850c9265 1654 break;
1655
5101a5f9 1656 case OP_ADC:
850c9265 1657 case OP_SBB:
5101a5f9 1658 assert_operand_cnt(2);
1659 propagate_lmod(po, &po->operand[0], &po->operand[1]);
1660 fprintf(fout, " %s %s= %s + cond_c;",
1661 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
1662 op_to_c(po),
1663 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
1664 last_arith_dst = &po->operand[0];
1665 delayed_flag_op = NULL;
850c9265 1666 break;
1667
1668 case OP_INC:
1669 case OP_DEC:
1670 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
1671 strcpy(buf2, po->op == OP_INC ? "++" : "--");
5101a5f9 1672 fprintf(fout, " %s%s;", buf1, buf2);
1673 last_arith_dst = &po->operand[0];
1674 delayed_flag_op = NULL;
1675 break;
1676
1677 case OP_NEG:
1678 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
1679 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0], 0);
1680 fprintf(fout, " %s = -%s%s;", buf1,
1681 lmod_cast_s(po, po->operand[0].lmod), buf2);
850c9265 1682 last_arith_dst = &po->operand[0];
69a3cdfc 1683 delayed_flag_op = NULL;
850c9265 1684 break;
1685
1686 case OP_IMUL:
1687 if (po->operand_cnt == 2)
1688 goto dualop_arith;
1689 ferr(po, "TODO imul\n");
1690 last_arith_dst = &po->operand[0];
69a3cdfc 1691 delayed_flag_op = NULL;
91977a1c 1692 break;
1693
5101a5f9 1694 case OP_DIV:
1695 case OP_IDIV:
1696 assert_operand_cnt(1);
1697 if (po->operand[0].lmod != OPLM_DWORD)
1698 ferr(po, "unhandled lmod %d\n", po->operand[0].lmod);
1699
1700 // 32bit division is common, look for it
1701 if (scan_for_cdq_edx(i - 1) >= 0) {
1702 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], 0);
1703 strcpy(buf2, lmod_cast(po, po->operand[0].lmod,
1704 po->op == OP_IDIV));
1705 fprintf(fout, " edx = %seax %% %s%s;\n", buf2, buf2, buf1);
1706 fprintf(fout, " eax = %seax / %s%s;", buf2, buf2, buf1);
1707 }
1708 else
1709 ferr(po, "TODO 64bit divident\n");
1710 break;
1711
91977a1c 1712 case OP_TEST:
1713 case OP_CMP:
850c9265 1714 propagate_lmod(po, &po->operand[0], &po->operand[1]);
69a3cdfc 1715 if (po->pfomask != 0) {
1716 for (j = 0; j < 8; j++) {
1717 if (po->pfomask & (1 << j)) {
1718 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
1719 fprintf(fout, " cond_%s = %s;",
1720 parsed_flag_op_names[j], buf1);
1721 }
1722 }
1723 }
1724 else
1725 no_output = 1;
1726 delayed_flag_op = po;
91977a1c 1727 break;
1728
69a3cdfc 1729 // note: we reuse OP_Jcc for SETcc, only flags differ
91977a1c 1730 case OP_JO ... OP_JG:
5101a5f9 1731 if (po->flags & OPF_JMP)
850c9265 1732 fprintf(fout, " goto %s;", po->operand[0].name);
5101a5f9 1733 // else SETcc - should already be handled
850c9265 1734 break;
1735
1736 case OP_JMP:
1737 fprintf(fout, " goto %s;", po->operand[0].name);
91977a1c 1738 break;
1739
1740 case OP_CALL:
5101a5f9 1741 assert_operand_cnt(1);
1742 if (po->operand[0].type != OPT_LABEL)
1743 ferr(po, "unhandled call type\n");
1744
850c9265 1745 pp = po->datap;
91977a1c 1746 if (pp == NULL)
850c9265 1747 ferr(po, "NULL pp\n");
91977a1c 1748
1749 fprintf(fout, " ");
1750 if (!IS(pp->ret_type, "void")) {
1751 fprintf(fout, "eax = ");
1752 if (strchr(pp->ret_type, '*'))
1753 fprintf(fout, "(u32)");
1754 }
850c9265 1755 fprintf(fout, "%s(", opr_name(po, 0));
91977a1c 1756 for (arg = 0; arg < pp->argc; arg++) {
1757 if (arg > 0)
1758 fprintf(fout, ", ");
1759 if (pp->arg[arg].reg != NULL) {
850c9265 1760 fprintf(fout, "%s", pp->arg[arg].reg);
91977a1c 1761 continue;
1762 }
1763
1764 // stack arg
1765 tmp_op = pp->arg[arg].datap;
1766 if (tmp_op == NULL)
850c9265 1767 ferr(po, "parsed_op missing for arg%d\n", arg);
69a3cdfc 1768 if (tmp_op->datap) {
1769 fprintf(fout, "s_a%ld", (long)tmp_op->datap);
1770 }
1771 else {
1772 fprintf(fout, "%s",
1773 out_src_opr(buf1, sizeof(buf1),
1774 tmp_op, &tmp_op->operand[0], 0));
1775 }
91977a1c 1776 }
1777 fprintf(fout, ");");
1778 break;
1779
1780 case OP_RET:
1781 if (IS(g_func_pp.ret_type, "void"))
1782 fprintf(fout, " return;");
1783 else
1784 fprintf(fout, " return eax;");
1785 break;
1786
1787 case OP_PUSH:
69a3cdfc 1788 if (po->datap) {
1789 // special case - saved func arg
1790 fprintf(fout, " s_a%ld = %s;", (long)po->datap,
1791 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], 0));
1792 break;
1793 }
850c9265 1794 ferr(po, "push encountered\n");
91977a1c 1795 break;
1796
1797 case OP_POP:
850c9265 1798 ferr(po, "pop encountered\n");
91977a1c 1799 break;
1800
1801 default:
1802 no_output = 1;
69a3cdfc 1803 ferr(po, "unhandled op type %d, flags %x\n",
1804 po->op, po->flags);
91977a1c 1805 break;
1806 }
1807
1808 if (g_comment[0] != 0) {
1809 fprintf(fout, " // %s", g_comment);
1810 g_comment[0] = 0;
1811 no_output = 0;
1812 }
1813 if (!no_output)
1814 fprintf(fout, "\n");
5101a5f9 1815
1816 // see is delayed flag stuff is still valid
1817 if (delayed_flag_op != NULL && delayed_flag_op != po) {
1818 if (is_any_opr_modified(delayed_flag_op, po))
1819 delayed_flag_op = NULL;
1820 }
1821
1822 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
1823 if (is_opr_modified(last_arith_dst, po))
1824 last_arith_dst = NULL;
1825 }
91977a1c 1826 }
1827
1828 fprintf(fout, "}\n\n");
1829
1830 // cleanup
1831 for (i = 0; i < opcnt; i++) {
1832 if (ops[i].op == OP_CALL) {
1833 pp = ops[i].datap;
1834 if (pp) {
1835 proto_release(pp);
1836 free(pp);
1837 }
1838 }
1839 }
1840 proto_release(&g_func_pp);
1841}
c36e914d 1842
91977a1c 1843int main(int argc, char *argv[])
1844{
1845 FILE *fout, *fasm, *fhdr;
1846 char line[256];
1847 char words[16][256];
1848 int in_func = 0;
1849 int eq_alloc;
1850 int pi = 0;
1851 int len;
1852 char *p;
1853 int wordc;
1854
1855 if (argc != 4) {
1856 printf("usage:\n%s <.c> <.asm> <hdrf>\n",
1857 argv[0]);
1858 return 1;
1859 }
1860
1861 hdrfn = argv[3];
1862 fhdr = fopen(hdrfn, "r");
1863 my_assert_not(fhdr, NULL);
1864
1865 asmfn = argv[2];
1866 fasm = fopen(asmfn, "r");
1867 my_assert_not(fasm, NULL);
1868
1869 fout = fopen(argv[1], "w");
1870 my_assert_not(fout, NULL);
1871
1872 eq_alloc = 128;
1873 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
1874 my_assert_not(g_eqs, NULL);
1875
1876 while (fgets(line, sizeof(line), fasm))
1877 {
1878 asmln++;
1879
1880 p = sskip(line);
1881 if (*p == 0 || *p == ';')
1882 continue;
1883
1884 memset(words, 0, sizeof(words));
1885 for (wordc = 0; wordc < 16; wordc++) {
1886 p = sskip(next_word(words[wordc], sizeof(words[0]), p));
1887 if (*p == 0 || *p == ';') {
1888 wordc++;
1889 break;
1890 }
1891 }
1892
1893 if (wordc == 0) {
1894 // shouldn't happen
1895 awarn("wordc == 0?\n");
1896 continue;
1897 }
1898
1899 // don't care about this:
1900 if (words[0][0] == '.'
1901 || IS(words[0], "include")
1902 || IS(words[0], "assume") || IS(words[1], "segment")
1903 || IS(words[0], "align"))
1904 {
1905 continue;
1906 }
1907
1908 if (IS(words[1], "proc")) {
1909 if (in_func)
1910 aerr("proc '%s' while in_func '%s'?\n",
1911 words[0], g_func);
1912 strcpy(g_func, words[0]);
1913 in_func = 1;
1914 continue;
1915 }
1916
1917 if (IS(words[1], "endp")) {
1918 if (!in_func)
1919 aerr("endp '%s' while not in_func?\n", words[0]);
1920 if (!IS(g_func, words[0]))
1921 aerr("endp '%s' while in_func '%s'?\n",
1922 words[0], g_func);
1923 gen_func(fout, fhdr, g_func, pi);
1924 in_func = 0;
1925 g_func[0] = 0;
1926 if (pi != 0) {
1927 memset(&ops, 0, pi * sizeof(ops[0]));
1928 memset(g_labels, 0, pi * sizeof(g_labels[0]));
1929 pi = 0;
1930 }
1931 g_eqcnt = 0;
91977a1c 1932 continue;
1933 }
1934
1935 if (IS(words[1], "=")) {
1936 if (wordc != 5)
1937 aerr("unhandled equ, wc=%d\n", wordc);
1938 if (g_eqcnt >= eq_alloc) {
1939 eq_alloc *= 2;
1940 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
1941 my_assert_not(g_eqs, NULL);
1942 }
1943
1944 len = strlen(words[0]);
1945 if (len > sizeof(g_eqs[0].name) - 1)
1946 aerr("equ name too long: %d\n", len);
1947 strcpy(g_eqs[g_eqcnt].name, words[0]);
1948
1949 if (!IS(words[3], "ptr"))
1950 aerr("unhandled equ\n");
1951 if (IS(words[2], "dword"))
1952 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
1953 else if (IS(words[2], "word"))
1954 g_eqs[g_eqcnt].lmod = OPLM_WORD;
1955 else if (IS(words[2], "byte"))
1956 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
1957 else
1958 aerr("bad lmod: '%s'\n", words[2]);
1959
1960 g_eqs[g_eqcnt].offset = parse_number(words[4]);
1961 g_eqcnt++;
1962 continue;
1963 }
1964
1965 if (pi >= ARRAY_SIZE(ops))
1966 aerr("too many ops\n");
1967
1968 p = strchr(words[0], ':');
1969 if (p != NULL) {
1970 len = p - words[0];
1971 if (len > sizeof(g_labels[0]) - 1)
1972 aerr("label too long: %d\n", len);
1973 if (g_labels[pi][0] != 0)
1974 aerr("dupe label?\n");
1975 memcpy(g_labels[pi], words[0], len);
1976 g_labels[pi][len] = 0;
1977 continue;
1978 }
1979
1980 parse_op(&ops[pi], words, wordc);
1981 pi++;
1982
1983 (void)proto_parse;
1984 }
1985
1986 fclose(fout);
1987 fclose(fasm);
1988 fclose(fhdr);
1989
1990 return 0;
c36e914d 1991}
91977a1c 1992
1993// vim:ts=2:shiftwidth=2:expandtab