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