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