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