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