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