translate: fixes for call reg tracking
[ia32rtools.git] / tools / translate.c
CommitLineData
7637b6cc 1/*
2 * ia32rtools
2c10ea1f 3 * (C) notaz, 2013-2015
7637b6cc 4 *
5 * This work is licensed under the terms of 3-clause BSD license.
6 * See COPYING file in the top-level directory.
7 */
8
33c35af6 9#define _GNU_SOURCE
c36e914d 10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13
14#include "my_assert.h"
15#include "my_str.h"
9ea60b8d 16#include "common.h"
c36e914d 17
18#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
19#define IS(w, y) !strcmp(w, y)
39b168b8 20#define IS_START(w, y) !strncmp(w, y, strlen(y))
c36e914d 21
22#include "protoparse.h"
23
06c5d854 24static const char *asmfn;
c36e914d 25static int asmln;
06c5d854 26static FILE *g_fhdr;
c36e914d 27
940e8e66 28#define anote(fmt, ...) \
29 printf("%s:%d: note: " fmt, asmfn, asmln, ##__VA_ARGS__)
c36e914d 30#define awarn(fmt, ...) \
940e8e66 31 printf("%s:%d: warning: " fmt, asmfn, asmln, ##__VA_ARGS__)
c36e914d 32#define aerr(fmt, ...) do { \
940e8e66 33 printf("%s:%d: error: " fmt, asmfn, asmln, ##__VA_ARGS__); \
33c35af6 34 fcloseall(); \
c36e914d 35 exit(1); \
36} while (0)
37
054f95b2 38#include "masm_tools.h"
39
69a3cdfc 40enum op_flags {
5e49b270 41 OPF_RMD = (1 << 0), /* removed from code generation */
87bf6cec 42 OPF_DATA = (1 << 1), /* data processing - writes to dst opr */
43 OPF_FLAGS = (1 << 2), /* sets flags */
5c024ef7 44 OPF_JMP = (1 << 3), /* branch, call */
04abc5d6 45 OPF_CJMP = (1 << 4), /* cond. branch (cc or jecxz/loop) */
5c024ef7 46 OPF_CC = (1 << 5), /* uses flags */
47 OPF_TAIL = (1 << 6), /* ret or tail call */
48 OPF_RSAVE = (1 << 7), /* push/pop is local reg save/load */
49 OPF_REP = (1 << 8), /* prefixed by rep */
50 OPF_REPZ = (1 << 9), /* rep is repe/repz */
51 OPF_REPNZ = (1 << 10), /* rep is repne/repnz */
9af2d373 52 OPF_FARG = (1 << 11), /* push collected as func arg */
53 OPF_FARGNR = (1 << 12), /* push collected as func arg (no reuse) */
54 OPF_EBP_S = (1 << 13), /* ebp used as scratch here, not BP */
55 OPF_DF = (1 << 14), /* DF flag set */
56 OPF_ATAIL = (1 << 15), /* tail call with reused arg frame */
57 OPF_32BIT = (1 << 16), /* 32bit division */
58 OPF_LOCK = (1 << 17), /* op has lock prefix */
59 OPF_VAPUSH = (1 << 18), /* vararg ptr push (as call arg) */
26677139 60 OPF_DONE = (1 << 19), /* already fully handled by analysis */
25a330eb 61 OPF_PPUSH = (1 << 20), /* part of complex push-pop graph */
b2bd20c0 62 OPF_NOREGS = (1 << 21), /* don't track regs of this op */
d4a985bd 63 OPF_FPUSH = (1 << 22), /* pushes x87 stack */
64 OPF_FPOP = (1 << 23), /* pops x87 stack */
65 OPF_FSHIFT = (1 << 24), /* x87 stack shift is actually needed */
c36e914d 66};
67
68enum op_op {
69 OP_INVAL,
33c35af6 70 OP_NOP,
c36e914d 71 OP_PUSH,
72 OP_POP,
591721d7 73 OP_LEAVE,
c36e914d 74 OP_MOV,
850c9265 75 OP_LEA,
76 OP_MOVZX,
77 OP_MOVSX,
108e9fe3 78 OP_XCHG,
850c9265 79 OP_NOT,
04abc5d6 80 OP_XLAT,
5101a5f9 81 OP_CDQ,
092f64e1 82 OP_LODS,
33c35af6 83 OP_STOS,
d4e3b5db 84 OP_MOVS,
7ba45c34 85 OP_CMPS,
591721d7 86 OP_SCAS,
87 OP_STD,
88 OP_CLD,
c36e914d 89 OP_RET,
90 OP_ADD,
91977a1c 91 OP_SUB,
850c9265 92 OP_AND,
93 OP_OR,
94 OP_XOR,
95 OP_SHL,
96 OP_SHR,
97 OP_SAR,
04abc5d6 98 OP_SHLD,
3b2f4044 99 OP_SHRD,
d4e3b5db 100 OP_ROL,
101 OP_ROR,
cb090db0 102 OP_RCL,
103 OP_RCR,
69a3cdfc 104 OP_ADC,
850c9265 105 OP_SBB,
1f84f6b3 106 OP_BSF,
850c9265 107 OP_INC,
108 OP_DEC,
5101a5f9 109 OP_NEG,
850c9265 110 OP_MUL,
111 OP_IMUL,
5101a5f9 112 OP_DIV,
113 OP_IDIV,
c36e914d 114 OP_TEST,
115 OP_CMP,
116 OP_CALL,
117 OP_JMP,
5c024ef7 118 OP_JECXZ,
04abc5d6 119 OP_LOOP,
092f64e1 120 OP_JCC,
121 OP_SCC,
d4a985bd 122 // x87
123 OP_FLD,
124 OP_FILD,
125 OP_FLDc,
126 OP_FST,
127 OP_FADD,
128 OP_FDIV,
129 OP_FMUL,
130 OP_FSUB,
131 OP_FDIVR,
132 OP_FSUBR,
133 OP_FIADD,
134 OP_FIDIV,
135 OP_FIMUL,
136 OP_FISUB,
137 OP_FIDIVR,
138 OP_FISUBR,
139 // mmx
140 OP_EMMS,
141 // pseudo-ops for lib calls
142 OPP_FTOL,
143 // undefined
144 OP_UD2,
c36e914d 145};
146
147enum opr_type {
87bf6cec 148 OPT_UNSPEC,
149 OPT_REG,
150 OPT_REGMEM,
151 OPT_LABEL,
850c9265 152 OPT_OFFSET,
87bf6cec 153 OPT_CONST,
c36e914d 154};
155
2b43685d 156// must be sorted (larger len must be further in enum)
c36e914d 157enum opr_lenmod {
91977a1c 158 OPLM_UNSPEC,
159 OPLM_BYTE,
160 OPLM_WORD,
161 OPLM_DWORD,
90307a99 162 OPLM_QWORD,
c36e914d 163};
164
e83ea7ed 165#define MAX_EXITS 128
166
850c9265 167#define MAX_OPERANDS 3
92d715b6 168#define NAMELEN 112
c36e914d 169
b2bd20c0 170#define OPR_INIT(type_, lmod_, reg_) \
171 { type_, lmod_, reg_, }
172
c36e914d 173struct parsed_opr {
91977a1c 174 enum opr_type type;
175 enum opr_lenmod lmod;
b2bd20c0 176 int reg;
7ba45c34 177 unsigned int is_ptr:1; // pointer in C
178 unsigned int is_array:1; // array in C
a3684be1 179 unsigned int type_from_var:1; // .. in header, sometimes wrong
2b43685d 180 unsigned int size_mismatch:1; // type override differs from C
181 unsigned int size_lt:1; // type override is larger than C
ddaf8bd7 182 unsigned int had_ds:1; // had ds: prefix
c7ed83dd 183 const struct parsed_proto *pp; // for OPT_LABEL
91977a1c 184 unsigned int val;
92d715b6 185 char name[NAMELEN];
c36e914d 186};
187
188struct parsed_op {
91977a1c 189 enum op_op op;
190 struct parsed_opr operand[MAX_OPERANDS];
69a3cdfc 191 unsigned int flags;
092f64e1 192 unsigned char pfo;
193 unsigned char pfo_inv;
194 unsigned char operand_cnt;
3a5101d7 195 unsigned char p_argnum; // arg push: altered before call arg #
196 unsigned char p_arggrp; // arg push: arg group # for above
197 unsigned char p_argpass;// arg push: arg of host func
198 short p_argnext;// arg push: same arg pushed elsewhere or -1
69a3cdfc 199 int regmask_src; // all referensed regs
200 int regmask_dst;
940e8e66 201 int pfomask; // flagop: parsed_flag_op that can't be delayed
940e8e66 202 int cc_scratch; // scratch storage during analysis
4c45fa73 203 int bt_i; // branch target for branches
204 struct parsed_data *btj;// branch targets for jumptables
c7ed83dd 205 struct parsed_proto *pp;// parsed_proto for OP_CALL
91977a1c 206 void *datap;
8eb12e72 207 int asmln;
91977a1c 208};
209
69a3cdfc 210// datap:
865f1aca 211// on start: function/data type hint (sctproto)
212// after analysis:
2c10ea1f 213// (OPF_CC) - points to one of (OPF_FLAGS) that affects cc op
25a330eb 214// OP_PUSH - points to OP_POP in complex push/pop graph
215// OP_POP - points to OP_PUSH in simple push/pop pair
69a3cdfc 216
91977a1c 217struct parsed_equ {
218 char name[64];
219 enum opr_lenmod lmod;
220 int offset;
c36e914d 221};
222
4c45fa73 223struct parsed_data {
224 char label[256];
225 enum opr_type type;
226 enum opr_lenmod lmod;
227 int count;
228 int count_alloc;
229 struct {
230 union {
231 char *label;
63df67be 232 unsigned int val;
4c45fa73 233 } u;
234 int bt_i;
235 } *d;
236};
237
238struct label_ref {
239 int i;
240 struct label_ref *next;
241};
242
1bafb621 243enum ida_func_attr {
244 IDAFA_BP_FRAME = (1 << 0),
245 IDAFA_LIB_FUNC = (1 << 1),
246 IDAFA_STATIC = (1 << 2),
247 IDAFA_NORETURN = (1 << 3),
248 IDAFA_THUNK = (1 << 4),
249 IDAFA_FPD = (1 << 5),
250};
251
7e08c224 252enum sct_func_attr {
253 SCTFA_CLEAR_SF = (1 << 0), // clear stack frame
254};
255
d4a985bd 256enum x87_const {
257 X87_CONST_1 = 1,
258 X87_CONST_2T,
259 X87_CONST_2E,
260 X87_CONST_PI,
261 X87_CONST_LG2,
262 X87_CONST_LN2,
263 X87_CONST_Z,
264};
265
3a5101d7 266// note: limited to 32k due to p_argnext
267#define MAX_OPS 4096
268#define MAX_ARG_GRP 2
c36e914d 269
270static struct parsed_op ops[MAX_OPS];
91977a1c 271static struct parsed_equ *g_eqs;
272static int g_eqcnt;
d7857c3a 273static char *g_labels[MAX_OPS];
4c45fa73 274static struct label_ref g_label_refs[MAX_OPS];
bd96f656 275static const struct parsed_proto *g_func_pp;
4c45fa73 276static struct parsed_data *g_func_pd;
277static int g_func_pd_cnt;
d4a985bd 278static int g_func_lmods;
91977a1c 279static char g_func[256];
280static char g_comment[256];
281static int g_bp_frame;
1bafb621 282static int g_sp_frame;
a2c1d768 283static int g_stack_frame_used;
1bafb621 284static int g_stack_fsz;
4c45fa73 285static int g_ida_func_attr;
7e08c224 286static int g_sct_func_attr;
287static int g_stack_clear_start; // in dwords
288static int g_stack_clear_len;
30c8c549 289static int g_skip_func;
89ff3147 290static int g_allow_regfunc;
92d715b6 291static int g_quiet_pp;
9af2d373 292static int g_header_mode;
92d715b6 293
91977a1c 294#define ferr(op_, fmt, ...) do { \
bfacdc83 295 printf("%s:%d: error %u: [%s] '%s': " fmt, asmfn, (op_)->asmln, \
296 __LINE__, g_func, dump_op(op_), ##__VA_ARGS__); \
33c35af6 297 fcloseall(); \
91977a1c 298 exit(1); \
299} while (0)
de50b98b 300#define fnote(op_, fmt, ...) \
8eb12e72 301 printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
de50b98b 302 dump_op(op_), ##__VA_ARGS__)
91977a1c 303
26677139 304#define ferr_assert(op_, cond) do { \
2b70f6d3 305 if (!(cond)) ferr(op_, "assertion '%s' failed\n", #cond); \
26677139 306} while (0)
307
90307a99 308const char *regs_r32[] = {
309 "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
310 // not r32, but list here for easy parsing and printing
311 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
d4a985bd 312 "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"
90307a99 313};
91977a1c 314const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
315const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
316const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
317
d4a985bd 318enum x86_regs {
319 xUNSPEC = -1,
320 xAX, xBX, xCX, xDX,
321 xSI, xDI, xBP, xSP,
322 xMM0, xMM1, xMM2, xMM3, // mmx
323 xMM4, xMM5, xMM6, xMM7,
324 xST0, xST1, xST2, xST3, // x87
325 xST4, xST5, xST6, xST7,
326};
327
328#define mxAX (1 << xAX)
329#define mxDX (1 << xDX)
330#define mxST0 (1 << xST0)
331#define mxST1 (1 << xST1)
91977a1c 332
69a3cdfc 333// possible basic comparison types (without inversion)
334enum parsed_flag_op {
335 PFO_O, // 0 OF=1
336 PFO_C, // 2 CF=1
337 PFO_Z, // 4 ZF=1
338 PFO_BE, // 6 CF=1||ZF=1
339 PFO_S, // 8 SF=1
340 PFO_P, // a PF=1
341 PFO_L, // c SF!=OF
342 PFO_LE, // e ZF=1||SF!=OF
343};
344
90307a99 345#define PFOB_O (1 << PFO_O)
346#define PFOB_C (1 << PFO_C)
347#define PFOB_Z (1 << PFO_Z)
348#define PFOB_S (1 << PFO_S)
349
69a3cdfc 350static const char *parsed_flag_op_names[] = {
351 "o", "c", "z", "be", "s", "p", "l", "le"
352};
353
91977a1c 354static int char_array_i(const char *array[], size_t len, const char *s)
355{
356 int i;
c36e914d 357
91977a1c 358 for (i = 0; i < len; i++)
359 if (IS(s, array[i]))
360 return i;
c36e914d 361
91977a1c 362 return -1;
363}
364
63df67be 365static void printf_number(char *buf, size_t buf_size,
366 unsigned long number)
91977a1c 367{
5101a5f9 368 // output in C-friendly form
369 snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
370}
91977a1c 371
fdd5548a 372static int check_segment_prefix(const char *s)
373{
374 if (s[0] == 0 || s[1] != 's' || s[2] != ':')
375 return 0;
376
377 switch (s[0]) {
378 case 'c': return 1;
379 case 'd': return 2;
380 case 's': return 3;
381 case 'e': return 4;
382 case 'f': return 5;
383 case 'g': return 6;
384 default: return 0;
385 }
386}
387
5101a5f9 388static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
389{
390 int reg;
91977a1c 391
5101a5f9 392 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
90307a99 393 if (reg >= 8) {
394 *reg_lmod = OPLM_QWORD;
395 return reg;
396 }
5101a5f9 397 if (reg >= 0) {
398 *reg_lmod = OPLM_DWORD;
399 return reg;
91977a1c 400 }
5101a5f9 401 reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
402 if (reg >= 0) {
403 *reg_lmod = OPLM_WORD;
404 return reg;
405 }
406 reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
407 if (reg >= 0) {
408 *reg_lmod = OPLM_BYTE;
409 return reg;
410 }
411 reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
412 if (reg >= 0) {
413 *reg_lmod = OPLM_BYTE;
414 return reg;
850c9265 415 }
416
417 return -1;
91977a1c 418}
419
5101a5f9 420static int parse_indmode(char *name, int *regmask, int need_c_cvt)
421{
422 enum opr_lenmod lmod;
423 char cvtbuf[256];
424 char *d = cvtbuf;
425 char *s = name;
426 char w[64];
427 long number;
428 int reg;
429 int c = 0;
430
431 *d = 0;
432
433 while (*s != 0) {
434 d += strlen(d);
435 while (my_isblank(*s))
436 s++;
437 for (; my_issep(*s); d++, s++)
438 *d = *s;
439 while (my_isblank(*s))
440 s++;
441 *d = 0;
442
fdd5548a 443 // skip '?s:' prefixes
444 if (check_segment_prefix(s))
87bf6cec 445 s += 3;
446
5101a5f9 447 s = next_idt(w, sizeof(w), s);
448 if (w[0] == 0)
449 break;
450 c++;
451
452 reg = parse_reg(&lmod, w);
453 if (reg >= 0) {
454 *regmask |= 1 << reg;
455 goto pass;
456 }
457
458 if ('0' <= w[0] && w[0] <= '9') {
459 number = parse_number(w);
460 printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
461 continue;
462 }
463
464 // probably some label/identifier - pass
465
466pass:
467 snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
468 }
469
470 if (need_c_cvt)
471 strcpy(name, cvtbuf);
472
473 return c;
474}
475
4c45fa73 476static int is_reg_in_str(const char *s)
477{
478 int i;
479
480 if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
481 return 0;
482
483 for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
484 if (!strncmp(s, regs_r32[i], 3))
485 return 1;
486
487 return 0;
488}
489
09bc6fd5 490static const char *parse_stack_el(const char *name, char *extra_reg,
491 int early_try)
d4e3b5db 492{
4c45fa73 493 const char *p, *p2, *s;
1bafb621 494 char *endp = NULL;
d4e3b5db 495 char buf[32];
1bafb621 496 long val;
d4e3b5db 497 int len;
498
09bc6fd5 499 if (g_bp_frame || early_try)
500 {
501 p = name;
502 if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
503 p += 4;
504 if (extra_reg != NULL) {
505 strncpy(extra_reg, name, 3);
506 extra_reg[4] = 0;
507 }
4c45fa73 508 }
4c45fa73 509
09bc6fd5 510 if (IS_START(p, "ebp+")) {
511 p += 4;
4c45fa73 512
09bc6fd5 513 p2 = strchr(p, '+');
514 if (p2 != NULL && is_reg_in_str(p)) {
515 if (extra_reg != NULL) {
516 strncpy(extra_reg, p, p2 - p);
517 extra_reg[p2 - p] = 0;
518 }
519 p = p2 + 1;
4c45fa73 520 }
4c45fa73 521
09bc6fd5 522 if (!('0' <= *p && *p <= '9'))
523 return p;
4c45fa73 524
09bc6fd5 525 return NULL;
526 }
4c45fa73 527 }
528
39b168b8 529 if (!IS_START(name, "esp+"))
d4e3b5db 530 return NULL;
531
037f4971 532 s = name + 4;
533 p = strchr(s, '+');
d4e3b5db 534 if (p) {
037f4971 535 if (is_reg_in_str(s)) {
536 if (extra_reg != NULL) {
537 strncpy(extra_reg, s, p - s);
538 extra_reg[p - s] = 0;
539 }
540 s = p + 1;
541 p = strchr(s, '+');
542 if (p == NULL)
543 aerr("%s IDA stackvar not set?\n", __func__);
544 }
1bafb621 545 if (!('0' <= *s && *s <= '9')) {
037f4971 546 aerr("%s IDA stackvar offset not set?\n", __func__);
d4e3b5db 547 return NULL;
1bafb621 548 }
549 if (s[0] == '0' && s[1] == 'x')
550 s += 2;
551 len = p - s;
d4e3b5db 552 if (len < sizeof(buf) - 1) {
1bafb621 553 strncpy(buf, s, len);
d4e3b5db 554 buf[len] = 0;
1bafb621 555 val = strtol(buf, &endp, 16);
556 if (val == 0 || *endp != 0) {
557 aerr("%s num parse fail for '%s'\n", __func__, buf);
558 return NULL;
559 }
d4e3b5db 560 }
561 p++;
562 }
563 else
564 p = name + 4;
565
566 if ('0' <= *p && *p <= '9')
567 return NULL;
568
569 return p;
570}
571
850c9265 572static int guess_lmod_from_name(struct parsed_opr *opr)
573{
04abc5d6 574 if (IS_START(opr->name, "dword_") || IS_START(opr->name, "off_")) {
850c9265 575 opr->lmod = OPLM_DWORD;
576 return 1;
577 }
04abc5d6 578 if (IS_START(opr->name, "word_")) {
850c9265 579 opr->lmod = OPLM_WORD;
580 return 1;
581 }
04abc5d6 582 if (IS_START(opr->name, "byte_")) {
850c9265 583 opr->lmod = OPLM_BYTE;
584 return 1;
585 }
04abc5d6 586 if (IS_START(opr->name, "qword_")) {
90307a99 587 opr->lmod = OPLM_QWORD;
588 return 1;
589 }
850c9265 590 return 0;
591}
592
3ebea2cf 593static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
594 const struct parsed_type *c_type)
06c5d854 595{
06c5d854 596 static const char *dword_types[] = {
c0de9015 597 "uint32_t", "int", "_DWORD", "UINT_PTR", "DWORD",
4741fdfe 598 "WPARAM", "LPARAM", "UINT", "__int32",
09bc6fd5 599 "LONG", "HIMC", "BOOL", "size_t",
feb0ee5d 600 "float",
06c5d854 601 };
602 static const char *word_types[] = {
fe18709a 603 "uint16_t", "int16_t", "_WORD", "WORD",
2b43685d 604 "unsigned __int16", "__int16",
06c5d854 605 };
606 static const char *byte_types[] = {
2b43685d 607 "uint8_t", "int8_t", "char",
89ff3147 608 "unsigned __int8", "__int8", "BYTE", "_BYTE",
4741fdfe 609 "CHAR", "_UNKNOWN",
b4878d2b 610 // structures.. deal the same as with _UNKNOWN for now
611 "CRITICAL_SECTION",
06c5d854 612 };
3ebea2cf 613 const char *n;
06c5d854 614 int i;
615
3ebea2cf 616 if (c_type->is_ptr) {
617 *lmod = OPLM_DWORD;
06c5d854 618 return 1;
619 }
620
3ebea2cf 621 n = skip_type_mod(c_type->name);
06c5d854 622
3ebea2cf 623 for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
624 if (IS(n, dword_types[i])) {
625 *lmod = OPLM_DWORD;
06c5d854 626 return 1;
627 }
628 }
629
630 for (i = 0; i < ARRAY_SIZE(word_types); i++) {
3ebea2cf 631 if (IS(n, word_types[i])) {
632 *lmod = OPLM_WORD;
06c5d854 633 return 1;
634 }
635 }
636
637 for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
3ebea2cf 638 if (IS(n, byte_types[i])) {
639 *lmod = OPLM_BYTE;
06c5d854 640 return 1;
641 }
642 }
643
06c5d854 644 return 0;
645}
646
c7ed83dd 647static char *default_cast_to(char *buf, size_t buf_size,
648 struct parsed_opr *opr)
649{
650 buf[0] = 0;
651
865f1aca 652 if (!opr->is_ptr || strchr(opr->name, '['))
c7ed83dd 653 return buf;
654 if (opr->pp == NULL || opr->pp->type.name == NULL
655 || opr->pp->is_fptr)
656 {
657 snprintf(buf, buf_size, "%s", "(void *)");
658 return buf;
659 }
660
661 snprintf(buf, buf_size, "(%s)", opr->pp->type.name);
662 return buf;
663}
664
4c45fa73 665static enum opr_type lmod_from_directive(const char *d)
666{
667 if (IS(d, "dd"))
668 return OPLM_DWORD;
669 else if (IS(d, "dw"))
670 return OPLM_WORD;
671 else if (IS(d, "db"))
672 return OPLM_BYTE;
673
674 aerr("unhandled directive: '%s'\n", d);
675 return OPLM_UNSPEC;
676}
677
5101a5f9 678static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
679 int *regmask)
680{
681 opr->type = OPT_REG;
682 opr->reg = reg;
683 opr->lmod = lmod;
684 *regmask |= 1 << reg;
685}
686
39b168b8 687static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
688 int *extra_offs);
87bf6cec 689
69a3cdfc 690static int parse_operand(struct parsed_opr *opr,
691 int *regmask, int *regmask_indirect,
1bafb621 692 char words[16][256], int wordc, int w, unsigned int op_flags)
c36e914d 693{
92d715b6 694 const struct parsed_proto *pp = NULL;
850c9265 695 enum opr_lenmod tmplmod;
63df67be 696 unsigned long number;
89ff3147 697 char buf[256];
850c9265 698 int ret, len;
1bafb621 699 int wordc_in;
89ff3147 700 char *p;
850c9265 701 int i;
c36e914d 702
1bafb621 703 if (w >= wordc)
704 aerr("parse_operand w %d, wordc %d\n", w, wordc);
c36e914d 705
1bafb621 706 opr->reg = xUNSPEC;
91977a1c 707
1bafb621 708 for (i = w; i < wordc; i++) {
709 len = strlen(words[i]);
710 if (words[i][len - 1] == ',') {
711 words[i][len - 1] = 0;
712 wordc = i + 1;
713 break;
714 }
715 }
c36e914d 716
1bafb621 717 wordc_in = wordc - w;
c36e914d 718
1bafb621 719 if ((op_flags & OPF_JMP) && wordc_in > 0
720 && !('0' <= words[w][0] && words[w][0] <= '9'))
721 {
722 const char *label = NULL;
723
724 if (wordc_in == 3 && !strncmp(words[w], "near", 4)
725 && IS(words[w + 1], "ptr"))
726 label = words[w + 2];
727 else if (wordc_in == 2 && IS(words[w], "short"))
728 label = words[w + 1];
729 else if (wordc_in == 1
730 && strchr(words[w], '[') == NULL
731 && parse_reg(&tmplmod, words[w]) < 0)
732 label = words[w];
733
734 if (label != NULL) {
735 opr->type = OPT_LABEL;
fdd5548a 736 ret = check_segment_prefix(label);
737 if (ret != 0) {
738 if (ret >= 5)
739 aerr("fs/gs used\n");
ddaf8bd7 740 opr->had_ds = 1;
39b168b8 741 label += 3;
ddaf8bd7 742 }
1bafb621 743 strcpy(opr->name, label);
744 return wordc;
745 }
746 }
c36e914d 747
1bafb621 748 if (wordc_in >= 3) {
749 if (IS(words[w + 1], "ptr")) {
750 if (IS(words[w], "dword"))
751 opr->lmod = OPLM_DWORD;
752 else if (IS(words[w], "word"))
753 opr->lmod = OPLM_WORD;
754 else if (IS(words[w], "byte"))
755 opr->lmod = OPLM_BYTE;
90307a99 756 else if (IS(words[w], "qword"))
757 opr->lmod = OPLM_QWORD;
1bafb621 758 else
759 aerr("type parsing failed\n");
760 w += 2;
761 wordc_in = wordc - w;
762 }
763 }
764
39b168b8 765 if (wordc_in == 2) {
766 if (IS(words[w], "offset")) {
767 opr->type = OPT_OFFSET;
27ebfaed 768 opr->lmod = OPLM_DWORD;
39b168b8 769 strcpy(opr->name, words[w + 1]);
27ebfaed 770 pp = proto_parse(g_fhdr, opr->name, 1);
771 goto do_label;
39b168b8 772 }
773 if (IS(words[w], "(offset")) {
89ff3147 774 p = strchr(words[w + 1], ')');
39b168b8 775 if (p == NULL)
776 aerr("parse of bracketed offset failed\n");
777 *p = 0;
778 opr->type = OPT_OFFSET;
779 strcpy(opr->name, words[w + 1]);
780 return wordc;
781 }
1bafb621 782 }
c36e914d 783
1bafb621 784 if (wordc_in != 1)
850c9265 785 aerr("parse_operand 1 word expected\n");
c36e914d 786
fdd5548a 787 ret = check_segment_prefix(words[w]);
788 if (ret != 0) {
789 if (ret >= 5)
790 aerr("fs/gs used\n");
ddaf8bd7 791 opr->had_ds = 1;
89ff3147 792 memmove(words[w], words[w] + 3, strlen(words[w]) - 2);
ddaf8bd7 793 }
89ff3147 794 strcpy(opr->name, words[w]);
c36e914d 795
850c9265 796 if (words[w][0] == '[') {
797 opr->type = OPT_REGMEM;
798 ret = sscanf(words[w], "[%[^]]]", opr->name);
799 if (ret != 1)
800 aerr("[] parse failure\n");
87bf6cec 801
5101a5f9 802 parse_indmode(opr->name, regmask_indirect, 1);
09bc6fd5 803 if (opr->lmod == OPLM_UNSPEC && parse_stack_el(opr->name, NULL, 1))
804 {
87bf6cec 805 // might be an equ
d4e3b5db 806 struct parsed_equ *eq =
09bc6fd5 807 equ_find(NULL, parse_stack_el(opr->name, NULL, 1), &i);
87bf6cec 808 if (eq)
809 opr->lmod = eq->lmod;
d4a985bd 810
811 // might be unaligned access
812 g_func_lmods |= 1 << OPLM_BYTE;
87bf6cec 813 }
850c9265 814 return wordc;
815 }
816 else if (strchr(words[w], '[')) {
817 // label[reg] form
89ff3147 818 p = strchr(words[w], '[');
850c9265 819 opr->type = OPT_REGMEM;
89ff3147 820 parse_indmode(p, regmask_indirect, 0);
821 strncpy(buf, words[w], p - words[w]);
822 buf[p - words[w]] = 0;
823 pp = proto_parse(g_fhdr, buf, 1);
824 goto do_label;
850c9265 825 }
826 else if (('0' <= words[w][0] && words[w][0] <= '9')
827 || words[w][0] == '-')
828 {
5101a5f9 829 number = parse_number(words[w]);
91977a1c 830 opr->type = OPT_CONST;
5101a5f9 831 opr->val = number;
832 printf_number(opr->name, sizeof(opr->name), number);
91977a1c 833 return wordc;
850c9265 834 }
c36e914d 835
5101a5f9 836 ret = parse_reg(&tmplmod, opr->name);
837 if (ret >= 0) {
838 setup_reg_opr(opr, ret, tmplmod, regmask);
850c9265 839 return wordc;
840 }
841
842 // most likely var in data segment
843 opr->type = OPT_LABEL;
92d715b6 844 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
89ff3147 845
846do_label:
bd96f656 847 if (pp != NULL) {
1cd4a663 848 if (pp->is_fptr || pp->is_func) {
06c5d854 849 opr->lmod = OPLM_DWORD;
850 opr->is_ptr = 1;
851 }
2b43685d 852 else {
840257f6 853 tmplmod = OPLM_UNSPEC;
bd96f656 854 if (!guess_lmod_from_c_type(&tmplmod, &pp->type))
2b43685d 855 anote("unhandled C type '%s' for '%s'\n",
bd96f656 856 pp->type.name, opr->name);
2b43685d 857
a3684be1 858 if (opr->lmod == OPLM_UNSPEC) {
2b43685d 859 opr->lmod = tmplmod;
a3684be1 860 opr->type_from_var = 1;
861 }
2b43685d 862 else if (opr->lmod != tmplmod) {
863 opr->size_mismatch = 1;
864 if (tmplmod < opr->lmod)
865 opr->size_lt = 1;
866 }
a652aa9f 867 opr->is_ptr = pp->type.is_ptr;
3ebea2cf 868 }
bd96f656 869 opr->is_array = pp->type.is_array;
06c5d854 870 }
c7ed83dd 871 opr->pp = pp;
06c5d854 872
850c9265 873 if (opr->lmod == OPLM_UNSPEC)
874 guess_lmod_from_name(opr);
850c9265 875 return wordc;
c36e914d 876}
877
33c35af6 878static const struct {
879 const char *name;
880 unsigned int flags;
881} pref_table[] = {
882 { "rep", OPF_REP },
7ba45c34 883 { "repe", OPF_REP|OPF_REPZ },
884 { "repz", OPF_REP|OPF_REPZ },
885 { "repne", OPF_REP|OPF_REPNZ },
886 { "repnz", OPF_REP|OPF_REPNZ },
037f4971 887 { "lock", OPF_LOCK }, // ignored for now..
33c35af6 888};
889
5c024ef7 890#define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
891
c36e914d 892static const struct {
850c9265 893 const char *name;
894 enum op_op op;
092f64e1 895 unsigned short minopr;
896 unsigned short maxopr;
69a3cdfc 897 unsigned int flags;
092f64e1 898 unsigned char pfo;
899 unsigned char pfo_inv;
c36e914d 900} op_table[] = {
33c35af6 901 { "nop", OP_NOP, 0, 0, 0 },
69a3cdfc 902 { "push", OP_PUSH, 1, 1, 0 },
903 { "pop", OP_POP, 1, 1, OPF_DATA },
591721d7 904 { "leave",OP_LEAVE, 0, 0, OPF_DATA },
69a3cdfc 905 { "mov" , OP_MOV, 2, 2, OPF_DATA },
906 { "lea", OP_LEA, 2, 2, OPF_DATA },
907 { "movzx",OP_MOVZX, 2, 2, OPF_DATA },
908 { "movsx",OP_MOVSX, 2, 2, OPF_DATA },
108e9fe3 909 { "xchg", OP_XCHG, 2, 2, OPF_DATA },
69a3cdfc 910 { "not", OP_NOT, 1, 1, OPF_DATA },
04abc5d6 911 { "xlat", OP_XLAT, 0, 0, OPF_DATA },
5101a5f9 912 { "cdq", OP_CDQ, 0, 0, OPF_DATA },
092f64e1 913 { "lodsb",OP_LODS, 0, 0, OPF_DATA },
914 { "lodsw",OP_LODS, 0, 0, OPF_DATA },
915 { "lodsd",OP_LODS, 0, 0, OPF_DATA },
33c35af6 916 { "stosb",OP_STOS, 0, 0, OPF_DATA },
917 { "stosw",OP_STOS, 0, 0, OPF_DATA },
918 { "stosd",OP_STOS, 0, 0, OPF_DATA },
d4e3b5db 919 { "movsb",OP_MOVS, 0, 0, OPF_DATA },
920 { "movsw",OP_MOVS, 0, 0, OPF_DATA },
921 { "movsd",OP_MOVS, 0, 0, OPF_DATA },
7ba45c34 922 { "cmpsb",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
923 { "cmpsw",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
924 { "cmpsd",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
591721d7 925 { "scasb",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
926 { "scasw",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
927 { "scasd",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
928 { "std", OP_STD, 0, 0, OPF_DATA }, // special flag
929 { "cld", OP_CLD, 0, 0, OPF_DATA },
69a3cdfc 930 { "add", OP_ADD, 2, 2, OPF_DATA|OPF_FLAGS },
931 { "sub", OP_SUB, 2, 2, OPF_DATA|OPF_FLAGS },
932 { "and", OP_AND, 2, 2, OPF_DATA|OPF_FLAGS },
933 { "or", OP_OR, 2, 2, OPF_DATA|OPF_FLAGS },
934 { "xor", OP_XOR, 2, 2, OPF_DATA|OPF_FLAGS },
935 { "shl", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
936 { "shr", OP_SHR, 2, 2, OPF_DATA|OPF_FLAGS },
937 { "sal", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
938 { "sar", OP_SAR, 2, 2, OPF_DATA|OPF_FLAGS },
04abc5d6 939 { "shld", OP_SHLD, 3, 3, OPF_DATA|OPF_FLAGS },
3b2f4044 940 { "shrd", OP_SHRD, 3, 3, OPF_DATA|OPF_FLAGS },
d4e3b5db 941 { "rol", OP_ROL, 2, 2, OPF_DATA|OPF_FLAGS },
942 { "ror", OP_ROR, 2, 2, OPF_DATA|OPF_FLAGS },
092f64e1 943 { "rcl", OP_RCL, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
944 { "rcr", OP_RCR, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
945 { "adc", OP_ADC, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
946 { "sbb", OP_SBB, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1f84f6b3 947 { "bsf", OP_BSF, 2, 2, OPF_DATA|OPF_FLAGS },
69a3cdfc 948 { "inc", OP_INC, 1, 1, OPF_DATA|OPF_FLAGS },
949 { "dec", OP_DEC, 1, 1, OPF_DATA|OPF_FLAGS },
5101a5f9 950 { "neg", OP_NEG, 1, 1, OPF_DATA|OPF_FLAGS },
951 { "mul", OP_MUL, 1, 1, OPF_DATA|OPF_FLAGS },
69a3cdfc 952 { "imul", OP_IMUL, 1, 3, OPF_DATA|OPF_FLAGS },
5101a5f9 953 { "div", OP_DIV, 1, 1, OPF_DATA|OPF_FLAGS },
954 { "idiv", OP_IDIV, 1, 1, OPF_DATA|OPF_FLAGS },
69a3cdfc 955 { "test", OP_TEST, 2, 2, OPF_FLAGS },
956 { "cmp", OP_CMP, 2, 2, OPF_FLAGS },
a3684be1 957 { "retn", OP_RET, 0, 1, OPF_TAIL },
de50b98b 958 { "call", OP_CALL, 1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
69a3cdfc 959 { "jmp", OP_JMP, 1, 1, OPF_JMP },
5c024ef7 960 { "jecxz",OP_JECXZ, 1, 1, OPF_JMP|OPF_CJMP },
04abc5d6 961 { "loop", OP_LOOP, 1, 1, OPF_JMP|OPF_CJMP|OPF_DATA },
092f64e1 962 { "jo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 0 }, // 70 OF=1
963 { "jno", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 1 }, // 71 OF=0
964 { "jc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72 CF=1
965 { "jb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72
966 { "jnc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73 CF=0
967 { "jnb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
968 { "jae", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
969 { "jz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74 ZF=1
970 { "je", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74
971 { "jnz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75 ZF=0
972 { "jne", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75
973 { "jbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76 CF=1||ZF=1
974 { "jna", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76
975 { "ja", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77 CF=0&&ZF=0
976 { "jnbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77
977 { "js", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 0 }, // 78 SF=1
978 { "jns", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 1 }, // 79 SF=0
979 { "jp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a PF=1
980 { "jpe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a
981 { "jnp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b PF=0
982 { "jpo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b
983 { "jl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c SF!=OF
984 { "jnge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c
985 { "jge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d SF=OF
986 { "jnl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d
987 { "jle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e ZF=1||SF!=OF
988 { "jng", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e
989 { "jg", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f ZF=0&&SF=OF
990 { "jnle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f
991 { "seto", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 0 },
992 { "setno", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 1 },
993 { "setc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
994 { "setb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
995 { "setnc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
996 { "setae", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
997 { "setnb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
998 { "setz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
999 { "sete", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1000 { "setnz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1001 { "setne", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1002 { "setbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1003 { "setna", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1004 { "seta", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1005 { "setnbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1006 { "sets", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 0 },
1007 { "setns", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 1 },
1008 { "setp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1009 { "setpe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1010 { "setnp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1011 { "setpo", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1012 { "setl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1013 { "setnge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1014 { "setge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1015 { "setnl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1016 { "setle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1017 { "setng", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1018 { "setg", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1019 { "setnle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
90307a99 1020 // x87
d4a985bd 1021 { "fld", OP_FLD, 1, 1, OPF_FPUSH },
1022 { "fild", OP_FILD, 1, 1, OPF_FPUSH },
1023 { "fld1", OP_FLDc, 0, 0, OPF_FPUSH },
1024 { "fldz", OP_FLDc, 0, 0, OPF_FPUSH },
1025 { "fstp", OP_FST, 1, 1, OPF_FPOP },
1026 { "fst", OP_FST, 1, 1, 0 },
1027 { "fadd", OP_FADD, 0, 2, 0 },
1028 { "faddp", OP_FADD, 0, 2, OPF_FPOP },
1029 { "fdiv", OP_FDIV, 0, 2, 0 },
1030 { "fdivp", OP_FDIV, 0, 2, OPF_FPOP },
1031 { "fmul", OP_FMUL, 0, 2, 0 },
1032 { "fmulp", OP_FMUL, 0, 2, OPF_FPOP },
1033 { "fsub", OP_FSUB, 0, 2, 0 },
1034 { "fsubp", OP_FSUB, 0, 2, OPF_FPOP },
1035 { "fdivr", OP_FDIVR, 0, 2, 0 },
1036 { "fdivrp", OP_FDIVR, 0, 2, OPF_FPOP },
1037 { "fsubr", OP_FSUBR, 0, 2, 0 },
1038 { "fsubrp", OP_FSUBR, 0, 2, OPF_FPOP },
1039 { "fiadd", OP_FIADD, 1, 1, 0 },
1040 { "fidiv", OP_FIDIV, 1, 1, 0 },
1041 { "fimul", OP_FIMUL, 1, 1, 0 },
1042 { "fisub", OP_FISUB, 1, 1, 0 },
1043 { "fidivr", OP_FIDIVR, 1, 1, 0 },
1044 { "fisubr", OP_FISUBR, 1, 1, 0 },
90307a99 1045 // mmx
d4a985bd 1046 { "emms", OP_EMMS, 0, 0, OPF_DATA },
1047 { "movq", OP_MOV, 2, 2, OPF_DATA },
1048 // pseudo-ops for lib calls
1049 { "_ftol", OPP_FTOL },
2c10ea1f 1050 // must be last
1051 { "ud2", OP_UD2 },
69a3cdfc 1052};
c36e914d 1053
1054static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
1055{
bfa4a6ee 1056 enum opr_lenmod lmod = OPLM_UNSPEC;
33c35af6 1057 int prefix_flags = 0;
69a3cdfc 1058 int regmask_ind;
1059 int regmask;
33c35af6 1060 int op_w = 0;
91977a1c 1061 int opr = 0;
33c35af6 1062 int w = 0;
acd03176 1063 int i, j;
c36e914d 1064
33c35af6 1065 for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
1066 if (IS(words[w], pref_table[i].name)) {
1067 prefix_flags = pref_table[i].flags;
1068 break;
1069 }
1070 }
1071
1072 if (prefix_flags) {
1073 if (wordc <= 1)
1074 aerr("lone prefix: '%s'\n", words[0]);
1075 w++;
1076 }
1077
1078 op_w = w;
91977a1c 1079 for (i = 0; i < ARRAY_SIZE(op_table); i++) {
33c35af6 1080 if (IS(words[w], op_table[i].name))
69a3cdfc 1081 break;
1082 }
c36e914d 1083
2c10ea1f 1084 if (i == ARRAY_SIZE(op_table)) {
30c8c549 1085 if (!g_skip_func)
1086 aerr("unhandled op: '%s'\n", words[0]);
2c10ea1f 1087 i--; // OP_UD2
1088 }
33c35af6 1089 w++;
c36e914d 1090
69a3cdfc 1091 op->op = op_table[i].op;
33c35af6 1092 op->flags = op_table[i].flags | prefix_flags;
092f64e1 1093 op->pfo = op_table[i].pfo;
1094 op->pfo_inv = op_table[i].pfo_inv;
69a3cdfc 1095 op->regmask_src = op->regmask_dst = 0;
8eb12e72 1096 op->asmln = asmln;
69a3cdfc 1097
2c10ea1f 1098 if (op->op == OP_UD2)
1099 return;
1100
92d715b6 1101 for (opr = 0; opr < op_table[i].maxopr; opr++) {
1102 if (opr >= op_table[i].minopr && w >= wordc)
1103 break;
1104
69a3cdfc 1105 regmask = regmask_ind = 0;
1106 w = parse_operand(&op->operand[opr], &regmask, &regmask_ind,
1107 words, wordc, w, op->flags);
1108
1109 if (opr == 0 && (op->flags & OPF_DATA))
1110 op->regmask_dst = regmask;
92d715b6 1111 else
1112 op->regmask_src |= regmask;
1113 op->regmask_src |= regmask_ind;
d4a985bd 1114
1115 if (op->operand[opr].lmod != OPLM_UNSPEC)
1116 g_func_lmods |= 1 << op->operand[opr].lmod;
91977a1c 1117 }
c36e914d 1118
91977a1c 1119 if (w < wordc)
1120 aerr("parse_op %s incomplete: %d/%d\n",
1121 words[0], w, wordc);
5101a5f9 1122
1123 // special cases
1124 op->operand_cnt = opr;
1125 if (!strncmp(op_table[i].name, "set", 3))
1126 op->operand[0].lmod = OPLM_BYTE;
1127
5101a5f9 1128 switch (op->op) {
92d715b6 1129 // first operand is not dst
1130 case OP_CMP:
1131 case OP_TEST:
1132 op->regmask_src |= op->regmask_dst;
1133 op->regmask_dst = 0;
1134 break;
1135
1136 // first operand is src too
1137 case OP_NOT:
1138 case OP_ADD:
1139 case OP_AND:
1140 case OP_OR:
1141 case OP_RCL:
1142 case OP_RCR:
1143 case OP_ADC:
1144 case OP_INC:
1145 case OP_DEC:
1146 case OP_NEG:
1147 // more below..
1148 op->regmask_src |= op->regmask_dst;
1149 break;
1150
1151 // special
1152 case OP_XCHG:
1153 op->regmask_src |= op->regmask_dst;
1154 op->regmask_dst |= op->regmask_src;
1155 goto check_align;
1156
1157 case OP_SUB:
1158 case OP_SBB:
1159 case OP_XOR:
1160 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1161 && op->operand[0].lmod == op->operand[1].lmod
1162 && op->operand[0].reg == op->operand[1].reg
1163 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1164 {
1165 op->regmask_src = 0;
1166 }
1167 else
1168 op->regmask_src |= op->regmask_dst;
1169 break;
1170
1171 // ops with implicit argumets
04abc5d6 1172 case OP_XLAT:
1173 op->operand_cnt = 2;
1174 setup_reg_opr(&op->operand[0], xAX, OPLM_BYTE, &op->regmask_src);
1175 op->regmask_dst = op->regmask_src;
3947cf24 1176 setup_reg_opr(&op->operand[1], xBX, OPLM_DWORD, &op->regmask_src);
04abc5d6 1177 break;
1178
5101a5f9 1179 case OP_CDQ:
1180 op->operand_cnt = 2;
1181 setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
1182 setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
1183 break;
1184
092f64e1 1185 case OP_LODS:
33c35af6 1186 case OP_STOS:
591721d7 1187 case OP_SCAS:
591721d7 1188 if (words[op_w][4] == 'b')
33c35af6 1189 lmod = OPLM_BYTE;
591721d7 1190 else if (words[op_w][4] == 'w')
33c35af6 1191 lmod = OPLM_WORD;
591721d7 1192 else if (words[op_w][4] == 'd')
33c35af6 1193 lmod = OPLM_DWORD;
acd03176 1194 j = 0;
3947cf24 1195 op->regmask_src = 0;
acd03176 1196 setup_reg_opr(&op->operand[j++], op->op == OP_LODS ? xSI : xDI,
3947cf24 1197 OPLM_DWORD, &op->regmask_src);
d4e3b5db 1198 op->regmask_dst = op->regmask_src;
3947cf24 1199 setup_reg_opr(&op->operand[j++], xAX, lmod,
092f64e1 1200 op->op == OP_LODS ? &op->regmask_dst : &op->regmask_src);
3947cf24 1201 if (op->flags & OPF_REP) {
1202 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1203 op->regmask_dst |= 1 << xCX;
1204 }
acd03176 1205 op->operand_cnt = j;
33c35af6 1206 break;
1207
d4e3b5db 1208 case OP_MOVS:
7ba45c34 1209 case OP_CMPS:
7ba45c34 1210 if (words[op_w][4] == 'b')
d4e3b5db 1211 lmod = OPLM_BYTE;
7ba45c34 1212 else if (words[op_w][4] == 'w')
d4e3b5db 1213 lmod = OPLM_WORD;
7ba45c34 1214 else if (words[op_w][4] == 'd')
d4e3b5db 1215 lmod = OPLM_DWORD;
acd03176 1216 j = 0;
3947cf24 1217 op->regmask_src = 0;
1218 // note: lmod is not correct, don't have where to place it
acd03176 1219 setup_reg_opr(&op->operand[j++], xDI, lmod, &op->regmask_src);
1220 setup_reg_opr(&op->operand[j++], xSI, OPLM_DWORD, &op->regmask_src);
1221 if (op->flags & OPF_REP)
1222 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1223 op->operand_cnt = j;
d4e3b5db 1224 op->regmask_dst = op->regmask_src;
1225 break;
1226
04abc5d6 1227 case OP_LOOP:
1228 op->regmask_dst = 1 << xCX;
1229 // fallthrough
5c024ef7 1230 case OP_JECXZ:
04abc5d6 1231 op->operand_cnt = 2;
5c024ef7 1232 op->regmask_src = 1 << xCX;
04abc5d6 1233 op->operand[1].type = OPT_REG;
1234 op->operand[1].reg = xCX;
1235 op->operand[1].lmod = OPLM_DWORD;
5c024ef7 1236 break;
1237
5101a5f9 1238 case OP_IMUL:
b2bd20c0 1239 if (op->operand_cnt == 2) {
1240 if (op->operand[0].type != OPT_REG)
1241 aerr("reg expected\n");
1242 op->regmask_src |= 1 << op->operand[0].reg;
1243 }
5101a5f9 1244 if (op->operand_cnt != 1)
1245 break;
1246 // fallthrough
1247 case OP_MUL:
1248 // singleop mul
92d715b6 1249 op->regmask_src |= op->regmask_dst;
5101a5f9 1250 op->regmask_dst = (1 << xDX) | (1 << xAX);
5101a5f9 1251 if (op->operand[0].lmod == OPLM_UNSPEC)
1252 op->operand[0].lmod = OPLM_DWORD;
1253 break;
1254
1255 case OP_DIV:
1256 case OP_IDIV:
1257 // we could set up operands for edx:eax, but there is no real need to
1258 // (see is_opr_modified())
92d715b6 1259 op->regmask_src |= op->regmask_dst;
1260 op->regmask_dst = (1 << xDX) | (1 << xAX);
5101a5f9 1261 if (op->operand[0].lmod == OPLM_UNSPEC)
1262 op->operand[0].lmod = OPLM_DWORD;
1263 break;
1264
1265 case OP_SHL:
1266 case OP_SHR:
1267 case OP_SAR:
d4e3b5db 1268 case OP_ROL:
1269 case OP_ROR:
92d715b6 1270 op->regmask_src |= op->regmask_dst;
5101a5f9 1271 if (op->operand[1].lmod == OPLM_UNSPEC)
1272 op->operand[1].lmod = OPLM_BYTE;
1273 break;
1274
acd03176 1275 case OP_SHLD:
3b2f4044 1276 case OP_SHRD:
92d715b6 1277 op->regmask_src |= op->regmask_dst;
3b2f4044 1278 if (op->operand[2].lmod == OPLM_UNSPEC)
1279 op->operand[2].lmod = OPLM_BYTE;
1280 break;
1281
7ba45c34 1282 case OP_PUSH:
92d715b6 1283 op->regmask_src |= op->regmask_dst;
1284 op->regmask_dst = 0;
7ba45c34 1285 if (op->operand[0].lmod == OPLM_UNSPEC
1286 && (op->operand[0].type == OPT_CONST
1287 || op->operand[0].type == OPT_OFFSET
1288 || op->operand[0].type == OPT_LABEL))
1289 op->operand[0].lmod = OPLM_DWORD;
1290 break;
1291
3ebea2cf 1292 // alignment
1293 case OP_MOV:
092f64e1 1294 check_align:
3ebea2cf 1295 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
092f64e1 1296 && op->operand[0].lmod == op->operand[1].lmod
1297 && op->operand[0].reg == op->operand[1].reg
92d715b6 1298 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
3ebea2cf 1299 {
b2bd20c0 1300 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
092f64e1 1301 op->regmask_src = op->regmask_dst = 0;
3ebea2cf 1302 }
1303 break;
1304
de50b98b 1305 case OP_LEA:
1306 if (op->operand[0].type == OPT_REG
1307 && op->operand[1].type == OPT_REGMEM)
1308 {
1309 char buf[16];
1310 snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1311 if (IS(buf, op->operand[1].name))
b2bd20c0 1312 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
de50b98b 1313 }
1314 break;
1315
89ff3147 1316 case OP_CALL:
1317 // trashed regs must be explicitly detected later
1318 op->regmask_dst = 0;
1319 break;
1320
92d715b6 1321 case OP_LEAVE:
1322 op->regmask_dst = (1 << xBP) | (1 << xSP);
1323 op->regmask_src = 1 << xBP;
1324 break;
1325
d4a985bd 1326 case OP_FLD:
1327 case OP_FILD:
1328 op->regmask_dst |= mxST0;
1329 break;
1330
1331 case OP_FLDc:
1332 op->regmask_dst |= mxST0;
1333 if (IS(words[op_w] + 3, "1"))
1334 op->operand[0].val = X87_CONST_1;
1335 else if (IS(words[op_w] + 3, "z"))
1336 op->operand[0].val = X87_CONST_Z;
1337 else
1338 aerr("TODO\n");
1339 break;
1340
1341 case OP_FST:
1342 op->regmask_src |= mxST0;
1343 break;
1344
1345 case OP_FADD:
1346 case OP_FDIV:
1347 case OP_FMUL:
1348 case OP_FSUB:
1349 case OP_FDIVR:
1350 case OP_FSUBR:
1351 op->regmask_src |= mxST0;
1352 if (op->operand_cnt == 2)
1353 op->regmask_src |= op->regmask_dst;
1354 else if (op->operand_cnt == 1) {
1355 memcpy(&op->operand[1], &op->operand[0], sizeof(op->operand[1]));
1356 op->operand[0].type = OPT_REG;
1357 op->operand[0].lmod = OPLM_QWORD;
1358 op->operand[0].reg = xST0;
1359 op->regmask_dst |= mxST0;
1360 }
1361 else
1362 // IDA doesn't use this
1363 aerr("no operands?\n");
1364 break;
1365
1366 case OP_FIADD:
1367 case OP_FIDIV:
1368 case OP_FIMUL:
1369 case OP_FISUB:
1370 case OP_FIDIVR:
1371 case OP_FISUBR:
1372 op->regmask_src |= mxST0;
1373 op->regmask_dst |= mxST0;
1374 break;
1375
5101a5f9 1376 default:
1377 break;
1378 }
2b70f6d3 1379
1380 if (op->operand[0].type == OPT_REG
2b70f6d3 1381 && op->operand[1].type == OPT_CONST)
1382 {
acd03176 1383 struct parsed_opr *op1 = &op->operand[1];
1384 if ((op->op == OP_AND && op1->val == 0)
1385 || (op->op == OP_OR
1386 && (op1->val == ~0
1387 || (op->operand[0].lmod == OPLM_WORD && op1->val == 0xffff)
1388 || (op->operand[0].lmod == OPLM_BYTE && op1->val == 0xff))))
2b70f6d3 1389 {
1390 op->regmask_src = 0;
1391 }
1392 }
c36e914d 1393}
1394
092f64e1 1395static const char *op_name(struct parsed_op *po)
850c9265 1396{
092f64e1 1397 static char buf[16];
1398 char *p;
850c9265 1399 int i;
1400
092f64e1 1401 if (po->op == OP_JCC || po->op == OP_SCC) {
1402 p = buf;
1403 *p++ = (po->op == OP_JCC) ? 'j' : 's';
1404 if (po->pfo_inv)
1405 *p++ = 'n';
1406 strcpy(p, parsed_flag_op_names[po->pfo]);
1407 return buf;
1408 }
1409
850c9265 1410 for (i = 0; i < ARRAY_SIZE(op_table); i++)
092f64e1 1411 if (op_table[i].op == po->op)
850c9265 1412 return op_table[i].name;
1413
1414 return "???";
1415}
1416
1417// debug
1418static const char *dump_op(struct parsed_op *po)
1419{
1420 static char out[128];
1421 char *p = out;
1422 int i;
1423
4c45fa73 1424 if (po == NULL)
1425 return "???";
1426
092f64e1 1427 snprintf(out, sizeof(out), "%s", op_name(po));
850c9265 1428 for (i = 0; i < po->operand_cnt; i++) {
1429 p += strlen(p);
1430 if (i > 0)
1431 *p++ = ',';
1432 snprintf(p, sizeof(out) - (p - out),
1433 po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1434 po->operand[i].name);
1435 }
1436
1437 return out;
1438}
1439
4c45fa73 1440static const char *lmod_type_u(struct parsed_op *po,
1441 enum opr_lenmod lmod)
1442{
1443 switch (lmod) {
90307a99 1444 case OPLM_QWORD:
1445 return "u64";
4c45fa73 1446 case OPLM_DWORD:
1447 return "u32";
1448 case OPLM_WORD:
1449 return "u16";
1450 case OPLM_BYTE:
1451 return "u8";
1452 default:
1453 ferr(po, "invalid lmod: %d\n", lmod);
1454 return "(_invalid_)";
1455 }
1456}
1457
d4e3b5db 1458static const char *lmod_cast_u(struct parsed_op *po,
1459 enum opr_lenmod lmod)
1460{
1461 switch (lmod) {
90307a99 1462 case OPLM_QWORD:
1463 return "";
d4e3b5db 1464 case OPLM_DWORD:
1465 return "";
1466 case OPLM_WORD:
1467 return "(u16)";
1468 case OPLM_BYTE:
1469 return "(u8)";
1470 default:
1471 ferr(po, "invalid lmod: %d\n", lmod);
1472 return "(_invalid_)";
1473 }
1474}
1475
1476static const char *lmod_cast_u_ptr(struct parsed_op *po,
1477 enum opr_lenmod lmod)
1478{
1479 switch (lmod) {
90307a99 1480 case OPLM_QWORD:
1481 return "*(u64 *)";
d4e3b5db 1482 case OPLM_DWORD:
1483 return "*(u32 *)";
1484 case OPLM_WORD:
1485 return "*(u16 *)";
1486 case OPLM_BYTE:
1487 return "*(u8 *)";
1488 default:
1489 ferr(po, "invalid lmod: %d\n", lmod);
1490 return "(_invalid_)";
1491 }
1492}
1493
1494static const char *lmod_cast_s(struct parsed_op *po,
1495 enum opr_lenmod lmod)
1496{
1497 switch (lmod) {
90307a99 1498 case OPLM_QWORD:
1499 return "(s64)";
d4e3b5db 1500 case OPLM_DWORD:
1501 return "(s32)";
1502 case OPLM_WORD:
1503 return "(s16)";
1504 case OPLM_BYTE:
1505 return "(s8)";
1506 default:
1507 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1508 return "(_invalid_)";
1509 }
1510}
1511
1512static const char *lmod_cast(struct parsed_op *po,
1513 enum opr_lenmod lmod, int is_signed)
1514{
1515 return is_signed ?
1516 lmod_cast_s(po, lmod) :
1517 lmod_cast_u(po, lmod);
1518}
1519
1520static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1521{
1522 switch (lmod) {
90307a99 1523 case OPLM_QWORD:
1524 return 8;
d4e3b5db 1525 case OPLM_DWORD:
1526 return 4;
1527 case OPLM_WORD:
1528 return 2;
1529 case OPLM_BYTE:
1530 return 1;
1531 default:
1532 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1533 return 0;
1534 }
1535}
1536
91977a1c 1537static const char *opr_name(struct parsed_op *po, int opr_num)
c36e914d 1538{
91977a1c 1539 if (opr_num >= po->operand_cnt)
1540 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1541 return po->operand[opr_num].name;
c36e914d 1542}
1543
91977a1c 1544static unsigned int opr_const(struct parsed_op *po, int opr_num)
c36e914d 1545{
91977a1c 1546 if (opr_num >= po->operand_cnt)
1547 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1548 if (po->operand[opr_num].type != OPT_CONST)
1549 ferr(po, "opr %d: const expected\n", opr_num);
1550 return po->operand[opr_num].val;
1551}
c36e914d 1552
91977a1c 1553static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1554{
90307a99 1555 if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
91977a1c 1556 ferr(po, "invalid reg: %d\n", popr->reg);
1557 return regs_r32[popr->reg];
1558}
c36e914d 1559
e7f5bc39 1560static int check_simple_cast(const char *cast, int *bits, int *is_signed)
1561{
1562 if (IS_START(cast, "(s8)") || IS_START(cast, "(u8)"))
1563 *bits = 8;
1564 else if (IS_START(cast, "(s16)") || IS_START(cast, "(u16)"))
1565 *bits = 16;
1566 else if (IS_START(cast, "(s32)") || IS_START(cast, "(u32)"))
1567 *bits = 32;
1568 else if (IS_START(cast, "(s64)") || IS_START(cast, "(u64)"))
1569 *bits = 64;
1570 else
1571 return -1;
1572
1573 *is_signed = cast[1] == 's' ? 1 : 0;
1574 return 0;
1575}
1576
1577static int check_deref_cast(const char *cast, int *bits)
1578{
1579 if (IS_START(cast, "*(u8 *)"))
1580 *bits = 8;
1581 else if (IS_START(cast, "*(u16 *)"))
1582 *bits = 16;
1583 else if (IS_START(cast, "*(u32 *)"))
1584 *bits = 32;
1585 else if (IS_START(cast, "*(u64 *)"))
1586 *bits = 64;
1587 else
1588 return -1;
1589
1590 return 0;
1591}
1592
a2c1d768 1593// cast1 is the "final" cast
1594static const char *simplify_cast(const char *cast1, const char *cast2)
1595{
1596 static char buf[256];
e7f5bc39 1597 int bits1, bits2;
1598 int s1, s2;
a2c1d768 1599
1600 if (cast1[0] == 0)
1601 return cast2;
1602 if (cast2[0] == 0)
1603 return cast1;
1604 if (IS(cast1, cast2))
1605 return cast1;
e7f5bc39 1606
1607 if (check_simple_cast(cast1, &bits1, &s1) == 0
1608 && check_simple_cast(cast2, &bits2, &s2) == 0)
1609 {
1610 if (bits1 <= bits2)
1611 return cast1;
1612 }
1613 if (check_simple_cast(cast1, &bits1, &s1) == 0
1614 && check_deref_cast(cast2, &bits2) == 0)
1615 {
1616 if (bits1 == bits2) {
1617 snprintf(buf, sizeof(buf), "*(%c%d *)", s1 ? 's' : 'u', bits1);
1618 return buf;
1619 }
1620 }
1621
1cd4a663 1622 if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1623 return cast1;
a2c1d768 1624
1625 snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1626 return buf;
1627}
1628
1629static const char *simplify_cast_num(const char *cast, unsigned int val)
1630{
1631 if (IS(cast, "(u8)") && val < 0x100)
1632 return "";
1633 if (IS(cast, "(s8)") && val < 0x80)
1634 return "";
1635 if (IS(cast, "(u16)") && val < 0x10000)
1636 return "";
1637 if (IS(cast, "(s16)") && val < 0x8000)
1638 return "";
1639 if (IS(cast, "(s32)") && val < 0x80000000)
1640 return "";
1641
1642 return cast;
1643}
1644
39b168b8 1645static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1646 int *extra_offs)
91977a1c 1647{
39b168b8 1648 const char *p;
1649 char *endp;
1650 int namelen;
850c9265 1651 int i;
1652
39b168b8 1653 *extra_offs = 0;
1654 namelen = strlen(name);
1655
1656 p = strchr(name, '+');
1657 if (p != NULL) {
1658 namelen = p - name;
1659 if (namelen <= 0)
1660 ferr(po, "equ parse failed for '%s'\n", name);
1661
1662 if (IS_START(p, "0x"))
1663 p += 2;
1664 *extra_offs = strtol(p, &endp, 16);
1665 if (*endp != 0)
1666 ferr(po, "equ parse failed for '%s'\n", name);
1667 }
1668
850c9265 1669 for (i = 0; i < g_eqcnt; i++)
39b168b8 1670 if (strncmp(g_eqs[i].name, name, namelen) == 0
1671 && g_eqs[i].name[namelen] == 0)
850c9265 1672 break;
87bf6cec 1673 if (i >= g_eqcnt) {
1674 if (po != NULL)
1675 ferr(po, "unresolved equ name: '%s'\n", name);
1676 return NULL;
1677 }
850c9265 1678
1679 return &g_eqs[i];
1680}
1681
1cd4a663 1682static int is_stack_access(struct parsed_op *po,
1683 const struct parsed_opr *popr)
850c9265 1684{
09bc6fd5 1685 return (parse_stack_el(popr->name, NULL, 0)
1cd4a663 1686 || (g_bp_frame && !(po->flags & OPF_EBP_S)
1687 && IS_START(popr->name, "ebp")));
1688}
1689
1690static void parse_stack_access(struct parsed_op *po,
1691 const char *name, char *ofs_reg, int *offset_out,
037f4971 1692 int *stack_ra_out, const char **bp_arg_out, int is_lea)
1cd4a663 1693{
1694 const char *bp_arg = "";
1695 const char *p = NULL;
91977a1c 1696 struct parsed_equ *eq;
4f12f671 1697 char *endp = NULL;
d4e3b5db 1698 int stack_ra = 0;
39b168b8 1699 int offset = 0;
91977a1c 1700
1cd4a663 1701 ofs_reg[0] = 0;
a3684be1 1702
1703 if (IS_START(name, "ebp-")
1704 || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1705 {
1706 p = name + 4;
1707 if (IS_START(p, "0x"))
1708 p += 2;
1709 offset = strtoul(p, &endp, 16);
1710 if (name[3] == '-')
1711 offset = -offset;
1712 if (*endp != 0)
1713 ferr(po, "ebp- parse of '%s' failed\n", name);
1714 }
1715 else {
09bc6fd5 1716 bp_arg = parse_stack_el(name, ofs_reg, 0);
4f12f671 1717 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1718 eq = equ_find(po, bp_arg, &offset);
1719 if (eq == NULL)
1720 ferr(po, "detected but missing eq\n");
1721 offset += eq->offset;
1722 }
39b168b8 1723
d4e3b5db 1724 if (!strncmp(name, "ebp", 3))
1725 stack_ra = 4;
1726
037f4971 1727 // yes it sometimes LEAs ra for compares..
1728 if (!is_lea && ofs_reg[0] == 0
1729 && stack_ra <= offset && offset < stack_ra + 4)
1730 {
39b168b8 1731 ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
037f4971 1732 }
d4e3b5db 1733
1cd4a663 1734 *offset_out = offset;
1735 *stack_ra_out = stack_ra;
1736 if (bp_arg_out)
1737 *bp_arg_out = bp_arg;
1738}
1739
5f70a34f 1740static int stack_frame_access(struct parsed_op *po,
1cd4a663 1741 struct parsed_opr *popr, char *buf, size_t buf_size,
1742 const char *name, const char *cast, int is_src, int is_lea)
1743{
1744 enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1745 const char *prefix = "";
1746 const char *bp_arg = NULL;
1747 char ofs_reg[16] = { 0, };
1748 int i, arg_i, arg_s;
1749 int unaligned = 0;
1750 int stack_ra = 0;
1751 int offset = 0;
5f70a34f 1752 int retval = -1;
1cd4a663 1753 int sf_ofs;
1754 int lim;
1755
1756 if (po->flags & OPF_EBP_S)
1757 ferr(po, "stack_frame_access while ebp is scratch\n");
1758
037f4971 1759 parse_stack_access(po, name, ofs_reg, &offset,
1760 &stack_ra, &bp_arg, is_lea);
1cd4a663 1761
4f12f671 1762 if (offset > stack_ra)
1763 {
39b168b8 1764 arg_i = (offset - stack_ra - 4) / 4;
bd96f656 1765 if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
4f12f671 1766 {
bd96f656 1767 if (g_func_pp->is_vararg
1768 && arg_i == g_func_pp->argc_stack && is_lea)
1769 {
4f12f671 1770 // should be va_list
1771 if (cast[0] == 0)
1772 cast = "(u32)";
1773 snprintf(buf, buf_size, "%sap", cast);
5f70a34f 1774 return -1;
4f12f671 1775 }
1776 ferr(po, "offset %d (%s,%d) doesn't map to any arg\n",
1777 offset, bp_arg, arg_i);
1778 }
4c45fa73 1779 if (ofs_reg[0] != 0)
7ba45c34 1780 ferr(po, "offset reg on arg access?\n");
91977a1c 1781
bd96f656 1782 for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1783 if (g_func_pp->arg[i].reg != NULL)
91977a1c 1784 continue;
1785 if (arg_s == arg_i)
1786 break;
1787 arg_s++;
1788 }
bd96f656 1789 if (i == g_func_pp->argc)
91977a1c 1790 ferr(po, "arg %d not in prototype?\n", arg_i);
850c9265 1791
bd96f656 1792 popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
5f70a34f 1793 retval = i;
de50b98b 1794
1795 switch (popr->lmod)
7ba45c34 1796 {
1797 case OPLM_BYTE:
4f12f671 1798 if (is_lea)
1799 ferr(po, "lea/byte to arg?\n");
7ba45c34 1800 if (is_src && (offset & 3) == 0)
a2c1d768 1801 snprintf(buf, buf_size, "%sa%d",
1802 simplify_cast(cast, "(u8)"), i + 1);
7ba45c34 1803 else
a2c1d768 1804 snprintf(buf, buf_size, "%sBYTE%d(a%d)",
1805 cast, offset & 3, i + 1);
7ba45c34 1806 break;
1807
1808 case OPLM_WORD:
4f12f671 1809 if (is_lea)
1810 ferr(po, "lea/word to arg?\n");
a3684be1 1811 if (offset & 1) {
1812 unaligned = 1;
1813 if (!is_src) {
1814 if (offset & 2)
1815 ferr(po, "problematic arg store\n");
a2c1d768 1816 snprintf(buf, buf_size, "%s((char *)&a%d + 1)",
1817 simplify_cast(cast, "*(u16 *)"), i + 1);
a3684be1 1818 }
1819 else
1820 ferr(po, "unaligned arg word load\n");
1821 }
1822 else if (is_src && (offset & 2) == 0)
a2c1d768 1823 snprintf(buf, buf_size, "%sa%d",
1824 simplify_cast(cast, "(u16)"), i + 1);
7ba45c34 1825 else
a2c1d768 1826 snprintf(buf, buf_size, "%s%sWORD(a%d)",
1827 cast, (offset & 2) ? "HI" : "LO", i + 1);
7ba45c34 1828 break;
1829
1830 case OPLM_DWORD:
3ebea2cf 1831 if (cast[0])
1832 prefix = cast;
1833 else if (is_src)
1834 prefix = "(u32)";
a3684be1 1835
de50b98b 1836 if (offset & 3) {
a3684be1 1837 unaligned = 1;
2b43685d 1838 if (is_lea)
1839 snprintf(buf, buf_size, "(u32)&a%d + %d",
1840 i + 1, offset & 3);
a3684be1 1841 else if (!is_src)
1842 ferr(po, "unaligned arg store\n");
1843 else {
1844 // mov edx, [ebp+arg_4+2]; movsx ecx, dx
2b43685d 1845 snprintf(buf, buf_size, "%s(a%d >> %d)",
1846 prefix, i + 1, (offset & 3) * 8);
a3684be1 1847 }
de50b98b 1848 }
1849 else {
1850 snprintf(buf, buf_size, "%s%sa%d",
1851 prefix, is_lea ? "&" : "", i + 1);
1852 }
7ba45c34 1853 break;
1854
1855 default:
de50b98b 1856 ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
7ba45c34 1857 }
1858
a3684be1 1859 if (unaligned)
1860 snprintf(g_comment, sizeof(g_comment), "%s unaligned", bp_arg);
1861
7ba45c34 1862 // common problem
bd96f656 1863 guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
a2c1d768 1864 if (tmp_lmod != OPLM_DWORD
de041e5b 1865 && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
1866 < lmod_bytes(po, popr->lmod) + (offset & 3))))
a2c1d768 1867 {
1868 ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
1869 i + 1, offset, g_func_pp->arg[i].type.name);
1870 }
4741fdfe 1871 // can't check this because msvc likes to reuse
1872 // arg space for scratch..
1873 //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
1874 // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
91977a1c 1875 }
4f12f671 1876 else
1877 {
1bafb621 1878 if (g_stack_fsz == 0)
1879 ferr(po, "stack var access without stackframe\n");
a2c1d768 1880 g_stack_frame_used = 1;
850c9265 1881
39b168b8 1882 sf_ofs = g_stack_fsz + offset;
de50b98b 1883 lim = (ofs_reg[0] != 0) ? -4 : 0;
1884 if (offset > 0 || sf_ofs < lim)
39b168b8 1885 ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
850c9265 1886
1887 if (is_lea)
33c35af6 1888 prefix = "(u32)&";
3ebea2cf 1889 else
1890 prefix = cast;
850c9265 1891
de50b98b 1892 switch (popr->lmod)
850c9265 1893 {
1894 case OPLM_BYTE:
7ba45c34 1895 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1896 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
850c9265 1897 break;
7ba45c34 1898
850c9265 1899 case OPLM_WORD:
7ba45c34 1900 if ((sf_ofs & 1) || ofs_reg[0] != 0) {
1901 // known unaligned or possibly unaligned
1902 strcat(g_comment, " unaligned");
1903 if (prefix[0] == 0)
1904 prefix = "*(u16 *)&";
1905 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1906 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1907 break;
1908 }
1909 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
850c9265 1910 break;
7ba45c34 1911
850c9265 1912 case OPLM_DWORD:
7ba45c34 1913 if ((sf_ofs & 3) || ofs_reg[0] != 0) {
1914 // known unaligned or possibly unaligned
1915 strcat(g_comment, " unaligned");
1916 if (prefix[0] == 0)
1917 prefix = "*(u32 *)&";
1918 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1919 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1920 break;
1921 }
1922 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
850c9265 1923 break;
7ba45c34 1924
d4a985bd 1925 case OPLM_QWORD:
1926 ferr_assert(po, !(sf_ofs & 7));
1927 ferr_assert(po, ofs_reg[0] == 0);
1928 // float callers set is_lea
1929 ferr_assert(po, is_lea);
1930 snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
1931 break;
1932
850c9265 1933 default:
de50b98b 1934 ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
850c9265 1935 }
91977a1c 1936 }
5f70a34f 1937
1938 return retval;
91977a1c 1939}
c36e914d 1940
89ff3147 1941static void check_func_pp(struct parsed_op *po,
1942 const struct parsed_proto *pp, const char *pfx)
1943{
179b79a9 1944 enum opr_lenmod tmp_lmod;
b74c31e3 1945 char buf[256];
179b79a9 1946 int ret, i;
b74c31e3 1947
89ff3147 1948 if (pp->argc_reg != 0) {
b74c31e3 1949 if (/*!g_allow_regfunc &&*/ !pp->is_fastcall) {
1950 pp_print(buf, sizeof(buf), pp);
1951 ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
1952 }
89ff3147 1953 if (pp->argc_stack > 0 && pp->argc_reg != 2)
1954 ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
1955 pfx, pp->argc_reg, pp->argc_stack);
1956 }
179b79a9 1957
1958 // fptrs must use 32bit args, callsite might have no information and
1959 // lack a cast to smaller types, which results in incorrectly masked
1960 // args passed (callee may assume masked args, it does on ARM)
61e29183 1961 if (!pp->is_osinc) {
179b79a9 1962 for (i = 0; i < pp->argc; i++) {
1963 ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
1964 if (ret && tmp_lmod != OPLM_DWORD)
1965 ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
1966 i + 1, pp->arg[i].type.name);
1967 }
1968 }
89ff3147 1969}
1970
7aca4698 1971static const char *check_label_read_ref(struct parsed_op *po,
1972 const char *name)
3ebea2cf 1973{
840257f6 1974 const struct parsed_proto *pp;
1975
36595fd2 1976 pp = proto_parse(g_fhdr, name, 0);
840257f6 1977 if (pp == NULL)
1978 ferr(po, "proto_parse failed for ref '%s'\n", name);
1979
89ff3147 1980 if (pp->is_func)
1981 check_func_pp(po, pp, "ref");
7aca4698 1982
1983 return pp->name;
3ebea2cf 1984}
1985
91977a1c 1986static char *out_src_opr(char *buf, size_t buf_size,
591721d7 1987 struct parsed_op *po, struct parsed_opr *popr, const char *cast,
3ebea2cf 1988 int is_lea)
91977a1c 1989{
850c9265 1990 char tmp1[256], tmp2[256];
1991 char expr[256];
7aca4698 1992 const char *name;
a2c1d768 1993 char *p;
850c9265 1994 int ret;
1995
3ebea2cf 1996 if (cast == NULL)
1997 cast = "";
1998
91977a1c 1999 switch (popr->type) {
2000 case OPT_REG:
850c9265 2001 if (is_lea)
2002 ferr(po, "lea from reg?\n");
2003
91977a1c 2004 switch (popr->lmod) {
90307a99 2005 case OPLM_QWORD:
2006 snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2007 break;
91977a1c 2008 case OPLM_DWORD:
3ebea2cf 2009 snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
91977a1c 2010 break;
850c9265 2011 case OPLM_WORD:
a2c1d768 2012 snprintf(buf, buf_size, "%s%s",
2013 simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
850c9265 2014 break;
2015 case OPLM_BYTE:
5101a5f9 2016 if (popr->name[1] == 'h') // XXX..
a2c1d768 2017 snprintf(buf, buf_size, "%s(%s >> 8)",
2018 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
5101a5f9 2019 else
a2c1d768 2020 snprintf(buf, buf_size, "%s%s",
2021 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
850c9265 2022 break;
91977a1c 2023 default:
2024 ferr(po, "invalid src lmod: %d\n", popr->lmod);
2025 }
2026 break;
850c9265 2027
91977a1c 2028 case OPT_REGMEM:
1cd4a663 2029 if (is_stack_access(po, popr)) {
de50b98b 2030 stack_frame_access(po, popr, buf, buf_size,
3ebea2cf 2031 popr->name, cast, 1, is_lea);
91977a1c 2032 break;
2033 }
850c9265 2034
2035 strcpy(expr, popr->name);
2036 if (strchr(expr, '[')) {
2037 // special case: '[' can only be left for label[reg] form
2038 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2039 if (ret != 2)
2040 ferr(po, "parse failure for '%s'\n", expr);
a2c1d768 2041 if (tmp1[0] == '(') {
2042 // (off_4FFF50+3)[eax]
2043 p = strchr(tmp1 + 1, ')');
2044 if (p == NULL || p[1] != 0)
2045 ferr(po, "parse failure (2) for '%s'\n", expr);
2046 *p = 0;
2047 memmove(tmp1, tmp1 + 1, strlen(tmp1));
2048 }
33c35af6 2049 snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
850c9265 2050 }
2051
2052 // XXX: do we need more parsing?
2053 if (is_lea) {
2054 snprintf(buf, buf_size, "%s", expr);
2055 break;
2056 }
2057
a2c1d768 2058 snprintf(buf, buf_size, "%s(%s)",
2059 simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
91977a1c 2060 break;
850c9265 2061
91977a1c 2062 case OPT_LABEL:
7aca4698 2063 name = check_label_read_ref(po, popr->name);
3ebea2cf 2064 if (cast[0] == 0 && popr->is_ptr)
2065 cast = "(u32)";
2b43685d 2066
850c9265 2067 if (is_lea)
7aca4698 2068 snprintf(buf, buf_size, "(u32)&%s", name);
2b43685d 2069 else if (popr->size_lt)
2070 snprintf(buf, buf_size, "%s%s%s%s", cast,
2071 lmod_cast_u_ptr(po, popr->lmod),
7aca4698 2072 popr->is_array ? "" : "&", name);
850c9265 2073 else
7aca4698 2074 snprintf(buf, buf_size, "%s%s%s", cast, name,
7ba45c34 2075 popr->is_array ? "[0]" : "");
850c9265 2076 break;
2077
2078 case OPT_OFFSET:
7aca4698 2079 name = check_label_read_ref(po, popr->name);
3ebea2cf 2080 if (cast[0] == 0)
2081 cast = "(u32)";
850c9265 2082 if (is_lea)
2083 ferr(po, "lea an offset?\n");
7aca4698 2084 snprintf(buf, buf_size, "%s&%s", cast, name);
91977a1c 2085 break;
850c9265 2086
91977a1c 2087 case OPT_CONST:
850c9265 2088 if (is_lea)
2089 ferr(po, "lea from const?\n");
2090
a2c1d768 2091 printf_number(tmp1, sizeof(tmp1), popr->val);
ddaf8bd7 2092 if (popr->val == 0 && strchr(cast, '*'))
2093 snprintf(buf, buf_size, "NULL");
2094 else
2095 snprintf(buf, buf_size, "%s%s",
2096 simplify_cast_num(cast, popr->val), tmp1);
91977a1c 2097 break;
850c9265 2098
91977a1c 2099 default:
2100 ferr(po, "invalid src type: %d\n", popr->type);
2101 }
2102
2103 return buf;
2104}
c36e914d 2105
de50b98b 2106// note: may set is_ptr (we find that out late for ebp frame..)
91977a1c 2107static char *out_dst_opr(char *buf, size_t buf_size,
2108 struct parsed_op *po, struct parsed_opr *popr)
2109{
2110 switch (popr->type) {
2111 case OPT_REG:
2112 switch (popr->lmod) {
90307a99 2113 case OPLM_QWORD:
2114 snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2115 break;
91977a1c 2116 case OPLM_DWORD:
2117 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2118 break;
850c9265 2119 case OPLM_WORD:
2120 // ugh..
2121 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2122 break;
2123 case OPLM_BYTE:
2124 // ugh..
5101a5f9 2125 if (popr->name[1] == 'h') // XXX..
2126 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2127 else
2128 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
850c9265 2129 break;
91977a1c 2130 default:
2131 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2132 }
2133 break;
850c9265 2134
2135 case OPT_REGMEM:
1cd4a663 2136 if (is_stack_access(po, popr)) {
de50b98b 2137 stack_frame_access(po, popr, buf, buf_size,
3ebea2cf 2138 popr->name, "", 0, 0);
850c9265 2139 break;
2140 }
2141
3ebea2cf 2142 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
850c9265 2143
bfa4a6ee 2144 case OPT_LABEL:
2b43685d 2145 if (popr->size_mismatch)
2146 snprintf(buf, buf_size, "%s%s%s",
2147 lmod_cast_u_ptr(po, popr->lmod),
2148 popr->is_array ? "" : "&", popr->name);
2149 else
2150 snprintf(buf, buf_size, "%s%s", popr->name,
2151 popr->is_array ? "[0]" : "");
bfa4a6ee 2152 break;
2153
91977a1c 2154 default:
2155 ferr(po, "invalid dst type: %d\n", popr->type);
2156 }
2157
2158 return buf;
2159}
c36e914d 2160
3ebea2cf 2161static char *out_src_opr_u32(char *buf, size_t buf_size,
2162 struct parsed_op *po, struct parsed_opr *popr)
2163{
2164 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2165}
2166
d4a985bd 2167static char *out_src_opr_float(char *buf, size_t buf_size,
2168 struct parsed_op *po, struct parsed_opr *popr)
2169{
2170 const char *cast = NULL;
2171 char tmp[256];
2172
2173 switch (popr->type) {
2174 case OPT_REG:
2175 if (popr->reg < xST0 || popr->reg > xST7)
2176 ferr(po, "bad reg: %d\n", popr->reg);
2177
2178 snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2179 break;
2180
2181 case OPT_REGMEM:
2182 case OPT_LABEL:
2183 case OPT_OFFSET:
2184 switch (popr->lmod) {
2185 case OPLM_QWORD:
2186 cast = "double";
2187 break;
2188 case OPLM_DWORD:
2189 cast = "float";
2190 break;
2191 default:
2192 ferr(po, "unhandled lmod: %d\n", popr->lmod);
2193 break;
2194 }
2195 out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2196 snprintf(buf, buf_size, "*((%s *)%s)", cast, tmp);
2197 break;
2198
2199 default:
2200 ferr(po, "invalid float type: %d\n", popr->type);
2201 }
2202
2203 return buf;
2204}
2205
2206static char *out_dst_opr_float(char *buf, size_t buf_size,
2207 struct parsed_op *po, struct parsed_opr *popr)
2208{
2209 // same?
2210 return out_src_opr_float(buf, buf_size, po, popr);
2211}
2212
91977a1c 2213static void out_test_for_cc(char *buf, size_t buf_size,
940e8e66 2214 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
69a3cdfc 2215 enum opr_lenmod lmod, const char *expr)
91977a1c 2216{
69a3cdfc 2217 const char *cast, *scast;
91977a1c 2218
69a3cdfc 2219 cast = lmod_cast_u(po, lmod);
2220 scast = lmod_cast_s(po, lmod);
2221
2222 switch (pfo) {
2223 case PFO_Z:
87bf6cec 2224 case PFO_BE: // CF=1||ZF=1; CF=0
850c9265 2225 snprintf(buf, buf_size, "(%s%s %s 0)",
940e8e66 2226 cast, expr, is_inv ? "!=" : "==");
91977a1c 2227 break;
850c9265 2228
5101a5f9 2229 case PFO_S:
2230 case PFO_L: // SF!=OF; OF=0
2231 snprintf(buf, buf_size, "(%s%s %s 0)",
940e8e66 2232 scast, expr, is_inv ? ">=" : "<");
5101a5f9 2233 break;
2234
87bf6cec 2235 case PFO_LE: // ZF=1||SF!=OF; OF=0
69a3cdfc 2236 snprintf(buf, buf_size, "(%s%s %s 0)",
940e8e66 2237 scast, expr, is_inv ? ">" : "<=");
850c9265 2238 break;
2239
91977a1c 2240 default:
69a3cdfc 2241 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
91977a1c 2242 }
2243}
c36e914d 2244
850c9265 2245static void out_cmp_for_cc(char *buf, size_t buf_size,
a2c1d768 2246 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
850c9265 2247{
a2c1d768 2248 const char *cast, *scast, *cast_use;
2249 char buf1[256], buf2[256];
2250 enum opr_lenmod lmod;
2251
90307a99 2252 if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
a2c1d768 2253 ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2254 po->operand[0].lmod, po->operand[1].lmod);
2255 lmod = po->operand[0].lmod;
850c9265 2256
69a3cdfc 2257 cast = lmod_cast_u(po, lmod);
2258 scast = lmod_cast_s(po, lmod);
850c9265 2259
a2c1d768 2260 switch (pfo) {
2261 case PFO_C:
2262 case PFO_Z:
2263 case PFO_BE: // !a
2264 cast_use = cast;
2265 break;
2266
2267 case PFO_S:
2268 case PFO_L: // !ge
2269 case PFO_LE:
2270 cast_use = scast;
2271 break;
2272
2273 default:
2274 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2275 }
2276
2277 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
90307a99 2278 if (po->op == OP_DEC)
2279 snprintf(buf2, sizeof(buf2), "1");
2280 else
2281 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_use, 0);
a2c1d768 2282
69a3cdfc 2283 switch (pfo) {
5101a5f9 2284 case PFO_C:
2285 // note: must be unsigned compare
a2c1d768 2286 snprintf(buf, buf_size, "(%s %s %s)",
2287 buf1, is_inv ? ">=" : "<", buf2);
5101a5f9 2288 break;
2289
69a3cdfc 2290 case PFO_Z:
a2c1d768 2291 snprintf(buf, buf_size, "(%s %s %s)",
2292 buf1, is_inv ? "!=" : "==", buf2);
850c9265 2293 break;
2294
5101a5f9 2295 case PFO_BE: // !a
850c9265 2296 // note: must be unsigned compare
a2c1d768 2297 snprintf(buf, buf_size, "(%s %s %s)",
2298 buf1, is_inv ? ">" : "<=", buf2);
2299
2300 // annoying case
2301 if (is_inv && lmod == OPLM_BYTE
2302 && po->operand[1].type == OPT_CONST
2303 && po->operand[1].val == 0xff)
2304 {
2305 snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2306 snprintf(buf, buf_size, "(0)");
2307 }
5101a5f9 2308 break;
2309
2310 // note: must be signed compare
2311 case PFO_S:
2312 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
a2c1d768 2313 scast, buf1, buf2, is_inv ? ">=" : "<");
850c9265 2314 break;
2315
5101a5f9 2316 case PFO_L: // !ge
a2c1d768 2317 snprintf(buf, buf_size, "(%s %s %s)",
2318 buf1, is_inv ? ">=" : "<", buf2);
850c9265 2319 break;
2320
90307a99 2321 case PFO_LE: // !g
a2c1d768 2322 snprintf(buf, buf_size, "(%s %s %s)",
2323 buf1, is_inv ? ">" : "<=", buf2);
5101a5f9 2324 break;
2325
850c9265 2326 default:
a2c1d768 2327 break;
850c9265 2328 }
2329}
2330
69a3cdfc 2331static void out_cmp_test(char *buf, size_t buf_size,
940e8e66 2332 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
69a3cdfc 2333{
2334 char buf1[256], buf2[256], buf3[256];
2335
2336 if (po->op == OP_TEST) {
2337 if (IS(opr_name(po, 0), opr_name(po, 1))) {
3ebea2cf 2338 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
69a3cdfc 2339 }
2340 else {
3ebea2cf 2341 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2342 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
69a3cdfc 2343 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2344 }
940e8e66 2345 out_test_for_cc(buf, buf_size, po, pfo, is_inv,
69a3cdfc 2346 po->operand[0].lmod, buf3);
2347 }
2348 else if (po->op == OP_CMP) {
a2c1d768 2349 out_cmp_for_cc(buf, buf_size, po, pfo, is_inv);
69a3cdfc 2350 }
2351 else
2352 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2353}
2354
850c9265 2355static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
91977a1c 2356 struct parsed_opr *popr2)
2357{
2358 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2359 ferr(po, "missing lmod for both operands\n");
2360
2361 if (popr1->lmod == OPLM_UNSPEC)
2362 popr1->lmod = popr2->lmod;
2363 else if (popr2->lmod == OPLM_UNSPEC)
2364 popr2->lmod = popr1->lmod;
a3684be1 2365 else if (popr1->lmod != popr2->lmod) {
2366 if (popr1->type_from_var) {
2367 popr1->size_mismatch = 1;
2368 if (popr1->lmod < popr2->lmod)
2369 popr1->size_lt = 1;
2370 popr1->lmod = popr2->lmod;
2371 }
2372 else if (popr2->type_from_var) {
2373 popr2->size_mismatch = 1;
2374 if (popr2->lmod < popr1->lmod)
2375 popr2->size_lt = 1;
2376 popr2->lmod = popr1->lmod;
2377 }
2378 else
2379 ferr(po, "conflicting lmods: %d vs %d\n",
2380 popr1->lmod, popr2->lmod);
2381 }
91977a1c 2382}
c36e914d 2383
850c9265 2384static const char *op_to_c(struct parsed_op *po)
2385{
2386 switch (po->op)
2387 {
2388 case OP_ADD:
5101a5f9 2389 case OP_ADC:
850c9265 2390 return "+";
2391 case OP_SUB:
5101a5f9 2392 case OP_SBB:
850c9265 2393 return "-";
2394 case OP_AND:
2395 return "&";
2396 case OP_OR:
2397 return "|";
2398 case OP_XOR:
2399 return "^";
2400 case OP_SHL:
2401 return "<<";
2402 case OP_SHR:
2403 return ">>";
2404 case OP_MUL:
2405 case OP_IMUL:
2406 return "*";
2407 default:
2408 ferr(po, "op_to_c was supplied with %d\n", po->op);
2409 }
2410}
2411
de50b98b 2412// last op in stream - unconditional branch or ret
2413#define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
092f64e1 2414 || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
037f4971 2415 && ops[_i].op != OP_CALL))
de50b98b 2416
db63af51 2417#define check_i(po, i) \
2418 if ((i) < 0) \
2419 ferr(po, "bad " #i ": %d\n", i)
2420
e83ea7ed 2421// note: this skips over calls and rm'd stuff assuming they're handled
2422// so it's intended to use at one of final passes
2423static int scan_for_pop(int i, int opcnt, int magic, int reg,
b2bd20c0 2424 int depth, int flags_set)
850c9265 2425{
87bf6cec 2426 struct parsed_op *po;
e83ea7ed 2427 int relevant;
87bf6cec 2428 int ret = 0;
4c45fa73 2429 int j;
87bf6cec 2430
850c9265 2431 for (; i < opcnt; i++) {
87bf6cec 2432 po = &ops[i];
2433 if (po->cc_scratch == magic)
b2bd20c0 2434 return ret; // already checked
87bf6cec 2435 po->cc_scratch = magic;
2436
89ff3147 2437 if (po->flags & OPF_TAIL) {
2438 if (po->op == OP_CALL) {
b2bd20c0 2439 if (po->pp != NULL && po->pp->is_noreturn)
2440 // assume no stack cleanup for noreturn
2441 return 1;
89ff3147 2442 }
87bf6cec 2443 return -1; // deadend
89ff3147 2444 }
87bf6cec 2445
e83ea7ed 2446 if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
850c9265 2447 continue;
2448
87bf6cec 2449 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4c45fa73 2450 if (po->btj != NULL) {
2451 // jumptable
da87ae38 2452 for (j = 0; j < po->btj->count; j++) {
db63af51 2453 check_i(po, po->btj->d[j].bt_i);
e83ea7ed 2454 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
b2bd20c0 2455 depth, flags_set);
4c45fa73 2456 if (ret < 0)
2457 return ret; // dead end
2458 }
da87ae38 2459 return ret;
4c45fa73 2460 }
2461
db63af51 2462 check_i(po, po->bt_i);
5c024ef7 2463 if (po->flags & OPF_CJMP) {
e83ea7ed 2464 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
b2bd20c0 2465 depth, flags_set);
87bf6cec 2466 if (ret < 0)
2467 return ret; // dead end
2468 }
2469 else {
2470 i = po->bt_i - 1;
2471 }
2472 continue;
2473 }
2474
e83ea7ed 2475 relevant = 0;
d4e3b5db 2476 if ((po->op == OP_POP || po->op == OP_PUSH)
e83ea7ed 2477 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
87bf6cec 2478 {
e83ea7ed 2479 relevant = 1;
2480 }
2481
2482 if (po->op == OP_PUSH) {
2483 depth++;
e83ea7ed 2484 }
2485 else if (po->op == OP_POP) {
b2bd20c0 2486 if (relevant && depth == 0) {
2487 po->flags |= flags_set;
e83ea7ed 2488 return 1;
2489 }
b2bd20c0 2490 depth--;
87bf6cec 2491 }
850c9265 2492 }
2493
b2bd20c0 2494 return -1;
850c9265 2495}
2496
e83ea7ed 2497// scan for 'reg' pop backwards starting from i
2498// intended to use for register restore search, so other reg
2499// references are considered an error
2500static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
850c9265 2501{
e83ea7ed 2502 struct parsed_op *po;
2503 struct label_ref *lr;
2504 int ret = 0;
2505
2506 ops[i].cc_scratch = magic;
2507
2508 while (1)
2509 {
2510 if (g_labels[i] != NULL) {
2511 lr = &g_label_refs[i];
2512 for (; lr != NULL; lr = lr->next) {
2513 check_i(&ops[i], lr->i);
2514 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2515 if (ret < 0)
2516 return ret;
2517 }
2518 if (i > 0 && LAST_OP(i - 1))
2519 return ret;
2520 }
2521
2522 i--;
2523 if (i < 0)
2524 break;
2525
2526 if (ops[i].cc_scratch == magic)
2527 return ret;
2528 ops[i].cc_scratch = magic;
2529
2530 po = &ops[i];
2531 if (po->op == OP_POP && po->operand[0].reg == reg) {
2532 if (po->flags & (OPF_RMD|OPF_DONE))
2533 return -1;
2534
2535 po->flags |= set_flags;
2536 return 1;
2537 }
2538
2539 // this also covers the case where we reach corresponding push
2540 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2541 return -1;
2542 }
2543
2544 // nothing interesting on this path
2545 return 0;
2546}
2547
2548static void find_reachable_exits(int i, int opcnt, int magic,
2549 int *exits, int *exit_count)
2550{
2551 struct parsed_op *po;
850c9265 2552 int j;
2553
e83ea7ed 2554 for (; i < opcnt; i++)
2555 {
2556 po = &ops[i];
2557 if (po->cc_scratch == magic)
2558 return;
2559 po->cc_scratch = magic;
2560
2561 if (po->flags & OPF_TAIL) {
2562 ferr_assert(po, *exit_count < MAX_EXITS);
2563 exits[*exit_count] = i;
2564 (*exit_count)++;
2565 return;
2566 }
850c9265 2567
e83ea7ed 2568 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2569 if (po->flags & OPF_RMD)
69a3cdfc 2570 continue;
850c9265 2571
e83ea7ed 2572 if (po->btj != NULL) {
2573 for (j = 0; j < po->btj->count; j++) {
2574 check_i(po, po->btj->d[j].bt_i);
2575 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2576 exits, exit_count);
2577 }
2578 return;
850c9265 2579 }
2580
e83ea7ed 2581 check_i(po, po->bt_i);
2582 if (po->flags & OPF_CJMP)
2583 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2584 else
2585 i = po->bt_i - 1;
2586 continue;
850c9265 2587 }
2588 }
e83ea7ed 2589}
2590
2591// scan for 'reg' pop backwards starting from exits (all paths)
2592static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2593{
2594 static int exits[MAX_EXITS];
2595 static int exit_count;
2596 int j, ret;
850c9265 2597
e83ea7ed 2598 if (!set_flags) {
2599 exit_count = 0;
2600 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2601 &exit_count);
2602 ferr_assert(&ops[i], exit_count > 0);
2603 }
2604
2605 for (j = 0; j < exit_count; j++) {
2606 ret = scan_for_rsave_pop_reg(exits[j], i + opcnt * 16 + set_flags,
2607 reg, set_flags);
2608 if (ret == -1)
2609 return -1;
2610 }
2611
b2bd20c0 2612 return 1;
850c9265 2613}
2614
e83ea7ed 2615// scan for one or more pop of push <const>
2616static int scan_for_pop_const_r(int i, int opcnt, int magic,
2617 int push_i, int is_probe)
9af2d373 2618{
25a330eb 2619 struct parsed_op *po;
e83ea7ed 2620 struct label_ref *lr;
2621 int ret = 0;
9af2d373 2622 int j;
2623
e83ea7ed 2624 for (; i < opcnt; i++)
2625 {
2626 po = &ops[i];
2627 if (po->cc_scratch == magic)
2628 return ret; // already checked
2629 po->cc_scratch = magic;
2630
2631 if (po->flags & OPF_JMP) {
2632 if (po->flags & OPF_RMD)
2633 continue;
2634 if (po->op == OP_CALL)
2635 return -1;
2636
2637 if (po->btj != NULL) {
2638 for (j = 0; j < po->btj->count; j++) {
2639 check_i(po, po->btj->d[j].bt_i);
2640 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2641 push_i, is_probe);
2642 if (ret < 0)
2643 return ret;
2644 }
2645 return ret;
2646 }
25a330eb 2647
e83ea7ed 2648 check_i(po, po->bt_i);
2649 if (po->flags & OPF_CJMP) {
2650 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2651 is_probe);
2652 if (ret < 0)
2653 return ret;
2654 }
2655 else {
2656 i = po->bt_i - 1;
2657 }
25a330eb 2658 continue;
2659 }
2660
e83ea7ed 2661 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2662 return -1;
2663
2664 if (g_labels[i] != NULL) {
2665 // all refs must be visited
2666 lr = &g_label_refs[i];
2667 for (; lr != NULL; lr = lr->next) {
2668 check_i(po, lr->i);
2669 if (ops[lr->i].cc_scratch != magic)
2670 return -1;
2671 }
2672 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2673 return -1;
2674 }
2675
2676 if (po->op == OP_POP)
9af2d373 2677 {
e83ea7ed 2678 if (po->flags & (OPF_RMD|OPF_DONE))
2679 return -1;
2680
2681 if (!is_probe) {
2682 po->flags |= OPF_DONE;
2683 po->datap = &ops[push_i];
2684 }
2685 return 1;
9af2d373 2686 }
e83ea7ed 2687 }
9af2d373 2688
e83ea7ed 2689 return -1;
2690}
25a330eb 2691
e83ea7ed 2692static void scan_for_pop_const(int i, int opcnt, int magic)
2693{
2694 int ret;
2695
2696 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
2697 if (ret == 1) {
2698 ops[i].flags |= OPF_RMD | OPF_DONE;
2699 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
2700 }
2701}
2702
2703// check if all branch targets within a marked path are also marked
2704// note: the path checked must not be empty or end with a branch
2705static int check_path_branches(int opcnt, int magic)
2706{
2707 struct parsed_op *po;
2708 int i, j;
2709
2710 for (i = 0; i < opcnt; i++) {
2711 po = &ops[i];
2712 if (po->cc_scratch != magic)
2713 continue;
2714
2715 if (po->flags & OPF_JMP) {
2716 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
2717 continue;
2718
2719 if (po->btj != NULL) {
2720 for (j = 0; j < po->btj->count; j++) {
2721 check_i(po, po->btj->d[j].bt_i);
2722 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
2723 return 0;
2724 }
25a330eb 2725 }
e83ea7ed 2726
2727 check_i(po, po->bt_i);
2728 if (ops[po->bt_i].cc_scratch != magic)
2729 return 0;
2730 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
2731 return 0;
2732 }
2733 }
2734
2735 return 1;
2736}
2737
2738// scan for multiple pushes for given pop
2739static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
2740 int is_probe)
2741{
2742 int reg = ops[pop_i].operand[0].reg;
2743 struct parsed_op *po;
2744 struct label_ref *lr;
2745 int ret = 0;
2746
2747 ops[i].cc_scratch = magic;
2748
2749 while (1)
2750 {
2751 if (g_labels[i] != NULL) {
2752 lr = &g_label_refs[i];
2753 for (; lr != NULL; lr = lr->next) {
2754 check_i(&ops[i], lr->i);
2755 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
2756 if (ret < 0)
2757 return ret;
25a330eb 2758 }
e83ea7ed 2759 if (i > 0 && LAST_OP(i - 1))
2760 return ret;
2761 }
2762
2763 i--;
2764 if (i < 0)
9af2d373 2765 break;
e83ea7ed 2766
2767 if (ops[i].cc_scratch == magic)
2768 return ret;
2769 ops[i].cc_scratch = magic;
2770
2771 po = &ops[i];
2772 if (po->op == OP_CALL)
2773 return -1;
2774 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
2775 return -1;
2776
2777 if (po->op == OP_PUSH)
2778 {
2779 if (po->datap != NULL)
2780 return -1;
2781 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2782 // leave this case for reg save/restore handlers
2783 return -1;
2784
2785 if (!is_probe) {
2786 po->flags |= OPF_PPUSH | OPF_DONE;
2787 po->datap = &ops[pop_i];
2788 }
2789 return 1;
2790 }
2791 }
2792
2793 return -1;
2794}
2795
2796static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
2797{
2798 int magic = i + opcnt * 14;
2799 int ret;
2800
2801 ret = scan_pushes_for_pop_r(i, magic, i, 1);
2802 if (ret == 1) {
2803 ret = check_path_branches(opcnt, magic);
2804 if (ret == 1) {
2805 ops[i].flags |= OPF_PPUSH | OPF_DONE;
2806 *regmask_pp |= 1 << ops[i].operand[0].reg;
2807 scan_pushes_for_pop_r(i, magic + 1, i, 0);
9af2d373 2808 }
2809 }
2810}
2811
591721d7 2812static void scan_propagate_df(int i, int opcnt)
2813{
2814 struct parsed_op *po = &ops[i];
2815 int j;
2816
2817 for (; i < opcnt; i++) {
2818 po = &ops[i];
2819 if (po->flags & OPF_DF)
2820 return; // already resolved
2821 po->flags |= OPF_DF;
2822
2823 if (po->op == OP_CALL)
2824 ferr(po, "call with DF set?\n");
2825
2826 if (po->flags & OPF_JMP) {
2827 if (po->btj != NULL) {
2828 // jumptable
db63af51 2829 for (j = 0; j < po->btj->count; j++) {
2830 check_i(po, po->btj->d[j].bt_i);
591721d7 2831 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
db63af51 2832 }
591721d7 2833 return;
2834 }
2835
b2bd20c0 2836 if (po->flags & OPF_RMD)
2837 continue;
db63af51 2838 check_i(po, po->bt_i);
5c024ef7 2839 if (po->flags & OPF_CJMP)
591721d7 2840 scan_propagate_df(po->bt_i, opcnt);
2841 else
2842 i = po->bt_i - 1;
2843 continue;
2844 }
2845
2846 if (po->flags & OPF_TAIL)
2847 break;
2848
2849 if (po->op == OP_CLD) {
5e49b270 2850 po->flags |= OPF_RMD | OPF_DONE;
591721d7 2851 return;
2852 }
2853 }
2854
2855 ferr(po, "missing DF clear?\n");
2856}
2857
db63af51 2858// is operand 'opr' referenced by parsed_op 'po'?
2859static int is_opr_referenced(const struct parsed_opr *opr,
2860 const struct parsed_op *po)
2861{
2862 int i, mask;
2863
2864 if (opr->type == OPT_REG) {
2865 mask = po->regmask_dst | po->regmask_src;
2866 if (po->op == OP_CALL)
2867 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
2868 if ((1 << opr->reg) & mask)
2869 return 1;
2870 else
2871 return 0;
2872 }
2873
2874 for (i = 0; i < po->operand_cnt; i++)
2875 if (IS(po->operand[0].name, opr->name))
2876 return 1;
2877
2878 return 0;
2879}
2880
2881// is operand 'opr' read by parsed_op 'po'?
2882static int is_opr_read(const struct parsed_opr *opr,
2883 const struct parsed_op *po)
2884{
db63af51 2885 if (opr->type == OPT_REG) {
b2bd20c0 2886 if (po->regmask_src & (1 << opr->reg))
db63af51 2887 return 1;
2888 else
2889 return 0;
2890 }
2891
2892 // yes I'm lazy
2893 return 0;
2894}
2895
1cd4a663 2896// is operand 'opr' modified by parsed_op 'po'?
5101a5f9 2897static int is_opr_modified(const struct parsed_opr *opr,
69a3cdfc 2898 const struct parsed_op *po)
2899{
89ff3147 2900 int mask;
2901
89ff3147 2902 if (opr->type == OPT_REG) {
2903 if (po->op == OP_CALL) {
b2bd20c0 2904 mask = po->regmask_dst;
2905 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
2906 if (mask & (1 << opr->reg))
89ff3147 2907 return 1;
2908 else
2909 return 0;
2910 }
2911
b2bd20c0 2912 if (po->regmask_dst & (1 << opr->reg))
2913 return 1;
2914 else
2915 return 0;
69a3cdfc 2916 }
2917
2918 return IS(po->operand[0].name, opr->name);
2919}
2920
5101a5f9 2921// is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
2922static int is_any_opr_modified(const struct parsed_op *po_test,
89ff3147 2923 const struct parsed_op *po, int c_mode)
5101a5f9 2924{
89ff3147 2925 int mask;
5101a5f9 2926 int i;
2927
2928 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
2929 return 0;
2930
de50b98b 2931 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
2932 return 0;
2933
2934 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
2935 return 1;
2936
2937 // in reality, it can wreck any register, but in decompiled C
2b43685d 2938 // version it can only overwrite eax or edx:eax
89ff3147 2939 mask = (1 << xAX) | (1 << xDX);
2940 if (!c_mode)
2941 mask |= 1 << xCX;
2942
de50b98b 2943 if (po->op == OP_CALL
89ff3147 2944 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
5101a5f9 2945 return 1;
2946
2947 for (i = 0; i < po_test->operand_cnt; i++)
2948 if (IS(po_test->operand[i].name, po->operand[0].name))
2949 return 1;
2950
2951 return 0;
2952}
2953
940e8e66 2954// scan for any po_test operand modification in range given
89ff3147 2955static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
2956 int c_mode)
69a3cdfc 2957{
2b43685d 2958 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
2959 return -1;
2960
69a3cdfc 2961 for (; i < opcnt; i++) {
89ff3147 2962 if (is_any_opr_modified(po_test, &ops[i], c_mode))
69a3cdfc 2963 return i;
2964 }
2965
2966 return -1;
2967}
2968
940e8e66 2969// scan for po_test operand[0] modification in range given
2970static int scan_for_mod_opr0(struct parsed_op *po_test,
2971 int i, int opcnt)
2972{
2973 for (; i < opcnt; i++) {
2974 if (is_opr_modified(&po_test->operand[0], &ops[i]))
2975 return i;
2976 }
2977
2978 return -1;
2979}
2980
04f8a628 2981static int scan_for_flag_set(int i, int magic, int *branched,
2982 int *setters, int *setter_cnt)
69a3cdfc 2983{
04f8a628 2984 struct label_ref *lr;
2b43685d 2985 int ret;
de50b98b 2986
2987 while (i >= 0) {
04f8a628 2988 if (ops[i].cc_scratch == magic) {
04abc5d6 2989 // is this a problem?
2990 //ferr(&ops[i], "%s looped\n", __func__);
2991 return 0;
04f8a628 2992 }
2993 ops[i].cc_scratch = magic;
2994
d7857c3a 2995 if (g_labels[i] != NULL) {
2b43685d 2996 *branched = 1;
04f8a628 2997
2998 lr = &g_label_refs[i];
2999 for (; lr->next; lr = lr->next) {
92d715b6 3000 check_i(&ops[i], lr->i);
04f8a628 3001 ret = scan_for_flag_set(lr->i, magic,
3002 branched, setters, setter_cnt);
3003 if (ret < 0)
3004 return ret;
3005 }
3006
92d715b6 3007 check_i(&ops[i], lr->i);
de50b98b 3008 if (i > 0 && LAST_OP(i - 1)) {
94d447fb 3009 i = lr->i;
de50b98b 3010 continue;
3011 }
04f8a628 3012 ret = scan_for_flag_set(lr->i, magic,
3013 branched, setters, setter_cnt);
2b43685d 3014 if (ret < 0)
3015 return ret;
de50b98b 3016 }
3017 i--;
3018
2b43685d 3019 if (ops[i].flags & OPF_FLAGS) {
3020 setters[*setter_cnt] = i;
3021 (*setter_cnt)++;
3022 return 0;
3023 }
69a3cdfc 3024
5c024ef7 3025 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
69a3cdfc 3026 return -1;
69a3cdfc 3027 }
3028
3029 return -1;
3030}
3031
5101a5f9 3032// scan back for cdq, if anything modifies edx, fail
3033static int scan_for_cdq_edx(int i)
3034{
cdfaeed7 3035 while (i >= 0) {
d7857c3a 3036 if (g_labels[i] != NULL) {
cdfaeed7 3037 if (g_label_refs[i].next != NULL)
3038 return -1;
3039 if (i > 0 && LAST_OP(i - 1)) {
3040 i = g_label_refs[i].i;
3041 continue;
3042 }
3043 return -1;
3044 }
3045 i--;
3046
5101a5f9 3047 if (ops[i].op == OP_CDQ)
3048 return i;
3049
3050 if (ops[i].regmask_dst & (1 << xDX))
3051 return -1;
5101a5f9 3052 }
3053
3054 return -1;
3055}
3056
64c59faf 3057static int scan_for_reg_clear(int i, int reg)
3058{
cdfaeed7 3059 while (i >= 0) {
d7857c3a 3060 if (g_labels[i] != NULL) {
cdfaeed7 3061 if (g_label_refs[i].next != NULL)
3062 return -1;
3063 if (i > 0 && LAST_OP(i - 1)) {
3064 i = g_label_refs[i].i;
3065 continue;
3066 }
3067 return -1;
3068 }
3069 i--;
3070
64c59faf 3071 if (ops[i].op == OP_XOR
3072 && ops[i].operand[0].lmod == OPLM_DWORD
3073 && ops[i].operand[0].reg == ops[i].operand[1].reg
3074 && ops[i].operand[0].reg == reg)
3075 return i;
3076
3077 if (ops[i].regmask_dst & (1 << reg))
3078 return -1;
64c59faf 3079 }
3080
3081 return -1;
3082}
3083
ee2361b9 3084static void patch_esp_adjust(struct parsed_op *po, int adj)
3085{
3086 ferr_assert(po, po->op == OP_ADD);
3087 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3088 ferr_assert(po, po->operand[1].type == OPT_CONST);
3089
3090 // this is a bit of a hack, but deals with use of
3091 // single adj for multiple calls
3092 po->operand[1].val -= adj;
3093 po->flags |= OPF_RMD;
3094 if (po->operand[1].val == 0)
3095 po->flags |= OPF_DONE;
3096 ferr_assert(po, (int)po->operand[1].val >= 0);
3097}
3098
1bafb621 3099// scan for positive, constant esp adjust
ee2361b9 3100// multipath case is preliminary
9af2d373 3101static int scan_for_esp_adjust(int i, int opcnt,
ee2361b9 3102 int adj_expect, int *adj, int *is_multipath, int do_update)
1bafb621 3103{
bfacdc83 3104 int adj_expect_unknown = 0;
7ba45c34 3105 struct parsed_op *po;
46411e6c 3106 int first_pop = -1;
bfacdc83 3107 int adj_best = 0;
4741fdfe 3108
ee2361b9 3109 *adj = *is_multipath = 0;
bfacdc83 3110 if (adj_expect < 0) {
3111 adj_expect_unknown = 1;
3112 adj_expect = 32 * 4; // enough?
3113 }
7ba45c34 3114
9af2d373 3115 for (; i < opcnt && *adj < adj_expect; i++) {
d7857c3a 3116 if (g_labels[i] != NULL)
ee2361b9 3117 *is_multipath = 1;
a2c1d768 3118
5e49b270 3119 po = &ops[i];
3120 if (po->flags & OPF_DONE)
3121 continue;
3122
7ba45c34 3123 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3124 if (po->operand[1].type != OPT_CONST)
1bafb621 3125 ferr(&ops[i], "non-const esp adjust?\n");
7ba45c34 3126 *adj += po->operand[1].val;
1bafb621 3127 if (*adj & 3)
3128 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
ee2361b9 3129 if (do_update) {
3130 if (!*is_multipath)
3131 patch_esp_adjust(po, adj_expect);
3132 else
3133 po->flags |= OPF_RMD;
3134 }
1bafb621 3135 return i;
3136 }
5e49b270 3137 else if (po->op == OP_PUSH) {
5c024ef7 3138 //if (first_pop == -1)
3139 // first_pop = -2; // none
7ba45c34 3140 *adj -= lmod_bytes(po, po->operand[0].lmod);
46411e6c 3141 }
5e49b270 3142 else if (po->op == OP_POP) {
91ca764a 3143 if (!(po->flags & OPF_DONE)) {
3144 // seems like msvc only uses 'pop ecx' for stack realignment..
3145 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3146 break;
3147 if (first_pop == -1 && *adj >= 0)
3148 first_pop = i;
3149 }
ee2361b9 3150 if (do_update && *adj >= 0) {
3151 po->flags |= OPF_RMD;
3152 if (!*is_multipath)
b2bd20c0 3153 po->flags |= OPF_DONE | OPF_NOREGS;
ee2361b9 3154 }
3155
7ba45c34 3156 *adj += lmod_bytes(po, po->operand[0].lmod);
bfacdc83 3157 if (*adj > adj_best)
3158 adj_best = *adj;
46411e6c 3159 }
e56ab892 3160 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
4741fdfe 3161 if (po->op == OP_JMP && po->btj == NULL) {
5e49b270 3162 if (po->bt_i <= i)
3163 break;
4741fdfe 3164 i = po->bt_i - 1;
3165 continue;
3166 }
e56ab892 3167 if (po->op != OP_CALL)
a2c1d768 3168 break;
e56ab892 3169 if (po->operand[0].type != OPT_LABEL)
a2c1d768 3170 break;
91ca764a 3171 if (po->pp != NULL && po->pp->is_stdcall)
89ff3147 3172 break;
bfacdc83 3173 if (adj_expect_unknown && first_pop >= 0)
3174 break;
91ca764a 3175 // assume it's another cdecl call
e56ab892 3176 }
a2c1d768 3177 }
7ba45c34 3178
108e9fe3 3179 if (first_pop >= 0) {
bfacdc83 3180 // probably only 'pop ecx' was used
3181 *adj = adj_best;
46411e6c 3182 return first_pop;
1bafb621 3183 }
3184
3185 return -1;
3186}
3187
a3684be1 3188static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3189{
3190 struct parsed_op *po;
3191 int j;
3192
3193 if (i < 0)
3194 ferr(ops, "%s: followed bad branch?\n", __func__);
3195
3196 for (; i < opcnt; i++) {
3197 po = &ops[i];
3198 if (po->cc_scratch == magic)
3199 return;
3200 po->cc_scratch = magic;
3201 po->flags |= flags;
3202
3203 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3204 if (po->btj != NULL) {
3205 // jumptable
3206 for (j = 0; j < po->btj->count; j++)
3207 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3208 return;
3209 }
3210
3211 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
5c024ef7 3212 if (!(po->flags & OPF_CJMP))
a3684be1 3213 return;
3214 }
3215 if (po->flags & OPF_TAIL)
3216 return;
3217 }
3218}
3219
1cd4a663 3220static const struct parsed_proto *try_recover_pp(
da87ae38 3221 struct parsed_op *po, const struct parsed_opr *opr, int *search_instead)
1cd4a663 3222{
3223 const struct parsed_proto *pp = NULL;
89ff3147 3224 char buf[256];
3225 char *p;
1cd4a663 3226
3227 // maybe an arg of g_func?
3228 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3229 {
3230 char ofs_reg[16] = { 0, };
3231 int arg, arg_s, arg_i;
3232 int stack_ra = 0;
3233 int offset = 0;
3234
9af2d373 3235 if (g_header_mode)
3236 return NULL;
3237
1cd4a663 3238 parse_stack_access(po, opr->name, ofs_reg,
037f4971 3239 &offset, &stack_ra, NULL, 0);
1cd4a663 3240 if (ofs_reg[0] != 0)
3241 ferr(po, "offset reg on arg access?\n");
da87ae38 3242 if (offset <= stack_ra) {
3243 // search who set the stack var instead
3244 if (search_instead != NULL)
3245 *search_instead = 1;
3246 return NULL;
3247 }
1cd4a663 3248
3249 arg_i = (offset - stack_ra - 4) / 4;
3250 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3251 if (g_func_pp->arg[arg].reg != NULL)
3252 continue;
3253 if (arg_s == arg_i)
3254 break;
3255 arg_s++;
3256 }
3257 if (arg == g_func_pp->argc)
3258 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3259
3260 pp = g_func_pp->arg[arg].fptr;
3261 if (pp == NULL)
46411e6c 3262 ferr(po, "icall sa: arg%d is not a fptr?\n", arg + 1);
89ff3147 3263 check_func_pp(po, pp, "icall arg");
3264 }
3265 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3266 // label[index]
3267 p = strchr(opr->name + 1, '[');
3268 memcpy(buf, opr->name, p - opr->name);
3269 buf[p - opr->name] = 0;
92d715b6 3270 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
1cd4a663 3271 }
3272 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
9af2d373 3273 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3274 if (pp == NULL) {
3275 if (!g_header_mode)
3276 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3277 }
3278 else
3279 check_func_pp(po, pp, "reg-fptr ref");
1cd4a663 3280 }
3281
3282 return pp;
3283}
3284
da87ae38 3285static void scan_for_call_type(int i, const struct parsed_opr *opr,
db63af51 3286 int magic, const struct parsed_proto **pp_found, int *pp_i,
3287 int *multi)
1cd4a663 3288{
3289 const struct parsed_proto *pp = NULL;
3290 struct parsed_op *po;
3291 struct label_ref *lr;
3292
037f4971 3293 ops[i].cc_scratch = magic;
1cd4a663 3294
037f4971 3295 while (1) {
d7857c3a 3296 if (g_labels[i] != NULL) {
1cd4a663 3297 lr = &g_label_refs[i];
92d715b6 3298 for (; lr != NULL; lr = lr->next) {
3299 check_i(&ops[i], lr->i);
db63af51 3300 scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
92d715b6 3301 }
46411e6c 3302 if (i > 0 && LAST_OP(i - 1))
3303 return;
1cd4a663 3304 }
037f4971 3305
1cd4a663 3306 i--;
037f4971 3307 if (i < 0)
3308 break;
3309
3310 if (ops[i].cc_scratch == magic)
3311 return;
3312 ops[i].cc_scratch = magic;
1cd4a663 3313
3314 if (!(ops[i].flags & OPF_DATA))
3315 continue;
3316 if (!is_opr_modified(opr, &ops[i]))
3317 continue;
3318 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3319 // most probably trashed by some processing
3320 *pp_found = NULL;
3321 return;
3322 }
3323
3324 opr = &ops[i].operand[1];
3325 if (opr->type != OPT_REG)
3326 break;
3327 }
3328
3329 po = (i >= 0) ? &ops[i] : ops;
3330
3331 if (i < 0) {
3332 // reached the top - can only be an arg-reg
04abc5d6 3333 if (opr->type != OPT_REG || g_func_pp == NULL)
1cd4a663 3334 return;
3335
3336 for (i = 0; i < g_func_pp->argc; i++) {
3337 if (g_func_pp->arg[i].reg == NULL)
3338 continue;
3339 if (IS(opr->name, g_func_pp->arg[i].reg))
3340 break;
3341 }
3342 if (i == g_func_pp->argc)
3343 return;
3344 pp = g_func_pp->arg[i].fptr;
3345 if (pp == NULL)
46411e6c 3346 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3347 i + 1, g_func_pp->arg[i].reg);
89ff3147 3348 check_func_pp(po, pp, "icall reg-arg");
1cd4a663 3349 }
3350 else
da87ae38 3351 pp = try_recover_pp(po, opr, NULL);
1cd4a663 3352
89ff3147 3353 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
1cd4a663 3354 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3355 || (*pp_found)->is_stdcall != pp->is_stdcall
89ff3147 3356 || (*pp_found)->is_fptr != pp->is_fptr
1cd4a663 3357 || (*pp_found)->argc != pp->argc
3358 || (*pp_found)->argc_reg != pp->argc_reg
3359 || (*pp_found)->argc_stack != pp->argc_stack)
3360 {
3361 ferr(po, "icall: parsed_proto mismatch\n");
3362 }
89ff3147 3363 *multi = 1;
1cd4a663 3364 }
db63af51 3365 if (pp != NULL) {
1cd4a663 3366 *pp_found = pp;
db63af51 3367 *pp_i = po - ops;
3368 }
1cd4a663 3369}
3370
66bdb2b0 3371static void add_label_ref(struct label_ref *lr, int op_i)
9af2d373 3372{
66bdb2b0 3373 struct label_ref *lr_new;
9af2d373 3374
66bdb2b0 3375 if (lr->i == -1) {
3376 lr->i = op_i;
3377 return;
3378 }
9af2d373 3379
66bdb2b0 3380 lr_new = calloc(1, sizeof(*lr_new));
3381 lr_new->i = op_i;
3382 lr_new->next = lr->next;
3383 lr->next = lr_new;
3384}
3385
3386static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3387{
3388 struct parsed_op *po = &ops[i];
3389 struct parsed_data *pd;
3390 char label[NAMELEN], *p;
3391 int len, j, l;
3392
3393 p = strchr(po->operand[0].name, '[');
3394 if (p == NULL)
3395 return NULL;
3396
3397 len = p - po->operand[0].name;
3398 strncpy(label, po->operand[0].name, len);
3399 label[len] = 0;
3400
3401 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3402 if (IS(g_func_pd[j].label, label)) {
3403 pd = &g_func_pd[j];
3404 break;
3405 }
3406 }
3407 if (pd == NULL)
3408 //ferr(po, "label '%s' not parsed?\n", label);
3409 return NULL;
3410
3411 if (pd->type != OPT_OFFSET)
3412 ferr(po, "label '%s' with non-offset data?\n", label);
3413
3414 // find all labels, link
3415 for (j = 0; j < pd->count; j++) {
3416 for (l = 0; l < opcnt; l++) {
3417 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3418 add_label_ref(&g_label_refs[l], i);
3419 pd->d[j].bt_i = l;
3420 break;
3421 }
3422 }
3423 }
3424
3425 return pd;
3426}
3427
3428static void clear_labels(int count)
3429{
3430 int i;
3431
3432 for (i = 0; i < count; i++) {
3433 if (g_labels[i] != NULL) {
3434 free(g_labels[i]);
3435 g_labels[i] = NULL;
3436 }
3437 }
3438}
3439
b2bd20c0 3440static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3441{
3442 int regmask = 0;
3443 int i, reg;
3444
3445 for (i = 0; i < pp->argc; i++) {
3446 if (pp->arg[i].reg != NULL) {
3447 reg = char_array_i(regs_r32,
3448 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3449 if (reg < 0)
3450 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3451 pp->arg[i].reg, pp->name);
3452 regmask |= 1 << reg;
3453 }
3454 }
3455
3456 return regmask;
3457}
3458
3459static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3460{
4d247254 3461 int regmask = 0;
3462 int i, reg;
3463
3464 if (pp->has_retreg) {
3465 for (i = 0; i < pp->argc; i++) {
3466 if (pp->arg[i].type.is_retreg) {
3467 reg = char_array_i(regs_r32,
3468 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3469 ferr_assert(ops, reg >= 0);
3470 regmask |= 1 << reg;
3471 }
3472 }
3473 }
3474
b2bd20c0 3475 if (strstr(pp->ret_type.name, "int64"))
4d247254 3476 return regmask | (1 << xAX) | (1 << xDX);
d4a985bd 3477 if (IS(pp->ret_type.name, "float")
3478 || IS(pp->ret_type.name, "double"))
3479 {
4d247254 3480 return regmask | mxST0;
d4a985bd 3481 }
b2bd20c0 3482 if (strcasecmp(pp->ret_type.name, "void") == 0)
4d247254 3483 return regmask;
b2bd20c0 3484
4d247254 3485 return regmask | mxAX;
b2bd20c0 3486}
3487
66bdb2b0 3488static void resolve_branches_parse_calls(int opcnt)
3489{
d4a985bd 3490 static const struct {
3491 const char *name;
3492 enum op_op op;
3493 unsigned int flags;
3494 unsigned int regmask_src;
3495 unsigned int regmask_dst;
3496 } pseudo_ops[] = {
3497 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3498 };
66bdb2b0 3499 const struct parsed_proto *pp_c;
3500 struct parsed_proto *pp;
3501 struct parsed_data *pd;
3502 struct parsed_op *po;
3503 const char *tmpname;
b2bd20c0 3504 int i, l;
3505 int ret;
66bdb2b0 3506
3507 for (i = 0; i < opcnt; i++)
3508 {
3509 po = &ops[i];
3510 po->bt_i = -1;
3511 po->btj = NULL;
3512
865f1aca 3513 if (po->datap != NULL) {
3514 pp = calloc(1, sizeof(*pp));
3515 my_assert_not(pp, NULL);
3516
3517 ret = parse_protostr(po->datap, pp);
3518 if (ret < 0)
3519 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3520 free(po->datap);
3521 po->datap = NULL;
3522 po->pp = pp;
3523 }
3524
66bdb2b0 3525 if (po->op == OP_CALL) {
3526 pp = NULL;
3527
865f1aca 3528 if (po->pp != NULL)
3529 pp = po->pp;
3530 else if (po->operand[0].type == OPT_LABEL)
3531 {
66bdb2b0 3532 tmpname = opr_name(po, 0);
3533 if (IS_START(tmpname, "loc_"))
3534 ferr(po, "call to loc_*\n");
d4a985bd 3535
3536 // convert some calls to pseudo-ops
3537 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3538 if (!IS(tmpname, pseudo_ops[l].name))
3539 continue;
3540
3541 po->op = pseudo_ops[l].op;
3542 po->operand_cnt = 0;
3543 po->regmask_src = pseudo_ops[l].regmask_src;
3544 po->regmask_dst = pseudo_ops[l].regmask_dst;
3545 po->flags = pseudo_ops[l].flags;
3546 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3547 break;
3548 }
3549 if (l < ARRAY_SIZE(pseudo_ops))
3550 continue;
3551
66bdb2b0 3552 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3553 if (!g_header_mode && pp_c == NULL)
3554 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3555
3556 if (pp_c != NULL) {
3557 pp = proto_clone(pp_c);
3558 my_assert_not(pp, NULL);
3559 }
3560 }
66bdb2b0 3561
3562 if (pp != NULL) {
3563 if (pp->is_fptr)
3564 check_func_pp(po, pp, "fptr var call");
3565 if (pp->is_noreturn)
3566 po->flags |= OPF_TAIL;
3567 }
3568 po->pp = pp;
3569 continue;
3570 }
3571
3572 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3573 continue;
3574
3575 if (po->operand[0].type == OPT_REGMEM) {
3576 pd = try_resolve_jumptab(i, opcnt);
3577 if (pd == NULL)
3578 goto tailcall;
3579
3580 po->btj = pd;
3581 continue;
3582 }
3583
3584 for (l = 0; l < opcnt; l++) {
3585 if (g_labels[l] != NULL
3586 && IS(po->operand[0].name, g_labels[l]))
3587 {
3588 if (l == i + 1 && po->op == OP_JMP) {
3589 // yet another alignment type..
3590 po->flags |= OPF_RMD|OPF_DONE;
3591 break;
3592 }
3593 add_label_ref(&g_label_refs[l], i);
3594 po->bt_i = l;
3595 break;
3596 }
3597 }
3598
3599 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3600 continue;
3601
3602 if (po->operand[0].type == OPT_LABEL)
3603 // assume tail call
3604 goto tailcall;
3605
3606 ferr(po, "unhandled branch\n");
3607
3608tailcall:
3609 po->op = OP_CALL;
3610 po->flags |= OPF_TAIL;
3611 if (i > 0 && ops[i - 1].op == OP_POP)
3612 po->flags |= OPF_ATAIL;
3613 i--; // reprocess
3614 }
9af2d373 3615}
3616
3617static void scan_prologue_epilogue(int opcnt)
3618{
3619 int ecx_push = 0, esp_sub = 0;
3620 int found;
3621 int i, j, l;
3622
3623 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
3624 && ops[1].op == OP_MOV
3625 && IS(opr_name(&ops[1], 0), "ebp")
3626 && IS(opr_name(&ops[1], 1), "esp"))
3627 {
3628 g_bp_frame = 1;
b2bd20c0 3629 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3630 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
9af2d373 3631 i = 2;
3632
3633 if (ops[2].op == OP_SUB && IS(opr_name(&ops[2], 0), "esp")) {
3634 g_stack_fsz = opr_const(&ops[2], 1);
b2bd20c0 3635 ops[2].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
9af2d373 3636 i++;
3637 }
3638 else {
3639 // another way msvc builds stack frame..
3640 i = 2;
3641 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3642 g_stack_fsz += 4;
b2bd20c0 3643 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
9af2d373 3644 ecx_push++;
3645 i++;
3646 }
3647 // and another way..
3648 if (i == 2 && ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3649 && ops[i].operand[1].type == OPT_CONST
3650 && ops[i + 1].op == OP_CALL
3651 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3652 {
3653 g_stack_fsz += ops[i].operand[1].val;
b2bd20c0 3654 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
9af2d373 3655 i++;
b2bd20c0 3656 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
9af2d373 3657 i++;
3658 }
3659 }
3660
3661 found = 0;
3662 do {
3663 for (; i < opcnt; i++)
66bdb2b0 3664 if (ops[i].flags & OPF_TAIL)
9af2d373 3665 break;
3666 j = i - 1;
3667 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
66bdb2b0 3668 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3669 break;
3670 i--;
9af2d373 3671 j--;
3672 }
3673
3674 if ((ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
3675 || ops[j].op == OP_LEAVE)
3676 {
b2bd20c0 3677 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
9af2d373 3678 }
66bdb2b0 3679 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
3680 && ops[i].pp->is_noreturn)
3681 {
3682 // on noreturn, msvc sometimes cleans stack, sometimes not
3683 i++;
3684 found = 1;
3685 continue;
3686 }
9af2d373 3687 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3688 ferr(&ops[j], "'pop ebp' expected\n");
3689
3690 if (g_stack_fsz != 0) {
bfacdc83 3691 if (ops[j].op == OP_LEAVE)
3692 j--;
3693 else if (ops[j].op == OP_POP
3694 && ops[j - 1].op == OP_MOV
9af2d373 3695 && IS(opr_name(&ops[j - 1], 0), "esp")
3696 && IS(opr_name(&ops[j - 1], 1), "ebp"))
3697 {
b2bd20c0 3698 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
bfacdc83 3699 j -= 2;
9af2d373 3700 }
bfacdc83 3701 else if (!(g_ida_func_attr & IDAFA_NORETURN))
9af2d373 3702 {
bfacdc83 3703 ferr(&ops[j], "esp restore expected\n");
9af2d373 3704 }
3705
bfacdc83 3706 if (ecx_push && j >= 0 && ops[j].op == OP_POP
3707 && IS(opr_name(&ops[j], 0), "ecx"))
9af2d373 3708 {
bfacdc83 3709 ferr(&ops[j], "unexpected ecx pop\n");
9af2d373 3710 }
3711 }
3712
3713 found = 1;
3714 i++;
3715 } while (i < opcnt);
3716
66bdb2b0 3717 if (!found)
3718 ferr(ops, "missing ebp epilogue\n");
9af2d373 3719 return;
3720 }
3721
3722 // non-bp frame
3723 i = 0;
3724 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
b2bd20c0 3725 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
9af2d373 3726 g_stack_fsz += 4;
3727 ecx_push++;
3728 i++;
3729 }
3730
3731 for (; i < opcnt; i++) {
3732 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
3733 break;
3734 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
3735 && ops[i].operand[1].type == OPT_CONST)
3736 {
3737 g_stack_fsz = ops[i].operand[1].val;
b2bd20c0 3738 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
9af2d373 3739 esp_sub = 1;
3740 break;
3741 }
3742 }
3743
3744 if (ecx_push && !esp_sub) {
3745 // could actually be args for a call..
3746 for (; i < opcnt; i++)
3747 if (ops[i].op != OP_PUSH)
3748 break;
3749
3750 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
3751 const struct parsed_proto *pp;
3752 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
3753 j = pp ? pp->argc_stack : 0;
3754 while (i > 0 && j > 0) {
3755 i--;
3756 if (ops[i].op == OP_PUSH) {
b2bd20c0 3757 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
9af2d373 3758 j--;
3759 }
3760 }
3761 if (j != 0)
3762 ferr(&ops[i], "unhandled prologue\n");
3763
3764 // recheck
3765 i = g_stack_fsz = ecx_push = 0;
3766 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3767 if (!(ops[i].flags & OPF_RMD))
3768 break;
3769 g_stack_fsz += 4;
3770 ecx_push++;
3771 i++;
3772 }
3773 }
3774 }
3775
3776 found = 0;
3777 if (ecx_push || esp_sub)
3778 {
3779 g_sp_frame = 1;
3780
3781 i++;
3782 do {
3783 for (; i < opcnt; i++)
66bdb2b0 3784 if (ops[i].flags & OPF_TAIL)
9af2d373 3785 break;
3786 j = i - 1;
3787 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
66bdb2b0 3788 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3789 break;
3790 i--;
9af2d373 3791 j--;
3792 }
3793
3794 if (ecx_push > 0) {
3795 for (l = 0; l < ecx_push; l++) {
3796 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
3797 /* pop ecx */;
3798 else if (ops[j].op == OP_ADD
3799 && IS(opr_name(&ops[j], 0), "esp")
3800 && ops[j].operand[1].type == OPT_CONST)
3801 {
3802 /* add esp, N */
5e49b270 3803 l += ops[j].operand[1].val / 4 - 1;
9af2d373 3804 }
3805 else
3806 ferr(&ops[j], "'pop ecx' expected\n");
3807
b2bd20c0 3808 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
9af2d373 3809 j--;
3810 }
3811 if (l != ecx_push)
3812 ferr(&ops[j], "epilogue scan failed\n");
3813
3814 found = 1;
3815 }
3816
3817 if (esp_sub) {
3818 if (ops[j].op != OP_ADD
3819 || !IS(opr_name(&ops[j], 0), "esp")
3820 || ops[j].operand[1].type != OPT_CONST
3821 || ops[j].operand[1].val != g_stack_fsz)
3822 ferr(&ops[j], "'add esp' expected\n");
3823
b2bd20c0 3824 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
9af2d373 3825 ops[j].operand[1].val = 0; // hack for stack arg scanner
3826 found = 1;
3827 }
3828
3829 i++;
3830 } while (i < opcnt);
66bdb2b0 3831
3832 if (!found)
3833 ferr(ops, "missing esp epilogue\n");
9af2d373 3834 }
3835}
3836
23fd0b11 3837// find an instruction that changed opr before i op
db63af51 3838// *op_i must be set to -1 by the caller
865f1aca 3839// *is_caller is set to 1 if one source is determined to be g_func arg
92d715b6 3840// returns 1 if found, *op_i is then set to origin
865f1aca 3841// returns -1 if multiple origins are found
23fd0b11 3842static int resolve_origin(int i, const struct parsed_opr *opr,
92d715b6 3843 int magic, int *op_i, int *is_caller)
1f84f6b3 3844{
3845 struct label_ref *lr;
3846 int ret = 0;
3847
92d715b6 3848 if (ops[i].cc_scratch == magic)
3849 return 0;
1f84f6b3 3850 ops[i].cc_scratch = magic;
3851
3852 while (1) {
d7857c3a 3853 if (g_labels[i] != NULL) {
1f84f6b3 3854 lr = &g_label_refs[i];
92d715b6 3855 for (; lr != NULL; lr = lr->next) {
3856 check_i(&ops[i], lr->i);
3857 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
3858 }
1f84f6b3 3859 if (i > 0 && LAST_OP(i - 1))
3860 return ret;
3861 }
3862
3863 i--;
92d715b6 3864 if (i < 0) {
3865 if (is_caller != NULL)
3866 *is_caller = 1;
1f84f6b3 3867 return -1;
92d715b6 3868 }
1f84f6b3 3869
3870 if (ops[i].cc_scratch == magic)
ebc4dc43 3871 return ret;
1f84f6b3 3872 ops[i].cc_scratch = magic;
3873
3874 if (!(ops[i].flags & OPF_DATA))
3875 continue;
3876 if (!is_opr_modified(opr, &ops[i]))
3877 continue;
23fd0b11 3878
3879 if (*op_i >= 0) {
3880 if (*op_i == i)
ebc4dc43 3881 return ret | 1;
3882
23fd0b11 3883 // XXX: could check if the other op does the same
3884 return -1;
3885 }
3886
3887 *op_i = i;
ebc4dc43 3888 return ret | 1;
23fd0b11 3889 }
3890}
3891
db63af51 3892// find an instruction that previously referenced opr
3893// if multiple results are found - fail
3894// *op_i must be set to -1 by the caller
3895// returns 1 if found, *op_i is then set to referencer insn
3896static int resolve_last_ref(int i, const struct parsed_opr *opr,
3897 int magic, int *op_i)
3898{
3899 struct label_ref *lr;
3900 int ret = 0;
3901
3902 if (ops[i].cc_scratch == magic)
3903 return 0;
3904 ops[i].cc_scratch = magic;
3905
3906 while (1) {
3907 if (g_labels[i] != NULL) {
3908 lr = &g_label_refs[i];
3909 for (; lr != NULL; lr = lr->next) {
3910 check_i(&ops[i], lr->i);
3911 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
3912 }
3913 if (i > 0 && LAST_OP(i - 1))
3914 return ret;
3915 }
3916
3917 i--;
3918 if (i < 0)
3919 return -1;
3920
3921 if (ops[i].cc_scratch == magic)
3922 return 0;
3923 ops[i].cc_scratch = magic;
3924
3925 if (!is_opr_referenced(opr, &ops[i]))
3926 continue;
3927
3928 if (*op_i >= 0)
3929 return -1;
3930
3931 *op_i = i;
3932 return 1;
3933 }
3934}
3935
3936// find next instruction that reads opr
db63af51 3937// *op_i must be set to -1 by the caller
b2bd20c0 3938// on return, *op_i is set to first referencer insn
3939// returns 1 if exactly 1 referencer is found
db63af51 3940static int find_next_read(int i, int opcnt,
3941 const struct parsed_opr *opr, int magic, int *op_i)
3942{
3943 struct parsed_op *po;
3944 int j, ret = 0;
3945
3946 for (; i < opcnt; i++)
3947 {
3948 if (ops[i].cc_scratch == magic)
b2bd20c0 3949 return ret;
db63af51 3950 ops[i].cc_scratch = magic;
3951
3952 po = &ops[i];
3953 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3954 if (po->btj != NULL) {
3955 // jumptable
3956 for (j = 0; j < po->btj->count; j++) {
3957 check_i(po, po->btj->d[j].bt_i);
3958 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
3959 magic, op_i);
3960 }
3961 return ret;
3962 }
3963
3964 if (po->flags & OPF_RMD)
3965 continue;
3966 check_i(po, po->bt_i);
3967 if (po->flags & OPF_CJMP) {
b2bd20c0 3968 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
db63af51 3969 if (ret < 0)
3970 return ret;
3971 }
b2bd20c0 3972 else
3973 i = po->bt_i - 1;
db63af51 3974 continue;
3975 }
3976
3977 if (!is_opr_read(opr, po)) {
acd03176 3978 if (is_opr_modified(opr, po)
3979 && (po->op == OP_CALL
3980 || ((po->flags & OPF_DATA)
3981 && po->operand[0].lmod == OPLM_DWORD)))
3982 {
db63af51 3983 // it's overwritten
b2bd20c0 3984 return ret;
acd03176 3985 }
db63af51 3986 if (po->flags & OPF_TAIL)
b2bd20c0 3987 return ret;
db63af51 3988 continue;
3989 }
3990
3991 if (*op_i >= 0)
3992 return -1;
3993
3994 *op_i = i;
3995 return 1;
3996 }
3997
3998 return 0;
3999}
4000
23fd0b11 4001static int try_resolve_const(int i, const struct parsed_opr *opr,
4002 int magic, unsigned int *val)
4003{
4004 int s_i = -1;
92d715b6 4005 int ret;
23fd0b11 4006
92d715b6 4007 ret = resolve_origin(i, opr, magic, &s_i, NULL);
23fd0b11 4008 if (ret == 1) {
4009 i = s_i;
1f84f6b3 4010 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4011 return -1;
4012
4013 *val = ops[i].operand[1].val;
4014 return 1;
4015 }
23fd0b11 4016
4017 return -1;
1f84f6b3 4018}
4019
865f1aca 4020static const struct parsed_proto *resolve_icall(int i, int opcnt,
4021 int *pp_i, int *multi_src)
4022{
4023 const struct parsed_proto *pp = NULL;
4024 int search_advice = 0;
4025 int offset = -1;
4026 char name[256];
4027 char s_reg[4];
4028 int reg, len;
4029 int ret;
4030
4031 *multi_src = 0;
4032 *pp_i = -1;
4033
4034 switch (ops[i].operand[0].type) {
4035 case OPT_REGMEM:
4036 // try to resolve struct member calls
4037 ret = sscanf(ops[i].operand[0].name, "%3s+%x%n",
4038 s_reg, &offset, &len);
4039 if (ret == 2 && len == strlen(ops[i].operand[0].name))
4040 {
4041 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4042 if (reg >= 0) {
4043 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, reg);
4044 int j = -1;
4045 ret = resolve_origin(i, &opr, i + opcnt * 19, &j, NULL);
4046 if (ret != 1)
4047 break;
4048 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4049 && ops[j].operand[0].lmod == OPLM_DWORD
4050 && ops[j].pp == NULL) // no hint
4051 {
4052 // allow one simple dereference (directx)
4053 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4054 ops[j].operand[1].name);
4055 if (reg < 0)
4056 break;
4057 struct parsed_opr opr2 = OPR_INIT(OPT_REG, OPLM_DWORD, reg);
4058 int k = -1;
4059 ret = resolve_origin(j, &opr2, j + opcnt * 19, &k, NULL);
4060 if (ret != 1)
4061 break;
4062 j = k;
4063 }
4064 if (ops[j].op != OP_MOV)
4065 break;
4066 if (ops[j].operand[0].lmod != OPLM_DWORD)
4067 break;
4068 if (ops[j].pp != NULL) {
4069 // type hint in asm
4070 pp = ops[j].pp;
4071 }
4072 else if (ops[j].operand[1].type == OPT_REGMEM) {
4073 // allow 'hello[ecx]' - assume array of same type items
4074 ret = sscanf(ops[j].operand[1].name, "%[^[][e%2s]",
4075 name, s_reg);
4076 if (ret != 2)
4077 break;
4078 pp = proto_parse(g_fhdr, name, g_quiet_pp);
4079 }
4080 else if (ops[j].operand[1].type == OPT_LABEL)
4081 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4082 else
4083 break;
4084 if (pp == NULL)
4085 break;
4086 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4087 pp = NULL;
4088 break;
4089 }
4090 pp = proto_lookup_struct(g_fhdr, pp->type.name, offset);
4091 }
4092 break;
4093 }
4094 // fallthrough
4095 case OPT_LABEL:
4096 case OPT_OFFSET:
4097 pp = try_recover_pp(&ops[i], &ops[i].operand[0], &search_advice);
4098 if (!search_advice)
4099 break;
4100 // fallthrough
4101 default:
4102 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4103 pp_i, multi_src);
4104 break;
4105 }
4106
4107 return pp;
4108}
4109
26677139 4110static struct parsed_proto *process_call_early(int i, int opcnt,
4111 int *adj_i)
4112{
4113 struct parsed_op *po = &ops[i];
4114 struct parsed_proto *pp;
4115 int multipath = 0;
4116 int adj = 0;
bfacdc83 4117 int j, ret;
26677139 4118
4119 pp = po->pp;
4120 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4121 // leave for later
4122 return NULL;
4123
4124 // look for and make use of esp adjust
4125 *adj_i = ret = -1;
4126 if (!pp->is_stdcall && pp->argc_stack > 0)
4127 ret = scan_for_esp_adjust(i + 1, opcnt,
ee2361b9 4128 pp->argc_stack * 4, &adj, &multipath, 0);
26677139 4129 if (ret >= 0) {
4130 if (pp->argc_stack > adj / 4)
4131 return NULL;
4132 if (multipath)
4133 return NULL;
bfacdc83 4134 if (ops[ret].op == OP_POP) {
4135 for (j = 1; j < adj / 4; j++) {
4136 if (ops[ret + j].op != OP_POP
4137 || ops[ret + j].operand[0].reg != xCX)
4138 {
4139 return NULL;
4140 }
4141 }
4142 }
26677139 4143 }
4144
4145 *adj_i = ret;
4146 return pp;
4147}
4148
9af2d373 4149static struct parsed_proto *process_call(int i, int opcnt)
4150{
4151 struct parsed_op *po = &ops[i];
4152 const struct parsed_proto *pp_c;
4153 struct parsed_proto *pp;
4154 const char *tmpname;
db63af51 4155 int call_i = -1, ref_i = -1;
26677139 4156 int adj = 0, multipath = 0;
9af2d373 4157 int ret, arg;
4158
4159 tmpname = opr_name(po, 0);
4160 pp = po->pp;
4161 if (pp == NULL)
4162 {
4163 // indirect call
db63af51 4164 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
9af2d373 4165 if (pp_c != NULL) {
4166 if (!pp_c->is_func && !pp_c->is_fptr)
4167 ferr(po, "call to non-func: %s\n", pp_c->name);
4168 pp = proto_clone(pp_c);
4169 my_assert_not(pp, NULL);
26677139 4170 if (multipath)
9af2d373 4171 // not resolved just to single func
4172 pp->is_fptr = 1;
4173
4174 switch (po->operand[0].type) {
4175 case OPT_REG:
4176 // we resolved this call and no longer need the register
4177 po->regmask_src &= ~(1 << po->operand[0].reg);
db63af51 4178
4179 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4180 && ops[call_i].operand[1].type == OPT_LABEL)
4181 {
4182 // no other source users?
e83ea7ed 4183 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
db63af51 4184 &ref_i);
4185 if (ret == 1 && call_i == ref_i) {
4186 // and nothing uses it after us?
4187 ref_i = -1;
b2bd20c0 4188 find_next_read(i + 1, opcnt, &po->operand[0],
4189 i + opcnt * 11, &ref_i);
4190 if (ref_i == -1)
db63af51 4191 // then also don't need the source mov
b2bd20c0 4192 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
db63af51 4193 }
4194 }
9af2d373 4195 break;
4196 case OPT_REGMEM:
4197 pp->is_fptr = 1;
4198 break;
4199 default:
4200 break;
4201 }
4202 }
4203 if (pp == NULL) {
4204 pp = calloc(1, sizeof(*pp));
4205 my_assert_not(pp, NULL);
4206
4207 pp->is_fptr = 1;
ee2361b9 4208 ret = scan_for_esp_adjust(i + 1, opcnt,
bfacdc83 4209 -1, &adj, &multipath, 0);
26677139 4210 if (ret < 0 || adj < 0) {
9af2d373 4211 if (!g_allow_regfunc)
4212 ferr(po, "non-__cdecl indirect call unhandled yet\n");
4213 pp->is_unresolved = 1;
26677139 4214 adj = 0;
9af2d373 4215 }
26677139 4216 adj /= 4;
4217 if (adj > ARRAY_SIZE(pp->arg))
4218 ferr(po, "esp adjust too large: %d\n", adj);
9af2d373 4219 pp->ret_type.name = strdup("int");
26677139 4220 pp->argc = pp->argc_stack = adj;
9af2d373 4221 for (arg = 0; arg < pp->argc; arg++)
4222 pp->arg[arg].type.name = strdup("int");
4223 }
4224 po->pp = pp;
4225 }
4226
4227 // look for and make use of esp adjust
91ca764a 4228 multipath = 0;
9af2d373 4229 ret = -1;
bfacdc83 4230 if (!pp->is_stdcall && pp->argc_stack > 0) {
4231 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
9af2d373 4232 ret = scan_for_esp_adjust(i + 1, opcnt,
bfacdc83 4233 adj_expect, &adj, &multipath, 0);
4234 }
9af2d373 4235 if (ret >= 0) {
4236 if (pp->is_vararg) {
26677139 4237 if (adj / 4 < pp->argc_stack) {
4238 fnote(po, "(this call)\n");
4239 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
4240 adj, pp->argc_stack * 4);
4241 }
9af2d373 4242 // modify pp to make it have varargs as normal args
4243 arg = pp->argc;
26677139 4244 pp->argc += adj / 4 - pp->argc_stack;
9af2d373 4245 for (; arg < pp->argc; arg++) {
4246 pp->arg[arg].type.name = strdup("int");
4247 pp->argc_stack++;
4248 }
4249 if (pp->argc > ARRAY_SIZE(pp->arg))
4250 ferr(po, "too many args for '%s'\n", tmpname);
4251 }
26677139 4252 if (pp->argc_stack > adj / 4) {
9af2d373 4253 fnote(po, "(this call)\n");
4254 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
26677139 4255 tmpname, pp->argc_stack * 4, adj);
9af2d373 4256 }
4257
ee2361b9 4258 scan_for_esp_adjust(i + 1, opcnt,
4259 pp->argc_stack * 4, &adj, &multipath, 1);
9af2d373 4260 }
4261 else if (pp->is_vararg)
4262 ferr(po, "missing esp_adjust for vararg func '%s'\n",
4263 pp->name);
4264
4265 return pp;
4266}
4267
26677139 4268static int collect_call_args_early(struct parsed_op *po, int i,
4269 struct parsed_proto *pp, int *regmask)
4270{
4271 int arg, ret;
4272 int j;
4273
4274 for (arg = 0; arg < pp->argc; arg++)
4275 if (pp->arg[arg].reg == NULL)
4276 break;
4277
4278 // first see if it can be easily done
4279 for (j = i; j > 0 && arg < pp->argc; )
4280 {
4281 if (g_labels[j] != NULL)
4282 return -1;
4283 j--;
4284
4285 if (ops[j].op == OP_CALL)
4286 return -1;
4287 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP)
4288 return -1;
4289 else if (ops[j].op == OP_POP)
4290 return -1;
4291 else if (ops[j].flags & OPF_CJMP)
4292 return -1;
4293 else if (ops[j].op == OP_PUSH) {
4294 if (ops[j].flags & (OPF_FARG|OPF_FARGNR))
4295 return -1;
4296 ret = scan_for_mod(&ops[j], j + 1, i, 1);
4297 if (ret >= 0)
4298 return -1;
4299
4300 if (pp->arg[arg].type.is_va_list)
4301 return -1;
4302
4303 // next arg
4304 for (arg++; arg < pp->argc; arg++)
4305 if (pp->arg[arg].reg == NULL)
4306 break;
4307 }
4308 }
4309
4310 if (arg < pp->argc)
4311 return -1;
4312
4313 // now do it
4314 for (arg = 0; arg < pp->argc; arg++)
4315 if (pp->arg[arg].reg == NULL)
4316 break;
4317
4318 for (j = i; j > 0 && arg < pp->argc; )
4319 {
4320 j--;
4321
4322 if (ops[j].op == OP_PUSH)
4323 {
4324 ops[j].p_argnext = -1;
4325 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
4326 pp->arg[arg].datap = &ops[j];
4327
4328 if (ops[j].operand[0].type == OPT_REG)
4329 *regmask |= 1 << ops[j].operand[0].reg;
4330
5e49b270 4331 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
26677139 4332 ops[j].flags &= ~OPF_RSAVE;
4333
4334 // next arg
4335 for (arg++; arg < pp->argc; arg++)
4336 if (pp->arg[arg].reg == NULL)
4337 break;
4338 }
4339 }
4340
4341 return 0;
4342}
4343
89ff3147 4344static int collect_call_args_r(struct parsed_op *po, int i,
3a5101d7 4345 struct parsed_proto *pp, int *regmask, int *save_arg_vars,
4346 int *arg_grp, int arg, int magic, int need_op_saving, int may_reuse)
e56ab892 4347{
4348 struct parsed_proto *pp_tmp;
3a5101d7 4349 struct parsed_op *po_tmp;
e56ab892 4350 struct label_ref *lr;
2b43685d 4351 int need_to_save_current;
3a5101d7 4352 int arg_grp_current = 0;
4353 int save_args_seen = 0;
23fd0b11 4354 int save_args;
e56ab892 4355 int ret = 0;
5f70a34f 4356 int reg;
23fd0b11 4357 char buf[32];
4358 int j, k;
e56ab892 4359
a3684be1 4360 if (i < 0) {
a2c1d768 4361 ferr(po, "dead label encountered\n");
a3684be1 4362 return -1;
4363 }
e56ab892 4364
de50b98b 4365 for (; arg < pp->argc; arg++)
e56ab892 4366 if (pp->arg[arg].reg == NULL)
4367 break;
a3684be1 4368 magic = (magic & 0xffffff) | (arg << 24);
e56ab892 4369
89ff3147 4370 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
e56ab892 4371 {
a3684be1 4372 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
4373 if (ops[j].cc_scratch != magic) {
4374 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
4375 pp->name);
4376 return -1;
4377 }
4378 // ok: have already been here
4379 return 0;
4380 }
4381 ops[j].cc_scratch = magic;
4382
d7857c3a 4383 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
e56ab892 4384 lr = &g_label_refs[j];
4385 if (lr->next != NULL)
4386 need_op_saving = 1;
a652aa9f 4387 for (; lr->next; lr = lr->next) {
92d715b6 4388 check_i(&ops[j], lr->i);
5c024ef7 4389 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
a652aa9f 4390 may_reuse = 1;
89ff3147 4391 ret = collect_call_args_r(po, lr->i, pp, regmask, save_arg_vars,
3a5101d7 4392 arg_grp, arg, magic, need_op_saving, may_reuse);
a3684be1 4393 if (ret < 0)
4394 return ret;
a652aa9f 4395 }
e56ab892 4396
92d715b6 4397 check_i(&ops[j], lr->i);
5c024ef7 4398 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
a652aa9f 4399 may_reuse = 1;
de50b98b 4400 if (j > 0 && LAST_OP(j - 1)) {
e56ab892 4401 // follow last branch in reverse
4402 j = lr->i;
4403 continue;
4404 }
4405 need_op_saving = 1;
89ff3147 4406 ret = collect_call_args_r(po, lr->i, pp, regmask, save_arg_vars,
3a5101d7 4407 arg_grp, arg, magic, need_op_saving, may_reuse);
a3684be1 4408 if (ret < 0)
4409 return ret;
e56ab892 4410 }
4411 j--;
4412
4413 if (ops[j].op == OP_CALL)
4414 {
89ff3147 4415 if (pp->is_unresolved)
4416 break;
4417
092f64e1 4418 pp_tmp = ops[j].pp;
e56ab892 4419 if (pp_tmp == NULL)
7ae48d73 4420 ferr(po, "arg collect hit unparsed call '%s'\n",
4421 ops[j].operand[0].name);
a652aa9f 4422 if (may_reuse && pp_tmp->argc_stack > 0)
de50b98b 4423 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
4424 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
e56ab892 4425 }
fdd5548a 4426 // esp adjust of 0 means we collected it before
4427 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
4428 && (ops[j].operand[1].type != OPT_CONST
4429 || ops[j].operand[1].val != 0))
4430 {
89ff3147 4431 if (pp->is_unresolved)
4432 break;
4433
2b70f6d3 4434 fnote(po, "(this call)\n");
4435 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
fdd5548a 4436 arg, pp->argc, ops[j].operand[1].val);
de50b98b 4437 }
5e49b270 4438 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
9af2d373 4439 {
89ff3147 4440 if (pp->is_unresolved)
4441 break;
4442
2b70f6d3 4443 fnote(po, "(this call)\n");
4444 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
de50b98b 4445 }
5c024ef7 4446 else if (ops[j].flags & OPF_CJMP)
de50b98b 4447 {
89ff3147 4448 if (pp->is_unresolved)
4449 break;
4450
a652aa9f 4451 may_reuse = 1;
de50b98b 4452 }
91ca764a 4453 else if (ops[j].op == OP_PUSH
4454 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
e56ab892 4455 {
89ff3147 4456 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
4457 break;
4458
3a5101d7 4459 ops[j].p_argnext = -1;
4460 po_tmp = pp->arg[arg].datap;
4461 if (po_tmp != NULL)
4462 ops[j].p_argnext = po_tmp - ops;
e56ab892 4463 pp->arg[arg].datap = &ops[j];
3a5101d7 4464
2b43685d 4465 need_to_save_current = 0;
23fd0b11 4466 save_args = 0;
5f70a34f 4467 reg = -1;
4468 if (ops[j].operand[0].type == OPT_REG)
4469 reg = ops[j].operand[0].reg;
4470
e56ab892 4471 if (!need_op_saving) {
89ff3147 4472 ret = scan_for_mod(&ops[j], j + 1, i, 1);
2b43685d 4473 need_to_save_current = (ret >= 0);
e56ab892 4474 }
2b43685d 4475 if (need_op_saving || need_to_save_current) {
e56ab892 4476 // mark this push as one that needs operand saving
4477 ops[j].flags &= ~OPF_RMD;
5f70a34f 4478 if (ops[j].p_argnum == 0) {
4479 ops[j].p_argnum = arg + 1;
23fd0b11 4480 save_args |= 1 << arg;
de50b98b 4481 }
fdd5548a 4482 else if (ops[j].p_argnum < arg + 1) {
4483 // XXX: might kill valid var..
4484 //*save_arg_vars &= ~(1 << (ops[j].p_argnum - 1));
4485 ops[j].p_argnum = arg + 1;
4486 save_args |= 1 << arg;
4487 }
3a5101d7 4488
4489 if (save_args_seen & (1 << (ops[j].p_argnum - 1))) {
4490 save_args_seen = 0;
4491 arg_grp_current++;
4492 if (arg_grp_current >= MAX_ARG_GRP)
4493 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
4494 ops[j].p_argnum, pp->name);
4495 }
e56ab892 4496 }
5f70a34f 4497 else if (ops[j].p_argnum == 0)
e56ab892 4498 ops[j].flags |= OPF_RMD;
4499
a652aa9f 4500 // some PUSHes are reused by different calls on other branches,
de50b98b 4501 // but that can't happen if we didn't branch, so they
4502 // can be removed from future searches (handles nested calls)
a652aa9f 4503 if (!may_reuse)
9af2d373 4504 ops[j].flags |= OPF_FARGNR;
de50b98b 4505
9af2d373 4506 ops[j].flags |= OPF_FARG;
da87ae38 4507 ops[j].flags &= ~OPF_RSAVE;
4508
23fd0b11 4509 // check for __VALIST
04abc5d6 4510 if (!pp->is_unresolved && g_func_pp != NULL
4511 && pp->arg[arg].type.is_va_list)
4512 {
23fd0b11 4513 k = -1;
92d715b6 4514 ret = resolve_origin(j, &ops[j].operand[0],
4515 magic + 1, &k, NULL);
5f70a34f 4516 if (ret == 1 && k >= 0)
23fd0b11 4517 {
5f70a34f 4518 if (ops[k].op == OP_LEA) {
acd03176 4519 if (!g_func_pp->is_vararg)
4520 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
4521 g_func_pp->name);
4522
5f70a34f 4523 snprintf(buf, sizeof(buf), "arg_%X",
4524 g_func_pp->argc_stack * 4);
acd03176 4525 if (strstr(ops[k].operand[1].name, buf)
4526 || strstr(ops[k].operand[1].name, "arglist"))
5f70a34f 4527 {
b2bd20c0 4528 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
4529 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
5f70a34f 4530 save_args &= ~(1 << arg);
4531 reg = -1;
4532 }
4533 else
acd03176 4534 ferr(&ops[k], "va_list arg detection failed\n");
5f70a34f 4535 }
4536 // check for va_list from g_func_pp arg too
4537 else if (ops[k].op == OP_MOV
4538 && is_stack_access(&ops[k], &ops[k].operand[1]))
4539 {
4540 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
4541 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
4542 if (ret >= 0) {
5e49b270 4543 ops[k].flags |= OPF_RMD | OPF_DONE;
5f70a34f 4544 ops[j].flags |= OPF_RMD;
4545 ops[j].p_argpass = ret + 1;
4546 save_args &= ~(1 << arg);
4547 reg = -1;
4548 }
4549 }
23fd0b11 4550 }
4551 }
4552
4553 *save_arg_vars |= save_args;
4554
4555 // tracking reg usage
5f70a34f 4556 if (reg >= 0)
4557 *regmask |= 1 << reg;
23fd0b11 4558
89ff3147 4559 arg++;
4560 if (!pp->is_unresolved) {
4561 // next arg
4562 for (; arg < pp->argc; arg++)
4563 if (pp->arg[arg].reg == NULL)
4564 break;
4565 }
a3684be1 4566 magic = (magic & 0xffffff) | (arg << 24);
e56ab892 4567 }
3a5101d7 4568
4569 if (ops[j].p_arggrp > arg_grp_current) {
4570 save_args_seen = 0;
4571 arg_grp_current = ops[j].p_arggrp;
4572 }
4573 if (ops[j].p_argnum > 0)
4574 save_args_seen |= 1 << (ops[j].p_argnum - 1);
e56ab892 4575 }
4576
4577 if (arg < pp->argc) {
4578 ferr(po, "arg collect failed for '%s': %d/%d\n",
4579 pp->name, arg, pp->argc);
89ff3147 4580 return -1;
e56ab892 4581 }
89ff3147 4582
3a5101d7 4583 if (arg_grp_current > *arg_grp)
4584 *arg_grp = arg_grp_current;
4585
89ff3147 4586 return arg;
4587}
4588
4589static int collect_call_args(struct parsed_op *po, int i,
4590 struct parsed_proto *pp, int *regmask, int *save_arg_vars,
4591 int magic)
4592{
3a5101d7 4593 // arg group is for cases when pushes for
4594 // multiple funcs are going on
4595 struct parsed_op *po_tmp;
4596 int save_arg_vars_current = 0;
4597 int arg_grp = 0;
89ff3147 4598 int ret;
4599 int a;
4600
3a5101d7 4601 ret = collect_call_args_r(po, i, pp, regmask,
4602 &save_arg_vars_current, &arg_grp, 0, magic, 0, 0);
89ff3147 4603 if (ret < 0)
4604 return ret;
4605
3a5101d7 4606 if (arg_grp != 0) {
4607 // propagate arg_grp
4608 for (a = 0; a < pp->argc; a++) {
4609 if (pp->arg[a].reg != NULL)
4610 continue;
4611
4612 po_tmp = pp->arg[a].datap;
4613 while (po_tmp != NULL) {
4614 po_tmp->p_arggrp = arg_grp;
4615 if (po_tmp->p_argnext > 0)
4616 po_tmp = &ops[po_tmp->p_argnext];
4617 else
4618 po_tmp = NULL;
4619 }
4620 }
4621 }
4622 save_arg_vars[arg_grp] |= save_arg_vars_current;
4623
89ff3147 4624 if (pp->is_unresolved) {
4625 pp->argc += ret;
4626 pp->argc_stack += ret;
4627 for (a = 0; a < pp->argc; a++)
4628 if (pp->arg[a].type.name == NULL)
4629 pp->arg[a].type.name = strdup("int");
4630 }
4631
e56ab892 4632 return ret;
4633}
4634
b2bd20c0 4635static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
4636 int regmask_now, int *regmask,
4637 int regmask_save_now, int *regmask_save,
4638 int *regmask_init, int regmask_arg)
4639{
4640 struct parsed_op *po;
d4a985bd 4641 unsigned int mask;
b2bd20c0 4642 int already_saved;
4643 int regmask_new;
4644 int regmask_op;
4645 int flags_set;
4646 int ret, reg;
4647 int j;
4648
4649 for (; i < opcnt; i++)
4650 {
4651 po = &ops[i];
4652 if (cbits[i >> 3] & (1 << (i & 7)))
4653 return;
4654 cbits[i >> 3] |= (1 << (i & 7));
4655
4656 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4657 if (po->flags & (OPF_RMD|OPF_DONE))
4658 continue;
4659 if (po->btj != NULL) {
4660 for (j = 0; j < po->btj->count; j++) {
4661 check_i(po, po->btj->d[j].bt_i);
4662 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
4663 regmask_now, regmask, regmask_save_now, regmask_save,
4664 regmask_init, regmask_arg);
4665 }
4666 return;
4667 }
4668
4669 check_i(po, po->bt_i);
4670 if (po->flags & OPF_CJMP)
4671 reg_use_pass(po->bt_i, opcnt, cbits,
4672 regmask_now, regmask, regmask_save_now, regmask_save,
4673 regmask_init, regmask_arg);
4674 else
4675 i = po->bt_i - 1;
4676 continue;
4677 }
4678
4679 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
4680 && !g_func_pp->is_userstack
4681 && po->operand[0].type == OPT_REG)
4682 {
4683 reg = po->operand[0].reg;
4684 ferr_assert(po, reg >= 0);
4685
4686 already_saved = 0;
4687 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
4688 if (regmask_now & (1 << reg)) {
4689 already_saved = regmask_save_now & (1 << reg);
4690 flags_set = OPF_RSAVE | OPF_DONE;
4691 }
4692
4693 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0);
4694 if (ret == 1) {
4695 scan_for_pop(i + 1, opcnt, i + opcnt * 4, reg, 0, flags_set);
4696 }
4697 else {
4698 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
4699 if (ret == 1) {
4700 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
4701 flags_set);
4702 }
4703 }
4704 if (ret == 1) {
4705 ferr_assert(po, !already_saved);
4706 po->flags |= flags_set;
4707
4708 if (regmask_now & (1 << reg)) {
4709 regmask_save_now |= (1 << reg);
4710 *regmask_save |= regmask_save_now;
4711 }
4712 continue;
4713 }
4714 }
4715 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
4716 reg = po->operand[0].reg;
4717 ferr_assert(po, reg >= 0);
4718
4719 if (regmask_save_now & (1 << reg))
4720 regmask_save_now &= ~(1 << reg);
4721 else
4722 regmask_now &= ~(1 << reg);
4723 continue;
4724 }
4725 else if (po->op == OP_CALL) {
4726 if ((po->regmask_dst & (1 << xAX))
4727 && !(po->regmask_dst & (1 << xDX)))
4728 {
4729 if (po->flags & OPF_TAIL)
4730 // don't need eax, will do "return f();" or "f(); return;"
4731 po->regmask_dst &= ~(1 << xAX);
4732 else {
4733 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
4734 j = -1;
4735 find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
4736 if (j == -1)
4737 // not used
4738 po->regmask_dst &= ~(1 << xAX);
4739 }
4740 }
4741 }
4742
4743 if (po->flags & OPF_NOREGS)
4744 continue;
4745
d4a985bd 4746 if (po->flags & OPF_FPUSH) {
4747 if (regmask_now & mxST1)
4748 ferr(po, "TODO: FPUSH on active ST1\n");
4749 if (regmask_now & mxST0)
4750 po->flags |= OPF_FSHIFT;
4751 mask = mxST0 | mxST1;
4752 regmask_now = (regmask_now & ~mask) | ((regmask_now & mxST0) << 1);
4753 }
4754
acd03176 4755 // if incomplete register is used, clear it on init to avoid
4756 // later use of uninitialized upper part in some situations
4757 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
4758 && po->operand[0].lmod != OPLM_DWORD)
4759 {
4760 reg = po->operand[0].reg;
4761 ferr_assert(po, reg >= 0);
4762
4763 if (!(regmask_now & (1 << reg)))
4764 *regmask_init |= 1 << reg;
4765 }
4766
b2bd20c0 4767 regmask_op = po->regmask_src | po->regmask_dst;
4768
4769 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
4770 regmask_new &= ~(1 << xSP);
4771 if (g_bp_frame && !(po->flags & OPF_EBP_S))
4772 regmask_new &= ~(1 << xBP);
4773
4774 if (po->op == OP_CALL) {
4775 // allow fastcall calls from anywhere, calee may be also sitting
4776 // in some fastcall table even when it's not using reg args
4777 if (regmask_new & po->regmask_src & (1 << xCX)) {
4778 *regmask_init |= (1 << xCX);
4779 regmask_now |= (1 << xCX);
4780 regmask_new &= ~(1 << xCX);
4781 }
4782 if (regmask_new & po->regmask_src & (1 << xDX)) {
4783 *regmask_init |= (1 << xDX);
4784 regmask_now |= (1 << xDX);
4785 regmask_new &= ~(1 << xDX);
4786 }
4787 }
4788
4789 if (regmask_new != 0)
4790 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
4791
4792 if (regmask_op & (1 << xBP)) {
4793 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
4794 if (po->regmask_dst & (1 << xBP))
4795 // compiler decided to drop bp frame and use ebp as scratch
4796 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
4797 else
4798 regmask_op &= ~(1 << xBP);
4799 }
4800 }
4801
4802 regmask_now |= regmask_op;
4803 *regmask |= regmask_now;
4804
d4a985bd 4805 // released regs
4806 if (po->flags & OPF_FPOP) {
4807 mask = mxST0 | mxST1;
4808 if (!(regmask_now & mask))
4809 ferr(po, "float pop on empty stack?\n");
4810 if (regmask_now & mxST1)
4811 po->flags |= OPF_FSHIFT;
4812 regmask_now = (regmask_now & ~mask) | ((regmask_now & mxST1) >> 1);
4813 }
4814
4815 if (po->flags & OPF_TAIL) {
4816 if (regmask_now & (mxST0 | mxST1))
4817 ferr(po, "float regs on tail: %x\n", regmask_now);
4d247254 4818
4819 // there is support for "conditional tailcall", sort of
4820 if (!(po->flags & OPF_CC))
4821 return;
d4a985bd 4822 }
b2bd20c0 4823 }
4824}
4825
89ff3147 4826static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
4827{
4828 int i;
4829
4830 for (i = 0; i < pp->argc; i++)
4831 if (pp->arg[i].reg == NULL)
4832 break;
4833
4834 if (pp->argc_stack)
4835 memmove(&pp->arg[i + 1], &pp->arg[i],
4836 sizeof(pp->arg[0]) * pp->argc_stack);
4837 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
4838 pp->arg[i].reg = strdup(reg);
4839 pp->arg[i].type.name = strdup("int");
4840 pp->argc++;
4841 pp->argc_reg++;
4842}
4843
04f8a628 4844static void output_std_flags(FILE *fout, struct parsed_op *po,
4845 int *pfomask, const char *dst_opr_text)
4846{
4847 if (*pfomask & (1 << PFO_Z)) {
4848 fprintf(fout, "\n cond_z = (%s%s == 0);",
4849 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
4850 *pfomask &= ~(1 << PFO_Z);
4851 }
4852 if (*pfomask & (1 << PFO_S)) {
4853 fprintf(fout, "\n cond_s = (%s%s < 0);",
4854 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
4855 *pfomask &= ~(1 << PFO_S);
4856 }
4857}
4858
c0de9015 4859enum {
4860 OPP_FORCE_NORETURN = (1 << 0),
4861 OPP_SIMPLE_ARGS = (1 << 1),
4862 OPP_ALIGN = (1 << 2),
4863};
4864
c0050df6 4865static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
c0de9015 4866 int flags)
c0050df6 4867{
c0de9015 4868 const char *cconv = "";
4869
c0050df6 4870 if (pp->is_fastcall)
c0de9015 4871 cconv = "__fastcall ";
c0050df6 4872 else if (pp->is_stdcall && pp->argc_reg == 0)
c0de9015 4873 cconv = "__stdcall ";
4874
4875 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
4876
4877 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
c0050df6 4878 fprintf(fout, "noreturn ");
4879}
4880
c0de9015 4881static void output_pp(FILE *fout, const struct parsed_proto *pp,
4882 int flags)
4883{
4884 int i;
4885
4886 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
4887 pp->ret_type.name);
4888 if (pp->is_fptr)
4889 fprintf(fout, "(");
4890 output_pp_attrs(fout, pp, flags);
4891 if (pp->is_fptr)
4892 fprintf(fout, "*");
4893 fprintf(fout, "%s", pp->name);
4894 if (pp->is_fptr)
4895 fprintf(fout, ")");
4896
4897 fprintf(fout, "(");
4898 for (i = 0; i < pp->argc; i++) {
4899 if (i > 0)
4900 fprintf(fout, ", ");
4901 if (pp->arg[i].fptr != NULL && !(flags & OPP_SIMPLE_ARGS)) {
4902 // func pointer
4903 output_pp(fout, pp->arg[i].fptr, 0);
4904 }
4905 else if (pp->arg[i].type.is_retreg) {
4906 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
4907 }
4908 else {
4909 fprintf(fout, "%s", pp->arg[i].type.name);
4910 if (!pp->is_fptr)
4911 fprintf(fout, " a%d", i + 1);
4912 }
4913 }
4914 if (pp->is_vararg) {
4915 if (i > 0)
4916 fprintf(fout, ", ");
4917 fprintf(fout, "...");
4918 }
4919 fprintf(fout, ")");
4920}
4921
3a5101d7 4922static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
4923{
4924 char buf1[16];
4925
4926 buf1[0] = 0;
4927 if (grp > 0)
4928 snprintf(buf1, sizeof(buf1), "%d", grp);
4929 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
4930
4931 return buf;
4932}
4933
9af2d373 4934static void gen_x_cleanup(int opcnt);
4935
91977a1c 4936static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
4937{
69a3cdfc 4938 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
850c9265 4939 struct parsed_opr *last_arith_dst = NULL;
3ebea2cf 4940 char buf1[256], buf2[256], buf3[256], cast[64];
ddaf8bd7 4941 struct parsed_proto *pp, *pp_tmp;
4c45fa73 4942 struct parsed_data *pd;
1f84f6b3 4943 unsigned int uval;
3a5101d7 4944 int save_arg_vars[MAX_ARG_GRP] = { 0, };
b2bd20c0 4945 unsigned char cbits[MAX_OPS / 8];
cb090db0 4946 int cond_vars = 0;
108e9fe3 4947 int need_tmp_var = 0;
2fe80fdb 4948 int need_tmp64 = 0;
91977a1c 4949 int had_decl = 0;
3ebea2cf 4950 int label_pending = 0;
25a330eb 4951 int regmask_save = 0; // regs saved/restored in this func
b2bd20c0 4952 int regmask_arg; // regs from this function args (fastcall, etc)
4953 int regmask_ret; // regs needed on ret
25a330eb 4954 int regmask_now; // temp
4955 int regmask_init = 0; // regs that need zero initialization
4956 int regmask_pp = 0; // regs used in complex push-pop graph
4957 int regmask = 0; // used regs
940e8e66 4958 int pfomask = 0;
64c59faf 4959 int found = 0;
91977a1c 4960 int no_output;
4c45fa73 4961 int i, j, l;
91977a1c 4962 int arg;
91977a1c 4963 int reg;
4964 int ret;
4965
1bafb621 4966 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
a2c1d768 4967 g_stack_frame_used = 0;
91977a1c 4968
36595fd2 4969 g_func_pp = proto_parse(fhdr, funcn, 0);
bd96f656 4970 if (g_func_pp == NULL)
91977a1c 4971 ferr(ops, "proto_parse failed for '%s'\n", funcn);
4972
b2bd20c0 4973 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
4974 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
4975
91977a1c 4976 // pass1:
87bf6cec 4977 // - resolve all branches
66bdb2b0 4978 // - parse calls with labels
4979 resolve_branches_parse_calls(opcnt);
840257f6 4980
66bdb2b0 4981 // pass2:
4982 // - handle ebp/esp frame, remove ops related to it
4983 scan_prologue_epilogue(opcnt);
87bf6cec 4984
4985 // pass3:
a2c1d768 4986 // - remove dead labels
b2bd20c0 4987 // - set regs needed at ret
1bafb621 4988 for (i = 0; i < opcnt; i++)
4989 {
d7857c3a 4990 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
4991 free(g_labels[i]);
4992 g_labels[i] = NULL;
4993 }
b2bd20c0 4994
4995 if (ops[i].op == OP_RET)
4996 ops[i].regmask_src |= regmask_ret;
66bdb2b0 4997 }
a2c1d768 4998
66bdb2b0 4999 // pass4:
5000 // - process trivial calls
5001 for (i = 0; i < opcnt; i++)
5002 {
69a3cdfc 5003 po = &ops[i];
5e49b270 5004 if (po->flags & (OPF_RMD|OPF_DONE))
91977a1c 5005 continue;
850c9265 5006
d4e3b5db 5007 if (po->op == OP_CALL)
26677139 5008 {
5009 pp = process_call_early(i, opcnt, &j);
5010 if (pp != NULL) {
5011 if (!(po->flags & OPF_ATAIL))
5012 // since we know the args, try to collect them
5013 if (collect_call_args_early(po, i, pp, &regmask) != 0)
5014 pp = NULL;
5015 }
5016
5017 if (pp != NULL) {
5018 if (j >= 0) {
5019 // commit esp adjust
5e49b270 5020 if (ops[j].op != OP_POP)
5021 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
bfacdc83 5022 else {
5023 for (l = 0; l < pp->argc_stack; l++)
b2bd20c0 5024 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
bfacdc83 5025 }
26677139 5026 }
5027
5028 if (strstr(pp->ret_type.name, "int64"))
5029 need_tmp64 = 1;
5030
5031 po->flags |= OPF_DONE;
5032 }
5033 }
5034 }
5035
66bdb2b0 5036 // pass5:
b2bd20c0 5037 // - process calls, stage 2
5038 // - handle some push/pop pairs
5039 // - scan for STD/CLD, propagate DF
26677139 5040 for (i = 0; i < opcnt; i++)
5041 {
5042 po = &ops[i];
b2bd20c0 5043 if (po->flags & OPF_RMD)
26677139 5044 continue;
5045
b2bd20c0 5046 if (po->op == OP_CALL)
69a3cdfc 5047 {
b2bd20c0 5048 if (!(po->flags & OPF_DONE)) {
5049 pp = process_call(i, opcnt);
91977a1c 5050
b2bd20c0 5051 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
5052 // since we know the args, collect them
5053 collect_call_args(po, i, pp, &regmask, save_arg_vars,
5054 i + opcnt * 2);
5055 }
5056 // for unresolved, collect after other passes
89ff3147 5057 }
2b43685d 5058
b2bd20c0 5059 pp = po->pp;
5060 ferr_assert(po, pp != NULL);
5061
5062 po->regmask_src |= get_pp_arg_regmask_src(pp);
5063 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
5064
d4a985bd 5065 if (po->regmask_dst & mxST0)
5066 po->flags |= OPF_FPUSH;
5067
2b43685d 5068 if (strstr(pp->ret_type.name, "int64"))
2fe80fdb 5069 need_tmp64 = 1;
b2bd20c0 5070
5071 continue;
91977a1c 5072 }
b2bd20c0 5073
5074 if (po->flags & OPF_DONE)
5075 continue;
5076
5077 if (po->op == OP_PUSH && !(po->flags & OPF_FARG)
ee2361b9 5078 && !(po->flags & OPF_RSAVE) && po->operand[0].type == OPT_CONST)
e83ea7ed 5079 {
5080 scan_for_pop_const(i, opcnt, i + opcnt * 12);
5081 }
5082 else if (po->op == OP_POP)
5083 scan_pushes_for_pop(i, opcnt, &regmask_pp);
b2bd20c0 5084 else if (po->op == OP_STD) {
5085 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
5086 scan_propagate_df(i + 1, opcnt);
5087 }
d4e3b5db 5088 }
5089
66bdb2b0 5090 // pass6:
d4e3b5db 5091 // - find POPs for PUSHes, rm both
5092 // - scan for all used registers
b2bd20c0 5093 memset(cbits, 0, sizeof(cbits));
5094 reg_use_pass(0, opcnt, cbits, 0, &regmask,
5095 0, &regmask_save, &regmask_init, regmask_arg);
5096
5097 // pass7:
d4e3b5db 5098 // - find flag set ops for their users
b2bd20c0 5099 // - do unresolved calls
1bafb621 5100 // - declare indirect functions
26677139 5101 for (i = 0; i < opcnt; i++)
5102 {
d4e3b5db 5103 po = &ops[i];
5e49b270 5104 if (po->flags & (OPF_RMD|OPF_DONE))
d4e3b5db 5105 continue;
5106
d4e3b5db 5107 if (po->flags & OPF_CC)
5108 {
2b43685d 5109 int setters[16], cnt = 0, branched = 0;
5110
04f8a628 5111 ret = scan_for_flag_set(i, i + opcnt * 6,
5112 &branched, setters, &cnt);
2b43685d 5113 if (ret < 0 || cnt <= 0)
5114 ferr(po, "unable to trace flag setter(s)\n");
5115 if (cnt > ARRAY_SIZE(setters))
5116 ferr(po, "too many flag setters\n");
d4e3b5db 5117
2b43685d 5118 for (j = 0; j < cnt; j++)
5119 {
5120 tmp_op = &ops[setters[j]]; // flag setter
5121 pfomask = 0;
5122
5123 // to get nicer code, we try to delay test and cmp;
5124 // if we can't because of operand modification, or if we
591721d7 5125 // have arith op, or branch, make it calculate flags explicitly
5126 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
5127 {
89ff3147 5128 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
092f64e1 5129 pfomask = 1 << po->pfo;
2b43685d 5130 }
4741fdfe 5131 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
092f64e1 5132 pfomask = 1 << po->pfo;
591721d7 5133 }
2b43685d 5134 else {
04f8a628 5135 // see if we'll be able to handle based on op result
5136 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
092f64e1 5137 && po->pfo != PFO_Z && po->pfo != PFO_S
5138 && po->pfo != PFO_P)
04f8a628 5139 || branched
2b43685d 5140 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
092f64e1 5141 {
5142 pfomask = 1 << po->pfo;
5143 }
2fe80fdb 5144
c8dbc5be 5145 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
5146 propagate_lmod(tmp_op, &tmp_op->operand[0],
5147 &tmp_op->operand[1]);
5148 if (tmp_op->operand[0].lmod == OPLM_DWORD)
5149 need_tmp64 = 1;
5150 }
2b43685d 5151 }
5152 if (pfomask) {
5153 tmp_op->pfomask |= pfomask;
cb090db0 5154 cond_vars |= pfomask;
2b43685d 5155 }
04f8a628 5156 // note: may overwrite, currently not a problem
5157 po->datap = tmp_op;
d4e3b5db 5158 }
5159
cb090db0 5160 if (po->op == OP_RCL || po->op == OP_RCR
5161 || po->op == OP_ADC || po->op == OP_SBB)
5162 cond_vars |= 1 << PFO_C;
d4e3b5db 5163 }
092f64e1 5164
5165 if (po->op == OP_CMPS || po->op == OP_SCAS) {
cb090db0 5166 cond_vars |= 1 << PFO_Z;
591721d7 5167 }
87bf6cec 5168 else if (po->op == OP_MUL
5169 || (po->op == OP_IMUL && po->operand_cnt == 1))
5170 {
c8dbc5be 5171 if (po->operand[0].lmod == OPLM_DWORD)
5172 need_tmp64 = 1;
87bf6cec 5173 }
89ff3147 5174 else if (po->op == OP_CALL) {
26677139 5175 // note: resolved non-reg calls are OPF_DONE already
092f64e1 5176 pp = po->pp;
b2bd20c0 5177 ferr_assert(po, pp != NULL);
89ff3147 5178
5179 if (pp->is_unresolved) {
ddaf8bd7 5180 int regmask_stack = 0;
3a5101d7 5181 collect_call_args(po, i, pp, &regmask, save_arg_vars,
89ff3147 5182 i + opcnt * 2);
5183
b74c31e3 5184 // this is pretty rough guess:
5185 // see ecx and edx were pushed (and not their saved versions)
5186 for (arg = 0; arg < pp->argc; arg++) {
5187 if (pp->arg[arg].reg != NULL)
5188 continue;
5189
5190 tmp_op = pp->arg[arg].datap;
5191 if (tmp_op == NULL)
5192 ferr(po, "parsed_op missing for arg%d\n", arg);
5f70a34f 5193 if (tmp_op->p_argnum == 0 && tmp_op->operand[0].type == OPT_REG)
b74c31e3 5194 regmask_stack |= 1 << tmp_op->operand[0].reg;
5195 }
5196
ddaf8bd7 5197 if (!((regmask_stack & (1 << xCX))
5198 && (regmask_stack & (1 << xDX))))
89ff3147 5199 {
5200 if (pp->argc_stack != 0
c0050df6 5201 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
89ff3147 5202 {
5203 pp_insert_reg_arg(pp, "ecx");
c0050df6 5204 pp->is_fastcall = 1;
ddaf8bd7 5205 regmask_init |= 1 << xCX;
89ff3147 5206 regmask |= 1 << xCX;
5207 }
5208 if (pp->argc_stack != 0
5209 || ((regmask | regmask_arg) & (1 << xDX)))
5210 {
5211 pp_insert_reg_arg(pp, "edx");
ddaf8bd7 5212 regmask_init |= 1 << xDX;
89ff3147 5213 regmask |= 1 << xDX;
5214 }
5215 }
c0050df6 5216
5217 // note: __cdecl doesn't fall into is_unresolved category
5218 if (pp->argc_stack > 0)
5219 pp->is_stdcall = 1;
ddaf8bd7 5220 }
1bafb621 5221 }
27ebfaed 5222 else if (po->op == OP_MOV && po->operand[0].pp != NULL
5223 && po->operand[1].pp != NULL)
5224 {
5225 // <var> = offset <something>
5226 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
5227 && !IS_START(po->operand[1].name, "off_"))
5228 {
5229 if (!po->operand[0].pp->is_fptr)
5230 ferr(po, "%s not declared as fptr when it should be\n",
5231 po->operand[0].name);
5232 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
5233 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
5234 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
5235 fnote(po, "var: %s\n", buf1);
5236 fnote(po, "func: %s\n", buf2);
5237 ferr(po, "^ mismatch\n");
5238 }
5239 }
5240 }
cb090db0 5241 else if (po->op == OP_DIV || po->op == OP_IDIV) {
acd03176 5242 if (po->operand[0].lmod == OPLM_DWORD) {
5243 // 32bit division is common, look for it
5244 if (po->op == OP_DIV)
5245 ret = scan_for_reg_clear(i, xDX);
5246 else
5247 ret = scan_for_cdq_edx(i);
5248 if (ret >= 0)
5249 po->flags |= OPF_32BIT;
5250 else
5251 need_tmp64 = 1;
5252 }
cb090db0 5253 else
acd03176 5254 need_tmp_var = 1;
cb090db0 5255 }
037f4971 5256 else if (po->op == OP_CLD)
5e49b270 5257 po->flags |= OPF_RMD | OPF_DONE;
d4a985bd 5258 else if (po->op == OPP_FTOL) {
5259 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
5260 j = -1;
5261 find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
5262 if (j == -1)
5263 po->flags |= OPF_32BIT;
5264 }
cb090db0 5265
acd03176 5266 if (po->op == OP_RCL || po->op == OP_RCR || po->op == OP_XCHG)
cb090db0 5267 need_tmp_var = 1;
91977a1c 5268 }
5269
60fe410c 5270 // output starts here
5271
5272 // define userstack size
5273 if (g_func_pp->is_userstack) {
5274 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
5275 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
5276 fprintf(fout, "#endif\n");
5277 }
5278
5279 // the function itself
c0de9015 5280 ferr_assert(ops, !g_func_pp->is_fptr);
5281 output_pp(fout, g_func_pp,
5282 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
5283 fprintf(fout, "\n{\n");
60fe410c 5284
5285 // declare indirect functions
5286 for (i = 0; i < opcnt; i++) {
5287 po = &ops[i];
5288 if (po->flags & OPF_RMD)
5289 continue;
5290
5291 if (po->op == OP_CALL) {
5292 pp = po->pp;
5293 if (pp == NULL)
5294 ferr(po, "NULL pp\n");
5295
5296 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
5297 if (pp->name[0] != 0) {
5298 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
5299 memcpy(pp->name, "i_", 2);
5300
5301 // might be declared already
5302 found = 0;
5303 for (j = 0; j < i; j++) {
5304 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
5305 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
5306 found = 1;
5307 break;
5308 }
5309 }
5310 }
5311 if (found)
5312 continue;
5313 }
5314 else
5315 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
5316
c0de9015 5317 fprintf(fout, " ");
5318 output_pp(fout, pp, OPP_SIMPLE_ARGS);
5319 fprintf(fout, ";\n");
60fe410c 5320 }
5321 }
5322 }
da87ae38 5323
4c45fa73 5324 // output LUTs/jumptables
5325 for (i = 0; i < g_func_pd_cnt; i++) {
5326 pd = &g_func_pd[i];
5327 fprintf(fout, " static const ");
5328 if (pd->type == OPT_OFFSET) {
5329 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
5330
5331 for (j = 0; j < pd->count; j++) {
5332 if (j > 0)
5333 fprintf(fout, ", ");
5334 fprintf(fout, "&&%s", pd->d[j].u.label);
5335 }
5336 }
5337 else {
5338 fprintf(fout, "%s %s[] =\n { ",
5339 lmod_type_u(ops, pd->lmod), pd->label);
5340
5341 for (j = 0; j < pd->count; j++) {
5342 if (j > 0)
5343 fprintf(fout, ", ");
5344 fprintf(fout, "%u", pd->d[j].u.val);
5345 }
5346 }
5347 fprintf(fout, " };\n");
1f84f6b3 5348 had_decl = 1;
4c45fa73 5349 }
5350
4f12f671 5351 // declare stack frame, va_arg
1f84f6b3 5352 if (g_stack_fsz) {
d4a985bd 5353 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
5354 if (g_func_lmods & (1 << OPLM_WORD))
5355 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
5356 if (g_func_lmods & (1 << OPLM_BYTE))
5357 fprintf(fout, " u8 b[%d];", g_stack_fsz);
5358 if (g_func_lmods & (1 << OPLM_QWORD))
5359 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
5360 fprintf(fout, " } sf;\n");
1f84f6b3 5361 had_decl = 1;
5362 }
5363
5364 if (g_func_pp->is_userstack) {
60fe410c 5365 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
5366 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
1f84f6b3 5367 had_decl = 1;
5368 }
850c9265 5369
1f84f6b3 5370 if (g_func_pp->is_vararg) {
4f12f671 5371 fprintf(fout, " va_list ap;\n");
1f84f6b3 5372 had_decl = 1;
5373 }
4f12f671 5374
940e8e66 5375 // declare arg-registers
bd96f656 5376 for (i = 0; i < g_func_pp->argc; i++) {
5377 if (g_func_pp->arg[i].reg != NULL) {
91977a1c 5378 reg = char_array_i(regs_r32,
bd96f656 5379 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
75ad0378 5380 if (regmask & (1 << reg)) {
1f84f6b3 5381 if (g_func_pp->arg[i].type.is_retreg)
5382 fprintf(fout, " u32 %s = *r_%s;\n",
5383 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
5384 else
5385 fprintf(fout, " u32 %s = (u32)a%d;\n",
5386 g_func_pp->arg[i].reg, i + 1);
75ad0378 5387 }
1f84f6b3 5388 else {
5389 if (g_func_pp->arg[i].type.is_retreg)
5390 ferr(ops, "retreg '%s' is unused?\n",
5391 g_func_pp->arg[i].reg);
75ad0378 5392 fprintf(fout, " // %s = a%d; // unused\n",
5393 g_func_pp->arg[i].reg, i + 1);
1f84f6b3 5394 }
91977a1c 5395 had_decl = 1;
5396 }
5397 }
5398
25a330eb 5399 // declare normal registers
75ad0378 5400 regmask_now = regmask & ~regmask_arg;
5401 regmask_now &= ~(1 << xSP);
90307a99 5402 if (regmask_now & 0x00ff) {
91977a1c 5403 for (reg = 0; reg < 8; reg++) {
75ad0378 5404 if (regmask_now & (1 << reg)) {
ddaf8bd7 5405 fprintf(fout, " u32 %s", regs_r32[reg]);
5406 if (regmask_init & (1 << reg))
5407 fprintf(fout, " = 0");
5408 fprintf(fout, ";\n");
91977a1c 5409 had_decl = 1;
5410 }
5411 }
5412 }
d4a985bd 5413 // ... mmx
90307a99 5414 if (regmask_now & 0xff00) {
5415 for (reg = 8; reg < 16; reg++) {
5416 if (regmask_now & (1 << reg)) {
5417 fprintf(fout, " mmxr %s", regs_r32[reg]);
5418 if (regmask_init & (1 << reg))
5419 fprintf(fout, " = { 0, }");
5420 fprintf(fout, ";\n");
5421 had_decl = 1;
5422 }
5423 }
5424 }
d4a985bd 5425 // ... x87
5426 if (regmask_now & 0xff0000) {
5427 for (reg = 16; reg < 24; reg++) {
5428 if (regmask_now & (1 << reg)) {
5429 fprintf(fout, " double f_st%d", reg - 16);
5430 if (regmask_init & (1 << reg))
5431 fprintf(fout, " = 0");
5432 fprintf(fout, ";\n");
5433 had_decl = 1;
5434 }
5435 }
5436 }
91977a1c 5437
d4e3b5db 5438 if (regmask_save) {
5439 for (reg = 0; reg < 8; reg++) {
5440 if (regmask_save & (1 << reg)) {
5441 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
5442 had_decl = 1;
5443 }
5444 }
5445 }
5446
3a5101d7 5447 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
5448 if (save_arg_vars[i] == 0)
5449 continue;
69a3cdfc 5450 for (reg = 0; reg < 32; reg++) {
3a5101d7 5451 if (save_arg_vars[i] & (1 << reg)) {
5452 fprintf(fout, " u32 %s;\n",
5453 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
69a3cdfc 5454 had_decl = 1;
5455 }
5456 }
5457 }
5458
25a330eb 5459 // declare push-pop temporaries
5460 if (regmask_pp) {
5461 for (reg = 0; reg < 8; reg++) {
5462 if (regmask_pp & (1 << reg)) {
5463 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
5464 had_decl = 1;
5465 }
5466 }
5467 }
5468
cb090db0 5469 if (cond_vars) {
69a3cdfc 5470 for (i = 0; i < 8; i++) {
cb090db0 5471 if (cond_vars & (1 << i)) {
69a3cdfc 5472 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
5473 had_decl = 1;
5474 }
5475 }
5476 }
5477
108e9fe3 5478 if (need_tmp_var) {
5479 fprintf(fout, " u32 tmp;\n");
5480 had_decl = 1;
5481 }
5482
2fe80fdb 5483 if (need_tmp64) {
5484 fprintf(fout, " u64 tmp64;\n");
87bf6cec 5485 had_decl = 1;
5486 }
5487
91977a1c 5488 if (had_decl)
5489 fprintf(fout, "\n");
5490
7e08c224 5491 // do stack clear, if needed
5492 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
5493 fprintf(fout, " ");
5494 if (g_stack_clear_len != 0) {
5495 if (g_stack_clear_len <= 4) {
5496 for (i = 0; i < g_stack_clear_len; i++)
5497 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
5498 fprintf(fout, "0;\n");
5499 }
5500 else {
5501 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
5502 g_stack_clear_start, g_stack_clear_len * 4);
5503 }
5504 }
5505 else
5506 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
5507 }
5508
bd96f656 5509 if (g_func_pp->is_vararg) {
5510 if (g_func_pp->argc_stack == 0)
4f12f671 5511 ferr(ops, "vararg func without stack args?\n");
bd96f656 5512 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
4f12f671 5513 }
5514
91977a1c 5515 // output ops
69a3cdfc 5516 for (i = 0; i < opcnt; i++)
5517 {
d7857c3a 5518 if (g_labels[i] != NULL) {
91977a1c 5519 fprintf(fout, "\n%s:\n", g_labels[i]);
3ebea2cf 5520 label_pending = 1;
2b43685d 5521
5522 delayed_flag_op = NULL;
5523 last_arith_dst = NULL;
3ebea2cf 5524 }
91977a1c 5525
69a3cdfc 5526 po = &ops[i];
5527 if (po->flags & OPF_RMD)
91977a1c 5528 continue;
5529
5530 no_output = 0;
5531
91977a1c 5532 #define assert_operand_cnt(n_) \
850c9265 5533 if (po->operand_cnt != n_) \
5534 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
5535
69a3cdfc 5536 // conditional/flag using op?
5537 if (po->flags & OPF_CC)
850c9265 5538 {
940e8e66 5539 int is_delayed = 0;
69a3cdfc 5540
04f8a628 5541 tmp_op = po->datap;
850c9265 5542
69a3cdfc 5543 // we go through all this trouble to avoid using parsed_flag_op,
5544 // which makes generated code much nicer
5545 if (delayed_flag_op != NULL)
850c9265 5546 {
092f64e1 5547 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
5548 po->pfo, po->pfo_inv);
940e8e66 5549 is_delayed = 1;
91977a1c 5550 }
850c9265 5551 else if (last_arith_dst != NULL
092f64e1 5552 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
04f8a628 5553 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
5554 ))
850c9265 5555 {
3ebea2cf 5556 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
092f64e1 5557 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
850c9265 5558 last_arith_dst->lmod, buf3);
940e8e66 5559 is_delayed = 1;
850c9265 5560 }
04f8a628 5561 else if (tmp_op != NULL) {
7ba45c34 5562 // use preprocessed flag calc results
092f64e1 5563 if (!(tmp_op->pfomask & (1 << po->pfo)))
5564 ferr(po, "not prepared for pfo %d\n", po->pfo);
69a3cdfc 5565
092f64e1 5566 // note: pfo_inv was not yet applied
69a3cdfc 5567 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
092f64e1 5568 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
69a3cdfc 5569 }
5570 else {
5571 ferr(po, "all methods of finding comparison failed\n");
5572 }
850c9265 5573
69a3cdfc 5574 if (po->flags & OPF_JMP) {
092f64e1 5575 fprintf(fout, " if %s", buf1);
850c9265 5576 }
cb090db0 5577 else if (po->op == OP_RCL || po->op == OP_RCR
5578 || po->op == OP_ADC || po->op == OP_SBB)
5579 {
940e8e66 5580 if (is_delayed)
5581 fprintf(fout, " cond_%s = %s;\n",
092f64e1 5582 parsed_flag_op_names[po->pfo], buf1);
850c9265 5583 }
5101a5f9 5584 else if (po->flags & OPF_DATA) { // SETcc
850c9265 5585 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
5586 fprintf(fout, " %s = %s;", buf2, buf1);
91977a1c 5587 }
69a3cdfc 5588 else {
5589 ferr(po, "unhandled conditional op\n");
5590 }
91977a1c 5591 }
5592
940e8e66 5593 pfomask = po->pfomask;
5594
4741fdfe 5595 if (po->flags & (OPF_REPZ|OPF_REPNZ)) {
b2bd20c0 5596 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
1f84f6b3 5597 ret = try_resolve_const(i, &opr, opcnt * 7 + i, &uval);
5598
5599 if (ret != 1 || uval == 0) {
5600 // we need initial flags for ecx=0 case..
5601 if (i > 0 && ops[i - 1].op == OP_XOR
5602 && IS(ops[i - 1].operand[0].name,
5603 ops[i - 1].operand[1].name))
5604 {
5605 fprintf(fout, " cond_z = ");
5606 if (pfomask & (1 << PFO_C))
5607 fprintf(fout, "cond_c = ");
5608 fprintf(fout, "0;\n");
5609 }
5610 else if (last_arith_dst != NULL) {
5611 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
5612 out_test_for_cc(buf1, sizeof(buf1), po, PFO_Z, 0,
5613 last_arith_dst->lmod, buf3);
5614 fprintf(fout, " cond_z = %s;\n", buf1);
5615 }
5616 else
5617 ferr(po, "missing initial ZF\n");
4741fdfe 5618 }
4741fdfe 5619 }
5620
850c9265 5621 switch (po->op)
91977a1c 5622 {
5623 case OP_MOV:
5624 assert_operand_cnt(2);
850c9265 5625 propagate_lmod(po, &po->operand[0], &po->operand[1]);
de50b98b 5626 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
c7ed83dd 5627 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
de50b98b 5628 fprintf(fout, " %s = %s;", buf1,
3ebea2cf 5629 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
c7ed83dd 5630 buf3, 0));
850c9265 5631 break;
5632
5633 case OP_LEA:
5634 assert_operand_cnt(2);
87bf6cec 5635 po->operand[1].lmod = OPLM_DWORD; // always
850c9265 5636 fprintf(fout, " %s = %s;",
5637 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
3ebea2cf 5638 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5639 NULL, 1));
850c9265 5640 break;
5641
5642 case OP_MOVZX:
5643 assert_operand_cnt(2);
91977a1c 5644 fprintf(fout, " %s = %s;",
850c9265 5645 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
3ebea2cf 5646 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
850c9265 5647 break;
5648
5649 case OP_MOVSX:
5650 assert_operand_cnt(2);
5651 switch (po->operand[1].lmod) {
5652 case OPLM_BYTE:
5653 strcpy(buf3, "(s8)");
5654 break;
5655 case OPLM_WORD:
5656 strcpy(buf3, "(s16)");
5657 break;
5658 default:
5659 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
5660 }
a2c1d768 5661 fprintf(fout, " %s = %s;",
850c9265 5662 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
a2c1d768 5663 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5664 buf3, 0));
850c9265 5665 break;
5666
108e9fe3 5667 case OP_XCHG:
5668 assert_operand_cnt(2);
5669 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5670 fprintf(fout, " tmp = %s;",
5671 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
5672 fprintf(fout, " %s = %s;",
5673 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
c7ed83dd 5674 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5675 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
5676 fprintf(fout, " %s = %stmp;",
5677 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
5678 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
108e9fe3 5679 snprintf(g_comment, sizeof(g_comment), "xchg");
5680 break;
5681
850c9265 5682 case OP_NOT:
5683 assert_operand_cnt(1);
5684 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5685 fprintf(fout, " %s = ~%s;", buf1, buf1);
5686 break;
5687
04abc5d6 5688 case OP_XLAT:
5689 assert_operand_cnt(2);
5690 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5691 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
5692 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
5693 strcpy(g_comment, "xlat");
5694 break;
5695
5101a5f9 5696 case OP_CDQ:
5697 assert_operand_cnt(2);
5698 fprintf(fout, " %s = (s32)%s >> 31;",
5699 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
3ebea2cf 5700 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5101a5f9 5701 strcpy(g_comment, "cdq");
5702 break;
5703
092f64e1 5704 case OP_LODS:
092f64e1 5705 if (po->flags & OPF_REP) {
acd03176 5706 assert_operand_cnt(3);
092f64e1 5707 // hmh..
5708 ferr(po, "TODO\n");
5709 }
5710 else {
acd03176 5711 assert_operand_cnt(2);
3947cf24 5712 fprintf(fout, " %s = %sesi; esi %c= %d;",
5713 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
5714 lmod_cast_u_ptr(po, po->operand[1].lmod),
092f64e1 5715 (po->flags & OPF_DF) ? '-' : '+',
3947cf24 5716 lmod_bytes(po, po->operand[1].lmod));
092f64e1 5717 strcpy(g_comment, "lods");
5718 }
5719 break;
5720
33c35af6 5721 case OP_STOS:
33c35af6 5722 if (po->flags & OPF_REP) {
acd03176 5723 assert_operand_cnt(3);
591721d7 5724 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
5725 (po->flags & OPF_DF) ? '-' : '+',
3947cf24 5726 lmod_bytes(po, po->operand[1].lmod));
d4e3b5db 5727 fprintf(fout, " %sedi = eax;",
3947cf24 5728 lmod_cast_u_ptr(po, po->operand[1].lmod));
33c35af6 5729 strcpy(g_comment, "rep stos");
5730 }
5731 else {
acd03176 5732 assert_operand_cnt(2);
092f64e1 5733 fprintf(fout, " %sedi = eax; edi %c= %d;",
3947cf24 5734 lmod_cast_u_ptr(po, po->operand[1].lmod),
591721d7 5735 (po->flags & OPF_DF) ? '-' : '+',
3947cf24 5736 lmod_bytes(po, po->operand[1].lmod));
33c35af6 5737 strcpy(g_comment, "stos");
5738 }
5739 break;
5740
d4e3b5db 5741 case OP_MOVS:
d4e3b5db 5742 j = lmod_bytes(po, po->operand[0].lmod);
5743 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
591721d7 5744 l = (po->flags & OPF_DF) ? '-' : '+';
d4e3b5db 5745 if (po->flags & OPF_REP) {
acd03176 5746 assert_operand_cnt(3);
d4e3b5db 5747 fprintf(fout,
591721d7 5748 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
5749 l, j, l, j);
d4e3b5db 5750 fprintf(fout,
5751 " %sedi = %sesi;", buf1, buf1);
5752 strcpy(g_comment, "rep movs");
5753 }
5754 else {
acd03176 5755 assert_operand_cnt(2);
092f64e1 5756 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
591721d7 5757 buf1, buf1, l, j, l, j);
d4e3b5db 5758 strcpy(g_comment, "movs");
5759 }
5760 break;
5761
7ba45c34 5762 case OP_CMPS:
7ba45c34 5763 // repe ~ repeat while ZF=1
7ba45c34 5764 j = lmod_bytes(po, po->operand[0].lmod);
5765 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
591721d7 5766 l = (po->flags & OPF_DF) ? '-' : '+';
7ba45c34 5767 if (po->flags & OPF_REP) {
acd03176 5768 assert_operand_cnt(3);
7ba45c34 5769 fprintf(fout,
1f84f6b3 5770 " for (; ecx != 0; ecx--) {\n");
4741fdfe 5771 if (pfomask & (1 << PFO_C)) {
5772 // ugh..
5773 fprintf(fout,
05381e4a 5774 " cond_c = %sesi < %sedi;\n", buf1, buf1);
4741fdfe 5775 pfomask &= ~(1 << PFO_C);
5776 }
7ba45c34 5777 fprintf(fout,
05381e4a 5778 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
1f84f6b3 5779 buf1, buf1, l, j, l, j);
5780 fprintf(fout,
5781 " if (cond_z %s 0) break;\n",
5782 (po->flags & OPF_REPZ) ? "==" : "!=");
7ba45c34 5783 fprintf(fout,
4741fdfe 5784 " }");
7ba45c34 5785 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
5786 (po->flags & OPF_REPZ) ? "e" : "ne");
5787 }
5788 else {
acd03176 5789 assert_operand_cnt(2);
7ba45c34 5790 fprintf(fout,
05381e4a 5791 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
591721d7 5792 buf1, buf1, l, j, l, j);
7ba45c34 5793 strcpy(g_comment, "cmps");
5794 }
5795 pfomask &= ~(1 << PFO_Z);
5796 last_arith_dst = NULL;
5797 delayed_flag_op = NULL;
5798 break;
5799
591721d7 5800 case OP_SCAS:
5801 // only does ZF (for now)
5802 // repe ~ repeat while ZF=1
3947cf24 5803 j = lmod_bytes(po, po->operand[1].lmod);
591721d7 5804 l = (po->flags & OPF_DF) ? '-' : '+';
5805 if (po->flags & OPF_REP) {
acd03176 5806 assert_operand_cnt(3);
591721d7 5807 fprintf(fout,
1f84f6b3 5808 " for (; ecx != 0; ecx--) {\n");
591721d7 5809 fprintf(fout,
1f84f6b3 5810 " cond_z = (%seax == %sedi); edi %c= %d;\n",
3947cf24 5811 lmod_cast_u(po, po->operand[1].lmod),
5812 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
1f84f6b3 5813 fprintf(fout,
5814 " if (cond_z %s 0) break;\n",
591721d7 5815 (po->flags & OPF_REPZ) ? "==" : "!=");
5816 fprintf(fout,
1f84f6b3 5817 " }");
591721d7 5818 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
5819 (po->flags & OPF_REPZ) ? "e" : "ne");
5820 }
5821 else {
acd03176 5822 assert_operand_cnt(2);
05381e4a 5823 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
3947cf24 5824 lmod_cast_u(po, po->operand[1].lmod),
5825 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
591721d7 5826 strcpy(g_comment, "scas");
5827 }
5828 pfomask &= ~(1 << PFO_Z);
5829 last_arith_dst = NULL;
5830 delayed_flag_op = NULL;
5831 break;
5832
850c9265 5833 // arithmetic w/flags
850c9265 5834 case OP_AND:
2b70f6d3 5835 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
5836 goto dualop_arith_const;
5837 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5838 goto dualop_arith;
5839
850c9265 5840 case OP_OR:
5101a5f9 5841 propagate_lmod(po, &po->operand[0], &po->operand[1]);
2b70f6d3 5842 if (po->operand[1].type == OPT_CONST) {
5843 j = lmod_bytes(po, po->operand[0].lmod);
5844 if (((1ull << j * 8) - 1) == po->operand[1].val)
5845 goto dualop_arith_const;
5846 }
5847 goto dualop_arith;
5848
850c9265 5849 dualop_arith:
5850 assert_operand_cnt(2);
850c9265 5851 fprintf(fout, " %s %s= %s;",
5852 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5853 op_to_c(po),
3ebea2cf 5854 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
04f8a628 5855 output_std_flags(fout, po, &pfomask, buf1);
5856 last_arith_dst = &po->operand[0];
5857 delayed_flag_op = NULL;
5858 break;
5859
2b70f6d3 5860 dualop_arith_const:
5861 // and 0, or ~0 used instead mov
5862 assert_operand_cnt(2);
5863 fprintf(fout, " %s = %s;",
5864 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5865 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5866 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
5867 output_std_flags(fout, po, &pfomask, buf1);
5868 last_arith_dst = &po->operand[0];
5869 delayed_flag_op = NULL;
5870 break;
5871
04f8a628 5872 case OP_SHL:
5873 case OP_SHR:
5874 assert_operand_cnt(2);
5875 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5876 if (pfomask & (1 << PFO_C)) {
5877 if (po->operand[1].type == OPT_CONST) {
5878 l = lmod_bytes(po, po->operand[0].lmod) * 8;
5879 j = po->operand[1].val;
5880 j %= l;
5881 if (j != 0) {
5882 if (po->op == OP_SHL)
5883 j = l - j;
5884 else
5885 j -= 1;
cb090db0 5886 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
5887 buf1, j);
04f8a628 5888 }
5889 else
5890 ferr(po, "zero shift?\n");
5891 }
5892 else
5893 ferr(po, "TODO\n");
5894 pfomask &= ~(1 << PFO_C);
840257f6 5895 }
04abc5d6 5896 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
04f8a628 5897 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
04abc5d6 5898 if (po->operand[1].type != OPT_CONST)
5899 fprintf(fout, " & 0x1f");
5900 fprintf(fout, ";");
04f8a628 5901 output_std_flags(fout, po, &pfomask, buf1);
850c9265 5902 last_arith_dst = &po->operand[0];
69a3cdfc 5903 delayed_flag_op = NULL;
850c9265 5904 break;
5905
d4e3b5db 5906 case OP_SAR:
5907 assert_operand_cnt(2);
5908 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5909 fprintf(fout, " %s = %s%s >> %s;", buf1,
5910 lmod_cast_s(po, po->operand[0].lmod), buf1,
3ebea2cf 5911 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
04f8a628 5912 output_std_flags(fout, po, &pfomask, buf1);
d4e3b5db 5913 last_arith_dst = &po->operand[0];
5914 delayed_flag_op = NULL;
5915 break;
5916
04abc5d6 5917 case OP_SHLD:
3b2f4044 5918 case OP_SHRD:
5919 assert_operand_cnt(3);
5920 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5921 l = lmod_bytes(po, po->operand[0].lmod) * 8;
3b2f4044 5922 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
acd03176 5923 if (po->operand[2].type != OPT_CONST) {
5924 // no handling for "undefined" case, hopefully not needed
5925 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
5926 strcpy(buf3, buf2);
5927 }
5928 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
5929 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
04abc5d6 5930 if (po->op == OP_SHLD) {
5931 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
5932 buf1, buf3, buf1, buf2, l, buf3);
5933 strcpy(g_comment, "shld");
5934 }
5935 else {
5936 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
5937 buf1, buf3, buf1, buf2, l, buf3);
5938 strcpy(g_comment, "shrd");
5939 }
3b2f4044 5940 output_std_flags(fout, po, &pfomask, buf1);
5941 last_arith_dst = &po->operand[0];
5942 delayed_flag_op = NULL;
5943 break;
5944
d4e3b5db 5945 case OP_ROL:
5946 case OP_ROR:
5947 assert_operand_cnt(2);
5948 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5949 if (po->operand[1].type == OPT_CONST) {
5950 j = po->operand[1].val;
5951 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
5952 fprintf(fout, po->op == OP_ROL ?
5953 " %s = (%s << %d) | (%s >> %d);" :
5954 " %s = (%s >> %d) | (%s << %d);",
5955 buf1, buf1, j, buf1,
5956 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
5957 }
5958 else
5959 ferr(po, "TODO\n");
04f8a628 5960 output_std_flags(fout, po, &pfomask, buf1);
d4e3b5db 5961 last_arith_dst = &po->operand[0];
5962 delayed_flag_op = NULL;
5963 break;
5964
cb090db0 5965 case OP_RCL:
5966 case OP_RCR:
5967 assert_operand_cnt(2);
5968 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5969 l = lmod_bytes(po, po->operand[0].lmod) * 8;
5970 if (po->operand[1].type == OPT_CONST) {
5971 j = po->operand[1].val % l;
5972 if (j == 0)
5973 ferr(po, "zero rotate\n");
5974 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
5975 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
5976 if (po->op == OP_RCL) {
5977 fprintf(fout,
5978 " %s = (%s << %d) | (cond_c << %d)",
5979 buf1, buf1, j, j - 1);
5980 if (j != 1)
5981 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
5982 }
5983 else {
5984 fprintf(fout,
5985 " %s = (%s >> %d) | (cond_c << %d)",
5986 buf1, buf1, j, l - j);
5987 if (j != 1)
5988 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
5989 }
5990 fprintf(fout, ";\n");
5991 fprintf(fout, " cond_c = tmp;");
5992 }
5993 else
5994 ferr(po, "TODO\n");
5995 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
5996 output_std_flags(fout, po, &pfomask, buf1);
5997 last_arith_dst = &po->operand[0];
5998 delayed_flag_op = NULL;
5999 break;
6000
5101a5f9 6001 case OP_XOR:
850c9265 6002 assert_operand_cnt(2);
6003 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5101a5f9 6004 if (IS(opr_name(po, 0), opr_name(po, 1))) {
6005 // special case for XOR
2fe80fdb 6006 if (pfomask & (1 << PFO_BE)) { // weird, but it happens..
6007 fprintf(fout, " cond_be = 1;\n");
6008 pfomask &= ~(1 << PFO_BE);
6009 }
5101a5f9 6010 fprintf(fout, " %s = 0;",
6011 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6012 last_arith_dst = &po->operand[0];
6013 delayed_flag_op = NULL;
850c9265 6014 break;
850c9265 6015 }
5101a5f9 6016 goto dualop_arith;
6017
2fe80fdb 6018 case OP_ADD:
6019 assert_operand_cnt(2);
6020 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6021 if (pfomask & (1 << PFO_C)) {
c8dbc5be 6022 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6023 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6024 if (po->operand[0].lmod == OPLM_DWORD) {
6025 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
6026 fprintf(fout, " cond_c = tmp64 >> 32;\n");
6027 fprintf(fout, " %s = (u32)tmp64;",
6028 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
d4a985bd 6029 strcat(g_comment, " add64");
c8dbc5be 6030 }
6031 else {
6032 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
6033 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
6034 fprintf(fout, " %s += %s;",
6035 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6036 buf2);
6037 }
2fe80fdb 6038 pfomask &= ~(1 << PFO_C);
6039 output_std_flags(fout, po, &pfomask, buf1);
6040 last_arith_dst = &po->operand[0];
6041 delayed_flag_op = NULL;
6042 break;
6043 }
6044 goto dualop_arith;
6045
6046 case OP_SUB:
6047 assert_operand_cnt(2);
6048 propagate_lmod(po, &po->operand[0], &po->operand[1]);
3b2f4044 6049 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
6050 for (j = 0; j <= PFO_LE; j++) {
6051 if (!(pfomask & (1 << j)))
6052 continue;
6053 if (j == PFO_Z || j == PFO_S)
6054 continue;
6055
6056 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0);
6057 fprintf(fout, " cond_%s = %s;\n",
6058 parsed_flag_op_names[j], buf1);
6059 pfomask &= ~(1 << j);
6060 }
2fe80fdb 6061 }
6062 goto dualop_arith;
6063
5101a5f9 6064 case OP_ADC:
850c9265 6065 case OP_SBB:
5101a5f9 6066 assert_operand_cnt(2);
6067 propagate_lmod(po, &po->operand[0], &po->operand[1]);
a2c1d768 6068 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
840257f6 6069 if (po->op == OP_SBB
6070 && IS(po->operand[0].name, po->operand[1].name))
6071 {
6072 // avoid use of unitialized var
a2c1d768 6073 fprintf(fout, " %s = -cond_c;", buf1);
94d447fb 6074 // carry remains what it was
6075 pfomask &= ~(1 << PFO_C);
840257f6 6076 }
6077 else {
a2c1d768 6078 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
3ebea2cf 6079 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
840257f6 6080 }
a2c1d768 6081 output_std_flags(fout, po, &pfomask, buf1);
5101a5f9 6082 last_arith_dst = &po->operand[0];
6083 delayed_flag_op = NULL;
850c9265 6084 break;
6085
1f84f6b3 6086 case OP_BSF:
6087 assert_operand_cnt(2);
6088 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6089 fprintf(fout, " %s = %s ? __builtin_ffs(%s) - 1 : 0;",
6090 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6091 buf2, buf2);
6092 output_std_flags(fout, po, &pfomask, buf1);
6093 last_arith_dst = &po->operand[0];
6094 delayed_flag_op = NULL;
d4a985bd 6095 strcat(g_comment, " bsf");
1f84f6b3 6096 break;
6097
850c9265 6098 case OP_DEC:
90307a99 6099 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
6100 for (j = 0; j <= PFO_LE; j++) {
6101 if (!(pfomask & (1 << j)))
6102 continue;
6103 if (j == PFO_Z || j == PFO_S || j == PFO_C)
6104 continue;
6105
6106 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0);
6107 fprintf(fout, " cond_%s = %s;\n",
6108 parsed_flag_op_names[j], buf1);
6109 pfomask &= ~(1 << j);
6110 }
6111 }
6112 // fallthrough
6113
6114 case OP_INC:
6115 if (pfomask & (1 << PFO_C))
6116 // carry is unaffected by inc/dec.. wtf?
6117 ferr(po, "carry propagation needed\n");
6118
850c9265 6119 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
1bafb621 6120 if (po->operand[0].type == OPT_REG) {
6121 strcpy(buf2, po->op == OP_INC ? "++" : "--");
6122 fprintf(fout, " %s%s;", buf1, buf2);
6123 }
6124 else {
6125 strcpy(buf2, po->op == OP_INC ? "+" : "-");
6126 fprintf(fout, " %s %s= 1;", buf1, buf2);
6127 }
a2c1d768 6128 output_std_flags(fout, po, &pfomask, buf1);
5101a5f9 6129 last_arith_dst = &po->operand[0];
6130 delayed_flag_op = NULL;
6131 break;
6132
6133 case OP_NEG:
6134 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
3ebea2cf 6135 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
5101a5f9 6136 fprintf(fout, " %s = -%s%s;", buf1,
6137 lmod_cast_s(po, po->operand[0].lmod), buf2);
850c9265 6138 last_arith_dst = &po->operand[0];
69a3cdfc 6139 delayed_flag_op = NULL;
940e8e66 6140 if (pfomask & (1 << PFO_C)) {
6141 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
6142 pfomask &= ~(1 << PFO_C);
6143 }
850c9265 6144 break;
6145
6146 case OP_IMUL:
de50b98b 6147 if (po->operand_cnt == 2) {
6148 propagate_lmod(po, &po->operand[0], &po->operand[1]);
850c9265 6149 goto dualop_arith;
de50b98b 6150 }
87bf6cec 6151 if (po->operand_cnt == 3)
6152 ferr(po, "TODO imul3\n");
6153 // fallthrough
6154 case OP_MUL:
6155 assert_operand_cnt(1);
c8dbc5be 6156 switch (po->operand[0].lmod) {
6157 case OPLM_DWORD:
6158 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
6159 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
6160 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
6161 fprintf(fout, " edx = tmp64 >> 32;\n");
6162 fprintf(fout, " eax = tmp64;");
6163 break;
6164 case OPLM_BYTE:
6165 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
6166 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
6167 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
6168 buf1, 0));
6169 break;
6170 default:
6171 ferr(po, "TODO: unhandled mul type\n");
6172 break;
6173 }
87bf6cec 6174 last_arith_dst = NULL;
69a3cdfc 6175 delayed_flag_op = NULL;
91977a1c 6176 break;
6177
5101a5f9 6178 case OP_DIV:
6179 case OP_IDIV:
6180 assert_operand_cnt(1);
cb090db0 6181 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
acd03176 6182 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
cb090db0 6183 po->op == OP_IDIV));
6184 switch (po->operand[0].lmod) {
6185 case OPLM_DWORD:
6186 if (po->flags & OPF_32BIT)
acd03176 6187 snprintf(buf2, sizeof(buf2), "%seax", cast);
cb090db0 6188 else {
6189 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
acd03176 6190 snprintf(buf2, sizeof(buf2), "%stmp64",
cb090db0 6191 (po->op == OP_IDIV) ? "(s64)" : "");
6192 }
6193 if (po->operand[0].type == OPT_REG
6194 && po->operand[0].reg == xDX)
6195 {
acd03176 6196 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
6197 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
6198 }
6199 else {
6200 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
6201 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
6202 }
6203 break;
6204 case OPLM_WORD:
6205 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
6206 snprintf(buf2, sizeof(buf2), "%stmp",
6207 (po->op == OP_IDIV) ? "(s32)" : "");
6208 if (po->operand[0].type == OPT_REG
6209 && po->operand[0].reg == xDX)
6210 {
6211 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
6212 buf2, cast, buf1);
6213 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
6214 buf2, cast, buf1);
cb090db0 6215 }
6216 else {
acd03176 6217 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
6218 buf2, cast, buf1);
6219 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
6220 buf2, cast, buf1);
cb090db0 6221 }
d4a985bd 6222 strcat(g_comment, " div16");
cb090db0 6223 break;
6224 default:
acd03176 6225 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
5101a5f9 6226 }
87bf6cec 6227 last_arith_dst = NULL;
6228 delayed_flag_op = NULL;
5101a5f9 6229 break;
6230
91977a1c 6231 case OP_TEST:
6232 case OP_CMP:
850c9265 6233 propagate_lmod(po, &po->operand[0], &po->operand[1]);
940e8e66 6234 if (pfomask != 0) {
69a3cdfc 6235 for (j = 0; j < 8; j++) {
940e8e66 6236 if (pfomask & (1 << j)) {
69a3cdfc 6237 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
6238 fprintf(fout, " cond_%s = %s;",
6239 parsed_flag_op_names[j], buf1);
6240 }
6241 }
940e8e66 6242 pfomask = 0;
69a3cdfc 6243 }
6244 else
6245 no_output = 1;
7ba45c34 6246 last_arith_dst = NULL;
69a3cdfc 6247 delayed_flag_op = po;
91977a1c 6248 break;
6249
092f64e1 6250 case OP_SCC:
6251 // SETcc - should already be handled
6252 break;
6253
69a3cdfc 6254 // note: we reuse OP_Jcc for SETcc, only flags differ
092f64e1 6255 case OP_JCC:
6256 fprintf(fout, "\n goto %s;", po->operand[0].name);
850c9265 6257 break;
6258
5c024ef7 6259 case OP_JECXZ:
6260 fprintf(fout, " if (ecx == 0)\n");
6261 fprintf(fout, " goto %s;", po->operand[0].name);
d4a985bd 6262 strcat(g_comment, " jecxz");
5c024ef7 6263 break;
6264
04abc5d6 6265 case OP_LOOP:
3947cf24 6266 fprintf(fout, " if (--ecx != 0)\n");
04abc5d6 6267 fprintf(fout, " goto %s;", po->operand[0].name);
d4a985bd 6268 strcat(g_comment, " loop");
04abc5d6 6269 break;
6270
850c9265 6271 case OP_JMP:
87bf6cec 6272 assert_operand_cnt(1);
de50b98b 6273 last_arith_dst = NULL;
6274 delayed_flag_op = NULL;
6275
4c45fa73 6276 if (po->operand[0].type == OPT_REGMEM) {
6277 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
6278 buf1, buf2);
6279 if (ret != 2)
6280 ferr(po, "parse failure for jmp '%s'\n",
6281 po->operand[0].name);
6282 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
6283 break;
6284 }
6285 else if (po->operand[0].type != OPT_LABEL)
6286 ferr(po, "unhandled jmp type\n");
87bf6cec 6287
850c9265 6288 fprintf(fout, " goto %s;", po->operand[0].name);
91977a1c 6289 break;
6290
6291 case OP_CALL:
5101a5f9 6292 assert_operand_cnt(1);
092f64e1 6293 pp = po->pp;
89ff3147 6294 my_assert_not(pp, NULL);
91977a1c 6295
092f64e1 6296 strcpy(buf3, " ");
6297 if (po->flags & OPF_CC) {
6298 // we treat conditional branch to another func
6299 // (yes such code exists..) as conditional tailcall
6300 strcat(buf3, " ");
6301 fprintf(fout, " {\n");
6302 }
6303
8eb12e72 6304 if (pp->is_fptr && !pp->is_arg) {
092f64e1 6305 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
1cd4a663 6306 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6307 "(void *)", 0));
8eb12e72 6308 if (pp->is_unresolved)
6309 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
6310 buf3, asmfn, po->asmln, pp->name);
6311 }
1bafb621 6312
092f64e1 6313 fprintf(fout, "%s", buf3);
2b43685d 6314 if (strstr(pp->ret_type.name, "int64")) {
87bf6cec 6315 if (po->flags & OPF_TAIL)
2b43685d 6316 ferr(po, "int64 and tail?\n");
2fe80fdb 6317 fprintf(fout, "tmp64 = ");
2b43685d 6318 }
6319 else if (!IS(pp->ret_type.name, "void")) {
6320 if (po->flags & OPF_TAIL) {
d4a985bd 6321 if (regmask_ret & mxAX) {
840257f6 6322 fprintf(fout, "return ");
6323 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
6324 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
6325 }
d4a985bd 6326 else if (regmask_ret & mxST0)
6327 ferr(po, "float tailcall\n");
2b43685d 6328 }
d4a985bd 6329 else if (po->regmask_dst & mxAX) {
87bf6cec 6330 fprintf(fout, "eax = ");
2b43685d 6331 if (pp->ret_type.is_ptr)
6332 fprintf(fout, "(u32)");
6333 }
d4a985bd 6334 else if (po->regmask_dst & mxST0) {
6335 fprintf(fout, "f_st0 = ");
6336 }
91977a1c 6337 }
87bf6cec 6338
ddaf8bd7 6339 if (pp->name[0] == 0)
6340 ferr(po, "missing pp->name\n");
6341 fprintf(fout, "%s%s(", pp->name,
6342 pp->has_structarg ? "_sa" : "");
39b168b8 6343
2fe80fdb 6344 if (po->flags & OPF_ATAIL) {
6345 if (pp->argc_stack != g_func_pp->argc_stack
6346 || (pp->argc_stack > 0
6347 && pp->is_stdcall != g_func_pp->is_stdcall))
6348 ferr(po, "incompatible tailcall\n");
1f84f6b3 6349 if (g_func_pp->has_retreg)
6350 ferr(po, "TODO: retreg+tailcall\n");
87bf6cec 6351
2fe80fdb 6352 for (arg = j = 0; arg < pp->argc; arg++) {
6353 if (arg > 0)
6354 fprintf(fout, ", ");
87bf6cec 6355
2fe80fdb 6356 cast[0] = 0;
6357 if (pp->arg[arg].type.is_ptr)
6358 snprintf(cast, sizeof(cast), "(%s)",
6359 pp->arg[arg].type.name);
91977a1c 6360
2fe80fdb 6361 if (pp->arg[arg].reg != NULL) {
6362 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6363 continue;
6364 }
6365 // stack arg
6366 for (; j < g_func_pp->argc; j++)
6367 if (g_func_pp->arg[j].reg == NULL)
6368 break;
6369 fprintf(fout, "%sa%d", cast, j + 1);
6370 j++;
69a3cdfc 6371 }
2fe80fdb 6372 }
6373 else {
6374 for (arg = 0; arg < pp->argc; arg++) {
6375 if (arg > 0)
6376 fprintf(fout, ", ");
6377
6378 cast[0] = 0;
6379 if (pp->arg[arg].type.is_ptr)
6380 snprintf(cast, sizeof(cast), "(%s)",
6381 pp->arg[arg].type.name);
6382
6383 if (pp->arg[arg].reg != NULL) {
1f84f6b3 6384 if (pp->arg[arg].type.is_retreg)
6385 fprintf(fout, "&%s", pp->arg[arg].reg);
6386 else
6387 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
2fe80fdb 6388 continue;
6389 }
6390
6391 // stack arg
6392 tmp_op = pp->arg[arg].datap;
6393 if (tmp_op == NULL)
6394 ferr(po, "parsed_op missing for arg%d\n", arg);
23fd0b11 6395
6396 if (tmp_op->flags & OPF_VAPUSH) {
6397 fprintf(fout, "ap");
6398 }
5f70a34f 6399 else if (tmp_op->p_argpass != 0) {
6400 fprintf(fout, "a%d", tmp_op->p_argpass);
6401 }
6402 else if (tmp_op->p_argnum != 0) {
3a5101d7 6403 fprintf(fout, "%s%s", cast,
6404 saved_arg_name(buf1, sizeof(buf1),
6405 tmp_op->p_arggrp, tmp_op->p_argnum));
2fe80fdb 6406 }
6407 else {
6408 fprintf(fout, "%s",
6409 out_src_opr(buf1, sizeof(buf1),
6410 tmp_op, &tmp_op->operand[0], cast, 0));
6411 }
69a3cdfc 6412 }
91977a1c 6413 }
6414 fprintf(fout, ");");
87bf6cec 6415
2b43685d 6416 if (strstr(pp->ret_type.name, "int64")) {
6417 fprintf(fout, "\n");
092f64e1 6418 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
6419 fprintf(fout, "%seax = tmp64;", buf3);
2b43685d 6420 }
6421
89ff3147 6422 if (pp->is_unresolved) {
8eb12e72 6423 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
89ff3147 6424 pp->argc_reg);
092f64e1 6425 strcat(g_comment, buf2);
89ff3147 6426 }
6427
87bf6cec 6428 if (po->flags & OPF_TAIL) {
840257f6 6429 ret = 0;
ddaf8bd7 6430 if (i == opcnt - 1 || pp->is_noreturn)
840257f6 6431 ret = 0;
6432 else if (IS(pp->ret_type.name, "void"))
6433 ret = 1;
b2bd20c0 6434 else if (!(regmask_ret & (1 << xAX)))
840257f6 6435 ret = 1;
6436 // else already handled as 'return f()'
6437
6438 if (ret) {
acd03176 6439 fprintf(fout, "\n%sreturn;", buf3);
6440 strcat(g_comment, " ^ tailcall");
3ebea2cf 6441 }
89ff3147 6442 else
ddaf8bd7 6443 strcat(g_comment, " tailcall");
acd03176 6444
6445 if ((regmask_ret & (1 << xAX))
6446 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
6447 {
6448 ferr(po, "int func -> void func tailcall?\n");
6449 }
87bf6cec 6450 }
ddaf8bd7 6451 if (pp->is_noreturn)
6452 strcat(g_comment, " noreturn");
2fe80fdb 6453 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
6454 strcat(g_comment, " argframe");
092f64e1 6455 if (po->flags & OPF_CC)
6456 strcat(g_comment, " cond");
6457
6458 if (po->flags & OPF_CC)
6459 fprintf(fout, "\n }");
6460
87bf6cec 6461 delayed_flag_op = NULL;
6462 last_arith_dst = NULL;
91977a1c 6463 break;
6464
6465 case OP_RET:
bd96f656 6466 if (g_func_pp->is_vararg)
4f12f671 6467 fprintf(fout, " va_end(ap);\n");
1f84f6b3 6468 if (g_func_pp->has_retreg) {
6469 for (arg = 0; arg < g_func_pp->argc; arg++)
6470 if (g_func_pp->arg[arg].type.is_retreg)
6471 fprintf(fout, " *r_%s = %s;\n",
6472 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
6473 }
4f12f671 6474
b2bd20c0 6475 if (!(regmask_ret & (1 << xAX))) {
3ebea2cf 6476 if (i != opcnt - 1 || label_pending)
6477 fprintf(fout, " return;");
6478 }
bd96f656 6479 else if (g_func_pp->ret_type.is_ptr) {
d4e3b5db 6480 fprintf(fout, " return (%s)eax;",
bd96f656 6481 g_func_pp->ret_type.name);
3ebea2cf 6482 }
2fe80fdb 6483 else if (IS(g_func_pp->ret_type.name, "__int64"))
6484 fprintf(fout, " return ((u64)edx << 32) | eax;");
91977a1c 6485 else
6486 fprintf(fout, " return eax;");
de50b98b 6487
6488 last_arith_dst = NULL;
6489 delayed_flag_op = NULL;
91977a1c 6490 break;
6491
6492 case OP_PUSH:
1f84f6b3 6493 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
5f70a34f 6494 if (po->p_argnum != 0) {
69a3cdfc 6495 // special case - saved func arg
3a5101d7 6496 fprintf(fout, " %s = %s;",
6497 saved_arg_name(buf2, sizeof(buf2),
6498 po->p_arggrp, po->p_argnum), buf1);
69a3cdfc 6499 break;
6500 }
d4e3b5db 6501 else if (po->flags & OPF_RSAVE) {
d4e3b5db 6502 fprintf(fout, " s_%s = %s;", buf1, buf1);
6503 break;
6504 }
25a330eb 6505 else if (po->flags & OPF_PPUSH) {
6506 tmp_op = po->datap;
6507 ferr_assert(po, tmp_op != NULL);
6508 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
6509 fprintf(fout, " pp_%s = %s;", buf2, buf1);
6510 break;
6511 }
1f84f6b3 6512 else if (g_func_pp->is_userstack) {
6513 fprintf(fout, " *(--esp) = %s;", buf1);
6514 break;
6515 }
e56ab892 6516 if (!(g_ida_func_attr & IDAFA_NORETURN))
6517 ferr(po, "stray push encountered\n");
6518 no_output = 1;
91977a1c 6519 break;
6520
6521 case OP_POP:
25a330eb 6522 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
d4e3b5db 6523 if (po->flags & OPF_RSAVE) {
d4e3b5db 6524 fprintf(fout, " %s = s_%s;", buf1, buf1);
6525 break;
6526 }
25a330eb 6527 else if (po->flags & OPF_PPUSH) {
e83ea7ed 6528 // push/pop graph / non-const
25a330eb 6529 ferr_assert(po, po->datap == NULL);
6530 fprintf(fout, " %s = pp_%s;", buf1, buf1);
6531 break;
6532 }
5c024ef7 6533 else if (po->datap != NULL) {
6534 // push/pop pair
6535 tmp_op = po->datap;
5c024ef7 6536 fprintf(fout, " %s = %s;", buf1,
6537 out_src_opr(buf2, sizeof(buf2),
6538 tmp_op, &tmp_op->operand[0],
c7ed83dd 6539 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
5c024ef7 6540 break;
6541 }
1f84f6b3 6542 else if (g_func_pp->is_userstack) {
25a330eb 6543 fprintf(fout, " %s = *esp++;", buf1);
1f84f6b3 6544 break;
6545 }
6546 else
6547 ferr(po, "stray pop encountered\n");
91977a1c 6548 break;
6549
33c35af6 6550 case OP_NOP:
2b43685d 6551 no_output = 1;
33c35af6 6552 break;
6553
d4a985bd 6554 // x87
6555 case OP_FLD:
6556 if (po->flags & OPF_FSHIFT)
6557 fprintf(fout, " f_st1 = f_st0;\n");
6558 if (po->operand[0].type == OPT_REG
6559 && po->operand[0].reg == xST0)
6560 {
6561 strcat(g_comment, " fld st");
6562 break;
6563 }
6564 fprintf(fout, " f_st0 = %s;",
6565 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0]));
6566 strcat(g_comment, " fld");
6567 break;
6568
6569 case OP_FILD:
6570 if (po->flags & OPF_FSHIFT)
6571 fprintf(fout, " f_st1 = f_st0;\n");
6572 fprintf(fout, " f_st0 = (double)%s;",
6573 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6574 lmod_cast(po, po->operand[0].lmod, 1), 0));
6575 strcat(g_comment, " fild");
6576 break;
6577
6578 case OP_FLDc:
6579 if (po->flags & OPF_FSHIFT)
6580 fprintf(fout, " f_st1 = f_st0;\n");
6581 fprintf(fout, " f_st0 = ");
6582 switch (po->operand[0].val) {
6583 case X87_CONST_1: fprintf(fout, "1.0;"); break;
6584 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
6585 default: ferr(po, "TODO\n"); break;
6586 }
6587 break;
6588
6589 case OP_FST:
6590 if ((po->flags & OPF_FPOP) && po->operand[0].type == OPT_REG
6591 && po->operand[0].reg == xST0)
6592 {
6593 no_output = 1;
6594 break;
6595 }
6596 fprintf(fout, " %s = f_st0;",
6597 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0]));
6598 if (po->flags & OPF_FSHIFT)
6599 fprintf(fout, "\n f_st0 = f_st1;");
6600 strcat(g_comment, " fst");
6601 break;
6602
6603 case OP_FADD:
6604 case OP_FDIV:
6605 case OP_FMUL:
6606 case OP_FSUB:
6607 switch (po->op) {
6608 case OP_FADD: j = '+'; break;
6609 case OP_FDIV: j = '/'; break;
6610 case OP_FMUL: j = '*'; break;
6611 case OP_FSUB: j = '-'; break;
6612 default: j = 'x'; break;
6613 }
6614 if (po->flags & OPF_FSHIFT) {
6615 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
6616 }
6617 else {
6618 fprintf(fout, " %s %c= %s;",
6619 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0]),
6620 j,
6621 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1]));
6622 }
6623 break;
6624
6625 case OP_FDIVR:
6626 case OP_FSUBR:
6627 if (po->flags & OPF_FSHIFT)
6628 snprintf(buf1, sizeof(buf1), "f_st0");
6629 else
6630 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0]);
6631 fprintf(fout, " %s = %s %c %s;", buf1,
6632 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1]),
6633 po->op == OP_FDIVR ? '/' : '-',
6634 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0]));
6635 break;
6636
6637 case OP_FIADD:
6638 case OP_FIDIV:
6639 case OP_FIMUL:
6640 case OP_FISUB:
6641 switch (po->op) {
6642 case OP_FIADD: j = '+'; break;
6643 case OP_FIDIV: j = '/'; break;
6644 case OP_FIMUL: j = '*'; break;
6645 case OP_FISUB: j = '-'; break;
6646 default: j = 'x'; break;
6647 }
6648 fprintf(fout, " f_st0 %c= (double)%s;", j,
6649 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6650 lmod_cast(po, po->operand[0].lmod, 1), 0));
6651 break;
6652
6653 case OP_FIDIVR:
6654 case OP_FISUBR:
6655 fprintf(fout, " f_st0 = %s %c f_st0;",
6656 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1]),
6657 po->op == OP_FIDIVR ? '/' : '-');
6658 break;
6659
6660 case OPP_FTOL:
6661 ferr_assert(po, po->flags & OPF_32BIT);
6662 fprintf(fout, " eax = (s32)f_st0;");
6663 if (po->flags & OPF_FSHIFT)
6664 fprintf(fout, "\n f_st0 = f_st1;");
6665 strcat(g_comment, " ftol");
6666 break;
6667
90307a99 6668 // mmx
6669 case OP_EMMS:
d4a985bd 6670 strcpy(g_comment, " (emms)");
90307a99 6671 break;
6672
91977a1c 6673 default:
6674 no_output = 1;
69a3cdfc 6675 ferr(po, "unhandled op type %d, flags %x\n",
6676 po->op, po->flags);
91977a1c 6677 break;
6678 }
6679
6680 if (g_comment[0] != 0) {
ddaf8bd7 6681 char *p = g_comment;
6682 while (my_isblank(*p))
6683 p++;
6684 fprintf(fout, " // %s", p);
91977a1c 6685 g_comment[0] = 0;
6686 no_output = 0;
6687 }
6688 if (!no_output)
6689 fprintf(fout, "\n");
5101a5f9 6690
2b43685d 6691 // some sanity checking
591721d7 6692 if (po->flags & OPF_REP) {
6693 if (po->op != OP_STOS && po->op != OP_MOVS
6694 && po->op != OP_CMPS && po->op != OP_SCAS)
6695 ferr(po, "unexpected rep\n");
6696 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
6697 && (po->op == OP_CMPS || po->op == OP_SCAS))
6698 ferr(po, "cmps/scas with plain rep\n");
6699 }
6700 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
6701 && po->op != OP_CMPS && po->op != OP_SCAS)
2b43685d 6702 ferr(po, "unexpected repz/repnz\n");
6703
940e8e66 6704 if (pfomask != 0)
7ba45c34 6705 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
940e8e66 6706
5101a5f9 6707 // see is delayed flag stuff is still valid
6708 if (delayed_flag_op != NULL && delayed_flag_op != po) {
89ff3147 6709 if (is_any_opr_modified(delayed_flag_op, po, 0))
5101a5f9 6710 delayed_flag_op = NULL;
6711 }
6712
6713 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
6714 if (is_opr_modified(last_arith_dst, po))
6715 last_arith_dst = NULL;
6716 }
3ebea2cf 6717
6718 label_pending = 0;
91977a1c 6719 }
6720
a2c1d768 6721 if (g_stack_fsz && !g_stack_frame_used)
6722 fprintf(fout, " (void)sf;\n");
6723
91977a1c 6724 fprintf(fout, "}\n\n");
6725
9af2d373 6726 gen_x_cleanup(opcnt);
6727}
6728
6729static void gen_x_cleanup(int opcnt)
6730{
6731 int i;
6732
91977a1c 6733 for (i = 0; i < opcnt; i++) {
4c45fa73 6734 struct label_ref *lr, *lr_del;
6735
6736 lr = g_label_refs[i].next;
6737 while (lr != NULL) {
6738 lr_del = lr;
6739 lr = lr->next;
6740 free(lr_del);
6741 }
6742 g_label_refs[i].i = -1;
6743 g_label_refs[i].next = NULL;
6744
91977a1c 6745 if (ops[i].op == OP_CALL) {
092f64e1 6746 if (ops[i].pp)
6747 proto_release(ops[i].pp);
91977a1c 6748 }
6749 }
bd96f656 6750 g_func_pp = NULL;
91977a1c 6751}
c36e914d 6752
92d715b6 6753struct func_proto_dep;
6754
6755struct func_prototype {
6756 char name[NAMELEN];
6757 int id;
6758 int argc_stack;
6759 int regmask_dep;
91ca764a 6760 int has_ret:3; // -1, 0, 1: unresolved, no, yes
92d715b6 6761 unsigned int dep_resolved:1;
6762 unsigned int is_stdcall:1;
6763 struct func_proto_dep *dep_func;
6764 int dep_func_cnt;
91ca764a 6765 const struct parsed_proto *pp; // seed pp, if any
92d715b6 6766};
6767
6768struct func_proto_dep {
6769 char *name;
6770 struct func_prototype *proto;
6771 int regmask_live; // .. at the time of call
6772 unsigned int ret_dep:1; // return from this is caller's return
6773};
6774
6775static struct func_prototype *hg_fp;
6776static int hg_fp_cnt;
6777
5fa1256f 6778static struct scanned_var {
6779 char name[NAMELEN];
6780 enum opr_lenmod lmod;
6781 unsigned int is_seeded:1;
61e29183 6782 unsigned int is_c_str:1;
c0de9015 6783 const struct parsed_proto *pp; // seed pp, if any
5fa1256f 6784} *hg_vars;
6785static int hg_var_cnt;
6786
9af2d373 6787static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
6788 int count);
6789
ebc4dc43 6790struct func_prototype *hg_fp_add(const char *funcn)
6791{
6792 struct func_prototype *fp;
6793
6794 if ((hg_fp_cnt & 0xff) == 0) {
6795 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
6796 my_assert_not(hg_fp, NULL);
6797 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
6798 }
6799
6800 fp = &hg_fp[hg_fp_cnt];
6801 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
6802 fp->id = hg_fp_cnt;
6803 fp->argc_stack = -1;
6804 hg_fp_cnt++;
6805
6806 return fp;
6807}
6808
92d715b6 6809static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
6810 const char *name)
6811{
6812 int i;
6813
6814 for (i = 0; i < fp->dep_func_cnt; i++)
6815 if (IS(fp->dep_func[i].name, name))
6816 return &fp->dep_func[i];
6817
6818 return NULL;
6819}
6820
6821static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
6822{
6823 // is it a dupe?
6824 if (hg_fp_find_dep(fp, name))
6825 return;
6826
6827 if ((fp->dep_func_cnt & 0xff) == 0) {
6828 fp->dep_func = realloc(fp->dep_func,
6829 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
6830 my_assert_not(fp->dep_func, NULL);
6831 memset(&fp->dep_func[fp->dep_func_cnt], 0,
6832 sizeof(fp->dep_func[0]) * 0x100);
6833 }
6834 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
6835 fp->dep_func_cnt++;
6836}
6837
6838static int hg_fp_cmp_name(const void *p1_, const void *p2_)
6839{
6840 const struct func_prototype *p1 = p1_, *p2 = p2_;
6841 return strcmp(p1->name, p2->name);
6842}
6843
6844#if 0
6845static int hg_fp_cmp_id(const void *p1_, const void *p2_)
6846{
6847 const struct func_prototype *p1 = p1_, *p2 = p2_;
6848 return p1->id - p2->id;
6849}
6850#endif
6851
91ca764a 6852// recursive register dep pass
6853// - track saved regs (part 2)
6854// - try to figure out arg-regs
6855// - calculate reg deps
6856static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
6857 struct func_prototype *fp, int regmask_save, int regmask_dst,
6858 int *regmask_dep, int *has_ret)
6859{
6860 struct func_proto_dep *dep;
6861 struct parsed_op *po;
6862 int from_caller = 0;
91ca764a 6863 int j, l;
6864 int reg;
6865 int ret;
6866
6867 for (; i < opcnt; i++)
6868 {
6869 if (cbits[i >> 3] & (1 << (i & 7)))
6870 return;
6871 cbits[i >> 3] |= (1 << (i & 7));
6872
6873 po = &ops[i];
6874
6875 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
04abc5d6 6876 if (po->flags & OPF_RMD)
6877 continue;
6878
91ca764a 6879 if (po->btj != NULL) {
6880 // jumptable
6881 for (j = 0; j < po->btj->count; j++) {
db63af51 6882 check_i(po, po->btj->d[j].bt_i);
91ca764a 6883 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
6884 regmask_save, regmask_dst, regmask_dep, has_ret);
6885 }
6886 return;
6887 }
6888
db63af51 6889 check_i(po, po->bt_i);
91ca764a 6890 if (po->flags & OPF_CJMP) {
6891 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
6892 regmask_save, regmask_dst, regmask_dep, has_ret);
6893 }
6894 else {
6895 i = po->bt_i - 1;
6896 }
6897 continue;
6898 }
6899
6900 if (po->flags & OPF_FARG)
6901 /* (just calculate register deps) */;
6902 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
6903 {
6904 reg = po->operand[0].reg;
b2bd20c0 6905 ferr_assert(po, reg >= 0);
91ca764a 6906
6907 if (po->flags & OPF_RSAVE) {
6908 regmask_save |= 1 << reg;
6909 continue;
6910 }
6911 if (po->flags & OPF_DONE)
6912 continue;
6913
b2bd20c0 6914 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0);
91ca764a 6915 if (ret == 1) {
6916 regmask_save |= 1 << reg;
6917 po->flags |= OPF_RMD;
b2bd20c0 6918 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, OPF_RMD);
91ca764a 6919 continue;
6920 }
6921 }
6922 else if (po->flags & OPF_RMD)
6923 continue;
6924 else if (po->op == OP_CALL) {
6925 po->regmask_dst |= 1 << xAX;
6926
6927 dep = hg_fp_find_dep(fp, po->operand[0].name);
6928 if (dep != NULL)
6929 dep->regmask_live = regmask_save | regmask_dst;
6930 }
6931 else if (po->op == OP_RET) {
6932 if (po->operand_cnt > 0) {
6933 fp->is_stdcall = 1;
6934 if (fp->argc_stack >= 0
6935 && fp->argc_stack != po->operand[0].val / 4)
6936 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
6937 fp->argc_stack = po->operand[0].val / 4;
6938 }
6939 }
6940
ebc4dc43 6941 // if has_ret is 0, there is uninitialized eax path,
6942 // which means it's most likely void func
91ca764a 6943 if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
6944 if (po->op == OP_CALL) {
6945 j = i;
6946 ret = 1;
6947 }
6948 else {
b2bd20c0 6949 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
91ca764a 6950 j = -1;
6951 from_caller = 0;
6952 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
6953 }
6954
ebc4dc43 6955 if (ret != 1 && from_caller) {
91ca764a 6956 // unresolved eax - probably void func
6957 *has_ret = 0;
6958 }
6959 else {
ebc4dc43 6960 if (j >= 0 && ops[j].op == OP_CALL) {
6961 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
91ca764a 6962 if (dep != NULL)
6963 dep->ret_dep = 1;
6964 else
6965 *has_ret = 1;
6966 }
6967 else
6968 *has_ret = 1;
6969 }
6970 }
6971
6972 l = regmask_save | regmask_dst;
6973 if (g_bp_frame && !(po->flags & OPF_EBP_S))
6974 l |= 1 << xBP;
6975
6976 l = po->regmask_src & ~l;
6977#if 0
6978 if (l)
6979 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
6980 l, regmask_dst, regmask_save, po->flags);
6981#endif
6982 *regmask_dep |= l;
6983 regmask_dst |= po->regmask_dst;
6984
6985 if (po->flags & OPF_TAIL)
6986 return;
6987 }
6988}
6989
92d715b6 6990static void gen_hdr(const char *funcn, int opcnt)
6991{
26677139 6992 int save_arg_vars[MAX_ARG_GRP] = { 0, };
91ca764a 6993 unsigned char cbits[MAX_OPS / 8];
ebc4dc43 6994 const struct parsed_proto *pp_c;
9af2d373 6995 struct parsed_proto *pp;
92d715b6 6996 struct func_prototype *fp;
92d715b6 6997 struct parsed_op *po;
26677139 6998 int regmask_dummy = 0;
91ca764a 6999 int regmask_dep;
92d715b6 7000 int max_bp_offset = 0;
91ca764a 7001 int has_ret;
bfacdc83 7002 int i, j, l;
7003 int ret;
92d715b6 7004
ebc4dc43 7005 pp_c = proto_parse(g_fhdr, funcn, 1);
7006 if (pp_c != NULL)
7007 // already in seed, will add to hg_fp later
9af2d373 7008 return;
ebc4dc43 7009
7010 fp = hg_fp_add(funcn);
9af2d373 7011
7012 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
7013 g_stack_frame_used = 0;
7014
92d715b6 7015 // pass1:
66bdb2b0 7016 // - resolve all branches
7017 // - parse calls with labels
7018 resolve_branches_parse_calls(opcnt);
7019
7020 // pass2:
9af2d373 7021 // - handle ebp/esp frame, remove ops related to it
7022 scan_prologue_epilogue(opcnt);
7023
66bdb2b0 7024 // pass3:
7025 // - remove dead labels
92d715b6 7026 // - collect calls
92d715b6 7027 for (i = 0; i < opcnt; i++)
7028 {
66bdb2b0 7029 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7030 free(g_labels[i]);
7031 g_labels[i] = NULL;
7032 }
92d715b6 7033
66bdb2b0 7034 po = &ops[i];
5e49b270 7035 if (po->flags & (OPF_RMD|OPF_DONE))
92d715b6 7036 continue;
7037
7038 if (po->op == OP_CALL) {
66bdb2b0 7039 if (po->operand[0].type == OPT_LABEL)
7040 hg_fp_add_dep(fp, opr_name(po, 0));
7041 else if (po->pp != NULL)
7042 hg_fp_add_dep(fp, po->pp->name);
92d715b6 7043 }
92d715b6 7044 }
7045
66bdb2b0 7046 // pass4:
92d715b6 7047 // - remove dead labels
9af2d373 7048 // - handle push <const>/pop pairs
92d715b6 7049 for (i = 0; i < opcnt; i++)
7050 {
d7857c3a 7051 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7052 free(g_labels[i]);
7053 g_labels[i] = NULL;
7054 }
9af2d373 7055
91ca764a 7056 po = &ops[i];
7057 if (po->flags & (OPF_RMD|OPF_DONE))
7058 continue;
7059
7060 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
e83ea7ed 7061 scan_for_pop_const(i, opcnt, i + opcnt * 13);
91ca764a 7062 }
7063
66bdb2b0 7064 // pass5:
91ca764a 7065 // - process trivial calls
7066 for (i = 0; i < opcnt; i++)
7067 {
9af2d373 7068 po = &ops[i];
5e49b270 7069 if (po->flags & (OPF_RMD|OPF_DONE))
9af2d373 7070 continue;
7071
26677139 7072 if (po->op == OP_CALL)
7073 {
7074 pp = process_call_early(i, opcnt, &j);
7075 if (pp != NULL) {
7076 if (!(po->flags & OPF_ATAIL))
7077 // since we know the args, try to collect them
7078 if (collect_call_args_early(po, i, pp, &regmask_dummy) != 0)
7079 pp = NULL;
7080 }
7081
7082 if (pp != NULL) {
7083 if (j >= 0) {
7084 // commit esp adjust
5e49b270 7085 if (ops[j].op != OP_POP)
7086 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
bfacdc83 7087 else {
7088 for (l = 0; l < pp->argc_stack; l++)
b2bd20c0 7089 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
bfacdc83 7090 }
26677139 7091 }
7092
7093 po->flags |= OPF_DONE;
7094 }
7095 }
26677139 7096 }
7097
66bdb2b0 7098 // pass6:
5e49b270 7099 // - track saved regs (simple)
26677139 7100 // - process calls
7101 for (i = 0; i < opcnt; i++)
7102 {
7103 po = &ops[i];
5e49b270 7104 if (po->flags & (OPF_RMD|OPF_DONE))
26677139 7105 continue;
7106
e83ea7ed 7107 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
7108 && po->operand[0].reg != xCX)
5e49b270 7109 {
e83ea7ed 7110 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
b2bd20c0 7111 if (ret == 1) {
91ca764a 7112 // regmask_save |= 1 << po->operand[0].reg; // do it later
7113 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
e83ea7ed 7114 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
5e49b270 7115 }
7116 }
e83ea7ed 7117 else if (po->op == OP_CALL)
26677139 7118 {
9af2d373 7119 pp = process_call(i, opcnt);
7120
7121 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
9af2d373 7122 // since we know the args, collect them
91ca764a 7123 ret = collect_call_args(po, i, pp, &regmask_dummy, save_arg_vars,
5e49b270 7124 i + opcnt * 1);
9af2d373 7125 }
7126 }
92d715b6 7127 }
7128
66bdb2b0 7129 // pass7
91ca764a 7130 memset(cbits, 0, sizeof(cbits));
7131 regmask_dep = 0;
7132 has_ret = -1;
7133
7134 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, &regmask_dep, &has_ret);
7135
7136 // find unreachable code - must be fixed in IDA
92d715b6 7137 for (i = 0; i < opcnt; i++)
7138 {
91ca764a 7139 if (cbits[i >> 3] & (1 << (i & 7)))
9af2d373 7140 continue;
92d715b6 7141
04abc5d6 7142 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
7143 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
7144 {
7145 // the compiler sometimes still generates code after
7146 // noreturn OS functions
7147 break;
7148 }
91ca764a 7149 if (ops[i].op != OP_NOP)
7150 ferr(&ops[i], "unreachable code\n");
92d715b6 7151 }
7152
9af2d373 7153 for (i = 0; i < g_eqcnt; i++) {
92d715b6 7154 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
7155 max_bp_offset = g_eqs[i].offset;
9af2d373 7156 }
92d715b6 7157
9af2d373 7158 if (fp->argc_stack < 0) {
92d715b6 7159 max_bp_offset = (max_bp_offset + 3) & ~3;
9af2d373 7160 fp->argc_stack = max_bp_offset / 4;
7161 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
92d715b6 7162 fp->argc_stack--;
7163 }
7164
7165 fp->regmask_dep = regmask_dep & ~(1 << xSP);
7166 fp->has_ret = has_ret;
91ca764a 7167#if 0
7168 printf("// has_ret %d, regmask_dep %x\n",
7169 fp->has_ret, fp->regmask_dep);
7170 output_hdr_fp(stdout, fp, 1);
ebc4dc43 7171 if (IS(funcn, "sub_10007F72")) exit(1);
91ca764a 7172#endif
9af2d373 7173
7174 gen_x_cleanup(opcnt);
92d715b6 7175}
7176
7177static void hg_fp_resolve_deps(struct func_prototype *fp)
7178{
7179 struct func_prototype fp_s;
91ca764a 7180 int dep;
92d715b6 7181 int i;
7182
7183 // this thing is recursive, so mark first..
7184 fp->dep_resolved = 1;
7185
7186 for (i = 0; i < fp->dep_func_cnt; i++) {
7187 strcpy(fp_s.name, fp->dep_func[i].name);
7188 fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
7189 sizeof(hg_fp[0]), hg_fp_cmp_name);
7190 if (fp->dep_func[i].proto != NULL) {
7191 if (!fp->dep_func[i].proto->dep_resolved)
7192 hg_fp_resolve_deps(fp->dep_func[i].proto);
7193
91ca764a 7194 dep = ~fp->dep_func[i].regmask_live
7195 & fp->dep_func[i].proto->regmask_dep;
7196 fp->regmask_dep |= dep;
7197 // printf("dep %s %s |= %x\n", fp->name,
7198 // fp->dep_func[i].name, dep);
92d715b6 7199
ebc4dc43 7200 if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
92d715b6 7201 fp->has_ret = fp->dep_func[i].proto->has_ret;
7202 }
7203 }
7204}
7205
9af2d373 7206static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7207 int count)
92d715b6 7208{
61e29183 7209 const struct parsed_proto *pp;
7210 char *p, namebuf[NAMELEN];
7211 const char *name;
92d715b6 7212 int regmask_dep;
7213 int argc_stack;
9af2d373 7214 int j, arg;
92d715b6 7215
9af2d373 7216 for (; count > 0; count--, fp++) {
92d715b6 7217 if (fp->has_ret == -1)
7218 fprintf(fout, "// ret unresolved\n");
7219#if 0
7220 fprintf(fout, "// dep:");
7221 for (j = 0; j < fp->dep_func_cnt; j++) {
7222 fprintf(fout, " %s/", fp->dep_func[j].name);
7223 if (fp->dep_func[j].proto != NULL)
7224 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
7225 fp->dep_func[j].proto->has_ret);
7226 }
7227 fprintf(fout, "\n");
7228#endif
7229
61e29183 7230 p = strchr(fp->name, '@');
7231 if (p != NULL) {
7232 memcpy(namebuf, fp->name, p - fp->name);
7233 namebuf[p - fp->name] = 0;
7234 name = namebuf;
7235 }
7236 else
7237 name = fp->name;
7238 if (name[0] == '_')
7239 name++;
7240
7241 pp = proto_parse(g_fhdr, name, 1);
7242 if (pp != NULL && pp->is_include)
7243 continue;
7244
c0de9015 7245 if (fp->pp != NULL) {
4e81a3a2 7246 // part of seed, output later
7247 continue;
c0de9015 7248 }
7249
92d715b6 7250 regmask_dep = fp->regmask_dep;
7251 argc_stack = fp->argc_stack;
7252
91ca764a 7253 fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
7254 (fp->has_ret ? "int" : "void"));
92d715b6 7255 if (regmask_dep && (fp->is_stdcall || argc_stack == 0)
7256 && (regmask_dep & ~((1 << xCX) | (1 << xDX))) == 0)
7257 {
9af2d373 7258 fprintf(fout, " __fastcall ");
92d715b6 7259 if (!(regmask_dep & (1 << xDX)) && argc_stack == 0)
7260 argc_stack = 1;
7261 else
7262 argc_stack += 2;
7263 regmask_dep = 0;
7264 }
7265 else if (regmask_dep && !fp->is_stdcall) {
7266 fprintf(fout, "/*__usercall*/ ");
92d715b6 7267 }
7268 else if (regmask_dep) {
7269 fprintf(fout, "/*__userpurge*/ ");
92d715b6 7270 }
7271 else if (fp->is_stdcall)
9af2d373 7272 fprintf(fout, " __stdcall ");
92d715b6 7273 else
9af2d373 7274 fprintf(fout, " __cdecl ");
92d715b6 7275
61e29183 7276 fprintf(fout, "%s(", name);
92d715b6 7277
7278 arg = 0;
7279 for (j = 0; j < xSP; j++) {
7280 if (regmask_dep & (1 << j)) {
7281 arg++;
7282 if (arg != 1)
7283 fprintf(fout, ", ");
91ca764a 7284 if (fp->pp != NULL)
7285 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
7286 else
7287 fprintf(fout, "int");
7288 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
92d715b6 7289 }
7290 }
7291
7292 for (j = 0; j < argc_stack; j++) {
7293 arg++;
7294 if (arg != 1)
7295 fprintf(fout, ", ");
91ca764a 7296 if (fp->pp != NULL) {
7297 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
7298 if (!fp->pp->arg[arg - 1].type.is_ptr)
7299 fprintf(fout, " ");
7300 }
7301 else
7302 fprintf(fout, "int ");
7303 fprintf(fout, "a%d", arg);
92d715b6 7304 }
7305
7306 fprintf(fout, ");\n");
7307 }
7308}
7309
9af2d373 7310static void output_hdr(FILE *fout)
7311{
5fa1256f 7312 static const char *lmod_c_names[] = {
7313 [OPLM_UNSPEC] = "???",
7314 [OPLM_BYTE] = "uint8_t",
7315 [OPLM_WORD] = "uint16_t",
7316 [OPLM_DWORD] = "uint32_t",
7317 [OPLM_QWORD] = "uint64_t",
7318 };
7319 const struct scanned_var *var;
ebc4dc43 7320 struct func_prototype *fp;
c0de9015 7321 char line[256] = { 0, };
ebc4dc43 7322 char name[256];
9af2d373 7323 int i;
7324
ebc4dc43 7325 // add stuff from headers
7326 for (i = 0; i < pp_cache_size; i++) {
7327 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
7328 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
7329 else
7330 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
7331 fp = hg_fp_add(name);
7332 fp->pp = &pp_cache[i];
7333 fp->argc_stack = fp->pp->argc_stack;
7334 fp->is_stdcall = fp->pp->is_stdcall;
b2bd20c0 7335 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
ebc4dc43 7336 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
7337 }
7338
9af2d373 7339 // resolve deps
7340 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
7341 for (i = 0; i < hg_fp_cnt; i++)
7342 hg_fp_resolve_deps(&hg_fp[i]);
7343
7344 // note: messes up .proto ptr, don't use
7345 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
7346
5fa1256f 7347 // output variables
7348 for (i = 0; i < hg_var_cnt; i++) {
7349 var = &hg_vars[i];
7350
4e81a3a2 7351 if (var->pp != NULL)
7352 // part of seed
7353 continue;
c0de9015 7354 else if (var->is_c_str)
61e29183 7355 fprintf(fout, "extern %-8s %s[];", "char", var->name);
7356 else
7357 fprintf(fout, "extern %-8s %s;",
7358 lmod_c_names[var->lmod], var->name);
5fa1256f 7359
7360 if (var->is_seeded)
7361 fprintf(fout, " // seeded");
7362 fprintf(fout, "\n");
7363 }
7364
7365 fprintf(fout, "\n");
7366
7367 // output function prototypes
9af2d373 7368 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
c0de9015 7369
4e81a3a2 7370 // seed passthrough
7371 fprintf(fout, "\n// - seed -\n");
c0de9015 7372
7373 rewind(g_fhdr);
4e81a3a2 7374 while (fgets(line, sizeof(line), g_fhdr))
7375 fwrite(line, 1, strlen(line), fout);
9af2d373 7376}
7377
61e29183 7378// '=' needs special treatment
7379// also ' quote
bfa4a6ee 7380static char *next_word_s(char *w, size_t wsize, char *s)
7381{
61e29183 7382 size_t i;
bfa4a6ee 7383
61e29183 7384 s = sskip(s);
bfa4a6ee 7385
61e29183 7386 i = 0;
7387 if (*s == '\'') {
7388 w[0] = s[0];
7389 for (i = 1; i < wsize - 1; i++) {
7390 if (s[i] == 0) {
7391 printf("warning: missing closing quote: \"%s\"\n", s);
7392 break;
7393 }
7394 if (s[i] == '\'')
7395 break;
7396 w[i] = s[i];
7397 }
7398 }
bfa4a6ee 7399
61e29183 7400 for (; i < wsize - 1; i++) {
7401 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
7402 break;
7403 w[i] = s[i];
7404 }
7405 w[i] = 0;
7406
7407 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
7408 printf("warning: '%s' truncated\n", w);
bfa4a6ee 7409
61e29183 7410 return s + i;
bfa4a6ee 7411}
7412
4c20744d 7413static int cmpstringp(const void *p1, const void *p2)
7414{
7415 return strcmp(*(char * const *)p1, *(char * const *)p2);
7416}
7417
7418static int is_xref_needed(char *p, char **rlist, int rlist_len)
7419{
7420 char *p2;
7421
7422 p = sskip(p);
7423 if (strstr(p, "..."))
7424 // unable to determine, assume needed
7425 return 1;
7426
7427 if (*p == '.') // .text, .data, ...
7428 // ref from other data or non-function -> no
7429 return 0;
7430
7431 p2 = strpbrk(p, "+:\r\n\x18");
7432 if (p2 != NULL)
7433 *p2 = 0;
7434 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
7435 // referenced from removed code
7436 return 0;
7437
7438 return 1;
7439}
7440
7441static int xrefs_show_need(FILE *fasm, char *p,
7442 char **rlist, int rlist_len)
7443{
7444 int found_need = 0;
7445 char line[256];
7446 long pos;
7447
7448 p = strrchr(p, ';');
7449 if (p != NULL && *p == ';' && IS_START(p + 2, "DATA XREF: ")) {
7450 p += 13;
7451 if (is_xref_needed(p, rlist, rlist_len))
7452 return 1;
7453 }
7454
7455 pos = ftell(fasm);
7456 while (1)
7457 {
7458 if (!my_fgets(line, sizeof(line), fasm))
7459 break;
7460 // non-first line is always indented
7461 if (!my_isblank(line[0]))
7462 break;
7463
7464 // should be no content, just comment
7465 p = sskip(line);
7466 if (*p != ';')
7467 break;
7468
7469 p = strrchr(p, ';');
7470 p += 2;
7471 // it's printed once, but no harm to check again
7472 if (IS_START(p, "DATA XREF: "))
7473 p += 11;
7474
7475 if (is_xref_needed(p, rlist, rlist_len)) {
7476 found_need = 1;
7477 break;
7478 }
7479 }
7480 fseek(fasm, pos, SEEK_SET);
7481 return found_need;
7482}
7483
7484static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
5fa1256f 7485{
5fa1256f 7486 struct scanned_var *var;
7487 char line[256] = { 0, };
61e29183 7488 char words[3][256];
5fa1256f 7489 char *p = NULL;
7490 int wordc;
61e29183 7491 int l;
5fa1256f 7492
7493 while (!feof(fasm))
7494 {
7495 // skip to next data section
7496 while (my_fgets(line, sizeof(line), fasm))
7497 {
7498 asmln++;
7499
7500 p = sskip(line);
7501 if (*p == 0 || *p == ';')
7502 continue;
7503
7504 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
7505 if (*p == 0 || *p == ';')
7506 continue;
7507
7508 if (*p != 's' || !IS_START(p, "segment para public"))
7509 continue;
7510
7511 break;
7512 }
7513
7514 if (p == NULL || !IS_START(p, "segment para public"))
7515 break;
7516 p = sskip(p + 19);
7517
7518 if (!IS_START(p, "'DATA'"))
7519 continue;
7520
7521 // now process it
7522 while (my_fgets(line, sizeof(line), fasm))
7523 {
7524 asmln++;
7525
7526 p = line;
7527 if (my_isblank(*p))
7528 continue;
7529
7530 p = sskip(p);
7531 if (*p == 0 || *p == ';')
7532 continue;
7533
7534 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
7535 words[wordc][0] = 0;
7536 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
7537 if (*p == 0 || *p == ';') {
7538 wordc++;
7539 break;
7540 }
7541 }
7542
7543 if (wordc == 2 && IS(words[1], "ends"))
7544 break;
61e29183 7545 if (wordc < 2)
7546 continue;
5fa1256f 7547
9ea60b8d 7548 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
7549 // when this starts, we don't need anything from this section
7550 break;
7551 }
7552
4c20744d 7553 // check refs comment(s)
7554 if (!xrefs_show_need(fasm, p, rlist, rlist_len))
7555 continue;
7556
5fa1256f 7557 if ((hg_var_cnt & 0xff) == 0) {
7558 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
7559 * (hg_var_cnt + 0x100));
7560 my_assert_not(hg_vars, NULL);
7561 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
7562 }
7563
7564 var = &hg_vars[hg_var_cnt++];
7565 snprintf(var->name, sizeof(var->name), "%s", words[0]);
7566
7567 // maybe already in seed header?
c0de9015 7568 var->pp = proto_parse(g_fhdr, var->name, 1);
7569 if (var->pp != NULL) {
7570 if (var->pp->is_fptr) {
5fa1256f 7571 var->lmod = OPLM_DWORD;
7572 //var->is_ptr = 1;
7573 }
c0de9015 7574 else if (var->pp->is_func)
7575 aerr("func?\n");
7576 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
5fa1256f 7577 aerr("unhandled C type '%s' for '%s'\n",
c0de9015 7578 var->pp->type.name, var->name);
5fa1256f 7579
7580 var->is_seeded = 1;
7581 continue;
7582 }
7583
7584 if (IS(words[1], "dd"))
7585 var->lmod = OPLM_DWORD;
7586 else if (IS(words[1], "dw"))
7587 var->lmod = OPLM_WORD;
61e29183 7588 else if (IS(words[1], "db")) {
5fa1256f 7589 var->lmod = OPLM_BYTE;
61e29183 7590 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
7591 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
7592 var->is_c_str = 1;
7593 }
7594 }
5fa1256f 7595 else if (IS(words[1], "dq"))
7596 var->lmod = OPLM_QWORD;
7597 //else if (IS(words[1], "dt"))
7598 else
7599 aerr("type '%s' not known\n", words[1]);
7600 }
7601 }
7602
7603 rewind(fasm);
7604 asmln = 0;
7605}
7606
7607static void set_label(int i, const char *name)
7608{
7609 const char *p;
7610 int len;
7611
7612 len = strlen(name);
7613 p = strchr(name, ':');
7614 if (p != NULL)
7615 len = p - name;
7616
7617 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
7618 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
7619 g_labels[i] = realloc(g_labels[i], len + 1);
7620 my_assert_not(g_labels[i], NULL);
7621 memcpy(g_labels[i], name, len);
7622 g_labels[i][len] = 0;
7623}
7624
e56ab892 7625struct chunk_item {
7626 char *name;
7627 long fptr;
de50b98b 7628 int asmln;
e56ab892 7629};
7630
cdfaeed7 7631static struct chunk_item *func_chunks;
7632static int func_chunk_cnt;
7633static int func_chunk_alloc;
7634
7635static void add_func_chunk(FILE *fasm, const char *name, int line)
7636{
7637 if (func_chunk_cnt >= func_chunk_alloc) {
7638 func_chunk_alloc *= 2;
7639 func_chunks = realloc(func_chunks,
7640 func_chunk_alloc * sizeof(func_chunks[0]));
7641 my_assert_not(func_chunks, NULL);
7642 }
7643 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
7644 func_chunks[func_chunk_cnt].name = strdup(name);
7645 func_chunks[func_chunk_cnt].asmln = line;
7646 func_chunk_cnt++;
7647}
7648
e56ab892 7649static int cmp_chunks(const void *p1, const void *p2)
7650{
7651 const struct chunk_item *c1 = p1, *c2 = p2;
7652 return strcmp(c1->name, c2->name);
7653}
7654
cdfaeed7 7655static void scan_ahead(FILE *fasm)
7656{
7657 char words[2][256];
7658 char line[256];
7659 long oldpos;
7660 int oldasmln;
7661 int wordc;
7662 char *p;
7663 int i;
7664
7665 oldpos = ftell(fasm);
7666 oldasmln = asmln;
7667
5fa1256f 7668 while (my_fgets(line, sizeof(line), fasm))
cdfaeed7 7669 {
7670 wordc = 0;
7671 asmln++;
7672
7673 p = sskip(line);
7674 if (*p == 0)
7675 continue;
7676
7677 if (*p == ';')
7678 {
7679 // get rid of random tabs
7680 for (i = 0; line[i] != 0; i++)
7681 if (line[i] == '\t')
7682 line[i] = ' ';
7683
7684 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
7685 {
7686 p += 30;
7687 next_word(words[0], sizeof(words[0]), p);
7688 if (words[0][0] == 0)
7689 aerr("missing name for func chunk?\n");
7690
7691 add_func_chunk(fasm, words[0], asmln);
7692 }
46b388c2 7693 else if (IS_START(p, "; sctend"))
7694 break;
7695
cdfaeed7 7696 continue;
7697 } // *p == ';'
7698
7699 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
7700 words[wordc][0] = 0;
7701 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
7702 if (*p == 0 || *p == ';') {
7703 wordc++;
7704 break;
7705 }
7706 }
7707
7708 if (wordc == 2 && IS(words[1], "ends"))
7709 break;
7710 }
7711
7712 fseek(fasm, oldpos, SEEK_SET);
7713 asmln = oldasmln;
7714}
7715
91977a1c 7716int main(int argc, char *argv[])
7717{
06c5d854 7718 FILE *fout, *fasm, *frlist;
4c45fa73 7719 struct parsed_data *pd = NULL;
7720 int pd_alloc = 0;
7721 char **rlist = NULL;
7722 int rlist_len = 0;
7723 int rlist_alloc = 0;
e56ab892 7724 int func_chunks_used = 0;
7725 int func_chunks_sorted = 0;
e56ab892 7726 int func_chunk_i = -1;
7727 long func_chunk_ret = 0;
de50b98b 7728 int func_chunk_ret_ln = 0;
cdfaeed7 7729 int scanned_ahead = 0;
91977a1c 7730 char line[256];
a2c1d768 7731 char words[20][256];
4c45fa73 7732 enum opr_lenmod lmod;
ddaf8bd7 7733 char *sctproto = NULL;
91977a1c 7734 int in_func = 0;
4c45fa73 7735 int pending_endp = 0;
bfa4a6ee 7736 int skip_func = 0;
940e8e66 7737 int skip_warned = 0;
91977a1c 7738 int eq_alloc;
bfa4a6ee 7739 int verbose = 0;
1f84f6b3 7740 int multi_seg = 0;
46b388c2 7741 int end = 0;
bfa4a6ee 7742 int arg_out;
89ff3147 7743 int arg;
91977a1c 7744 int pi = 0;
e56ab892 7745 int i, j;
7746 int ret, len;
91977a1c 7747 char *p;
7748 int wordc;
7749
89ff3147 7750 for (arg = 1; arg < argc; arg++) {
7751 if (IS(argv[arg], "-v"))
7752 verbose = 1;
7753 else if (IS(argv[arg], "-rf"))
7754 g_allow_regfunc = 1;
1f84f6b3 7755 else if (IS(argv[arg], "-m"))
7756 multi_seg = 1;
92d715b6 7757 else if (IS(argv[arg], "-hdr"))
9af2d373 7758 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
89ff3147 7759 else
7760 break;
bfa4a6ee 7761 }
7762
7763 if (argc < arg + 3) {
315b77eb 7764 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
7765 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
7766 "options:\n"
7767 " -hdr - header generation mode\n"
7768 " -rf - allow unannotated indirect calls\n"
7769 " -m - allow multiple .text sections\n"
7770 "[rlist] is a file with function names to skip,"
7771 " one per line\n",
92d715b6 7772 argv[0], argv[0]);
91977a1c 7773 return 1;
7774 }
7775
bfa4a6ee 7776 arg_out = arg++;
91977a1c 7777
bfa4a6ee 7778 asmfn = argv[arg++];
91977a1c 7779 fasm = fopen(asmfn, "r");
7780 my_assert_not(fasm, NULL);
7781
bfa4a6ee 7782 hdrfn = argv[arg++];
06c5d854 7783 g_fhdr = fopen(hdrfn, "r");
7784 my_assert_not(g_fhdr, NULL);
bfa4a6ee 7785
7786 rlist_alloc = 64;
7787 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
7788 my_assert_not(rlist, NULL);
7789 // needs special handling..
7790 rlist[rlist_len++] = "__alloca_probe";
7791
e56ab892 7792 func_chunk_alloc = 32;
7793 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
7794 my_assert_not(func_chunks, NULL);
7795
a2c1d768 7796 memset(words, 0, sizeof(words));
7797
bfa4a6ee 7798 for (; arg < argc; arg++) {
7799 frlist = fopen(argv[arg], "r");
7800 my_assert_not(frlist, NULL);
7801
5fa1256f 7802 while (my_fgets(line, sizeof(line), frlist)) {
bfa4a6ee 7803 p = sskip(line);
1cd4a663 7804 if (*p == 0 || *p == ';')
7805 continue;
7806 if (*p == '#') {
89ff3147 7807 if (IS_START(p, "#if 0")
7808 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
7809 {
1cd4a663 7810 skip_func = 1;
89ff3147 7811 }
1cd4a663 7812 else if (IS_START(p, "#endif"))
7813 skip_func = 0;
7814 continue;
7815 }
7816 if (skip_func)
bfa4a6ee 7817 continue;
7818
7819 p = next_word(words[0], sizeof(words[0]), p);
7820 if (words[0][0] == 0)
7821 continue;
7822
7823 if (rlist_len >= rlist_alloc) {
7824 rlist_alloc = rlist_alloc * 2 + 64;
7825 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
7826 my_assert_not(rlist, NULL);
7827 }
7828 rlist[rlist_len++] = strdup(words[0]);
7829 }
1cd4a663 7830 skip_func = 0;
bfa4a6ee 7831
7832 fclose(frlist);
7833 frlist = NULL;
7834 }
7835
7836 if (rlist_len > 0)
7837 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
7838
7839 fout = fopen(argv[arg_out], "w");
91977a1c 7840 my_assert_not(fout, NULL);
7841
7842 eq_alloc = 128;
7843 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
7844 my_assert_not(g_eqs, NULL);
7845
4c45fa73 7846 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
7847 g_label_refs[i].i = -1;
7848 g_label_refs[i].next = NULL;
7849 }
7850
5fa1256f 7851 if (g_header_mode)
4c20744d 7852 scan_variables(fasm, rlist, rlist_len);
5fa1256f 7853
7854 while (my_fgets(line, sizeof(line), fasm))
91977a1c 7855 {
4c45fa73 7856 wordc = 0;
91977a1c 7857 asmln++;
7858
7859 p = sskip(line);
1bafb621 7860 if (*p == 0)
91977a1c 7861 continue;
7862
de50b98b 7863 // get rid of random tabs
7864 for (i = 0; line[i] != 0; i++)
7865 if (line[i] == '\t')
7866 line[i] = ' ';
7867
e56ab892 7868 if (*p == ';')
7869 {
e56ab892 7870 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
7871 goto do_pending_endp; // eww..
7872
7873 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
7874 {
7875 static const char *attrs[] = {
7876 "bp-based frame",
7877 "library function",
7878 "static",
7879 "noreturn",
7880 "thunk",
7881 "fpd=",
7882 };
7883
7884 // parse IDA's attribute-list comment
7885 g_ida_func_attr = 0;
7886 p = sskip(p + 13);
7887
7888 for (; *p != 0; p = sskip(p)) {
7889 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
7890 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
7891 g_ida_func_attr |= 1 << i;
7892 p += strlen(attrs[i]);
7893 break;
7894 }
7895 }
7896 if (i == ARRAY_SIZE(attrs)) {
7897 anote("unparsed IDA attr: %s\n", p);
1bafb621 7898 break;
7899 }
e56ab892 7900 if (IS(attrs[i], "fpd=")) {
7901 p = next_word(words[0], sizeof(words[0]), p);
7902 // ignore for now..
7903 }
1bafb621 7904 }
e56ab892 7905 }
7e08c224 7906 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
7907 {
7908 static const char *attrs[] = {
7909 "clear_sf",
7910 };
7911
7912 // parse manual attribute-list comment
7913 g_sct_func_attr = 0;
7914 p = sskip(p + 10);
7915
7916 for (; *p != 0; p = sskip(p)) {
7917 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
7918 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
7919 g_sct_func_attr |= 1 << i;
7920 p += strlen(attrs[i]);
7921 break;
7922 }
7923 }
7924 if (i == 0 && *p == '=') {
7925 // clear_sf=start,len (in dwords)
7926 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
7927 &g_stack_clear_len, &j);
7928 if (ret < 2) {
7929 anote("unparsed clear_sf attr value: %s\n", p);
7930 break;
7931 }
7932 p += j;
7933 }
7934 else if (i == ARRAY_SIZE(attrs)) {
7935 anote("unparsed sct attr: %s\n", p);
7936 break;
7937 }
7938 }
7939 }
e56ab892 7940 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
7941 {
7942 p += 30;
7943 next_word(words[0], sizeof(words[0]), p);
7944 if (words[0][0] == 0)
cdfaeed7 7945 aerr("missing name for func chunk?\n");
7946
7947 if (!scanned_ahead) {
7948 add_func_chunk(fasm, words[0], asmln);
7949 func_chunks_sorted = 0;
e56ab892 7950 }
e56ab892 7951 }
7952 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
7953 {
7954 if (func_chunk_i >= 0) {
7955 if (func_chunk_i < func_chunk_cnt
7956 && IS(func_chunks[func_chunk_i].name, g_func))
7957 {
7958 // move on to next chunk
7959 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
7960 if (ret)
7961 aerr("seek failed for '%s' chunk #%d\n",
7962 g_func, func_chunk_i);
de50b98b 7963 asmln = func_chunks[func_chunk_i].asmln;
e56ab892 7964 func_chunk_i++;
7965 }
7966 else {
7967 if (func_chunk_ret == 0)
7968 aerr("no return from chunk?\n");
7969 fseek(fasm, func_chunk_ret, SEEK_SET);
de50b98b 7970 asmln = func_chunk_ret_ln;
e56ab892 7971 func_chunk_ret = 0;
7972 pending_endp = 1;
7973 }
1bafb621 7974 }
e56ab892 7975 }
7976 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
7977 func_chunks_used = 1;
7978 p += 20;
7979 if (IS_START(g_func, "sub_")) {
7980 unsigned long addr = strtoul(p, NULL, 16);
7981 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
cdfaeed7 7982 if (addr > f_addr && !scanned_ahead) {
b2bd20c0 7983 //anote("scan_ahead caused by '%s', addr %lx\n",
7984 // g_func, addr);
cdfaeed7 7985 scan_ahead(fasm);
7986 scanned_ahead = 1;
7987 func_chunks_sorted = 0;
7988 }
1bafb621 7989 }
7990 }
7991 continue;
e56ab892 7992 } // *p == ';'
1bafb621 7993
06c5d854 7994parse_words:
a2c1d768 7995 for (i = wordc; i < ARRAY_SIZE(words); i++)
7996 words[i][0] = 0;
cdfaeed7 7997 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
bfa4a6ee 7998 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
91977a1c 7999 if (*p == 0 || *p == ';') {
8000 wordc++;
8001 break;
8002 }
8003 }
a2c1d768 8004 if (*p != 0 && *p != ';')
8005 aerr("too many words\n");
91977a1c 8006
06c5d854 8007 // alow asm patches in comments
ddaf8bd7 8008 if (*p == ';') {
8009 if (IS_START(p, "; sctpatch:")) {
8010 p = sskip(p + 11);
8011 if (*p == 0 || *p == ';')
8012 continue;
8013 goto parse_words; // lame
8014 }
8015 if (IS_START(p, "; sctproto:")) {
8016 sctproto = strdup(p + 11);
8017 }
46b388c2 8018 else if (IS_START(p, "; sctend")) {
8019 end = 1;
8020 if (!pending_endp)
8021 break;
8022 }
06c5d854 8023 }
8024
91977a1c 8025 if (wordc == 0) {
8026 // shouldn't happen
8027 awarn("wordc == 0?\n");
8028 continue;
8029 }
8030
8031 // don't care about this:
8032 if (words[0][0] == '.'
8033 || IS(words[0], "include")
8034 || IS(words[0], "assume") || IS(words[1], "segment")
8035 || IS(words[0], "align"))
8036 {
8037 continue;
8038 }
8039
4c45fa73 8040do_pending_endp:
8041 // do delayed endp processing to collect switch jumptables
8042 if (pending_endp) {
30c8c549 8043 if (in_func && !g_skip_func && !end && wordc >= 2
4c45fa73 8044 && ((words[0][0] == 'd' && words[0][2] == 0)
8045 || (words[1][0] == 'd' && words[1][2] == 0)))
8046 {
8047 i = 1;
8048 if (words[1][0] == 'd' && words[1][2] == 0) {
8049 // label
8050 if (g_func_pd_cnt >= pd_alloc) {
8051 pd_alloc = pd_alloc * 2 + 16;
8052 g_func_pd = realloc(g_func_pd,
8053 sizeof(g_func_pd[0]) * pd_alloc);
8054 my_assert_not(g_func_pd, NULL);
8055 }
8056 pd = &g_func_pd[g_func_pd_cnt];
8057 g_func_pd_cnt++;
8058 memset(pd, 0, sizeof(*pd));
8059 strcpy(pd->label, words[0]);
8060 pd->type = OPT_CONST;
8061 pd->lmod = lmod_from_directive(words[1]);
8062 i = 2;
8063 }
8064 else {
da87ae38 8065 if (pd == NULL) {
8066 if (verbose)
8067 anote("skipping alignment byte?\n");
8068 continue;
8069 }
4c45fa73 8070 lmod = lmod_from_directive(words[0]);
8071 if (lmod != pd->lmod)
8072 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
8073 }
8074
8075 if (pd->count_alloc < pd->count + wordc) {
8076 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
8077 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
8078 my_assert_not(pd->d, NULL);
8079 }
8080 for (; i < wordc; i++) {
8081 if (IS(words[i], "offset")) {
8082 pd->type = OPT_OFFSET;
8083 i++;
8084 }
8085 p = strchr(words[i], ',');
8086 if (p != NULL)
8087 *p = 0;
8088 if (pd->type == OPT_OFFSET)
8089 pd->d[pd->count].u.label = strdup(words[i]);
8090 else
8091 pd->d[pd->count].u.val = parse_number(words[i]);
8092 pd->d[pd->count].bt_i = -1;
8093 pd->count++;
8094 }
8095 continue;
8096 }
8097
30c8c549 8098 if (in_func && !g_skip_func) {
9af2d373 8099 if (g_header_mode)
92d715b6 8100 gen_hdr(g_func, pi);
8101 else
8102 gen_func(fout, g_fhdr, g_func, pi);
8103 }
4c45fa73 8104
8105 pending_endp = 0;
8106 in_func = 0;
8107 g_ida_func_attr = 0;
7e08c224 8108 g_sct_func_attr = 0;
8109 g_stack_clear_start = 0;
8110 g_stack_clear_len = 0;
4c45fa73 8111 skip_warned = 0;
30c8c549 8112 g_skip_func = 0;
4c45fa73 8113 g_func[0] = 0;
e56ab892 8114 func_chunks_used = 0;
8115 func_chunk_i = -1;
4c45fa73 8116 if (pi != 0) {
8117 memset(&ops, 0, pi * sizeof(ops[0]));
d7857c3a 8118 clear_labels(pi);
4c45fa73 8119 pi = 0;
8120 }
8121 g_eqcnt = 0;
8122 for (i = 0; i < g_func_pd_cnt; i++) {
8123 pd = &g_func_pd[i];
8124 if (pd->type == OPT_OFFSET) {
8125 for (j = 0; j < pd->count; j++)
8126 free(pd->d[j].u.label);
8127 }
8128 free(pd->d);
8129 pd->d = NULL;
8130 }
8131 g_func_pd_cnt = 0;
d4a985bd 8132 g_func_lmods = 0;
4c45fa73 8133 pd = NULL;
46b388c2 8134
8135 if (end)
8136 break;
4c45fa73 8137 if (wordc == 0)
8138 continue;
8139 }
8140
91977a1c 8141 if (IS(words[1], "proc")) {
8142 if (in_func)
8143 aerr("proc '%s' while in_func '%s'?\n",
8144 words[0], g_func);
bfa4a6ee 8145 p = words[0];
ddaf8bd7 8146 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
30c8c549 8147 g_skip_func = 1;
91977a1c 8148 strcpy(g_func, words[0]);
d4e3b5db 8149 set_label(0, words[0]);
91977a1c 8150 in_func = 1;
8151 continue;
8152 }
8153
e56ab892 8154 if (IS(words[1], "endp"))
8155 {
91977a1c 8156 if (!in_func)
8157 aerr("endp '%s' while not in_func?\n", words[0]);
8158 if (!IS(g_func, words[0]))
8159 aerr("endp '%s' while in_func '%s'?\n",
8160 words[0], g_func);
bfa4a6ee 8161
ddaf8bd7 8162 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
8163 && ops[0].op == OP_JMP && ops[0].operand[0].had_ds)
8164 {
8165 // import jump
30c8c549 8166 g_skip_func = 1;
ddaf8bd7 8167 }
8168
30c8c549 8169 if (!g_skip_func && func_chunks_used) {
e56ab892 8170 // start processing chunks
8171 struct chunk_item *ci, key = { g_func, 0 };
8172
8173 func_chunk_ret = ftell(fasm);
de50b98b 8174 func_chunk_ret_ln = asmln;
e56ab892 8175 if (!func_chunks_sorted) {
8176 qsort(func_chunks, func_chunk_cnt,
8177 sizeof(func_chunks[0]), cmp_chunks);
8178 func_chunks_sorted = 1;
8179 }
8180 ci = bsearch(&key, func_chunks, func_chunk_cnt,
8181 sizeof(func_chunks[0]), cmp_chunks);
8182 if (ci == NULL)
8183 aerr("'%s' needs chunks, but none found\n", g_func);
8184 func_chunk_i = ci - func_chunks;
8185 for (; func_chunk_i > 0; func_chunk_i--)
8186 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
8187 break;
8188
8189 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
8190 if (ret)
8191 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
de50b98b 8192 asmln = func_chunks[func_chunk_i].asmln;
e56ab892 8193 func_chunk_i++;
8194 continue;
8195 }
4c45fa73 8196 pending_endp = 1;
91977a1c 8197 continue;
8198 }
8199
1f84f6b3 8200 if (wordc == 2 && IS(words[1], "ends")) {
46b388c2 8201 if (!multi_seg) {
8202 end = 1;
8203 if (pending_endp)
8204 goto do_pending_endp;
1f84f6b3 8205 break;
46b388c2 8206 }
1f84f6b3 8207
8208 // scan for next text segment
5fa1256f 8209 while (my_fgets(line, sizeof(line), fasm)) {
1f84f6b3 8210 asmln++;
8211 p = sskip(line);
8212 if (*p == 0 || *p == ';')
8213 continue;
8214
8215 if (strstr(p, "segment para public 'CODE' use32"))
8216 break;
8217 }
8218
8219 continue;
8220 }
a2c1d768 8221
bfa4a6ee 8222 p = strchr(words[0], ':');
8223 if (p != NULL) {
d4e3b5db 8224 set_label(pi, words[0]);
bfa4a6ee 8225 continue;
8226 }
8227
30c8c549 8228 if (!in_func || g_skip_func) {
8229 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
bfa4a6ee 8230 if (verbose)
8231 anote("skipping from '%s'\n", g_labels[pi]);
8232 skip_warned = 1;
8233 }
d7857c3a 8234 free(g_labels[pi]);
8235 g_labels[pi] = NULL;
bfa4a6ee 8236 continue;
8237 }
8238
ddaf8bd7 8239 if (wordc > 1 && IS(words[1], "="))
8240 {
91977a1c 8241 if (wordc != 5)
8242 aerr("unhandled equ, wc=%d\n", wordc);
8243 if (g_eqcnt >= eq_alloc) {
8244 eq_alloc *= 2;
8245 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
8246 my_assert_not(g_eqs, NULL);
8247 }
8248
8249 len = strlen(words[0]);
8250 if (len > sizeof(g_eqs[0].name) - 1)
8251 aerr("equ name too long: %d\n", len);
8252 strcpy(g_eqs[g_eqcnt].name, words[0]);
8253
8254 if (!IS(words[3], "ptr"))
8255 aerr("unhandled equ\n");
8256 if (IS(words[2], "dword"))
8257 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
8258 else if (IS(words[2], "word"))
8259 g_eqs[g_eqcnt].lmod = OPLM_WORD;
8260 else if (IS(words[2], "byte"))
8261 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
90307a99 8262 else if (IS(words[2], "qword"))
8263 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
91977a1c 8264 else
8265 aerr("bad lmod: '%s'\n", words[2]);
8266
8267 g_eqs[g_eqcnt].offset = parse_number(words[4]);
8268 g_eqcnt++;
8269 continue;
8270 }
8271
8272 if (pi >= ARRAY_SIZE(ops))
8273 aerr("too many ops\n");
8274
91977a1c 8275 parse_op(&ops[pi], words, wordc);
ddaf8bd7 8276
865f1aca 8277 ops[pi].datap = sctproto;
8278 sctproto = NULL;
91977a1c 8279 pi++;
91977a1c 8280 }
8281
9af2d373 8282 if (g_header_mode)
92d715b6 8283 output_hdr(fout);
8284
91977a1c 8285 fclose(fout);
8286 fclose(fasm);
06c5d854 8287 fclose(g_fhdr);
91977a1c 8288
8289 return 0;
c36e914d 8290}
91977a1c 8291
8292// vim:ts=2:shiftwidth=2:expandtab