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