translate: more float
[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 }
5f70a34f 7300 else if (tmp_op->p_argpass != 0) {
7301 fprintf(fout, "a%d", tmp_op->p_argpass);
7302 }
8c83cc48 7303 else if (pp->arg[arg].is_saved) {
7304 ferr_assert(po, tmp_op->p_argnum > 0);
3a5101d7 7305 fprintf(fout, "%s%s", cast,
7306 saved_arg_name(buf1, sizeof(buf1),
7307 tmp_op->p_arggrp, tmp_op->p_argnum));
2fe80fdb 7308 }
7309 else {
7310 fprintf(fout, "%s",
7311 out_src_opr(buf1, sizeof(buf1),
7312 tmp_op, &tmp_op->operand[0], cast, 0));
7313 }
69a3cdfc 7314 }
91977a1c 7315 }
7316 fprintf(fout, ");");
87bf6cec 7317
2b43685d 7318 if (strstr(pp->ret_type.name, "int64")) {
7319 fprintf(fout, "\n");
092f64e1 7320 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7321 fprintf(fout, "%seax = tmp64;", buf3);
2b43685d 7322 }
7323
89ff3147 7324 if (pp->is_unresolved) {
8eb12e72 7325 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
89ff3147 7326 pp->argc_reg);
092f64e1 7327 strcat(g_comment, buf2);
89ff3147 7328 }
7329
87bf6cec 7330 if (po->flags & OPF_TAIL) {
840257f6 7331 ret = 0;
ddaf8bd7 7332 if (i == opcnt - 1 || pp->is_noreturn)
840257f6 7333 ret = 0;
7334 else if (IS(pp->ret_type.name, "void"))
7335 ret = 1;
b2bd20c0 7336 else if (!(regmask_ret & (1 << xAX)))
840257f6 7337 ret = 1;
7338 // else already handled as 'return f()'
7339
7340 if (ret) {
acd03176 7341 fprintf(fout, "\n%sreturn;", buf3);
7342 strcat(g_comment, " ^ tailcall");
3ebea2cf 7343 }
89ff3147 7344 else
ddaf8bd7 7345 strcat(g_comment, " tailcall");
acd03176 7346
7347 if ((regmask_ret & (1 << xAX))
7348 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7349 {
7350 ferr(po, "int func -> void func tailcall?\n");
7351 }
87bf6cec 7352 }
ddaf8bd7 7353 if (pp->is_noreturn)
7354 strcat(g_comment, " noreturn");
2fe80fdb 7355 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7356 strcat(g_comment, " argframe");
092f64e1 7357 if (po->flags & OPF_CC)
7358 strcat(g_comment, " cond");
7359
7360 if (po->flags & OPF_CC)
7361 fprintf(fout, "\n }");
7362
87bf6cec 7363 delayed_flag_op = NULL;
7364 last_arith_dst = NULL;
91977a1c 7365 break;
7366
7367 case OP_RET:
bd96f656 7368 if (g_func_pp->is_vararg)
4f12f671 7369 fprintf(fout, " va_end(ap);\n");
1f84f6b3 7370 if (g_func_pp->has_retreg) {
7371 for (arg = 0; arg < g_func_pp->argc; arg++)
7372 if (g_func_pp->arg[arg].type.is_retreg)
7373 fprintf(fout, " *r_%s = %s;\n",
7374 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7375 }
4f12f671 7376
16057ce1 7377 if (regmask_ret & mxST0) {
7378 fprintf(fout, " return %s;", float_st0);
7379 }
7380 else if (!(regmask_ret & mxAX)) {
3ebea2cf 7381 if (i != opcnt - 1 || label_pending)
7382 fprintf(fout, " return;");
7383 }
bd96f656 7384 else if (g_func_pp->ret_type.is_ptr) {
d4e3b5db 7385 fprintf(fout, " return (%s)eax;",
bd96f656 7386 g_func_pp->ret_type.name);
3ebea2cf 7387 }
2fe80fdb 7388 else if (IS(g_func_pp->ret_type.name, "__int64"))
7389 fprintf(fout, " return ((u64)edx << 32) | eax;");
91977a1c 7390 else
7391 fprintf(fout, " return eax;");
de50b98b 7392
7393 last_arith_dst = NULL;
7394 delayed_flag_op = NULL;
91977a1c 7395 break;
7396
7397 case OP_PUSH:
1f84f6b3 7398 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
5f70a34f 7399 if (po->p_argnum != 0) {
69a3cdfc 7400 // special case - saved func arg
3a5101d7 7401 fprintf(fout, " %s = %s;",
7402 saved_arg_name(buf2, sizeof(buf2),
7403 po->p_arggrp, po->p_argnum), buf1);
69a3cdfc 7404 break;
7405 }
d4e3b5db 7406 else if (po->flags & OPF_RSAVE) {
d4e3b5db 7407 fprintf(fout, " s_%s = %s;", buf1, buf1);
7408 break;
7409 }
25a330eb 7410 else if (po->flags & OPF_PPUSH) {
7411 tmp_op = po->datap;
7412 ferr_assert(po, tmp_op != NULL);
7413 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7414 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7415 break;
7416 }
1f84f6b3 7417 else if (g_func_pp->is_userstack) {
7418 fprintf(fout, " *(--esp) = %s;", buf1);
7419 break;
7420 }
e56ab892 7421 if (!(g_ida_func_attr & IDAFA_NORETURN))
7422 ferr(po, "stray push encountered\n");
7423 no_output = 1;
91977a1c 7424 break;
7425
7426 case OP_POP:
25a330eb 7427 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
d4e3b5db 7428 if (po->flags & OPF_RSAVE) {
d4e3b5db 7429 fprintf(fout, " %s = s_%s;", buf1, buf1);
7430 break;
7431 }
25a330eb 7432 else if (po->flags & OPF_PPUSH) {
e83ea7ed 7433 // push/pop graph / non-const
25a330eb 7434 ferr_assert(po, po->datap == NULL);
7435 fprintf(fout, " %s = pp_%s;", buf1, buf1);
7436 break;
7437 }
5c024ef7 7438 else if (po->datap != NULL) {
7439 // push/pop pair
7440 tmp_op = po->datap;
5c024ef7 7441 fprintf(fout, " %s = %s;", buf1,
7442 out_src_opr(buf2, sizeof(buf2),
7443 tmp_op, &tmp_op->operand[0],
c7ed83dd 7444 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
5c024ef7 7445 break;
7446 }
1f84f6b3 7447 else if (g_func_pp->is_userstack) {
25a330eb 7448 fprintf(fout, " %s = *esp++;", buf1);
1f84f6b3 7449 break;
7450 }
7451 else
7452 ferr(po, "stray pop encountered\n");
91977a1c 7453 break;
7454
33c35af6 7455 case OP_NOP:
2b43685d 7456 no_output = 1;
33c35af6 7457 break;
7458
622eb2ef 7459 // pseudo ops
7460 case OPP_ALLSHL:
7461 case OPP_ALLSHR:
7462 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
8c83cc48 7463 fprintf(fout, " tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
622eb2ef 7464 po->op == OPP_ALLSHL ? "<<" : ">>");
7465 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
7466 strcat(g_comment, po->op == OPP_ALLSHL
7467 ? " allshl" : " allshr");
7468 break;
7469
d4a985bd 7470 // x87
7471 case OP_FLD:
fe18df39 7472 if (need_float_stack) {
7473 out_src_opr_float(buf1, sizeof(buf1),
7474 po, &po->operand[0], 1);
7475 if (po->regmask_src & mxSTa) {
7476 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7477 buf1);
7478 }
7479 else
7480 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
7481 }
7482 else {
7483 if (po->flags & OPF_FSHIFT)
7484 fprintf(fout, " f_st1 = f_st0;");
7485 if (po->operand[0].type == OPT_REG
7486 && po->operand[0].reg == xST0)
7487 {
7488 strcat(g_comment, " fld st");
7489 break;
7490 }
7491 fprintf(fout, " f_st0 = %s;",
7492 out_src_opr_float(buf1, sizeof(buf1),
7493 po, &po->operand[0], 0));
d4a985bd 7494 }
d4a985bd 7495 strcat(g_comment, " fld");
7496 break;
7497
7498 case OP_FILD:
fe18df39 7499 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7500 lmod_cast(po, po->operand[0].lmod, 1), 0);
7501 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7502 if (need_float_stack) {
7503 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
7504 }
7505 else {
7506 if (po->flags & OPF_FSHIFT)
7507 fprintf(fout, " f_st1 = f_st0;");
7508 fprintf(fout, " f_st0 = %s;", buf2);
7509 }
d4a985bd 7510 strcat(g_comment, " fild");
7511 break;
7512
7513 case OP_FLDc:
fe18df39 7514 if (need_float_stack)
7515 fprintf(fout, " f_st[--f_stp & 7] = ");
7516 else {
7517 if (po->flags & OPF_FSHIFT)
7518 fprintf(fout, " f_st1 = f_st0;");
7519 fprintf(fout, " f_st0 = ");
7520 }
d4a985bd 7521 switch (po->operand[0].val) {
fe18df39 7522 case X87_CONST_1: fprintf(fout, "1.0;"); break;
7523 case X87_CONST_LN2: fprintf(fout, "0.693147180559945;"); break;
7524 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
d4a985bd 7525 default: ferr(po, "TODO\n"); break;
7526 }
7527 break;
7528
7529 case OP_FST:
30620174 7530 if (po->flags & OPF_FARG) {
7531 // store to stack as func arg
7532 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7533 dead_dst = 0;
7534 }
7535 else {
7536 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7537 need_float_stack);
7538 dead_dst = po->operand[0].type == OPT_REG
7539 && po->operand[0].reg == xST0;
fe18df39 7540 }
30620174 7541 if (!dead_dst)
7542 fprintf(fout, " %s = %s;", buf1, float_st0);
16057ce1 7543 if (po->flags & OPF_FSHIFT) {
7544 if (need_float_stack)
7545 fprintf(fout, " f_stp++;");
7546 else
fe18df39 7547 fprintf(fout, " f_st0 = f_st1;");
d4a985bd 7548 }
fe18df39 7549 if (dead_dst && !(po->flags & OPF_FSHIFT))
7550 no_output = 1;
7551 else
7552 strcat(g_comment, " fst");
d4a985bd 7553 break;
7554
16057ce1 7555 case OP_FIST:
7556 fprintf(fout, " %s = %s%s;",
7557 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7558 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7559 if (po->flags & OPF_FSHIFT) {
7560 if (need_float_stack)
7561 fprintf(fout, " f_stp++;");
7562 else
7563 fprintf(fout, " f_st0 = f_st1;");
7564 }
7565 strcat(g_comment, " fist");
7566 break;
7567
d4a985bd 7568 case OP_FADD:
7569 case OP_FDIV:
7570 case OP_FMUL:
7571 case OP_FSUB:
fe18df39 7572 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7573 need_float_stack);
7574 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7575 need_float_stack);
7576 dead_dst = (po->flags & OPF_FPOP)
7577 && po->operand[0].type == OPT_REG
7578 && po->operand[0].reg == xST0;
d4a985bd 7579 switch (po->op) {
7580 case OP_FADD: j = '+'; break;
7581 case OP_FDIV: j = '/'; break;
7582 case OP_FMUL: j = '*'; break;
7583 case OP_FSUB: j = '-'; break;
7584 default: j = 'x'; break;
7585 }
fe18df39 7586 if (need_float_stack) {
7587 if (!dead_dst)
7588 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7589 if (po->flags & OPF_FSHIFT)
7590 fprintf(fout, " f_stp++;");
d4a985bd 7591 }
7592 else {
fe18df39 7593 if (po->flags & OPF_FSHIFT) {
7594 // note: assumes only 2 regs handled
7595 if (!dead_dst)
7596 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
7597 else
7598 fprintf(fout, " f_st0 = f_st1;");
7599 }
7600 else if (!dead_dst)
7601 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
d4a985bd 7602 }
fe18df39 7603 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
d4a985bd 7604 break;
7605
7606 case OP_FDIVR:
7607 case OP_FSUBR:
fe18df39 7608 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7609 need_float_stack);
7610 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7611 need_float_stack);
7612 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
7613 need_float_stack);
7614 dead_dst = (po->flags & OPF_FPOP)
7615 && po->operand[0].type == OPT_REG
7616 && po->operand[0].reg == xST0;
7617 j = po->op == OP_FDIVR ? '/' : '-';
7618 if (need_float_stack) {
7619 if (!dead_dst)
7620 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7621 if (po->flags & OPF_FSHIFT)
7622 fprintf(fout, " f_stp++;");
7623 }
7624 else {
7625 if (po->flags & OPF_FSHIFT) {
7626 if (!dead_dst)
7627 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
7628 else
7629 fprintf(fout, " f_st0 = f_st1;");
7630 }
7631 else if (!dead_dst)
7632 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7633 }
7634 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
d4a985bd 7635 break;
7636
7637 case OP_FIADD:
7638 case OP_FIDIV:
7639 case OP_FIMUL:
7640 case OP_FISUB:
7641 switch (po->op) {
7642 case OP_FIADD: j = '+'; break;
7643 case OP_FIDIV: j = '/'; break;
7644 case OP_FIMUL: j = '*'; break;
7645 case OP_FISUB: j = '-'; break;
7646 default: j = 'x'; break;
7647 }
fe18df39 7648 fprintf(fout, " %s %c= (%s)%s;", float_st0,
7649 j, float_type,
d4a985bd 7650 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7651 lmod_cast(po, po->operand[0].lmod, 1), 0));
7652 break;
7653
7654 case OP_FIDIVR:
7655 case OP_FISUBR:
fe18df39 7656 fprintf(fout, " %s = %s %c %s;", float_st0,
7657 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7658 need_float_stack),
7659 po->op == OP_FIDIVR ? '/' : '-', float_st0);
7660 break;
7661
16057ce1 7662 case OP_FCOM: {
7663 int mask, z_check;
7664 ferr_assert(po, po->datap != NULL);
7665 mask = (long)po->datap & 0xffff;
7666 z_check = ((long)po->datap >> 16) & 1;
7667 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7668 need_float_stack);
2c31fb4c 7669 if (mask == 0x0100 || mask == 0x0500) { // C0 -> <
16057ce1 7670 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
7671 float_st0, buf1);
7672 }
88eed95d 7673 else if (mask == 0x4000 || mask == 0x4400) { // C3 -> =
16057ce1 7674 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
7675 float_st0, buf1);
7676 }
7677 else if (mask == 0x4100) { // C3, C0
7678 if (z_check) {
7679 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
7680 float_st0, buf1);
7681 strcat(g_comment, " z_chk_det");
7682 }
7683 else {
7684 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
7685 "(%s < %s ? 0x0100 : 0);",
7686 float_st0, buf1, float_st0, buf1);
7687 }
7688 }
7689 else
7690 ferr(po, "unhandled sw mask: %x\n", mask);
7691 if (po->flags & OPF_FSHIFT) {
88eed95d 7692 if (need_float_stack) {
7693 if (po->flags & OPF_FPOPP)
7694 fprintf(fout, " f_stp += 2;");
7695 else
7696 fprintf(fout, " f_stp++;");
7697 }
7698 else {
7699 ferr_assert(po, !(po->flags & OPF_FPOPP));
16057ce1 7700 fprintf(fout, " f_st0 = f_st1;");
88eed95d 7701 }
16057ce1 7702 }
7703 break;
7704 }
7705
7706 case OP_FNSTSW:
7707 fprintf(fout, " %s = f_sw;",
7708 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7709 break;
7710
fe18df39 7711 case OP_FCHS:
7712 fprintf(fout, " %s = -%s;", float_st0, float_st0);
d4a985bd 7713 break;
7714
497a6d6b 7715 case OP_FCOS:
fe18df39 7716 fprintf(fout, " %s = cos%s(%s);", float_st0,
7717 need_double ? "" : "f", float_st0);
497a6d6b 7718 break;
7719
7720 case OP_FPATAN:
fe18df39 7721 if (need_float_stack) {
7722 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
7723 need_double ? "" : "f", float_st1, float_st0);
7724 fprintf(fout, " f_stp++;");
7725 }
7726 else {
7727 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
7728 need_double ? "" : "f");
7729 }
7730 break;
7731
7732 case OP_FYL2X:
7733 if (need_float_stack) {
7734 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
7735 float_st1, need_double ? "" : "f", float_st0);
7736 fprintf(fout, " f_stp++;");
7737 }
7738 else {
7739 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
7740 need_double ? "" : "f");
7741 }
8c83cc48 7742 strcat(g_comment, " fyl2x");
497a6d6b 7743 break;
7744
7745 case OP_FSIN:
fe18df39 7746 fprintf(fout, " %s = sin%s(%s);", float_st0,
7747 need_double ? "" : "f", float_st0);
497a6d6b 7748 break;
7749
7750 case OP_FSQRT:
fe18df39 7751 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
7752 need_double ? "" : "f", float_st0);
7753 break;
7754
7755 case OP_FXCH:
7756 dead_dst = po->operand[0].type == OPT_REG
7757 && po->operand[0].reg == xST0;
7758 if (!dead_dst) {
7759 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7760 need_float_stack);
7761 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
7762 float_st0, float_st0, buf1, buf1);
7763 strcat(g_comment, " fxch");
7764 }
7765 else
7766 no_output = 1;
497a6d6b 7767 break;
7768
d4a985bd 7769 case OPP_FTOL:
7770 ferr_assert(po, po->flags & OPF_32BIT);
fe18df39 7771 fprintf(fout, " eax = (s32)%s;", float_st0);
7772 if (po->flags & OPF_FSHIFT) {
7773 if (need_float_stack)
7774 fprintf(fout, " f_stp++;");
7775 else
7776 fprintf(fout, " f_st0 = f_st1;");
7777 }
d4a985bd 7778 strcat(g_comment, " ftol");
7779 break;
7780
8c83cc48 7781 case OPP_CIPOW:
7782 if (need_float_stack) {
7783 fprintf(fout, " %s = pow%s(%s, %s);", float_st1,
7784 need_double ? "" : "f", float_st1, float_st0);
7785 fprintf(fout, " f_stp++;");
7786 }
7787 else {
7788 fprintf(fout, " f_st0 = pow%s(f_st1, f_st0);",
7789 need_double ? "" : "f");
7790 }
7791 strcat(g_comment, " CIpow");
7792 break;
7793
11437ea1 7794 case OPP_ABORT:
7795 fprintf(fout, " do_skip_code_abort();");
7796 break;
7797
90307a99 7798 // mmx
7799 case OP_EMMS:
11437ea1 7800 fprintf(fout, " do_emms();");
90307a99 7801 break;
7802
91977a1c 7803 default:
7804 no_output = 1;
69a3cdfc 7805 ferr(po, "unhandled op type %d, flags %x\n",
7806 po->op, po->flags);
91977a1c 7807 break;
7808 }
7809
7810 if (g_comment[0] != 0) {
ddaf8bd7 7811 char *p = g_comment;
7812 while (my_isblank(*p))
7813 p++;
7814 fprintf(fout, " // %s", p);
91977a1c 7815 g_comment[0] = 0;
7816 no_output = 0;
7817 }
7818 if (!no_output)
7819 fprintf(fout, "\n");
5101a5f9 7820
2b43685d 7821 // some sanity checking
591721d7 7822 if (po->flags & OPF_REP) {
7823 if (po->op != OP_STOS && po->op != OP_MOVS
7824 && po->op != OP_CMPS && po->op != OP_SCAS)
7825 ferr(po, "unexpected rep\n");
7826 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
7827 && (po->op == OP_CMPS || po->op == OP_SCAS))
7828 ferr(po, "cmps/scas with plain rep\n");
7829 }
7830 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
7831 && po->op != OP_CMPS && po->op != OP_SCAS)
2b43685d 7832 ferr(po, "unexpected repz/repnz\n");
7833
940e8e66 7834 if (pfomask != 0)
7ba45c34 7835 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
940e8e66 7836
5101a5f9 7837 // see is delayed flag stuff is still valid
7838 if (delayed_flag_op != NULL && delayed_flag_op != po) {
89ff3147 7839 if (is_any_opr_modified(delayed_flag_op, po, 0))
5101a5f9 7840 delayed_flag_op = NULL;
7841 }
7842
7843 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
7844 if (is_opr_modified(last_arith_dst, po))
7845 last_arith_dst = NULL;
7846 }
3ebea2cf 7847
2c31fb4c 7848 if (!no_output)
7849 label_pending = 0;
91977a1c 7850 }
7851
a2c1d768 7852 if (g_stack_fsz && !g_stack_frame_used)
7853 fprintf(fout, " (void)sf;\n");
7854
91977a1c 7855 fprintf(fout, "}\n\n");
7856
9af2d373 7857 gen_x_cleanup(opcnt);
7858}
7859
7860static void gen_x_cleanup(int opcnt)
7861{
7862 int i;
7863
91977a1c 7864 for (i = 0; i < opcnt; i++) {
4c45fa73 7865 struct label_ref *lr, *lr_del;
7866
7867 lr = g_label_refs[i].next;
7868 while (lr != NULL) {
7869 lr_del = lr;
7870 lr = lr->next;
7871 free(lr_del);
7872 }
7873 g_label_refs[i].i = -1;
7874 g_label_refs[i].next = NULL;
7875
91977a1c 7876 if (ops[i].op == OP_CALL) {
092f64e1 7877 if (ops[i].pp)
7878 proto_release(ops[i].pp);
91977a1c 7879 }
7880 }
bd96f656 7881 g_func_pp = NULL;
91977a1c 7882}
c36e914d 7883
92d715b6 7884struct func_proto_dep;
7885
7886struct func_prototype {
7887 char name[NAMELEN];
7888 int id;
7889 int argc_stack;
7890 int regmask_dep;
91ca764a 7891 int has_ret:3; // -1, 0, 1: unresolved, no, yes
92d715b6 7892 unsigned int dep_resolved:1;
7893 unsigned int is_stdcall:1;
7894 struct func_proto_dep *dep_func;
7895 int dep_func_cnt;
91ca764a 7896 const struct parsed_proto *pp; // seed pp, if any
92d715b6 7897};
7898
7899struct func_proto_dep {
7900 char *name;
7901 struct func_prototype *proto;
7902 int regmask_live; // .. at the time of call
7903 unsigned int ret_dep:1; // return from this is caller's return
7904};
7905
7906static struct func_prototype *hg_fp;
7907static int hg_fp_cnt;
7908
5fa1256f 7909static struct scanned_var {
7910 char name[NAMELEN];
7911 enum opr_lenmod lmod;
7912 unsigned int is_seeded:1;
61e29183 7913 unsigned int is_c_str:1;
c0de9015 7914 const struct parsed_proto *pp; // seed pp, if any
5fa1256f 7915} *hg_vars;
7916static int hg_var_cnt;
7917
8c999988 7918static char **hg_refs;
7919static int hg_ref_cnt;
7920
9af2d373 7921static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7922 int count);
7923
8c999988 7924static struct func_prototype *hg_fp_add(const char *funcn)
ebc4dc43 7925{
7926 struct func_prototype *fp;
7927
7928 if ((hg_fp_cnt & 0xff) == 0) {
7929 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
7930 my_assert_not(hg_fp, NULL);
7931 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
7932 }
7933
7934 fp = &hg_fp[hg_fp_cnt];
7935 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
7936 fp->id = hg_fp_cnt;
7937 fp->argc_stack = -1;
7938 hg_fp_cnt++;
7939
7940 return fp;
7941}
7942
92d715b6 7943static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
7944 const char *name)
7945{
7946 int i;
7947
7948 for (i = 0; i < fp->dep_func_cnt; i++)
7949 if (IS(fp->dep_func[i].name, name))
7950 return &fp->dep_func[i];
7951
7952 return NULL;
7953}
7954
7955static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
7956{
7957 // is it a dupe?
7958 if (hg_fp_find_dep(fp, name))
7959 return;
7960
7961 if ((fp->dep_func_cnt & 0xff) == 0) {
7962 fp->dep_func = realloc(fp->dep_func,
7963 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
7964 my_assert_not(fp->dep_func, NULL);
7965 memset(&fp->dep_func[fp->dep_func_cnt], 0,
7966 sizeof(fp->dep_func[0]) * 0x100);
7967 }
7968 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
7969 fp->dep_func_cnt++;
7970}
7971
7972static int hg_fp_cmp_name(const void *p1_, const void *p2_)
7973{
7974 const struct func_prototype *p1 = p1_, *p2 = p2_;
7975 return strcmp(p1->name, p2->name);
7976}
7977
7978#if 0
7979static int hg_fp_cmp_id(const void *p1_, const void *p2_)
7980{
7981 const struct func_prototype *p1 = p1_, *p2 = p2_;
7982 return p1->id - p2->id;
7983}
7984#endif
7985
8c999988 7986static void hg_ref_add(const char *name)
7987{
7988 if ((hg_ref_cnt & 0xff) == 0) {
7989 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
7990 my_assert_not(hg_refs, NULL);
7991 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
7992 }
7993
7994 hg_refs[hg_ref_cnt] = strdup(name);
7995 my_assert_not(hg_refs[hg_ref_cnt], NULL);
7996 hg_ref_cnt++;
7997}
7998
91ca764a 7999// recursive register dep pass
8000// - track saved regs (part 2)
8001// - try to figure out arg-regs
8002// - calculate reg deps
8003static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
8004 struct func_prototype *fp, int regmask_save, int regmask_dst,
8005 int *regmask_dep, int *has_ret)
8006{
8007 struct func_proto_dep *dep;
8008 struct parsed_op *po;
8009 int from_caller = 0;
91ca764a 8010 int j, l;
8011 int reg;
8012 int ret;
8013
8014 for (; i < opcnt; i++)
8015 {
8016 if (cbits[i >> 3] & (1 << (i & 7)))
8017 return;
8018 cbits[i >> 3] |= (1 << (i & 7));
8019
8020 po = &ops[i];
8021
8022 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
04abc5d6 8023 if (po->flags & OPF_RMD)
8024 continue;
8025
91ca764a 8026 if (po->btj != NULL) {
8027 // jumptable
8028 for (j = 0; j < po->btj->count; j++) {
db63af51 8029 check_i(po, po->btj->d[j].bt_i);
91ca764a 8030 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
8031 regmask_save, regmask_dst, regmask_dep, has_ret);
8032 }
8033 return;
8034 }
8035
db63af51 8036 check_i(po, po->bt_i);
91ca764a 8037 if (po->flags & OPF_CJMP) {
8038 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
8039 regmask_save, regmask_dst, regmask_dep, has_ret);
8040 }
8041 else {
8042 i = po->bt_i - 1;
8043 }
8044 continue;
8045 }
8046
8047 if (po->flags & OPF_FARG)
8048 /* (just calculate register deps) */;
8049 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
8050 {
8051 reg = po->operand[0].reg;
b2bd20c0 8052 ferr_assert(po, reg >= 0);
91ca764a 8053
8054 if (po->flags & OPF_RSAVE) {
8055 regmask_save |= 1 << reg;
8056 continue;
8057 }
8058 if (po->flags & OPF_DONE)
8059 continue;
8060
93b5bd18 8061 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0, 0);
91ca764a 8062 if (ret == 1) {
8063 regmask_save |= 1 << reg;
8064 po->flags |= OPF_RMD;
93b5bd18 8065 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, OPF_RMD);
91ca764a 8066 continue;
8067 }
8068 }
8069 else if (po->flags & OPF_RMD)
8070 continue;
8071 else if (po->op == OP_CALL) {
8072 po->regmask_dst |= 1 << xAX;
8073
8074 dep = hg_fp_find_dep(fp, po->operand[0].name);
e627c4d0 8075 if (dep != NULL) {
91ca764a 8076 dep->regmask_live = regmask_save | regmask_dst;
e627c4d0 8077 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8078 dep->regmask_live |= 1 << xBP;
8079 }
91ca764a 8080 }
8081 else if (po->op == OP_RET) {
8082 if (po->operand_cnt > 0) {
8083 fp->is_stdcall = 1;
8084 if (fp->argc_stack >= 0
8085 && fp->argc_stack != po->operand[0].val / 4)
8086 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
8087 fp->argc_stack = po->operand[0].val / 4;
8088 }
8089 }
8090
ebc4dc43 8091 // if has_ret is 0, there is uninitialized eax path,
8092 // which means it's most likely void func
91ca764a 8093 if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
8094 if (po->op == OP_CALL) {
8095 j = i;
8096 ret = 1;
8097 }
8098 else {
b2bd20c0 8099 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
91ca764a 8100 j = -1;
8101 from_caller = 0;
8102 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
8103 }
8104
ebc4dc43 8105 if (ret != 1 && from_caller) {
91ca764a 8106 // unresolved eax - probably void func
8107 *has_ret = 0;
8108 }
8109 else {
ebc4dc43 8110 if (j >= 0 && ops[j].op == OP_CALL) {
8111 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
91ca764a 8112 if (dep != NULL)
8113 dep->ret_dep = 1;
8114 else
8115 *has_ret = 1;
8116 }
8117 else
8118 *has_ret = 1;
8119 }
8120 }
8121
8122 l = regmask_save | regmask_dst;
8123 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8124 l |= 1 << xBP;
8125
8126 l = po->regmask_src & ~l;
8127#if 0
8128 if (l)
8129 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
8130 l, regmask_dst, regmask_save, po->flags);
8131#endif
8132 *regmask_dep |= l;
8133 regmask_dst |= po->regmask_dst;
8134
8135 if (po->flags & OPF_TAIL)
8136 return;
8137 }
8138}
8139
92d715b6 8140static void gen_hdr(const char *funcn, int opcnt)
8141{
91ca764a 8142 unsigned char cbits[MAX_OPS / 8];
ebc4dc43 8143 const struct parsed_proto *pp_c;
9af2d373 8144 struct parsed_proto *pp;
92d715b6 8145 struct func_prototype *fp;
92d715b6 8146 struct parsed_op *po;
26677139 8147 int regmask_dummy = 0;
91ca764a 8148 int regmask_dep;
92d715b6 8149 int max_bp_offset = 0;
91ca764a 8150 int has_ret;
bfacdc83 8151 int i, j, l;
8152 int ret;
92d715b6 8153
ebc4dc43 8154 pp_c = proto_parse(g_fhdr, funcn, 1);
8155 if (pp_c != NULL)
8156 // already in seed, will add to hg_fp later
9af2d373 8157 return;
ebc4dc43 8158
8159 fp = hg_fp_add(funcn);
9af2d373 8160
8161 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
8162 g_stack_frame_used = 0;
ba93cc12 8163 g_seh_size = 0;
9af2d373 8164
92d715b6 8165 // pass1:
66bdb2b0 8166 // - resolve all branches
8167 // - parse calls with labels
8168 resolve_branches_parse_calls(opcnt);
8169
8170 // pass2:
9af2d373 8171 // - handle ebp/esp frame, remove ops related to it
f9327ad4 8172 scan_prologue_epilogue(opcnt, NULL);
9af2d373 8173
66bdb2b0 8174 // pass3:
8175 // - remove dead labels
92d715b6 8176 // - collect calls
92d715b6 8177 for (i = 0; i < opcnt; i++)
8178 {
66bdb2b0 8179 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8180 free(g_labels[i]);
8181 g_labels[i] = NULL;
8182 }
92d715b6 8183
66bdb2b0 8184 po = &ops[i];
5e49b270 8185 if (po->flags & (OPF_RMD|OPF_DONE))
92d715b6 8186 continue;
8187
8188 if (po->op == OP_CALL) {
66bdb2b0 8189 if (po->operand[0].type == OPT_LABEL)
8190 hg_fp_add_dep(fp, opr_name(po, 0));
8191 else if (po->pp != NULL)
8192 hg_fp_add_dep(fp, po->pp->name);
92d715b6 8193 }
92d715b6 8194 }
8195
66bdb2b0 8196 // pass4:
92d715b6 8197 // - remove dead labels
9af2d373 8198 // - handle push <const>/pop pairs
92d715b6 8199 for (i = 0; i < opcnt; i++)
8200 {
d7857c3a 8201 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8202 free(g_labels[i]);
8203 g_labels[i] = NULL;
8204 }
9af2d373 8205
91ca764a 8206 po = &ops[i];
8207 if (po->flags & (OPF_RMD|OPF_DONE))
8208 continue;
8209
8210 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
e83ea7ed 8211 scan_for_pop_const(i, opcnt, i + opcnt * 13);
91ca764a 8212 }
8213
66bdb2b0 8214 // pass5:
91ca764a 8215 // - process trivial calls
8216 for (i = 0; i < opcnt; i++)
8217 {
9af2d373 8218 po = &ops[i];
5e49b270 8219 if (po->flags & (OPF_RMD|OPF_DONE))
9af2d373 8220 continue;
8221
26677139 8222 if (po->op == OP_CALL)
8223 {
8224 pp = process_call_early(i, opcnt, &j);
8225 if (pp != NULL) {
8226 if (!(po->flags & OPF_ATAIL))
8227 // since we know the args, try to collect them
30620174 8228 if (collect_call_args_early(i, pp, NULL, NULL) != 0)
26677139 8229 pp = NULL;
8230 }
8231
8232 if (pp != NULL) {
8233 if (j >= 0) {
8234 // commit esp adjust
5e49b270 8235 if (ops[j].op != OP_POP)
8236 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
bfacdc83 8237 else {
8238 for (l = 0; l < pp->argc_stack; l++)
b2bd20c0 8239 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
bfacdc83 8240 }
26677139 8241 }
8242
8243 po->flags |= OPF_DONE;
8244 }
8245 }
26677139 8246 }
8247
66bdb2b0 8248 // pass6:
5e49b270 8249 // - track saved regs (simple)
26677139 8250 // - process calls
8251 for (i = 0; i < opcnt; i++)
8252 {
8253 po = &ops[i];
5e49b270 8254 if (po->flags & (OPF_RMD|OPF_DONE))
26677139 8255 continue;
8256
e83ea7ed 8257 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
8258 && po->operand[0].reg != xCX)
5e49b270 8259 {
e83ea7ed 8260 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
b2bd20c0 8261 if (ret == 1) {
91ca764a 8262 // regmask_save |= 1 << po->operand[0].reg; // do it later
8263 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
e83ea7ed 8264 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
5e49b270 8265 }
8266 }
e83ea7ed 8267 else if (po->op == OP_CALL)
26677139 8268 {
9af2d373 8269 pp = process_call(i, opcnt);
8270
8271 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
9af2d373 8272 // since we know the args, collect them
8c83cc48 8273 ret = collect_call_args(po, i, pp, &regmask_dummy,
8274 i + opcnt * 1);
9af2d373 8275 }
8276 }
92d715b6 8277 }
8278
66bdb2b0 8279 // pass7
91ca764a 8280 memset(cbits, 0, sizeof(cbits));
8281 regmask_dep = 0;
8282 has_ret = -1;
8283
8284 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, &regmask_dep, &has_ret);
8285
8286 // find unreachable code - must be fixed in IDA
92d715b6 8287 for (i = 0; i < opcnt; i++)
8288 {
91ca764a 8289 if (cbits[i >> 3] & (1 << (i & 7)))
9af2d373 8290 continue;
92d715b6 8291
04abc5d6 8292 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
8293 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
8294 {
8295 // the compiler sometimes still generates code after
8296 // noreturn OS functions
8297 break;
8298 }
ea43585b 8299 if (ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
91ca764a 8300 ferr(&ops[i], "unreachable code\n");
92d715b6 8301 }
8302
9af2d373 8303 for (i = 0; i < g_eqcnt; i++) {
92d715b6 8304 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
8305 max_bp_offset = g_eqs[i].offset;
9af2d373 8306 }
92d715b6 8307
9af2d373 8308 if (fp->argc_stack < 0) {
92d715b6 8309 max_bp_offset = (max_bp_offset + 3) & ~3;
9af2d373 8310 fp->argc_stack = max_bp_offset / 4;
8311 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
92d715b6 8312 fp->argc_stack--;
8313 }
8314
622eb2ef 8315 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
92d715b6 8316 fp->has_ret = has_ret;
91ca764a 8317#if 0
8318 printf("// has_ret %d, regmask_dep %x\n",
8319 fp->has_ret, fp->regmask_dep);
8320 output_hdr_fp(stdout, fp, 1);
ebc4dc43 8321 if (IS(funcn, "sub_10007F72")) exit(1);
91ca764a 8322#endif
9af2d373 8323
8324 gen_x_cleanup(opcnt);
92d715b6 8325}
8326
8327static void hg_fp_resolve_deps(struct func_prototype *fp)
8328{
8329 struct func_prototype fp_s;
91ca764a 8330 int dep;
92d715b6 8331 int i;
8332
8333 // this thing is recursive, so mark first..
8334 fp->dep_resolved = 1;
8335
8336 for (i = 0; i < fp->dep_func_cnt; i++) {
8337 strcpy(fp_s.name, fp->dep_func[i].name);
8338 fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8339 sizeof(hg_fp[0]), hg_fp_cmp_name);
8340 if (fp->dep_func[i].proto != NULL) {
8341 if (!fp->dep_func[i].proto->dep_resolved)
8342 hg_fp_resolve_deps(fp->dep_func[i].proto);
8343
91ca764a 8344 dep = ~fp->dep_func[i].regmask_live
8345 & fp->dep_func[i].proto->regmask_dep;
8346 fp->regmask_dep |= dep;
8347 // printf("dep %s %s |= %x\n", fp->name,
8348 // fp->dep_func[i].name, dep);
92d715b6 8349
ebc4dc43 8350 if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
92d715b6 8351 fp->has_ret = fp->dep_func[i].proto->has_ret;
8352 }
8353 }
8354}
8355
8c999988 8356// make all thiscall/edx arg functions referenced from .data fastcall
8357static void do_func_refs_from_data(void)
8358{
8359 struct func_prototype *fp, fp_s;
8360 int i;
8361
8362 for (i = 0; i < hg_ref_cnt; i++) {
8363 strcpy(fp_s.name, hg_refs[i]);
8364 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8365 sizeof(hg_fp[0]), hg_fp_cmp_name);
8366 if (fp == NULL)
8367 continue;
8368
8369 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
8370 fp->regmask_dep |= mxCX | mxDX;
8371 }
8372}
8373
9af2d373 8374static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8375 int count)
92d715b6 8376{
61e29183 8377 const struct parsed_proto *pp;
8378 char *p, namebuf[NAMELEN];
8379 const char *name;
92d715b6 8380 int regmask_dep;
226e8df1 8381 int argc_normal;
9af2d373 8382 int j, arg;
92d715b6 8383
9af2d373 8384 for (; count > 0; count--, fp++) {
92d715b6 8385 if (fp->has_ret == -1)
8386 fprintf(fout, "// ret unresolved\n");
8387#if 0
8388 fprintf(fout, "// dep:");
8389 for (j = 0; j < fp->dep_func_cnt; j++) {
8390 fprintf(fout, " %s/", fp->dep_func[j].name);
8391 if (fp->dep_func[j].proto != NULL)
8392 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8393 fp->dep_func[j].proto->has_ret);
8394 }
8395 fprintf(fout, "\n");
8396#endif
8397
61e29183 8398 p = strchr(fp->name, '@');
8399 if (p != NULL) {
8400 memcpy(namebuf, fp->name, p - fp->name);
8401 namebuf[p - fp->name] = 0;
8402 name = namebuf;
8403 }
8404 else
8405 name = fp->name;
8406 if (name[0] == '_')
8407 name++;
8408
8409 pp = proto_parse(g_fhdr, name, 1);
8410 if (pp != NULL && pp->is_include)
8411 continue;
8412
c0de9015 8413 if (fp->pp != NULL) {
4e81a3a2 8414 // part of seed, output later
8415 continue;
c0de9015 8416 }
8417
92d715b6 8418 regmask_dep = fp->regmask_dep;
226e8df1 8419 argc_normal = fp->argc_stack;
92d715b6 8420
91ca764a 8421 fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
8422 (fp->has_ret ? "int" : "void"));
226e8df1 8423 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
8424 && (regmask_dep & ~mxCX) == 0)
8425 {
8426 fprintf(fout, "/*__thiscall*/ ");
8427 argc_normal++;
8428 regmask_dep = 0;
8429 }
8430 else if (regmask_dep && (fp->is_stdcall || fp->argc_stack == 0)
8431 && (regmask_dep & ~(mxCX | mxDX)) == 0)
92d715b6 8432 {
9af2d373 8433 fprintf(fout, " __fastcall ");
226e8df1 8434 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8435 argc_normal = 1;
92d715b6 8436 else
226e8df1 8437 argc_normal += 2;
92d715b6 8438 regmask_dep = 0;
8439 }
8440 else if (regmask_dep && !fp->is_stdcall) {
8441 fprintf(fout, "/*__usercall*/ ");
92d715b6 8442 }
8443 else if (regmask_dep) {
8444 fprintf(fout, "/*__userpurge*/ ");
92d715b6 8445 }
8446 else if (fp->is_stdcall)
9af2d373 8447 fprintf(fout, " __stdcall ");
92d715b6 8448 else
9af2d373 8449 fprintf(fout, " __cdecl ");
92d715b6 8450
61e29183 8451 fprintf(fout, "%s(", name);
92d715b6 8452
8453 arg = 0;
8454 for (j = 0; j < xSP; j++) {
8455 if (regmask_dep & (1 << j)) {
8456 arg++;
8457 if (arg != 1)
8458 fprintf(fout, ", ");
91ca764a 8459 if (fp->pp != NULL)
8460 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8461 else
8462 fprintf(fout, "int");
8463 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
92d715b6 8464 }
8465 }
8466
226e8df1 8467 for (j = 0; j < argc_normal; j++) {
92d715b6 8468 arg++;
8469 if (arg != 1)
8470 fprintf(fout, ", ");
91ca764a 8471 if (fp->pp != NULL) {
8472 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8473 if (!fp->pp->arg[arg - 1].type.is_ptr)
8474 fprintf(fout, " ");
8475 }
8476 else
8477 fprintf(fout, "int ");
8478 fprintf(fout, "a%d", arg);
92d715b6 8479 }
8480
8481 fprintf(fout, ");\n");
8482 }
8483}
8484
9af2d373 8485static void output_hdr(FILE *fout)
8486{
5fa1256f 8487 static const char *lmod_c_names[] = {
8488 [OPLM_UNSPEC] = "???",
8489 [OPLM_BYTE] = "uint8_t",
8490 [OPLM_WORD] = "uint16_t",
8491 [OPLM_DWORD] = "uint32_t",
8492 [OPLM_QWORD] = "uint64_t",
8493 };
8494 const struct scanned_var *var;
ebc4dc43 8495 struct func_prototype *fp;
c0de9015 8496 char line[256] = { 0, };
ebc4dc43 8497 char name[256];
9af2d373 8498 int i;
8499
ebc4dc43 8500 // add stuff from headers
8501 for (i = 0; i < pp_cache_size; i++) {
8502 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
8503 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
8504 else
8505 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
8506 fp = hg_fp_add(name);
8507 fp->pp = &pp_cache[i];
8508 fp->argc_stack = fp->pp->argc_stack;
8509 fp->is_stdcall = fp->pp->is_stdcall;
b2bd20c0 8510 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
ebc4dc43 8511 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
8512 }
8513
9af2d373 8514 // resolve deps
8515 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
8516 for (i = 0; i < hg_fp_cnt; i++)
8517 hg_fp_resolve_deps(&hg_fp[i]);
8518
8c999988 8519 // adjust functions referenced from data segment
8520 do_func_refs_from_data();
8521
9af2d373 8522 // note: messes up .proto ptr, don't use
8523 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
8524
5fa1256f 8525 // output variables
8526 for (i = 0; i < hg_var_cnt; i++) {
8527 var = &hg_vars[i];
8528
4e81a3a2 8529 if (var->pp != NULL)
8530 // part of seed
8531 continue;
c0de9015 8532 else if (var->is_c_str)
61e29183 8533 fprintf(fout, "extern %-8s %s[];", "char", var->name);
8534 else
8535 fprintf(fout, "extern %-8s %s;",
8536 lmod_c_names[var->lmod], var->name);
5fa1256f 8537
8538 if (var->is_seeded)
8539 fprintf(fout, " // seeded");
8540 fprintf(fout, "\n");
8541 }
8542
8543 fprintf(fout, "\n");
8544
8545 // output function prototypes
9af2d373 8546 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
c0de9015 8547
4e81a3a2 8548 // seed passthrough
8549 fprintf(fout, "\n// - seed -\n");
c0de9015 8550
8551 rewind(g_fhdr);
4e81a3a2 8552 while (fgets(line, sizeof(line), g_fhdr))
8553 fwrite(line, 1, strlen(line), fout);
9af2d373 8554}
8555
61e29183 8556// '=' needs special treatment
8557// also ' quote
bfa4a6ee 8558static char *next_word_s(char *w, size_t wsize, char *s)
8559{
61e29183 8560 size_t i;
bfa4a6ee 8561
61e29183 8562 s = sskip(s);
bfa4a6ee 8563
61e29183 8564 i = 0;
8c999988 8565 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
61e29183 8566 w[0] = s[0];
8567 for (i = 1; i < wsize - 1; i++) {
8568 if (s[i] == 0) {
8569 printf("warning: missing closing quote: \"%s\"\n", s);
8570 break;
8571 }
8572 if (s[i] == '\'')
8573 break;
8574 w[i] = s[i];
8575 }
8576 }
bfa4a6ee 8577
61e29183 8578 for (; i < wsize - 1; i++) {
8579 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
8580 break;
8581 w[i] = s[i];
8582 }
8583 w[i] = 0;
8584
8585 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
8586 printf("warning: '%s' truncated\n", w);
bfa4a6ee 8587
61e29183 8588 return s + i;
bfa4a6ee 8589}
8590
4c20744d 8591static int cmpstringp(const void *p1, const void *p2)
8592{
8593 return strcmp(*(char * const *)p1, *(char * const *)p2);
8594}
8595
8596static int is_xref_needed(char *p, char **rlist, int rlist_len)
8597{
8598 char *p2;
8599
8600 p = sskip(p);
8601 if (strstr(p, "..."))
8602 // unable to determine, assume needed
8603 return 1;
8604
8605 if (*p == '.') // .text, .data, ...
8606 // ref from other data or non-function -> no
8607 return 0;
8608
8609 p2 = strpbrk(p, "+:\r\n\x18");
8610 if (p2 != NULL)
8611 *p2 = 0;
8612 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8613 // referenced from removed code
8614 return 0;
8615
8616 return 1;
8617}
8618
8c999988 8619static int ida_xrefs_show_need(FILE *fasm, char *p,
4c20744d 8620 char **rlist, int rlist_len)
8621{
8622 int found_need = 0;
8623 char line[256];
8624 long pos;
8625
8626 p = strrchr(p, ';');
ea43585b 8627 if (p != NULL && *p == ';') {
8628 if (IS_START(p + 2, "sctref"))
4c20744d 8629 return 1;
ea43585b 8630 if (IS_START(p + 2, "DATA XREF: ")) {
8631 p += 13;
8632 if (is_xref_needed(p, rlist, rlist_len))
8633 return 1;
8634 }
4c20744d 8635 }
8636
8637 pos = ftell(fasm);
8638 while (1)
8639 {
8640 if (!my_fgets(line, sizeof(line), fasm))
8641 break;
8642 // non-first line is always indented
8643 if (!my_isblank(line[0]))
8644 break;
8645
8646 // should be no content, just comment
8647 p = sskip(line);
8648 if (*p != ';')
8649 break;
8650
8651 p = strrchr(p, ';');
8652 p += 2;
ea43585b 8653
8654 if (IS_START(p, "sctref")) {
8655 found_need = 1;
8656 break;
8657 }
8658
4c20744d 8659 // it's printed once, but no harm to check again
8660 if (IS_START(p, "DATA XREF: "))
8661 p += 11;
8662
8663 if (is_xref_needed(p, rlist, rlist_len)) {
8664 found_need = 1;
8665 break;
8666 }
8667 }
8668 fseek(fasm, pos, SEEK_SET);
8669 return found_need;
8670}
8671
8672static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
5fa1256f 8673{
5fa1256f 8674 struct scanned_var *var;
8675 char line[256] = { 0, };
8c999988 8676 char words[4][256];
8677 int no_identifier;
5fa1256f 8678 char *p = NULL;
8679 int wordc;
61e29183 8680 int l;
5fa1256f 8681
8682 while (!feof(fasm))
8683 {
8684 // skip to next data section
8685 while (my_fgets(line, sizeof(line), fasm))
8686 {
8687 asmln++;
8688
8689 p = sskip(line);
8690 if (*p == 0 || *p == ';')
8691 continue;
8692
8693 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
8694 if (*p == 0 || *p == ';')
8695 continue;
8696
8697 if (*p != 's' || !IS_START(p, "segment para public"))
8698 continue;
8699
8700 break;
8701 }
8702
8703 if (p == NULL || !IS_START(p, "segment para public"))
8704 break;
8705 p = sskip(p + 19);
8706
8707 if (!IS_START(p, "'DATA'"))
8708 continue;
8709
8710 // now process it
8711 while (my_fgets(line, sizeof(line), fasm))
8712 {
8713 asmln++;
8714
8715 p = line;
8c999988 8716 no_identifier = my_isblank(*p);
5fa1256f 8717
8718 p = sskip(p);
8719 if (*p == 0 || *p == ';')
8720 continue;
8721
8722 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8723 words[wordc][0] = 0;
8724 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8725 if (*p == 0 || *p == ';') {
8726 wordc++;
8727 break;
8728 }
8729 }
8730
8731 if (wordc == 2 && IS(words[1], "ends"))
8732 break;
61e29183 8733 if (wordc < 2)
8734 continue;
5fa1256f 8735
8c999988 8736 if (no_identifier) {
8737 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
8738 hg_ref_add(words[2]);
8739 continue;
8740 }
8741
9ea60b8d 8742 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
8743 // when this starts, we don't need anything from this section
8744 break;
8745 }
8746
4c20744d 8747 // check refs comment(s)
8c999988 8748 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
4c20744d 8749 continue;
8750
5fa1256f 8751 if ((hg_var_cnt & 0xff) == 0) {
8752 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
8753 * (hg_var_cnt + 0x100));
8754 my_assert_not(hg_vars, NULL);
8755 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
8756 }
8757
8758 var = &hg_vars[hg_var_cnt++];
8759 snprintf(var->name, sizeof(var->name), "%s", words[0]);
8760
8761 // maybe already in seed header?
c0de9015 8762 var->pp = proto_parse(g_fhdr, var->name, 1);
8763 if (var->pp != NULL) {
8764 if (var->pp->is_fptr) {
5fa1256f 8765 var->lmod = OPLM_DWORD;
8766 //var->is_ptr = 1;
8767 }
c0de9015 8768 else if (var->pp->is_func)
8769 aerr("func?\n");
8770 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
5fa1256f 8771 aerr("unhandled C type '%s' for '%s'\n",
c0de9015 8772 var->pp->type.name, var->name);
5fa1256f 8773
8774 var->is_seeded = 1;
8775 continue;
8776 }
8777
8c999988 8778 if (IS(words[1], "dd")) {
5fa1256f 8779 var->lmod = OPLM_DWORD;
8c999988 8780 if (wordc >= 4 && IS(words[2], "offset"))
8781 hg_ref_add(words[3]);
8782 }
5fa1256f 8783 else if (IS(words[1], "dw"))
8784 var->lmod = OPLM_WORD;
61e29183 8785 else if (IS(words[1], "db")) {
5fa1256f 8786 var->lmod = OPLM_BYTE;
61e29183 8787 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
8788 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
8789 var->is_c_str = 1;
8790 }
8791 }
5fa1256f 8792 else if (IS(words[1], "dq"))
8793 var->lmod = OPLM_QWORD;
8794 //else if (IS(words[1], "dt"))
8795 else
8796 aerr("type '%s' not known\n", words[1]);
8797 }
8798 }
8799
8800 rewind(fasm);
8801 asmln = 0;
8802}
8803
8804static void set_label(int i, const char *name)
8805{
8806 const char *p;
8807 int len;
8808
8809 len = strlen(name);
8810 p = strchr(name, ':');
8811 if (p != NULL)
8812 len = p - name;
8813
8814 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
8815 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
8816 g_labels[i] = realloc(g_labels[i], len + 1);
8817 my_assert_not(g_labels[i], NULL);
8818 memcpy(g_labels[i], name, len);
8819 g_labels[i][len] = 0;
8820}
8821
e56ab892 8822struct chunk_item {
8823 char *name;
8824 long fptr;
de50b98b 8825 int asmln;
e56ab892 8826};
8827
cdfaeed7 8828static struct chunk_item *func_chunks;
8829static int func_chunk_cnt;
8830static int func_chunk_alloc;
8831
8832static void add_func_chunk(FILE *fasm, const char *name, int line)
8833{
8834 if (func_chunk_cnt >= func_chunk_alloc) {
8835 func_chunk_alloc *= 2;
8836 func_chunks = realloc(func_chunks,
8837 func_chunk_alloc * sizeof(func_chunks[0]));
8838 my_assert_not(func_chunks, NULL);
8839 }
8840 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
8841 func_chunks[func_chunk_cnt].name = strdup(name);
8842 func_chunks[func_chunk_cnt].asmln = line;
8843 func_chunk_cnt++;
8844}
8845
e56ab892 8846static int cmp_chunks(const void *p1, const void *p2)
8847{
8848 const struct chunk_item *c1 = p1, *c2 = p2;
8849 return strcmp(c1->name, c2->name);
8850}
8851
ea43585b 8852static void scan_ahead_for_chunks(FILE *fasm)
cdfaeed7 8853{
8854 char words[2][256];
8855 char line[256];
8856 long oldpos;
8857 int oldasmln;
8858 int wordc;
8859 char *p;
8860 int i;
8861
8862 oldpos = ftell(fasm);
8863 oldasmln = asmln;
8864
5fa1256f 8865 while (my_fgets(line, sizeof(line), fasm))
cdfaeed7 8866 {
8867 wordc = 0;
8868 asmln++;
8869
8870 p = sskip(line);
8871 if (*p == 0)
8872 continue;
8873
8874 if (*p == ';')
8875 {
8876 // get rid of random tabs
8877 for (i = 0; line[i] != 0; i++)
8878 if (line[i] == '\t')
8879 line[i] = ' ';
8880
8881 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8882 {
8883 p += 30;
8884 next_word(words[0], sizeof(words[0]), p);
8885 if (words[0][0] == 0)
8886 aerr("missing name for func chunk?\n");
8887
8888 add_func_chunk(fasm, words[0], asmln);
8889 }
46b388c2 8890 else if (IS_START(p, "; sctend"))
8891 break;
8892
cdfaeed7 8893 continue;
8894 } // *p == ';'
8895
8896 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8897 words[wordc][0] = 0;
8898 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8899 if (*p == 0 || *p == ';') {
8900 wordc++;
8901 break;
8902 }
8903 }
8904
8905 if (wordc == 2 && IS(words[1], "ends"))
8906 break;
8907 }
8908
8909 fseek(fasm, oldpos, SEEK_SET);
8910 asmln = oldasmln;
8911}
8912
91977a1c 8913int main(int argc, char *argv[])
8914{
06c5d854 8915 FILE *fout, *fasm, *frlist;
4c45fa73 8916 struct parsed_data *pd = NULL;
8917 int pd_alloc = 0;
8918 char **rlist = NULL;
8919 int rlist_len = 0;
8920 int rlist_alloc = 0;
e56ab892 8921 int func_chunks_used = 0;
8922 int func_chunks_sorted = 0;
e56ab892 8923 int func_chunk_i = -1;
8924 long func_chunk_ret = 0;
de50b98b 8925 int func_chunk_ret_ln = 0;
cdfaeed7 8926 int scanned_ahead = 0;
91977a1c 8927 char line[256];
a2c1d768 8928 char words[20][256];
4c45fa73 8929 enum opr_lenmod lmod;
ddaf8bd7 8930 char *sctproto = NULL;
91977a1c 8931 int in_func = 0;
4c45fa73 8932 int pending_endp = 0;
11437ea1 8933 int skip_code = 0;
8934 int skip_code_end = 0;
940e8e66 8935 int skip_warned = 0;
91977a1c 8936 int eq_alloc;
bfa4a6ee 8937 int verbose = 0;
1f84f6b3 8938 int multi_seg = 0;
46b388c2 8939 int end = 0;
bfa4a6ee 8940 int arg_out;
89ff3147 8941 int arg;
91977a1c 8942 int pi = 0;
e56ab892 8943 int i, j;
8944 int ret, len;
91977a1c 8945 char *p;
8946 int wordc;
8947
89ff3147 8948 for (arg = 1; arg < argc; arg++) {
8949 if (IS(argv[arg], "-v"))
8950 verbose = 1;
8951 else if (IS(argv[arg], "-rf"))
8952 g_allow_regfunc = 1;
8c83cc48 8953 else if (IS(argv[arg], "-uc"))
8954 g_allow_user_icall = 1;
1f84f6b3 8955 else if (IS(argv[arg], "-m"))
8956 multi_seg = 1;
92d715b6 8957 else if (IS(argv[arg], "-hdr"))
9af2d373 8958 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
89ff3147 8959 else
8960 break;
bfa4a6ee 8961 }
8962
8963 if (argc < arg + 3) {
315b77eb 8964 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
8965 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
8966 "options:\n"
8967 " -hdr - header generation mode\n"
8968 " -rf - allow unannotated indirect calls\n"
8c83cc48 8969 " -uc - allow ind. calls/refs to __usercall\n"
315b77eb 8970 " -m - allow multiple .text sections\n"
8971 "[rlist] is a file with function names to skip,"
8972 " one per line\n",
92d715b6 8973 argv[0], argv[0]);
91977a1c 8974 return 1;
8975 }
8976
bfa4a6ee 8977 arg_out = arg++;
91977a1c 8978
bfa4a6ee 8979 asmfn = argv[arg++];
91977a1c 8980 fasm = fopen(asmfn, "r");
8981 my_assert_not(fasm, NULL);
8982
bfa4a6ee 8983 hdrfn = argv[arg++];
06c5d854 8984 g_fhdr = fopen(hdrfn, "r");
8985 my_assert_not(g_fhdr, NULL);
bfa4a6ee 8986
8987 rlist_alloc = 64;
8988 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
8989 my_assert_not(rlist, NULL);
8990 // needs special handling..
8991 rlist[rlist_len++] = "__alloca_probe";
8992
e56ab892 8993 func_chunk_alloc = 32;
8994 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
8995 my_assert_not(func_chunks, NULL);
8996
a2c1d768 8997 memset(words, 0, sizeof(words));
8998
bfa4a6ee 8999 for (; arg < argc; arg++) {
11437ea1 9000 int skip_func = 0;
9001
bfa4a6ee 9002 frlist = fopen(argv[arg], "r");
9003 my_assert_not(frlist, NULL);
9004
5fa1256f 9005 while (my_fgets(line, sizeof(line), frlist)) {
bfa4a6ee 9006 p = sskip(line);
1cd4a663 9007 if (*p == 0 || *p == ';')
9008 continue;
9009 if (*p == '#') {
89ff3147 9010 if (IS_START(p, "#if 0")
9011 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
9012 {
1cd4a663 9013 skip_func = 1;
89ff3147 9014 }
1cd4a663 9015 else if (IS_START(p, "#endif"))
9016 skip_func = 0;
9017 continue;
9018 }
9019 if (skip_func)
bfa4a6ee 9020 continue;
9021
9022 p = next_word(words[0], sizeof(words[0]), p);
9023 if (words[0][0] == 0)
9024 continue;
9025
9026 if (rlist_len >= rlist_alloc) {
9027 rlist_alloc = rlist_alloc * 2 + 64;
9028 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
9029 my_assert_not(rlist, NULL);
9030 }
9031 rlist[rlist_len++] = strdup(words[0]);
9032 }
9033
9034 fclose(frlist);
9035 frlist = NULL;
9036 }
9037
9038 if (rlist_len > 0)
9039 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
9040
9041 fout = fopen(argv[arg_out], "w");
91977a1c 9042 my_assert_not(fout, NULL);
9043
9044 eq_alloc = 128;
9045 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
9046 my_assert_not(g_eqs, NULL);
9047
4c45fa73 9048 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
9049 g_label_refs[i].i = -1;
9050 g_label_refs[i].next = NULL;
9051 }
9052
5fa1256f 9053 if (g_header_mode)
4c20744d 9054 scan_variables(fasm, rlist, rlist_len);
5fa1256f 9055
9056 while (my_fgets(line, sizeof(line), fasm))
91977a1c 9057 {
4c45fa73 9058 wordc = 0;
91977a1c 9059 asmln++;
9060
9061 p = sskip(line);
1bafb621 9062 if (*p == 0)
91977a1c 9063 continue;
9064
de50b98b 9065 // get rid of random tabs
9066 for (i = 0; line[i] != 0; i++)
9067 if (line[i] == '\t')
9068 line[i] = ' ';
9069
e56ab892 9070 if (*p == ';')
9071 {
e56ab892 9072 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
9073 goto do_pending_endp; // eww..
9074
9075 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
9076 {
9077 static const char *attrs[] = {
9078 "bp-based frame",
9079 "library function",
9080 "static",
9081 "noreturn",
9082 "thunk",
9083 "fpd=",
9084 };
9085
9086 // parse IDA's attribute-list comment
9087 g_ida_func_attr = 0;
9088 p = sskip(p + 13);
9089
9090 for (; *p != 0; p = sskip(p)) {
9091 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9092 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9093 g_ida_func_attr |= 1 << i;
9094 p += strlen(attrs[i]);
9095 break;
9096 }
9097 }
9098 if (i == ARRAY_SIZE(attrs)) {
9099 anote("unparsed IDA attr: %s\n", p);
1bafb621 9100 break;
9101 }
e56ab892 9102 if (IS(attrs[i], "fpd=")) {
9103 p = next_word(words[0], sizeof(words[0]), p);
9104 // ignore for now..
9105 }
1bafb621 9106 }
e56ab892 9107 }
7e08c224 9108 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
9109 {
9110 static const char *attrs[] = {
9111 "clear_sf",
226e8df1 9112 "clear_regmask",
7e08c224 9113 };
9114
9115 // parse manual attribute-list comment
9116 g_sct_func_attr = 0;
9117 p = sskip(p + 10);
9118
9119 for (; *p != 0; p = sskip(p)) {
9120 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9121 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9122 g_sct_func_attr |= 1 << i;
9123 p += strlen(attrs[i]);
9124 break;
9125 }
9126 }
226e8df1 9127 if (*p == '=') {
9128 j = ret = 0;
9129 if (i == 0)
9130 // clear_sf=start,len (in dwords)
9131 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
9132 &g_stack_clear_len, &j);
9133 else if (i == 1)
9134 // clear_regmask=<mask>
6135d8e6 9135 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
7e08c224 9136 if (ret < 2) {
226e8df1 9137 anote("unparsed attr value: %s\n", p);
7e08c224 9138 break;
9139 }
9140 p += j;
9141 }
9142 else if (i == ARRAY_SIZE(attrs)) {
9143 anote("unparsed sct attr: %s\n", p);
9144 break;
9145 }
9146 }
9147 }
e56ab892 9148 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9149 {
9150 p += 30;
9151 next_word(words[0], sizeof(words[0]), p);
9152 if (words[0][0] == 0)
cdfaeed7 9153 aerr("missing name for func chunk?\n");
9154
9155 if (!scanned_ahead) {
9156 add_func_chunk(fasm, words[0], asmln);
9157 func_chunks_sorted = 0;
e56ab892 9158 }
e56ab892 9159 }
9160 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
9161 {
9162 if (func_chunk_i >= 0) {
9163 if (func_chunk_i < func_chunk_cnt
9164 && IS(func_chunks[func_chunk_i].name, g_func))
9165 {
9166 // move on to next chunk
9167 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9168 if (ret)
9169 aerr("seek failed for '%s' chunk #%d\n",
9170 g_func, func_chunk_i);
de50b98b 9171 asmln = func_chunks[func_chunk_i].asmln;
e56ab892 9172 func_chunk_i++;
9173 }
9174 else {
9175 if (func_chunk_ret == 0)
9176 aerr("no return from chunk?\n");
9177 fseek(fasm, func_chunk_ret, SEEK_SET);
de50b98b 9178 asmln = func_chunk_ret_ln;
e56ab892 9179 func_chunk_ret = 0;
9180 pending_endp = 1;
9181 }
1bafb621 9182 }
e56ab892 9183 }
9184 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
9185 func_chunks_used = 1;
9186 p += 20;
9187 if (IS_START(g_func, "sub_")) {
9188 unsigned long addr = strtoul(p, NULL, 16);
9189 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
cdfaeed7 9190 if (addr > f_addr && !scanned_ahead) {
b2bd20c0 9191 //anote("scan_ahead caused by '%s', addr %lx\n",
9192 // g_func, addr);
ea43585b 9193 scan_ahead_for_chunks(fasm);
cdfaeed7 9194 scanned_ahead = 1;
9195 func_chunks_sorted = 0;
9196 }
1bafb621 9197 }
9198 }
9199 continue;
e56ab892 9200 } // *p == ';'
1bafb621 9201
06c5d854 9202parse_words:
a2c1d768 9203 for (i = wordc; i < ARRAY_SIZE(words); i++)
9204 words[i][0] = 0;
cdfaeed7 9205 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
bfa4a6ee 9206 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
91977a1c 9207 if (*p == 0 || *p == ';') {
9208 wordc++;
9209 break;
9210 }
9211 }
a2c1d768 9212 if (*p != 0 && *p != ';')
9213 aerr("too many words\n");
91977a1c 9214
11437ea1 9215 if (skip_code_end) {
9216 skip_code_end = 0;
9217 skip_code = 0;
9218 }
9219
9220 // allow asm patches in comments
ddaf8bd7 9221 if (*p == ';') {
9222 if (IS_START(p, "; sctpatch:")) {
9223 p = sskip(p + 11);
9224 if (*p == 0 || *p == ';')
9225 continue;
9226 goto parse_words; // lame
9227 }
9228 if (IS_START(p, "; sctproto:")) {
9229 sctproto = strdup(p + 11);
9230 }
46b388c2 9231 else if (IS_START(p, "; sctend")) {
9232 end = 1;
9233 if (!pending_endp)
9234 break;
9235 }
11437ea1 9236 else if (IS_START(p, "; sctskip_start")) {
9237 if (in_func && !g_skip_func) {
9238 if (!skip_code) {
9239 ops[pi].op = OPP_ABORT;
9240 ops[pi].asmln = asmln;
9241 pi++;
9242 }
9243 skip_code = 1;
9244 }
9245 }
9246 else if (IS_START(p, "; sctskip_end")) {
9247 if (skip_code)
9248 skip_code_end = 1;
9249 }
06c5d854 9250 }
9251
91977a1c 9252 if (wordc == 0) {
9253 // shouldn't happen
9254 awarn("wordc == 0?\n");
9255 continue;
9256 }
9257
9258 // don't care about this:
9259 if (words[0][0] == '.'
9260 || IS(words[0], "include")
9261 || IS(words[0], "assume") || IS(words[1], "segment")
9262 || IS(words[0], "align"))
9263 {
9264 continue;
9265 }
9266
4c45fa73 9267do_pending_endp:
9268 // do delayed endp processing to collect switch jumptables
9269 if (pending_endp) {
30c8c549 9270 if (in_func && !g_skip_func && !end && wordc >= 2
4c45fa73 9271 && ((words[0][0] == 'd' && words[0][2] == 0)
9272 || (words[1][0] == 'd' && words[1][2] == 0)))
9273 {
9274 i = 1;
9275 if (words[1][0] == 'd' && words[1][2] == 0) {
9276 // label
9277 if (g_func_pd_cnt >= pd_alloc) {
9278 pd_alloc = pd_alloc * 2 + 16;
9279 g_func_pd = realloc(g_func_pd,
9280 sizeof(g_func_pd[0]) * pd_alloc);
9281 my_assert_not(g_func_pd, NULL);
9282 }
9283 pd = &g_func_pd[g_func_pd_cnt];
9284 g_func_pd_cnt++;
9285 memset(pd, 0, sizeof(*pd));
9286 strcpy(pd->label, words[0]);
9287 pd->type = OPT_CONST;
9288 pd->lmod = lmod_from_directive(words[1]);
9289 i = 2;
9290 }
9291 else {
da87ae38 9292 if (pd == NULL) {
9293 if (verbose)
9294 anote("skipping alignment byte?\n");
9295 continue;
9296 }
4c45fa73 9297 lmod = lmod_from_directive(words[0]);
9298 if (lmod != pd->lmod)
9299 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
9300 }
9301
9302 if (pd->count_alloc < pd->count + wordc) {
9303 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
9304 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
9305 my_assert_not(pd->d, NULL);
9306 }
9307 for (; i < wordc; i++) {
9308 if (IS(words[i], "offset")) {
9309 pd->type = OPT_OFFSET;
9310 i++;
9311 }
9312 p = strchr(words[i], ',');
9313 if (p != NULL)
9314 *p = 0;
9315 if (pd->type == OPT_OFFSET)
9316 pd->d[pd->count].u.label = strdup(words[i]);
9317 else
e27467d0 9318 pd->d[pd->count].u.val = parse_number(words[i], 0);
4c45fa73 9319 pd->d[pd->count].bt_i = -1;
9320 pd->count++;
9321 }
9322 continue;
9323 }
9324
30c8c549 9325 if (in_func && !g_skip_func) {
9af2d373 9326 if (g_header_mode)
92d715b6 9327 gen_hdr(g_func, pi);
9328 else
9329 gen_func(fout, g_fhdr, g_func, pi);
9330 }
4c45fa73 9331
9332 pending_endp = 0;
9333 in_func = 0;
9334 g_ida_func_attr = 0;
7e08c224 9335 g_sct_func_attr = 0;
9336 g_stack_clear_start = 0;
9337 g_stack_clear_len = 0;
226e8df1 9338 g_regmask_init = 0;
4c45fa73 9339 skip_warned = 0;
30c8c549 9340 g_skip_func = 0;
4c45fa73 9341 g_func[0] = 0;
ba93cc12 9342 g_seh_found = 0;
e56ab892 9343 func_chunks_used = 0;
9344 func_chunk_i = -1;
4c45fa73 9345 if (pi != 0) {
9346 memset(&ops, 0, pi * sizeof(ops[0]));
d7857c3a 9347 clear_labels(pi);
4c45fa73 9348 pi = 0;
9349 }
9350 g_eqcnt = 0;
9351 for (i = 0; i < g_func_pd_cnt; i++) {
9352 pd = &g_func_pd[i];
9353 if (pd->type == OPT_OFFSET) {
9354 for (j = 0; j < pd->count; j++)
9355 free(pd->d[j].u.label);
9356 }
9357 free(pd->d);
9358 pd->d = NULL;
9359 }
9360 g_func_pd_cnt = 0;
d4a985bd 9361 g_func_lmods = 0;
4c45fa73 9362 pd = NULL;
46b388c2 9363
9364 if (end)
9365 break;
4c45fa73 9366 if (wordc == 0)
9367 continue;
9368 }
9369
91977a1c 9370 if (IS(words[1], "proc")) {
9371 if (in_func)
9372 aerr("proc '%s' while in_func '%s'?\n",
9373 words[0], g_func);
bfa4a6ee 9374 p = words[0];
ddaf8bd7 9375 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
30c8c549 9376 g_skip_func = 1;
91977a1c 9377 strcpy(g_func, words[0]);
d4e3b5db 9378 set_label(0, words[0]);
91977a1c 9379 in_func = 1;
9380 continue;
9381 }
9382
e56ab892 9383 if (IS(words[1], "endp"))
9384 {
91977a1c 9385 if (!in_func)
9386 aerr("endp '%s' while not in_func?\n", words[0]);
9387 if (!IS(g_func, words[0]))
9388 aerr("endp '%s' while in_func '%s'?\n",
9389 words[0], g_func);
11437ea1 9390 if (skip_code)
9391 aerr("endp '%s' while skipping code\n", words[0]);
bfa4a6ee 9392
ddaf8bd7 9393 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
ba93cc12 9394 && ops[0].op == OP_JMP && ops[0].operand[0].segment)
ddaf8bd7 9395 {
9396 // import jump
30c8c549 9397 g_skip_func = 1;
ddaf8bd7 9398 }
9399
30c8c549 9400 if (!g_skip_func && func_chunks_used) {
e56ab892 9401 // start processing chunks
9402 struct chunk_item *ci, key = { g_func, 0 };
9403
9404 func_chunk_ret = ftell(fasm);
de50b98b 9405 func_chunk_ret_ln = asmln;
e56ab892 9406 if (!func_chunks_sorted) {
9407 qsort(func_chunks, func_chunk_cnt,
9408 sizeof(func_chunks[0]), cmp_chunks);
9409 func_chunks_sorted = 1;
9410 }
9411 ci = bsearch(&key, func_chunks, func_chunk_cnt,
9412 sizeof(func_chunks[0]), cmp_chunks);
9413 if (ci == NULL)
9414 aerr("'%s' needs chunks, but none found\n", g_func);
9415 func_chunk_i = ci - func_chunks;
9416 for (; func_chunk_i > 0; func_chunk_i--)
9417 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
9418 break;
9419
9420 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9421 if (ret)
9422 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
de50b98b 9423 asmln = func_chunks[func_chunk_i].asmln;
e56ab892 9424 func_chunk_i++;
9425 continue;
9426 }
4c45fa73 9427 pending_endp = 1;
91977a1c 9428 continue;
9429 }
9430
1f84f6b3 9431 if (wordc == 2 && IS(words[1], "ends")) {
46b388c2 9432 if (!multi_seg) {
9433 end = 1;
9434 if (pending_endp)
9435 goto do_pending_endp;
1f84f6b3 9436 break;
46b388c2 9437 }
1f84f6b3 9438
9439 // scan for next text segment
5fa1256f 9440 while (my_fgets(line, sizeof(line), fasm)) {
1f84f6b3 9441 asmln++;
9442 p = sskip(line);
9443 if (*p == 0 || *p == ';')
9444 continue;
9445
9446 if (strstr(p, "segment para public 'CODE' use32"))
9447 break;
9448 }
9449
9450 continue;
9451 }
a2c1d768 9452
bfa4a6ee 9453 p = strchr(words[0], ':');
9454 if (p != NULL) {
d4e3b5db 9455 set_label(pi, words[0]);
bfa4a6ee 9456 continue;
9457 }
9458
11437ea1 9459 if (!in_func || g_skip_func || skip_code) {
30c8c549 9460 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
bfa4a6ee 9461 if (verbose)
9462 anote("skipping from '%s'\n", g_labels[pi]);
9463 skip_warned = 1;
9464 }
d7857c3a 9465 free(g_labels[pi]);
9466 g_labels[pi] = NULL;
bfa4a6ee 9467 continue;
9468 }
9469
ddaf8bd7 9470 if (wordc > 1 && IS(words[1], "="))
9471 {
91977a1c 9472 if (wordc != 5)
9473 aerr("unhandled equ, wc=%d\n", wordc);
9474 if (g_eqcnt >= eq_alloc) {
9475 eq_alloc *= 2;
9476 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
9477 my_assert_not(g_eqs, NULL);
9478 }
9479
9480 len = strlen(words[0]);
9481 if (len > sizeof(g_eqs[0].name) - 1)
9482 aerr("equ name too long: %d\n", len);
9483 strcpy(g_eqs[g_eqcnt].name, words[0]);
9484
9485 if (!IS(words[3], "ptr"))
9486 aerr("unhandled equ\n");
9487 if (IS(words[2], "dword"))
9488 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
9489 else if (IS(words[2], "word"))
9490 g_eqs[g_eqcnt].lmod = OPLM_WORD;
9491 else if (IS(words[2], "byte"))
9492 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
90307a99 9493 else if (IS(words[2], "qword"))
9494 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
91977a1c 9495 else
9496 aerr("bad lmod: '%s'\n", words[2]);
9497
e27467d0 9498 g_eqs[g_eqcnt].offset = parse_number(words[4], 0);
91977a1c 9499 g_eqcnt++;
9500 continue;
9501 }
9502
9503 if (pi >= ARRAY_SIZE(ops))
9504 aerr("too many ops\n");
9505
91977a1c 9506 parse_op(&ops[pi], words, wordc);
ddaf8bd7 9507
865f1aca 9508 ops[pi].datap = sctproto;
9509 sctproto = NULL;
91977a1c 9510 pi++;
91977a1c 9511 }
9512
9af2d373 9513 if (g_header_mode)
92d715b6 9514 output_hdr(fout);
9515
91977a1c 9516 fclose(fout);
9517 fclose(fasm);
06c5d854 9518 fclose(g_fhdr);
91977a1c 9519
9520 return 0;
c36e914d 9521}
91977a1c 9522
9523// vim:ts=2:shiftwidth=2:expandtab