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