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