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