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