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