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