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