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