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