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