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