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