translate: more noreturn cases, neg flags
[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
0ea6430c 2586 goto out;
89ff3147 2587 }
93b5bd18 2588 else
0ea6430c 2589 goto out;
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
0ea6430c 2640out:
93b5bd18 2641 // for noreturn, assume msvc skipped stack cleanup
2642 return seen_noreturn ? 1 : -1;
850c9265 2643}
2644
e83ea7ed 2645// scan for 'reg' pop backwards starting from i
2646// intended to use for register restore search, so other reg
2647// references are considered an error
2648static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
850c9265 2649{
e83ea7ed 2650 struct parsed_op *po;
2651 struct label_ref *lr;
2652 int ret = 0;
2653
2654 ops[i].cc_scratch = magic;
2655
2656 while (1)
2657 {
2658 if (g_labels[i] != NULL) {
2659 lr = &g_label_refs[i];
2660 for (; lr != NULL; lr = lr->next) {
2661 check_i(&ops[i], lr->i);
2662 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2663 if (ret < 0)
2664 return ret;
2665 }
2666 if (i > 0 && LAST_OP(i - 1))
2667 return ret;
2668 }
2669
2670 i--;
2671 if (i < 0)
2672 break;
2673
2674 if (ops[i].cc_scratch == magic)
2675 return ret;
2676 ops[i].cc_scratch = magic;
2677
2678 po = &ops[i];
2679 if (po->op == OP_POP && po->operand[0].reg == reg) {
2680 if (po->flags & (OPF_RMD|OPF_DONE))
2681 return -1;
2682
2683 po->flags |= set_flags;
2684 return 1;
2685 }
2686
2687 // this also covers the case where we reach corresponding push
2688 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2689 return -1;
2690 }
2691
2692 // nothing interesting on this path
2693 return 0;
2694}
2695
2696static void find_reachable_exits(int i, int opcnt, int magic,
2697 int *exits, int *exit_count)
2698{
2699 struct parsed_op *po;
850c9265 2700 int j;
2701
e83ea7ed 2702 for (; i < opcnt; i++)
2703 {
2704 po = &ops[i];
2705 if (po->cc_scratch == magic)
2706 return;
2707 po->cc_scratch = magic;
2708
2709 if (po->flags & OPF_TAIL) {
2710 ferr_assert(po, *exit_count < MAX_EXITS);
2711 exits[*exit_count] = i;
2712 (*exit_count)++;
2713 return;
2714 }
850c9265 2715
e83ea7ed 2716 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2717 if (po->flags & OPF_RMD)
69a3cdfc 2718 continue;
850c9265 2719
e83ea7ed 2720 if (po->btj != NULL) {
2721 for (j = 0; j < po->btj->count; j++) {
2722 check_i(po, po->btj->d[j].bt_i);
2723 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2724 exits, exit_count);
2725 }
2726 return;
850c9265 2727 }
2728
e83ea7ed 2729 check_i(po, po->bt_i);
2730 if (po->flags & OPF_CJMP)
2731 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2732 else
2733 i = po->bt_i - 1;
2734 continue;
850c9265 2735 }
2736 }
e83ea7ed 2737}
2738
2739// scan for 'reg' pop backwards starting from exits (all paths)
2740static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2741{
2742 static int exits[MAX_EXITS];
2743 static int exit_count;
2744 int j, ret;
850c9265 2745
e83ea7ed 2746 if (!set_flags) {
2747 exit_count = 0;
2748 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2749 &exit_count);
2750 ferr_assert(&ops[i], exit_count > 0);
2751 }
2752
2753 for (j = 0; j < exit_count; j++) {
2754 ret = scan_for_rsave_pop_reg(exits[j], i + opcnt * 16 + set_flags,
2755 reg, set_flags);
2756 if (ret == -1)
2757 return -1;
2758 }
2759
b2bd20c0 2760 return 1;
850c9265 2761}
2762
e83ea7ed 2763// scan for one or more pop of push <const>
2764static int scan_for_pop_const_r(int i, int opcnt, int magic,
2765 int push_i, int is_probe)
9af2d373 2766{
25a330eb 2767 struct parsed_op *po;
e83ea7ed 2768 struct label_ref *lr;
2769 int ret = 0;
9af2d373 2770 int j;
2771
e83ea7ed 2772 for (; i < opcnt; i++)
2773 {
2774 po = &ops[i];
2775 if (po->cc_scratch == magic)
2776 return ret; // already checked
2777 po->cc_scratch = magic;
2778
2779 if (po->flags & OPF_JMP) {
2780 if (po->flags & OPF_RMD)
2781 continue;
2782 if (po->op == OP_CALL)
2783 return -1;
2784
2785 if (po->btj != NULL) {
2786 for (j = 0; j < po->btj->count; j++) {
2787 check_i(po, po->btj->d[j].bt_i);
2788 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2789 push_i, is_probe);
2790 if (ret < 0)
2791 return ret;
2792 }
2793 return ret;
2794 }
25a330eb 2795
e83ea7ed 2796 check_i(po, po->bt_i);
2797 if (po->flags & OPF_CJMP) {
2798 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2799 is_probe);
2800 if (ret < 0)
2801 return ret;
2802 }
2803 else {
2804 i = po->bt_i - 1;
2805 }
25a330eb 2806 continue;
2807 }
2808
e83ea7ed 2809 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2810 return -1;
2811
2812 if (g_labels[i] != NULL) {
2813 // all refs must be visited
2814 lr = &g_label_refs[i];
2815 for (; lr != NULL; lr = lr->next) {
2816 check_i(po, lr->i);
2817 if (ops[lr->i].cc_scratch != magic)
2818 return -1;
2819 }
2820 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2821 return -1;
2822 }
2823
2824 if (po->op == OP_POP)
9af2d373 2825 {
e83ea7ed 2826 if (po->flags & (OPF_RMD|OPF_DONE))
2827 return -1;
2828
2829 if (!is_probe) {
2830 po->flags |= OPF_DONE;
2831 po->datap = &ops[push_i];
2832 }
2833 return 1;
9af2d373 2834 }
e83ea7ed 2835 }
9af2d373 2836
e83ea7ed 2837 return -1;
2838}
25a330eb 2839
e83ea7ed 2840static void scan_for_pop_const(int i, int opcnt, int magic)
2841{
2842 int ret;
2843
2844 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
2845 if (ret == 1) {
2846 ops[i].flags |= OPF_RMD | OPF_DONE;
2847 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
2848 }
2849}
2850
2851// check if all branch targets within a marked path are also marked
2852// note: the path checked must not be empty or end with a branch
2853static int check_path_branches(int opcnt, int magic)
2854{
2855 struct parsed_op *po;
2856 int i, j;
2857
2858 for (i = 0; i < opcnt; i++) {
2859 po = &ops[i];
2860 if (po->cc_scratch != magic)
2861 continue;
2862
2863 if (po->flags & OPF_JMP) {
2864 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
2865 continue;
2866
2867 if (po->btj != NULL) {
2868 for (j = 0; j < po->btj->count; j++) {
2869 check_i(po, po->btj->d[j].bt_i);
2870 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
2871 return 0;
2872 }
25a330eb 2873 }
e83ea7ed 2874
2875 check_i(po, po->bt_i);
2876 if (ops[po->bt_i].cc_scratch != magic)
2877 return 0;
2878 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
2879 return 0;
2880 }
2881 }
2882
2883 return 1;
2884}
2885
2886// scan for multiple pushes for given pop
2887static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
2888 int is_probe)
2889{
2890 int reg = ops[pop_i].operand[0].reg;
2891 struct parsed_op *po;
2892 struct label_ref *lr;
2893 int ret = 0;
2894
2895 ops[i].cc_scratch = magic;
2896
2897 while (1)
2898 {
2899 if (g_labels[i] != NULL) {
2900 lr = &g_label_refs[i];
2901 for (; lr != NULL; lr = lr->next) {
2902 check_i(&ops[i], lr->i);
2903 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
2904 if (ret < 0)
2905 return ret;
25a330eb 2906 }
e83ea7ed 2907 if (i > 0 && LAST_OP(i - 1))
2908 return ret;
2909 }
2910
2911 i--;
2912 if (i < 0)
9af2d373 2913 break;
e83ea7ed 2914
2915 if (ops[i].cc_scratch == magic)
2916 return ret;
2917 ops[i].cc_scratch = magic;
2918
2919 po = &ops[i];
2920 if (po->op == OP_CALL)
2921 return -1;
2922 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
2923 return -1;
2924
2925 if (po->op == OP_PUSH)
2926 {
2927 if (po->datap != NULL)
2928 return -1;
2929 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2930 // leave this case for reg save/restore handlers
2931 return -1;
2932
2933 if (!is_probe) {
2934 po->flags |= OPF_PPUSH | OPF_DONE;
2935 po->datap = &ops[pop_i];
2936 }
2937 return 1;
2938 }
2939 }
2940
2941 return -1;
2942}
2943
2944static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
2945{
2946 int magic = i + opcnt * 14;
2947 int ret;
2948
2949 ret = scan_pushes_for_pop_r(i, magic, i, 1);
2950 if (ret == 1) {
2951 ret = check_path_branches(opcnt, magic);
2952 if (ret == 1) {
2953 ops[i].flags |= OPF_PPUSH | OPF_DONE;
2954 *regmask_pp |= 1 << ops[i].operand[0].reg;
2955 scan_pushes_for_pop_r(i, magic + 1, i, 0);
9af2d373 2956 }
2957 }
2958}
2959
591721d7 2960static void scan_propagate_df(int i, int opcnt)
2961{
2962 struct parsed_op *po = &ops[i];
2963 int j;
2964
2965 for (; i < opcnt; i++) {
2966 po = &ops[i];
2967 if (po->flags & OPF_DF)
2968 return; // already resolved
2969 po->flags |= OPF_DF;
2970
2971 if (po->op == OP_CALL)
2972 ferr(po, "call with DF set?\n");
2973
2974 if (po->flags & OPF_JMP) {
2975 if (po->btj != NULL) {
2976 // jumptable
db63af51 2977 for (j = 0; j < po->btj->count; j++) {
2978 check_i(po, po->btj->d[j].bt_i);
591721d7 2979 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
db63af51 2980 }
591721d7 2981 return;
2982 }
2983
b2bd20c0 2984 if (po->flags & OPF_RMD)
2985 continue;
db63af51 2986 check_i(po, po->bt_i);
5c024ef7 2987 if (po->flags & OPF_CJMP)
591721d7 2988 scan_propagate_df(po->bt_i, opcnt);
2989 else
2990 i = po->bt_i - 1;
2991 continue;
2992 }
2993
2994 if (po->flags & OPF_TAIL)
2995 break;
2996
2997 if (po->op == OP_CLD) {
5e49b270 2998 po->flags |= OPF_RMD | OPF_DONE;
591721d7 2999 return;
3000 }
3001 }
3002
3003 ferr(po, "missing DF clear?\n");
3004}
3005
db63af51 3006// is operand 'opr' referenced by parsed_op 'po'?
3007static int is_opr_referenced(const struct parsed_opr *opr,
3008 const struct parsed_op *po)
3009{
3010 int i, mask;
3011
3012 if (opr->type == OPT_REG) {
3013 mask = po->regmask_dst | po->regmask_src;
3014 if (po->op == OP_CALL)
3015 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
3016 if ((1 << opr->reg) & mask)
3017 return 1;
3018 else
3019 return 0;
3020 }
3021
3022 for (i = 0; i < po->operand_cnt; i++)
3023 if (IS(po->operand[0].name, opr->name))
3024 return 1;
3025
3026 return 0;
3027}
3028
3029// is operand 'opr' read by parsed_op 'po'?
3030static int is_opr_read(const struct parsed_opr *opr,
3031 const struct parsed_op *po)
3032{
db63af51 3033 if (opr->type == OPT_REG) {
b2bd20c0 3034 if (po->regmask_src & (1 << opr->reg))
db63af51 3035 return 1;
3036 else
3037 return 0;
3038 }
3039
3040 // yes I'm lazy
3041 return 0;
3042}
3043
1cd4a663 3044// is operand 'opr' modified by parsed_op 'po'?
5101a5f9 3045static int is_opr_modified(const struct parsed_opr *opr,
69a3cdfc 3046 const struct parsed_op *po)
3047{
89ff3147 3048 int mask;
3049
89ff3147 3050 if (opr->type == OPT_REG) {
3051 if (po->op == OP_CALL) {
b2bd20c0 3052 mask = po->regmask_dst;
3053 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
3054 if (mask & (1 << opr->reg))
89ff3147 3055 return 1;
3056 else
3057 return 0;
3058 }
3059
b2bd20c0 3060 if (po->regmask_dst & (1 << opr->reg))
3061 return 1;
3062 else
3063 return 0;
69a3cdfc 3064 }
3065
3066 return IS(po->operand[0].name, opr->name);
3067}
3068
5101a5f9 3069// is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
3070static int is_any_opr_modified(const struct parsed_op *po_test,
89ff3147 3071 const struct parsed_op *po, int c_mode)
5101a5f9 3072{
89ff3147 3073 int mask;
5101a5f9 3074 int i;
3075
3076 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
3077 return 0;
3078
de50b98b 3079 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3080 return 0;
3081
3082 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
3083 return 1;
3084
3085 // in reality, it can wreck any register, but in decompiled C
2b43685d 3086 // version it can only overwrite eax or edx:eax
89ff3147 3087 mask = (1 << xAX) | (1 << xDX);
3088 if (!c_mode)
3089 mask |= 1 << xCX;
3090
de50b98b 3091 if (po->op == OP_CALL
89ff3147 3092 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
5101a5f9 3093 return 1;
3094
3095 for (i = 0; i < po_test->operand_cnt; i++)
3096 if (IS(po_test->operand[i].name, po->operand[0].name))
3097 return 1;
3098
3099 return 0;
3100}
3101
940e8e66 3102// scan for any po_test operand modification in range given
89ff3147 3103static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
3104 int c_mode)
69a3cdfc 3105{
2b43685d 3106 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3107 return -1;
3108
69a3cdfc 3109 for (; i < opcnt; i++) {
89ff3147 3110 if (is_any_opr_modified(po_test, &ops[i], c_mode))
69a3cdfc 3111 return i;
3112 }
3113
3114 return -1;
3115}
3116
940e8e66 3117// scan for po_test operand[0] modification in range given
3118static int scan_for_mod_opr0(struct parsed_op *po_test,
3119 int i, int opcnt)
3120{
3121 for (; i < opcnt; i++) {
3122 if (is_opr_modified(&po_test->operand[0], &ops[i]))
3123 return i;
3124 }
3125
3126 return -1;
3127}
3128
7f20f633 3129static int try_resolve_const(int i, const struct parsed_opr *opr,
3130 int magic, unsigned int *val);
3131
3132static int scan_for_flag_set(int i, int opcnt, int magic,
3133 int *branched, int *setters, int *setter_cnt)
69a3cdfc 3134{
04f8a628 3135 struct label_ref *lr;
2b43685d 3136 int ret;
de50b98b 3137
3138 while (i >= 0) {
04f8a628 3139 if (ops[i].cc_scratch == magic) {
04abc5d6 3140 // is this a problem?
3141 //ferr(&ops[i], "%s looped\n", __func__);
3142 return 0;
04f8a628 3143 }
3144 ops[i].cc_scratch = magic;
3145
d7857c3a 3146 if (g_labels[i] != NULL) {
2b43685d 3147 *branched = 1;
04f8a628 3148
3149 lr = &g_label_refs[i];
3150 for (; lr->next; lr = lr->next) {
92d715b6 3151 check_i(&ops[i], lr->i);
7f20f633 3152 ret = scan_for_flag_set(lr->i, opcnt, magic,
04f8a628 3153 branched, setters, setter_cnt);
3154 if (ret < 0)
3155 return ret;
3156 }
3157
92d715b6 3158 check_i(&ops[i], lr->i);
de50b98b 3159 if (i > 0 && LAST_OP(i - 1)) {
94d447fb 3160 i = lr->i;
de50b98b 3161 continue;
3162 }
7f20f633 3163 ret = scan_for_flag_set(lr->i, opcnt, magic,
04f8a628 3164 branched, setters, setter_cnt);
2b43685d 3165 if (ret < 0)
3166 return ret;
de50b98b 3167 }
3168 i--;
3169
2b43685d 3170 if (ops[i].flags & OPF_FLAGS) {
3171 setters[*setter_cnt] = i;
3172 (*setter_cnt)++;
7f20f633 3173
3174 if (ops[i].flags & OPF_REP) {
3175 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
3176 unsigned int uval;
3177
3178 ret = try_resolve_const(i, &opr, i + opcnt * 7, &uval);
3179 if (ret != 1 || uval == 0) {
3180 // can't treat it as full setter because of ecx=0 case,
3181 // also disallow delayed compare
3182 *branched = 1;
3183 continue;
3184 }
3185 }
3186
2b43685d 3187 return 0;
3188 }
69a3cdfc 3189
5c024ef7 3190 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
69a3cdfc 3191 return -1;
69a3cdfc 3192 }
3193
3194 return -1;
3195}
3196
5101a5f9 3197// scan back for cdq, if anything modifies edx, fail
3198static int scan_for_cdq_edx(int i)
3199{
cdfaeed7 3200 while (i >= 0) {
d7857c3a 3201 if (g_labels[i] != NULL) {
cdfaeed7 3202 if (g_label_refs[i].next != NULL)
3203 return -1;
3204 if (i > 0 && LAST_OP(i - 1)) {
3205 i = g_label_refs[i].i;
3206 continue;
3207 }
3208 return -1;
3209 }
3210 i--;
3211
5101a5f9 3212 if (ops[i].op == OP_CDQ)
3213 return i;
3214
3215 if (ops[i].regmask_dst & (1 << xDX))
3216 return -1;
5101a5f9 3217 }
3218
3219 return -1;
3220}
3221
64c59faf 3222static int scan_for_reg_clear(int i, int reg)
3223{
cdfaeed7 3224 while (i >= 0) {
d7857c3a 3225 if (g_labels[i] != NULL) {
cdfaeed7 3226 if (g_label_refs[i].next != NULL)
3227 return -1;
3228 if (i > 0 && LAST_OP(i - 1)) {
3229 i = g_label_refs[i].i;
3230 continue;
3231 }
3232 return -1;
3233 }
3234 i--;
3235
64c59faf 3236 if (ops[i].op == OP_XOR
3237 && ops[i].operand[0].lmod == OPLM_DWORD
3238 && ops[i].operand[0].reg == ops[i].operand[1].reg
3239 && ops[i].operand[0].reg == reg)
3240 return i;
3241
3242 if (ops[i].regmask_dst & (1 << reg))
3243 return -1;
64c59faf 3244 }
3245
3246 return -1;
3247}
3248
ee2361b9 3249static void patch_esp_adjust(struct parsed_op *po, int adj)
3250{
3251 ferr_assert(po, po->op == OP_ADD);
3252 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3253 ferr_assert(po, po->operand[1].type == OPT_CONST);
3254
3255 // this is a bit of a hack, but deals with use of
3256 // single adj for multiple calls
3257 po->operand[1].val -= adj;
3258 po->flags |= OPF_RMD;
3259 if (po->operand[1].val == 0)
3260 po->flags |= OPF_DONE;
3261 ferr_assert(po, (int)po->operand[1].val >= 0);
3262}
3263
1bafb621 3264// scan for positive, constant esp adjust
ee2361b9 3265// multipath case is preliminary
9af2d373 3266static int scan_for_esp_adjust(int i, int opcnt,
ee2361b9 3267 int adj_expect, int *adj, int *is_multipath, int do_update)
1bafb621 3268{
bfacdc83 3269 int adj_expect_unknown = 0;
7ba45c34 3270 struct parsed_op *po;
46411e6c 3271 int first_pop = -1;
bfacdc83 3272 int adj_best = 0;
4741fdfe 3273
ee2361b9 3274 *adj = *is_multipath = 0;
bfacdc83 3275 if (adj_expect < 0) {
3276 adj_expect_unknown = 1;
3277 adj_expect = 32 * 4; // enough?
3278 }
7ba45c34 3279
9af2d373 3280 for (; i < opcnt && *adj < adj_expect; i++) {
d7857c3a 3281 if (g_labels[i] != NULL)
ee2361b9 3282 *is_multipath = 1;
a2c1d768 3283
5e49b270 3284 po = &ops[i];
3285 if (po->flags & OPF_DONE)
3286 continue;
3287
7ba45c34 3288 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3289 if (po->operand[1].type != OPT_CONST)
1bafb621 3290 ferr(&ops[i], "non-const esp adjust?\n");
7ba45c34 3291 *adj += po->operand[1].val;
1bafb621 3292 if (*adj & 3)
3293 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
ee2361b9 3294 if (do_update) {
3295 if (!*is_multipath)
3296 patch_esp_adjust(po, adj_expect);
3297 else
3298 po->flags |= OPF_RMD;
3299 }
1bafb621 3300 return i;
3301 }
5e49b270 3302 else if (po->op == OP_PUSH) {
5c024ef7 3303 //if (first_pop == -1)
3304 // first_pop = -2; // none
7ba45c34 3305 *adj -= lmod_bytes(po, po->operand[0].lmod);
46411e6c 3306 }
5e49b270 3307 else if (po->op == OP_POP) {
91ca764a 3308 if (!(po->flags & OPF_DONE)) {
3309 // seems like msvc only uses 'pop ecx' for stack realignment..
3310 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3311 break;
3312 if (first_pop == -1 && *adj >= 0)
3313 first_pop = i;
3314 }
ee2361b9 3315 if (do_update && *adj >= 0) {
3316 po->flags |= OPF_RMD;
3317 if (!*is_multipath)
b2bd20c0 3318 po->flags |= OPF_DONE | OPF_NOREGS;
ee2361b9 3319 }
3320
7ba45c34 3321 *adj += lmod_bytes(po, po->operand[0].lmod);
bfacdc83 3322 if (*adj > adj_best)
3323 adj_best = *adj;
46411e6c 3324 }
e56ab892 3325 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
4741fdfe 3326 if (po->op == OP_JMP && po->btj == NULL) {
5e49b270 3327 if (po->bt_i <= i)
3328 break;
4741fdfe 3329 i = po->bt_i - 1;
3330 continue;
3331 }
e56ab892 3332 if (po->op != OP_CALL)
a2c1d768 3333 break;
e56ab892 3334 if (po->operand[0].type != OPT_LABEL)
a2c1d768 3335 break;
91ca764a 3336 if (po->pp != NULL && po->pp->is_stdcall)
89ff3147 3337 break;
bfacdc83 3338 if (adj_expect_unknown && first_pop >= 0)
3339 break;
91ca764a 3340 // assume it's another cdecl call
e56ab892 3341 }
a2c1d768 3342 }
7ba45c34 3343
108e9fe3 3344 if (first_pop >= 0) {
bfacdc83 3345 // probably only 'pop ecx' was used
3346 *adj = adj_best;
46411e6c 3347 return first_pop;
1bafb621 3348 }
3349
3350 return -1;
3351}
3352
a3684be1 3353static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3354{
3355 struct parsed_op *po;
3356 int j;
3357
3358 if (i < 0)
3359 ferr(ops, "%s: followed bad branch?\n", __func__);
3360
3361 for (; i < opcnt; i++) {
3362 po = &ops[i];
3363 if (po->cc_scratch == magic)
3364 return;
3365 po->cc_scratch = magic;
3366 po->flags |= flags;
3367
3368 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3369 if (po->btj != NULL) {
3370 // jumptable
3371 for (j = 0; j < po->btj->count; j++)
3372 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3373 return;
3374 }
3375
3376 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
5c024ef7 3377 if (!(po->flags & OPF_CJMP))
a3684be1 3378 return;
3379 }
3380 if (po->flags & OPF_TAIL)
3381 return;
3382 }
3383}
3384
1cd4a663 3385static const struct parsed_proto *try_recover_pp(
93b5bd18 3386 struct parsed_op *po, const struct parsed_opr *opr,
3387 int is_call, int *search_instead)
1cd4a663 3388{
3389 const struct parsed_proto *pp = NULL;
89ff3147 3390 char buf[256];
3391 char *p;
1cd4a663 3392
3393 // maybe an arg of g_func?
3394 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3395 {
3396 char ofs_reg[16] = { 0, };
3397 int arg, arg_s, arg_i;
3398 int stack_ra = 0;
3399 int offset = 0;
3400
9af2d373 3401 if (g_header_mode)
3402 return NULL;
3403
1cd4a663 3404 parse_stack_access(po, opr->name, ofs_reg,
037f4971 3405 &offset, &stack_ra, NULL, 0);
1cd4a663 3406 if (ofs_reg[0] != 0)
3407 ferr(po, "offset reg on arg access?\n");
da87ae38 3408 if (offset <= stack_ra) {
3409 // search who set the stack var instead
3410 if (search_instead != NULL)
3411 *search_instead = 1;
3412 return NULL;
3413 }
1cd4a663 3414
3415 arg_i = (offset - stack_ra - 4) / 4;
3416 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3417 if (g_func_pp->arg[arg].reg != NULL)
3418 continue;
3419 if (arg_s == arg_i)
3420 break;
3421 arg_s++;
3422 }
3423 if (arg == g_func_pp->argc)
3424 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3425
93b5bd18 3426 pp = g_func_pp->arg[arg].pp;
3427 if (is_call) {
3428 if (pp == NULL)
3429 ferr(po, "icall arg: arg%d has no pp\n", arg + 1);
3430 check_func_pp(po, pp, "icall arg");
3431 }
89ff3147 3432 }
3433 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3434 // label[index]
3435 p = strchr(opr->name + 1, '[');
3436 memcpy(buf, opr->name, p - opr->name);
3437 buf[p - opr->name] = 0;
92d715b6 3438 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
1cd4a663 3439 }
3440 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
9af2d373 3441 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3442 if (pp == NULL) {
3443 if (!g_header_mode)
3444 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3445 }
3446 else
3447 check_func_pp(po, pp, "reg-fptr ref");
1cd4a663 3448 }
3449
3450 return pp;
3451}
3452
da87ae38 3453static void scan_for_call_type(int i, const struct parsed_opr *opr,
db63af51 3454 int magic, const struct parsed_proto **pp_found, int *pp_i,
3455 int *multi)
1cd4a663 3456{
3457 const struct parsed_proto *pp = NULL;
3458 struct parsed_op *po;
3459 struct label_ref *lr;
3460
037f4971 3461 ops[i].cc_scratch = magic;
1cd4a663 3462
037f4971 3463 while (1) {
d7857c3a 3464 if (g_labels[i] != NULL) {
1cd4a663 3465 lr = &g_label_refs[i];
92d715b6 3466 for (; lr != NULL; lr = lr->next) {
3467 check_i(&ops[i], lr->i);
db63af51 3468 scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
92d715b6 3469 }
46411e6c 3470 if (i > 0 && LAST_OP(i - 1))
3471 return;
1cd4a663 3472 }
037f4971 3473
1cd4a663 3474 i--;
037f4971 3475 if (i < 0)
3476 break;
3477
3478 if (ops[i].cc_scratch == magic)
3479 return;
3480 ops[i].cc_scratch = magic;
1cd4a663 3481
3482 if (!(ops[i].flags & OPF_DATA))
3483 continue;
3484 if (!is_opr_modified(opr, &ops[i]))
3485 continue;
3486 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3487 // most probably trashed by some processing
3488 *pp_found = NULL;
3489 return;
3490 }
3491
3492 opr = &ops[i].operand[1];
3493 if (opr->type != OPT_REG)
3494 break;
3495 }
3496
3497 po = (i >= 0) ? &ops[i] : ops;
3498
3499 if (i < 0) {
3500 // reached the top - can only be an arg-reg
04abc5d6 3501 if (opr->type != OPT_REG || g_func_pp == NULL)
1cd4a663 3502 return;
3503
3504 for (i = 0; i < g_func_pp->argc; i++) {
3505 if (g_func_pp->arg[i].reg == NULL)
3506 continue;
3507 if (IS(opr->name, g_func_pp->arg[i].reg))
3508 break;
3509 }
3510 if (i == g_func_pp->argc)
3511 return;
93b5bd18 3512 pp = g_func_pp->arg[i].pp;
1cd4a663 3513 if (pp == NULL)
46411e6c 3514 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3515 i + 1, g_func_pp->arg[i].reg);
89ff3147 3516 check_func_pp(po, pp, "icall reg-arg");
1cd4a663 3517 }
3518 else
93b5bd18 3519 pp = try_recover_pp(po, opr, 1, NULL);
1cd4a663 3520
89ff3147 3521 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
1cd4a663 3522 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3523 || (*pp_found)->is_stdcall != pp->is_stdcall
89ff3147 3524 || (*pp_found)->is_fptr != pp->is_fptr
1cd4a663 3525 || (*pp_found)->argc != pp->argc
3526 || (*pp_found)->argc_reg != pp->argc_reg
3527 || (*pp_found)->argc_stack != pp->argc_stack)
3528 {
3529 ferr(po, "icall: parsed_proto mismatch\n");
3530 }
89ff3147 3531 *multi = 1;
1cd4a663 3532 }
db63af51 3533 if (pp != NULL) {
1cd4a663 3534 *pp_found = pp;
db63af51 3535 *pp_i = po - ops;
3536 }
1cd4a663 3537}
3538
66bdb2b0 3539static void add_label_ref(struct label_ref *lr, int op_i)
9af2d373 3540{
66bdb2b0 3541 struct label_ref *lr_new;
9af2d373 3542
66bdb2b0 3543 if (lr->i == -1) {
3544 lr->i = op_i;
3545 return;
3546 }
9af2d373 3547
66bdb2b0 3548 lr_new = calloc(1, sizeof(*lr_new));
3549 lr_new->i = op_i;
3550 lr_new->next = lr->next;
3551 lr->next = lr_new;
3552}
3553
3554static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3555{
3556 struct parsed_op *po = &ops[i];
3557 struct parsed_data *pd;
3558 char label[NAMELEN], *p;
3559 int len, j, l;
3560
3561 p = strchr(po->operand[0].name, '[');
3562 if (p == NULL)
3563 return NULL;
3564
3565 len = p - po->operand[0].name;
3566 strncpy(label, po->operand[0].name, len);
3567 label[len] = 0;
3568
3569 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3570 if (IS(g_func_pd[j].label, label)) {
3571 pd = &g_func_pd[j];
3572 break;
3573 }
3574 }
3575 if (pd == NULL)
3576 //ferr(po, "label '%s' not parsed?\n", label);
3577 return NULL;
3578
3579 if (pd->type != OPT_OFFSET)
3580 ferr(po, "label '%s' with non-offset data?\n", label);
3581
3582 // find all labels, link
3583 for (j = 0; j < pd->count; j++) {
3584 for (l = 0; l < opcnt; l++) {
3585 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3586 add_label_ref(&g_label_refs[l], i);
3587 pd->d[j].bt_i = l;
3588 break;
3589 }
3590 }
3591 }
3592
3593 return pd;
3594}
3595
3596static void clear_labels(int count)
3597{
3598 int i;
3599
3600 for (i = 0; i < count; i++) {
3601 if (g_labels[i] != NULL) {
3602 free(g_labels[i]);
3603 g_labels[i] = NULL;
3604 }
3605 }
3606}
3607
b2bd20c0 3608static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3609{
3610 int regmask = 0;
3611 int i, reg;
3612
3613 for (i = 0; i < pp->argc; i++) {
3614 if (pp->arg[i].reg != NULL) {
3615 reg = char_array_i(regs_r32,
3616 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3617 if (reg < 0)
3618 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3619 pp->arg[i].reg, pp->name);
3620 regmask |= 1 << reg;
3621 }
3622 }
3623
3624 return regmask;
3625}
3626
3627static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3628{
4d247254 3629 int regmask = 0;
3630 int i, reg;
3631
3632 if (pp->has_retreg) {
3633 for (i = 0; i < pp->argc; i++) {
3634 if (pp->arg[i].type.is_retreg) {
3635 reg = char_array_i(regs_r32,
3636 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3637 ferr_assert(ops, reg >= 0);
3638 regmask |= 1 << reg;
3639 }
3640 }
3641 }
3642
b2bd20c0 3643 if (strstr(pp->ret_type.name, "int64"))
4d247254 3644 return regmask | (1 << xAX) | (1 << xDX);
d4a985bd 3645 if (IS(pp->ret_type.name, "float")
3646 || IS(pp->ret_type.name, "double"))
3647 {
4d247254 3648 return regmask | mxST0;
d4a985bd 3649 }
b2bd20c0 3650 if (strcasecmp(pp->ret_type.name, "void") == 0)
4d247254 3651 return regmask;
b2bd20c0 3652
4d247254 3653 return regmask | mxAX;
b2bd20c0 3654}
3655
93b5bd18 3656static int are_ops_same(struct parsed_op *po1, struct parsed_op *po2)
3657{
3658 return po1->op == po2->op && po1->operand_cnt == po2->operand_cnt
3659 && memcmp(po1->operand, po2->operand,
3660 sizeof(po1->operand[0]) * po1->operand_cnt) == 0;
3661}
3662
66bdb2b0 3663static void resolve_branches_parse_calls(int opcnt)
3664{
d4a985bd 3665 static const struct {
3666 const char *name;
3667 enum op_op op;
3668 unsigned int flags;
3669 unsigned int regmask_src;
3670 unsigned int regmask_dst;
3671 } pseudo_ops[] = {
622eb2ef 3672 { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3673 { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3674 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
8c83cc48 3675 { "__CIpow", OPP_CIPOW, OPF_FPOP, mxST0|mxST1, mxST0 },
d4a985bd 3676 };
66bdb2b0 3677 const struct parsed_proto *pp_c;
3678 struct parsed_proto *pp;
3679 struct parsed_data *pd;
3680 struct parsed_op *po;
3681 const char *tmpname;
b2bd20c0 3682 int i, l;
3683 int ret;
66bdb2b0 3684
3685 for (i = 0; i < opcnt; i++)
3686 {
3687 po = &ops[i];
3688 po->bt_i = -1;
3689 po->btj = NULL;
3690
865f1aca 3691 if (po->datap != NULL) {
3692 pp = calloc(1, sizeof(*pp));
3693 my_assert_not(pp, NULL);
3694
3695 ret = parse_protostr(po->datap, pp);
3696 if (ret < 0)
3697 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3698 free(po->datap);
3699 po->datap = NULL;
3700 po->pp = pp;
3701 }
3702
66bdb2b0 3703 if (po->op == OP_CALL) {
3704 pp = NULL;
3705
865f1aca 3706 if (po->pp != NULL)
3707 pp = po->pp;
3708 else if (po->operand[0].type == OPT_LABEL)
3709 {
66bdb2b0 3710 tmpname = opr_name(po, 0);
3711 if (IS_START(tmpname, "loc_"))
3712 ferr(po, "call to loc_*\n");
16057ce1 3713 if (IS(tmpname, "__alloca_probe"))
3714 continue;
d4a985bd 3715
3716 // convert some calls to pseudo-ops
3717 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3718 if (!IS(tmpname, pseudo_ops[l].name))
3719 continue;
3720
3721 po->op = pseudo_ops[l].op;
3722 po->operand_cnt = 0;
3723 po->regmask_src = pseudo_ops[l].regmask_src;
3724 po->regmask_dst = pseudo_ops[l].regmask_dst;
3725 po->flags = pseudo_ops[l].flags;
3726 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3727 break;
3728 }
3729 if (l < ARRAY_SIZE(pseudo_ops))
3730 continue;
3731
66bdb2b0 3732 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3733 if (!g_header_mode && pp_c == NULL)
3734 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3735
3736 if (pp_c != NULL) {
3737 pp = proto_clone(pp_c);
3738 my_assert_not(pp, NULL);
3739 }
3740 }
66bdb2b0 3741
3742 if (pp != NULL) {
3743 if (pp->is_fptr)
3744 check_func_pp(po, pp, "fptr var call");
3745 if (pp->is_noreturn)
3746 po->flags |= OPF_TAIL;
3747 }
3748 po->pp = pp;
3749 continue;
3750 }
3751
3752 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3753 continue;
3754
3755 if (po->operand[0].type == OPT_REGMEM) {
3756 pd = try_resolve_jumptab(i, opcnt);
3757 if (pd == NULL)
3758 goto tailcall;
3759
3760 po->btj = pd;
3761 continue;
3762 }
3763
3764 for (l = 0; l < opcnt; l++) {
3765 if (g_labels[l] != NULL
3766 && IS(po->operand[0].name, g_labels[l]))
3767 {
3768 if (l == i + 1 && po->op == OP_JMP) {
3769 // yet another alignment type..
3770 po->flags |= OPF_RMD|OPF_DONE;
3771 break;
3772 }
3773 add_label_ref(&g_label_refs[l], i);
3774 po->bt_i = l;
3775 break;
3776 }
3777 }
3778
3779 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3780 continue;
3781
3782 if (po->operand[0].type == OPT_LABEL)
3783 // assume tail call
3784 goto tailcall;
3785
3786 ferr(po, "unhandled branch\n");
3787
3788tailcall:
3789 po->op = OP_CALL;
3790 po->flags |= OPF_TAIL;
3791 if (i > 0 && ops[i - 1].op == OP_POP)
3792 po->flags |= OPF_ATAIL;
3793 i--; // reprocess
3794 }
9af2d373 3795}
3796
3797static void scan_prologue_epilogue(int opcnt)
3798{
16057ce1 3799 int ecx_push = 0, esp_sub = 0, pusha = 0;
3800 int sandard_epilogue;
9af2d373 3801 int found;
3802 int i, j, l;
3803
3804 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
3805 && ops[1].op == OP_MOV
3806 && IS(opr_name(&ops[1], 0), "ebp")
3807 && IS(opr_name(&ops[1], 1), "esp"))
3808 {
3809 g_bp_frame = 1;
b2bd20c0 3810 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3811 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
9af2d373 3812 i = 2;
3813
16057ce1 3814 if (ops[i].op == OP_PUSHA) {
3815 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3816 pusha = 1;
3817 i++;
3818 }
3819
3820 if (ops[i].op == OP_SUB && IS(opr_name(&ops[i], 0), "esp")) {
3821 g_stack_fsz = opr_const(&ops[i], 1);
3822 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
9af2d373 3823 i++;
3824 }
3825 else {
3826 // another way msvc builds stack frame..
9af2d373 3827 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3828 g_stack_fsz += 4;
b2bd20c0 3829 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
9af2d373 3830 ecx_push++;
3831 i++;
3832 }
3833 // and another way..
3834 if (i == 2 && ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3835 && ops[i].operand[1].type == OPT_CONST
3836 && ops[i + 1].op == OP_CALL
3837 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3838 {
3839 g_stack_fsz += ops[i].operand[1].val;
b2bd20c0 3840 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
9af2d373 3841 i++;
b2bd20c0 3842 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
9af2d373 3843 i++;
3844 }
3845 }
3846
3847 found = 0;
3848 do {
3849 for (; i < opcnt; i++)
66bdb2b0 3850 if (ops[i].flags & OPF_TAIL)
9af2d373 3851 break;
3852 j = i - 1;
3853 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
66bdb2b0 3854 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3855 break;
3856 i--;
9af2d373 3857 j--;
3858 }
3859
16057ce1 3860 sandard_epilogue = 0;
3861 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
3862 {
3863 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3864 // the standard epilogue is sometimes even used without a sf
3865 if (ops[j - 1].op == OP_MOV
3866 && IS(opr_name(&ops[j - 1], 0), "esp")
3867 && IS(opr_name(&ops[j - 1], 1), "ebp"))
3868 sandard_epilogue = 1;
3869 }
3870 else if (ops[j].op == OP_LEAVE)
9af2d373 3871 {
b2bd20c0 3872 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
16057ce1 3873 sandard_epilogue = 1;
9af2d373 3874 }
66bdb2b0 3875 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
3876 && ops[i].pp->is_noreturn)
3877 {
3878 // on noreturn, msvc sometimes cleans stack, sometimes not
3879 i++;
3880 found = 1;
3881 continue;
3882 }
9af2d373 3883 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3884 ferr(&ops[j], "'pop ebp' expected\n");
3885
16057ce1 3886 if (g_stack_fsz != 0 || sandard_epilogue) {
bfacdc83 3887 if (ops[j].op == OP_LEAVE)
3888 j--;
16057ce1 3889 else if (sandard_epilogue) // mov esp, ebp
9af2d373 3890 {
b2bd20c0 3891 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
bfacdc83 3892 j -= 2;
9af2d373 3893 }
bfacdc83 3894 else if (!(g_ida_func_attr & IDAFA_NORETURN))
9af2d373 3895 {
bfacdc83 3896 ferr(&ops[j], "esp restore expected\n");
9af2d373 3897 }
3898
bfacdc83 3899 if (ecx_push && j >= 0 && ops[j].op == OP_POP
3900 && IS(opr_name(&ops[j], 0), "ecx"))
9af2d373 3901 {
bfacdc83 3902 ferr(&ops[j], "unexpected ecx pop\n");
9af2d373 3903 }
3904 }
3905
16057ce1 3906 if (pusha) {
3907 if (ops[j].op == OP_POPA)
3908 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3909 else
3910 ferr(&ops[j], "popa expected\n");
3911 }
3912
9af2d373 3913 found = 1;
3914 i++;
3915 } while (i < opcnt);
3916
66bdb2b0 3917 if (!found)
3918 ferr(ops, "missing ebp epilogue\n");
9af2d373 3919 return;
3920 }
3921
3922 // non-bp frame
3923 i = 0;
3924 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
b2bd20c0 3925 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
9af2d373 3926 g_stack_fsz += 4;
3927 ecx_push++;
3928 i++;
3929 }
3930
3931 for (; i < opcnt; i++) {
3932 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
3933 break;
3934 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
3935 && ops[i].operand[1].type == OPT_CONST)
3936 {
3937 g_stack_fsz = ops[i].operand[1].val;
b2bd20c0 3938 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
16057ce1 3939 i++;
3940 esp_sub = 1;
3941 break;
3942 }
3943 else if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3944 && ops[i].operand[1].type == OPT_CONST
3945 && ops[i + 1].op == OP_CALL
3946 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3947 {
3948 g_stack_fsz += ops[i].operand[1].val;
3949 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3950 i++;
3951 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3952 i++;
9af2d373 3953 esp_sub = 1;
3954 break;
3955 }
3956 }
3957
3958 if (ecx_push && !esp_sub) {
3959 // could actually be args for a call..
3960 for (; i < opcnt; i++)
3961 if (ops[i].op != OP_PUSH)
3962 break;
3963
3964 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
3965 const struct parsed_proto *pp;
3966 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
3967 j = pp ? pp->argc_stack : 0;
3968 while (i > 0 && j > 0) {
3969 i--;
3970 if (ops[i].op == OP_PUSH) {
b2bd20c0 3971 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
9af2d373 3972 j--;
3973 }
3974 }
3975 if (j != 0)
3976 ferr(&ops[i], "unhandled prologue\n");
3977
3978 // recheck
3979 i = g_stack_fsz = ecx_push = 0;
3980 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3981 if (!(ops[i].flags & OPF_RMD))
3982 break;
3983 g_stack_fsz += 4;
3984 ecx_push++;
3985 i++;
3986 }
3987 }
3988 }
3989
3990 found = 0;
3991 if (ecx_push || esp_sub)
3992 {
3993 g_sp_frame = 1;
3994
9af2d373 3995 do {
3996 for (; i < opcnt; i++)
66bdb2b0 3997 if (ops[i].flags & OPF_TAIL)
9af2d373 3998 break;
fe18df39 3999
9af2d373 4000 j = i - 1;
4001 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
66bdb2b0 4002 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4003 break;
4004 i--;
9af2d373 4005 j--;
4006 }
4007
4008 if (ecx_push > 0) {
4009 for (l = 0; l < ecx_push; l++) {
4010 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
4011 /* pop ecx */;
4012 else if (ops[j].op == OP_ADD
4013 && IS(opr_name(&ops[j], 0), "esp")
4014 && ops[j].operand[1].type == OPT_CONST)
4015 {
4016 /* add esp, N */
5e49b270 4017 l += ops[j].operand[1].val / 4 - 1;
9af2d373 4018 }
4019 else
4020 ferr(&ops[j], "'pop ecx' expected\n");
4021
b2bd20c0 4022 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
9af2d373 4023 j--;
4024 }
4025 if (l != ecx_push)
4026 ferr(&ops[j], "epilogue scan failed\n");
4027
4028 found = 1;
4029 }
4030
4031 if (esp_sub) {
4032 if (ops[j].op != OP_ADD
4033 || !IS(opr_name(&ops[j], 0), "esp")
4034 || ops[j].operand[1].type != OPT_CONST
4035 || ops[j].operand[1].val != g_stack_fsz)
622eb2ef 4036 {
4037 if (ops[i].op == OP_CALL && ops[i].pp != NULL
4038 && ops[i].pp->is_noreturn)
4039 {
4040 // noreturn tailcall with no epilogue
4041 i++;
4042 continue;
4043 }
9af2d373 4044 ferr(&ops[j], "'add esp' expected\n");
622eb2ef 4045 }
9af2d373 4046
b2bd20c0 4047 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
9af2d373 4048 ops[j].operand[1].val = 0; // hack for stack arg scanner
4049 found = 1;
4050 }
4051
4052 i++;
4053 } while (i < opcnt);
66bdb2b0 4054
4055 if (!found)
4056 ferr(ops, "missing esp epilogue\n");
9af2d373 4057 }
4058}
4059
23fd0b11 4060// find an instruction that changed opr before i op
db63af51 4061// *op_i must be set to -1 by the caller
865f1aca 4062// *is_caller is set to 1 if one source is determined to be g_func arg
92d715b6 4063// returns 1 if found, *op_i is then set to origin
865f1aca 4064// returns -1 if multiple origins are found
23fd0b11 4065static int resolve_origin(int i, const struct parsed_opr *opr,
92d715b6 4066 int magic, int *op_i, int *is_caller)
1f84f6b3 4067{
4068 struct label_ref *lr;
4069 int ret = 0;
4070
1f84f6b3 4071 while (1) {
d7857c3a 4072 if (g_labels[i] != NULL) {
1f84f6b3 4073 lr = &g_label_refs[i];
92d715b6 4074 for (; lr != NULL; lr = lr->next) {
4075 check_i(&ops[i], lr->i);
4076 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4077 }
1f84f6b3 4078 if (i > 0 && LAST_OP(i - 1))
4079 return ret;
4080 }
4081
4082 i--;
92d715b6 4083 if (i < 0) {
4084 if (is_caller != NULL)
4085 *is_caller = 1;
1f84f6b3 4086 return -1;
92d715b6 4087 }
1f84f6b3 4088
4089 if (ops[i].cc_scratch == magic)
ebc4dc43 4090 return ret;
1f84f6b3 4091 ops[i].cc_scratch = magic;
4092
4093 if (!(ops[i].flags & OPF_DATA))
4094 continue;
4095 if (!is_opr_modified(opr, &ops[i]))
4096 continue;
23fd0b11 4097
4098 if (*op_i >= 0) {
93b5bd18 4099 if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
ebc4dc43 4100 return ret | 1;
4101
23fd0b11 4102 return -1;
4103 }
4104
4105 *op_i = i;
ebc4dc43 4106 return ret | 1;
23fd0b11 4107 }
4108}
4109
db63af51 4110// find an instruction that previously referenced opr
4111// if multiple results are found - fail
4112// *op_i must be set to -1 by the caller
4113// returns 1 if found, *op_i is then set to referencer insn
4114static int resolve_last_ref(int i, const struct parsed_opr *opr,
4115 int magic, int *op_i)
4116{
4117 struct label_ref *lr;
4118 int ret = 0;
4119
db63af51 4120 while (1) {
4121 if (g_labels[i] != NULL) {
4122 lr = &g_label_refs[i];
4123 for (; lr != NULL; lr = lr->next) {
4124 check_i(&ops[i], lr->i);
4125 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4126 }
4127 if (i > 0 && LAST_OP(i - 1))
4128 return ret;
4129 }
4130
4131 i--;
4132 if (i < 0)
4133 return -1;
4134
4135 if (ops[i].cc_scratch == magic)
4136 return 0;
4137 ops[i].cc_scratch = magic;
4138
4139 if (!is_opr_referenced(opr, &ops[i]))
4140 continue;
4141
4142 if (*op_i >= 0)
4143 return -1;
4144
4145 *op_i = i;
4146 return 1;
4147 }
4148}
4149
16057ce1 4150// adjust datap of all reachable 'op' insns when moving back
4151// returns 1 if at least 1 op was found
4152// returns -1 if path without an op was found
4153static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4154{
4155 struct label_ref *lr;
4156 int ret = 0;
4157
4158 if (ops[i].cc_scratch == magic)
4159 return 0;
4160 ops[i].cc_scratch = magic;
4161
4162 while (1) {
4163 if (g_labels[i] != NULL) {
4164 lr = &g_label_refs[i];
4165 for (; lr != NULL; lr = lr->next) {
4166 check_i(&ops[i], lr->i);
4167 ret |= adjust_prev_op(lr->i, op, magic, datap);
4168 }
4169 if (i > 0 && LAST_OP(i - 1))
4170 return ret;
4171 }
4172
4173 i--;
4174 if (i < 0)
4175 return -1;
4176
4177 if (ops[i].cc_scratch == magic)
4178 return 0;
4179 ops[i].cc_scratch = magic;
4180
4181 if (ops[i].op != op)
4182 continue;
4183
4184 ops[i].datap = datap;
4185 return 1;
4186 }
4187}
4188
db63af51 4189// find next instruction that reads opr
db63af51 4190// *op_i must be set to -1 by the caller
b2bd20c0 4191// on return, *op_i is set to first referencer insn
4192// returns 1 if exactly 1 referencer is found
db63af51 4193static int find_next_read(int i, int opcnt,
4194 const struct parsed_opr *opr, int magic, int *op_i)
4195{
4196 struct parsed_op *po;
4197 int j, ret = 0;
4198
4199 for (; i < opcnt; i++)
4200 {
4201 if (ops[i].cc_scratch == magic)
b2bd20c0 4202 return ret;
db63af51 4203 ops[i].cc_scratch = magic;
4204
4205 po = &ops[i];
4206 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4207 if (po->btj != NULL) {
4208 // jumptable
4209 for (j = 0; j < po->btj->count; j++) {
4210 check_i(po, po->btj->d[j].bt_i);
4211 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4212 magic, op_i);
4213 }
4214 return ret;
4215 }
4216
4217 if (po->flags & OPF_RMD)
4218 continue;
4219 check_i(po, po->bt_i);
4220 if (po->flags & OPF_CJMP) {
b2bd20c0 4221 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
db63af51 4222 if (ret < 0)
4223 return ret;
4224 }
b2bd20c0 4225 else
4226 i = po->bt_i - 1;
db63af51 4227 continue;
4228 }
4229
4230 if (!is_opr_read(opr, po)) {
16057ce1 4231 int full_opr = 1;
4232 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4233 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
acd03176 4234 {
16057ce1 4235 full_opr = po->operand[0].lmod >= opr->lmod;
4236 }
4237 if (is_opr_modified(opr, po) && full_opr) {
db63af51 4238 // it's overwritten
b2bd20c0 4239 return ret;
acd03176 4240 }
db63af51 4241 if (po->flags & OPF_TAIL)
b2bd20c0 4242 return ret;
db63af51 4243 continue;
4244 }
4245
4246 if (*op_i >= 0)
4247 return -1;
4248
4249 *op_i = i;
4250 return 1;
4251 }
4252
4253 return 0;
4254}
4255
16057ce1 4256// find next instruction that reads opr
4257// *op_i must be set to -1 by the caller
4258// on return, *op_i is set to first flag user insn
4259// returns 1 if exactly 1 flag user is found
4260static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4261{
4262 struct parsed_op *po;
4263 int j, ret = 0;
4264
4265 for (; i < opcnt; i++)
4266 {
4267 if (ops[i].cc_scratch == magic)
4268 return ret;
4269 ops[i].cc_scratch = magic;
4270
4271 po = &ops[i];
4272 if (po->op == OP_CALL)
4273 return -1;
4274 if (po->flags & OPF_JMP) {
4275 if (po->btj != NULL) {
4276 // jumptable
4277 for (j = 0; j < po->btj->count; j++) {
4278 check_i(po, po->btj->d[j].bt_i);
4279 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4280 magic, op_i);
4281 }
4282 return ret;
4283 }
4284
4285 if (po->flags & OPF_RMD)
4286 continue;
4287 check_i(po, po->bt_i);
4288 if (po->flags & OPF_CJMP)
4289 goto found;
4290 else
4291 i = po->bt_i - 1;
4292 continue;
4293 }
4294
4295 if (!(po->flags & OPF_CC)) {
4296 if (po->flags & OPF_FLAGS)
4297 // flags changed
4298 return ret;
4299 if (po->flags & OPF_TAIL)
4300 return ret;
4301 continue;
4302 }
4303
4304found:
4305 if (*op_i >= 0)
4306 return -1;
4307
4308 *op_i = i;
4309 return 1;
4310 }
4311
4312 return 0;
4313}
4314
23fd0b11 4315static int try_resolve_const(int i, const struct parsed_opr *opr,
4316 int magic, unsigned int *val)
4317{
4318 int s_i = -1;
92d715b6 4319 int ret;
23fd0b11 4320
92d715b6 4321 ret = resolve_origin(i, opr, magic, &s_i, NULL);
23fd0b11 4322 if (ret == 1) {
4323 i = s_i;
1f84f6b3 4324 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4325 return -1;
4326
4327 *val = ops[i].operand[1].val;
4328 return 1;
4329 }
23fd0b11 4330
4331 return -1;
1f84f6b3 4332}
4333
16057ce1 4334static int resolve_used_bits(int i, int opcnt, int reg,
4335 int *mask, int *is_z_check)
4336{
4337 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4338 int j = -1, k = -1;
4339 int ret;
4340
4341 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4342 if (ret != 1)
4343 return -1;
4344
4345 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4346 if (k != -1) {
4347 fnote(&ops[j], "(first read)\n");
4348 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4349 }
4350
4351 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4352 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4353
4354 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4355 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4356
4357 *mask = ops[j].operand[1].val;
4358 if (ops[j].operand[0].lmod == OPLM_BYTE
4359 && ops[j].operand[0].name[1] == 'h')
4360 {
4361 *mask <<= 8;
4362 }
4363 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4364
4365 *is_z_check = 0;
4366 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4367 if (ret == 1)
4368 *is_z_check = ops[k].pfo == PFO_Z;
4369
4370 return 0;
4371}
4372
93b5bd18 4373static const struct parsed_proto *resolve_deref(int i, int magic,
4374 struct parsed_opr *opr, int level)
4375{
4376 struct parsed_opr opr_s = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
4377 const struct parsed_proto *pp = NULL;
4378 int from_caller = 0;
4379 char s_reg[4];
4380 int offset = 0;
4381 int len = 0;
4382 int j = -1;
4383 int k = -1;
4384 int reg;
4385 int ret;
4386
4387 ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4388 if (ret != 2 || len != strlen(opr->name)) {
4389 ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4390 if (ret != 1 || len != strlen(opr->name))
4391 return NULL;
4392 }
4393
4394 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4395 if (reg < 0)
4396 return NULL;
4397
4398 opr_s.reg = reg;
4399 ret = resolve_origin(i, &opr_s, i + magic, &j, NULL);
4400 if (ret != 1)
4401 return NULL;
4402
4403 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4404 && strlen(ops[j].operand[1].name) == 3
4405 && ops[j].operand[0].lmod == OPLM_DWORD
4406 && ops[j].pp == NULL // no hint
4407 && level == 0)
4408 {
4409 // allow one simple dereference (com/directx)
4410 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4411 ops[j].operand[1].name);
4412 if (reg < 0)
4413 return NULL;
4414 opr_s.reg = reg;
4415 ret = resolve_origin(j, &opr_s, j + magic, &k, NULL);
4416 if (ret != 1)
4417 return NULL;
4418 j = k;
4419 }
4420 if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
4421 return NULL;
4422
4423 if (ops[j].pp != NULL) {
4424 // type hint in asm
4425 pp = ops[j].pp;
4426 }
4427 else if (ops[j].operand[1].type == OPT_REGMEM) {
4428 pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
4429 if (pp == NULL) {
4430 // maybe structure ptr in structure
4431 pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
4432 }
4433 }
4434 else if (ops[j].operand[1].type == OPT_LABEL)
4435 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4436 else if (ops[j].operand[1].type == OPT_REG) {
4437 // maybe arg reg?
4438 k = -1;
4439 ret = resolve_origin(j, &ops[j].operand[1], i + magic,
4440 &k, &from_caller);
4441 if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
4442 for (k = 0; k < g_func_pp->argc; k++) {
4443 if (g_func_pp->arg[k].reg == NULL)
4444 continue;
4445 if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
4446 pp = g_func_pp->arg[k].pp;
4447 break;
4448 }
4449 }
4450 }
4451 }
4452
4453 if (pp == NULL)
4454 return NULL;
4455 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4456 if (offset != 0)
4457 ferr(&ops[j], "expected struct, got '%s %s'\n",
4458 pp->type.name, pp->name);
4459 return NULL;
4460 }
4461
4462 return proto_lookup_struct(g_fhdr, pp->type.name, offset);
4463}
4464
865f1aca 4465static const struct parsed_proto *resolve_icall(int i, int opcnt,
4466 int *pp_i, int *multi_src)
4467{
4468 const struct parsed_proto *pp = NULL;
4469 int search_advice = 0;
865f1aca 4470
4471 *multi_src = 0;
4472 *pp_i = -1;
4473
4474 switch (ops[i].operand[0].type) {
4475 case OPT_REGMEM:
4476 // try to resolve struct member calls
93b5bd18 4477 pp = resolve_deref(i, i + opcnt * 19, &ops[i].operand[0], 0);
4478 if (pp != NULL)
865f1aca 4479 break;
865f1aca 4480 // fallthrough
4481 case OPT_LABEL:
4482 case OPT_OFFSET:
93b5bd18 4483 pp = try_recover_pp(&ops[i], &ops[i].operand[0],
4484 1, &search_advice);
865f1aca 4485 if (!search_advice)
4486 break;
4487 // fallthrough
4488 default:
4489 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4490 pp_i, multi_src);
4491 break;
4492 }
4493
4494 return pp;
4495}
4496
26677139 4497static struct parsed_proto *process_call_early(int i, int opcnt,
4498 int *adj_i)
4499{
4500 struct parsed_op *po = &ops[i];
4501 struct parsed_proto *pp;
4502 int multipath = 0;
4503 int adj = 0;
bfacdc83 4504 int j, ret;
26677139 4505
4506 pp = po->pp;
4507 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4508 // leave for later
4509 return NULL;
4510
4511 // look for and make use of esp adjust
4512 *adj_i = ret = -1;
4513 if (!pp->is_stdcall && pp->argc_stack > 0)
4514 ret = scan_for_esp_adjust(i + 1, opcnt,
ee2361b9 4515 pp->argc_stack * 4, &adj, &multipath, 0);
26677139 4516 if (ret >= 0) {
4517 if (pp->argc_stack > adj / 4)
4518 return NULL;
4519 if (multipath)
4520 return NULL;
bfacdc83 4521 if (ops[ret].op == OP_POP) {
4522 for (j = 1; j < adj / 4; j++) {
4523 if (ops[ret + j].op != OP_POP
4524 || ops[ret + j].operand[0].reg != xCX)
4525 {
4526 return NULL;
4527 }
4528 }
4529 }
26677139 4530 }
4531
4532 *adj_i = ret;
4533 return pp;
4534}
4535
9af2d373 4536static struct parsed_proto *process_call(int i, int opcnt)
4537{
4538 struct parsed_op *po = &ops[i];
4539 const struct parsed_proto *pp_c;
4540 struct parsed_proto *pp;
4541 const char *tmpname;
db63af51 4542 int call_i = -1, ref_i = -1;
26677139 4543 int adj = 0, multipath = 0;
9af2d373 4544 int ret, arg;
4545
4546 tmpname = opr_name(po, 0);
4547 pp = po->pp;
4548 if (pp == NULL)
4549 {
4550 // indirect call
db63af51 4551 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
9af2d373 4552 if (pp_c != NULL) {
4553 if (!pp_c->is_func && !pp_c->is_fptr)
4554 ferr(po, "call to non-func: %s\n", pp_c->name);
4555 pp = proto_clone(pp_c);
4556 my_assert_not(pp, NULL);
26677139 4557 if (multipath)
9af2d373 4558 // not resolved just to single func
4559 pp->is_fptr = 1;
4560
4561 switch (po->operand[0].type) {
4562 case OPT_REG:
4563 // we resolved this call and no longer need the register
4564 po->regmask_src &= ~(1 << po->operand[0].reg);
db63af51 4565
4566 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4567 && ops[call_i].operand[1].type == OPT_LABEL)
4568 {
4569 // no other source users?
e83ea7ed 4570 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
db63af51 4571 &ref_i);
4572 if (ret == 1 && call_i == ref_i) {
4573 // and nothing uses it after us?
4574 ref_i = -1;
b2bd20c0 4575 find_next_read(i + 1, opcnt, &po->operand[0],
4576 i + opcnt * 11, &ref_i);
4577 if (ref_i == -1)
db63af51 4578 // then also don't need the source mov
b2bd20c0 4579 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
db63af51 4580 }
4581 }
9af2d373 4582 break;
4583 case OPT_REGMEM:
4584 pp->is_fptr = 1;
4585 break;
4586 default:
4587 break;
4588 }
4589 }
4590 if (pp == NULL) {
4591 pp = calloc(1, sizeof(*pp));
4592 my_assert_not(pp, NULL);
4593
4594 pp->is_fptr = 1;
ee2361b9 4595 ret = scan_for_esp_adjust(i + 1, opcnt,
bfacdc83 4596 -1, &adj, &multipath, 0);
26677139 4597 if (ret < 0 || adj < 0) {
9af2d373 4598 if (!g_allow_regfunc)
4599 ferr(po, "non-__cdecl indirect call unhandled yet\n");
4600 pp->is_unresolved = 1;
26677139 4601 adj = 0;
9af2d373 4602 }
26677139 4603 adj /= 4;
4604 if (adj > ARRAY_SIZE(pp->arg))
4605 ferr(po, "esp adjust too large: %d\n", adj);
9af2d373 4606 pp->ret_type.name = strdup("int");
26677139 4607 pp->argc = pp->argc_stack = adj;
9af2d373 4608 for (arg = 0; arg < pp->argc; arg++)
4609 pp->arg[arg].type.name = strdup("int");
4610 }
4611 po->pp = pp;
4612 }
4613
4614 // look for and make use of esp adjust
91ca764a 4615 multipath = 0;
9af2d373 4616 ret = -1;
bfacdc83 4617 if (!pp->is_stdcall && pp->argc_stack > 0) {
4618 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
9af2d373 4619 ret = scan_for_esp_adjust(i + 1, opcnt,
bfacdc83 4620 adj_expect, &adj, &multipath, 0);
4621 }
9af2d373 4622 if (ret >= 0) {
4623 if (pp->is_vararg) {
26677139 4624 if (adj / 4 < pp->argc_stack) {
4625 fnote(po, "(this call)\n");
4626 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
4627 adj, pp->argc_stack * 4);
4628 }
9af2d373 4629 // modify pp to make it have varargs as normal args
4630 arg = pp->argc;
26677139 4631 pp->argc += adj / 4 - pp->argc_stack;
9af2d373 4632 for (; arg < pp->argc; arg++) {
4633 pp->arg[arg].type.name = strdup("int");
4634 pp->argc_stack++;
4635 }
4636 if (pp->argc > ARRAY_SIZE(pp->arg))
4637 ferr(po, "too many args for '%s'\n", tmpname);
4638 }
26677139 4639 if (pp->argc_stack > adj / 4) {
9af2d373 4640 fnote(po, "(this call)\n");
4641 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
26677139 4642 tmpname, pp->argc_stack * 4, adj);
9af2d373 4643 }
4644
ee2361b9 4645 scan_for_esp_adjust(i + 1, opcnt,
4646 pp->argc_stack * 4, &adj, &multipath, 1);
9af2d373 4647 }
4648 else if (pp->is_vararg)
4649 ferr(po, "missing esp_adjust for vararg func '%s'\n",
4650 pp->name);
4651
4652 return pp;
4653}
4654
30620174 4655static int collect_call_args_no_push(int i, struct parsed_proto *pp,
4656 int *regmask_ffca)
4657{
4658 struct parsed_op *po;
4659 int offset = 0;
4660 int base_arg;
4661 int j, arg;
4662 int ret;
4663
4664 for (base_arg = 0; base_arg < pp->argc; base_arg++)
4665 if (pp->arg[base_arg].reg == NULL)
4666 break;
4667
4668 for (j = i; j > 0; )
4669 {
4670 ferr_assert(&ops[j], g_labels[j] == NULL);
4671 j--;
4672
4673 po = &ops[j];
4674 ferr_assert(po, po->op != OP_PUSH);
4675 if (po->op == OP_FST)
4676 {
4677 if (po->operand[0].type != OPT_REGMEM)
4678 continue;
4679 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
4680 if (ret != 0)
4681 continue;
4682 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3))
4683 ferr(po, "bad offset %d (%d args)\n", offset, pp->argc_stack);
4684
4685 arg = base_arg + offset / 4;
4686 po->p_argnext = -1;
4687 po->p_argnum = arg + 1;
4688 ferr_assert(po, pp->arg[arg].datap == NULL);
4689 pp->arg[arg].datap = po;
4690 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
4691 if (regmask_ffca != NULL)
4692 *regmask_ffca |= 1 << arg;
4693 }
4694 else if (po->op == OP_SUB && po->operand[0].reg == xSP
4695 && po->operand[1].type == OPT_CONST)
4696 {
4697 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4698 break;
4699 }
4700 }
4701
4702 for (arg = base_arg; arg < pp->argc; arg++) {
4703 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
4704 po = pp->arg[arg].datap;
4705 if (po == NULL)
4706 ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
4707 if (po->operand[0].lmod == OPLM_QWORD)
4708 arg++;
4709 }
4710
4711 return 0;
4712}
4713
4714static int collect_call_args_early(int i, struct parsed_proto *pp,
4715 int *regmask, int *regmask_ffca)
26677139 4716{
30620174 4717 struct parsed_op *po;
26677139 4718 int arg, ret;
4719 int j;
4720
4721 for (arg = 0; arg < pp->argc; arg++)
4722 if (pp->arg[arg].reg == NULL)
4723 break;
4724
4725 // first see if it can be easily done
4726 for (j = i; j > 0 && arg < pp->argc; )
4727 {
4728 if (g_labels[j] != NULL)
4729 return -1;
4730 j--;
4731
30620174 4732 po = &ops[j];
4733 if (po->op == OP_CALL)
26677139 4734 return -1;
30620174 4735 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
26677139 4736 return -1;
30620174 4737 else if (po->op == OP_POP)
26677139 4738 return -1;
30620174 4739 else if (po->flags & OPF_CJMP)
26677139 4740 return -1;
30620174 4741 else if (po->op == OP_PUSH) {
4742 if (po->flags & (OPF_FARG|OPF_FARGNR))
26677139 4743 return -1;
622eb2ef 4744 if (!g_header_mode) {
30620174 4745 ret = scan_for_mod(po, j + 1, i, 1);
622eb2ef 4746 if (ret >= 0)
4747 return -1;
4748 }
26677139 4749
4750 if (pp->arg[arg].type.is_va_list)
4751 return -1;
4752
4753 // next arg
4754 for (arg++; arg < pp->argc; arg++)
4755 if (pp->arg[arg].reg == NULL)
4756 break;
4757 }
30620174 4758 else if (po->op == OP_SUB && po->operand[0].reg == xSP
4759 && po->operand[1].type == OPT_CONST)
4760 {
4761 if (po->flags & (OPF_RMD|OPF_DONE))
4762 return -1;
4763 if (po->operand[1].val != pp->argc_stack * 4)
4764 ferr(po, "unexpected esp adjust: %d\n",
4765 po->operand[1].val * 4);
4766 ferr_assert(po, pp->argc - arg == pp->argc_stack);
4767 return collect_call_args_no_push(i, pp, regmask_ffca);
4768 }
26677139 4769 }
4770
4771 if (arg < pp->argc)
4772 return -1;
4773
4774 // now do it
4775 for (arg = 0; arg < pp->argc; arg++)
4776 if (pp->arg[arg].reg == NULL)
4777 break;
4778
4779 for (j = i; j > 0 && arg < pp->argc; )
4780 {
4781 j--;
4782
4783 if (ops[j].op == OP_PUSH)
4784 {
4785 ops[j].p_argnext = -1;
4786 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
4787 pp->arg[arg].datap = &ops[j];
4788
30620174 4789 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
26677139 4790 *regmask |= 1 << ops[j].operand[0].reg;
4791
5e49b270 4792 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
26677139 4793 ops[j].flags &= ~OPF_RSAVE;
4794
4795 // next arg
4796 for (arg++; arg < pp->argc; arg++)
4797 if (pp->arg[arg].reg == NULL)
4798 break;
4799 }
4800 }
4801
4802 return 0;
4803}
4804
8c83cc48 4805static int sync_argnum(struct parsed_op *po, int argnum)
4806{
4807 struct parsed_op *po_tmp;
4808
4809 // see if other branches don't have higher argnum
4810 for (po_tmp = po; po_tmp != NULL; ) {
4811 if (argnum < po_tmp->p_argnum)
4812 argnum = po_tmp->p_argnum;
4813 // note: p_argnext is active on current collect_call_args only
4814 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
4815 }
4816
4817 // make all argnums consistent
4818 for (po_tmp = po; po_tmp != NULL; ) {
4819 if (po_tmp->p_argnum != 0)
4820 po_tmp->p_argnum = argnum;
4821 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
4822 }
4823
4824 return argnum;
4825}
4826
89ff3147 4827static int collect_call_args_r(struct parsed_op *po, int i,
8c83cc48 4828 struct parsed_proto *pp, int *regmask, int *arg_grp,
4829 int arg, int argnum, int magic, int need_op_saving, int may_reuse)
e56ab892 4830{
4831 struct parsed_proto *pp_tmp;
3a5101d7 4832 struct parsed_op *po_tmp;
e56ab892 4833 struct label_ref *lr;
2b43685d 4834 int need_to_save_current;
3a5101d7 4835 int arg_grp_current = 0;
4836 int save_args_seen = 0;
e56ab892 4837 int ret = 0;
5f70a34f 4838 int reg;
23fd0b11 4839 char buf[32];
4840 int j, k;
e56ab892 4841
a3684be1 4842 if (i < 0) {
a2c1d768 4843 ferr(po, "dead label encountered\n");
a3684be1 4844 return -1;
4845 }
e56ab892 4846
8c83cc48 4847 for (; arg < pp->argc; arg++, argnum++)
e56ab892 4848 if (pp->arg[arg].reg == NULL)
4849 break;
a3684be1 4850 magic = (magic & 0xffffff) | (arg << 24);
e56ab892 4851
89ff3147 4852 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
e56ab892 4853 {
a3684be1 4854 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
4855 if (ops[j].cc_scratch != magic) {
4856 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
4857 pp->name);
4858 return -1;
4859 }
4860 // ok: have already been here
4861 return 0;
4862 }
4863 ops[j].cc_scratch = magic;
4864
d7857c3a 4865 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
e56ab892 4866 lr = &g_label_refs[j];
4867 if (lr->next != NULL)
4868 need_op_saving = 1;
a652aa9f 4869 for (; lr->next; lr = lr->next) {
92d715b6 4870 check_i(&ops[j], lr->i);
5c024ef7 4871 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
a652aa9f 4872 may_reuse = 1;
8c83cc48 4873 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
4874 arg, argnum, magic, need_op_saving, may_reuse);
a3684be1 4875 if (ret < 0)
4876 return ret;
a652aa9f 4877 }
e56ab892 4878
92d715b6 4879 check_i(&ops[j], lr->i);
5c024ef7 4880 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
a652aa9f 4881 may_reuse = 1;
de50b98b 4882 if (j > 0 && LAST_OP(j - 1)) {
e56ab892 4883 // follow last branch in reverse
4884 j = lr->i;
4885 continue;
4886 }
4887 need_op_saving = 1;
8c83cc48 4888 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
4889 arg, argnum, magic, need_op_saving, may_reuse);
a3684be1 4890 if (ret < 0)
4891 return ret;
e56ab892 4892 }
4893 j--;
4894
4895 if (ops[j].op == OP_CALL)
4896 {
89ff3147 4897 if (pp->is_unresolved)
4898 break;
4899
092f64e1 4900 pp_tmp = ops[j].pp;
e56ab892 4901 if (pp_tmp == NULL)
7ae48d73 4902 ferr(po, "arg collect hit unparsed call '%s'\n",
4903 ops[j].operand[0].name);
a652aa9f 4904 if (may_reuse && pp_tmp->argc_stack > 0)
de50b98b 4905 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
4906 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
e56ab892 4907 }
fdd5548a 4908 // esp adjust of 0 means we collected it before
4909 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
4910 && (ops[j].operand[1].type != OPT_CONST
4911 || ops[j].operand[1].val != 0))
4912 {
89ff3147 4913 if (pp->is_unresolved)
4914 break;
4915
2b70f6d3 4916 fnote(po, "(this call)\n");
4917 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
fdd5548a 4918 arg, pp->argc, ops[j].operand[1].val);
de50b98b 4919 }
5e49b270 4920 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
9af2d373 4921 {
89ff3147 4922 if (pp->is_unresolved)
4923 break;
4924
2b70f6d3 4925 fnote(po, "(this call)\n");
4926 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
de50b98b 4927 }
5c024ef7 4928 else if (ops[j].flags & OPF_CJMP)
de50b98b 4929 {
89ff3147 4930 if (pp->is_unresolved)
4931 break;
4932
a652aa9f 4933 may_reuse = 1;
de50b98b 4934 }
91ca764a 4935 else if (ops[j].op == OP_PUSH
4936 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
e56ab892 4937 {
89ff3147 4938 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
4939 break;
4940
3a5101d7 4941 ops[j].p_argnext = -1;
4942 po_tmp = pp->arg[arg].datap;
4943 if (po_tmp != NULL)
4944 ops[j].p_argnext = po_tmp - ops;
e56ab892 4945 pp->arg[arg].datap = &ops[j];
3a5101d7 4946
8c83cc48 4947 argnum = sync_argnum(&ops[j], argnum);
4948
2b43685d 4949 need_to_save_current = 0;
5f70a34f 4950 reg = -1;
4951 if (ops[j].operand[0].type == OPT_REG)
4952 reg = ops[j].operand[0].reg;
4953
e56ab892 4954 if (!need_op_saving) {
89ff3147 4955 ret = scan_for_mod(&ops[j], j + 1, i, 1);
2b43685d 4956 need_to_save_current = (ret >= 0);
e56ab892 4957 }
2b43685d 4958 if (need_op_saving || need_to_save_current) {
8c83cc48 4959 // mark this arg as one that needs operand saving
4960 pp->arg[arg].is_saved = 1;
3a5101d7 4961
8c83cc48 4962 if (save_args_seen & (1 << (argnum - 1))) {
3a5101d7 4963 save_args_seen = 0;
4964 arg_grp_current++;
4965 if (arg_grp_current >= MAX_ARG_GRP)
4966 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
8c83cc48 4967 argnum, pp->name);
3a5101d7 4968 }
e56ab892 4969 }
5f70a34f 4970 else if (ops[j].p_argnum == 0)
e56ab892 4971 ops[j].flags |= OPF_RMD;
4972
a652aa9f 4973 // some PUSHes are reused by different calls on other branches,
de50b98b 4974 // but that can't happen if we didn't branch, so they
4975 // can be removed from future searches (handles nested calls)
a652aa9f 4976 if (!may_reuse)
9af2d373 4977 ops[j].flags |= OPF_FARGNR;
de50b98b 4978
9af2d373 4979 ops[j].flags |= OPF_FARG;
da87ae38 4980 ops[j].flags &= ~OPF_RSAVE;
4981
23fd0b11 4982 // check for __VALIST
04abc5d6 4983 if (!pp->is_unresolved && g_func_pp != NULL
4984 && pp->arg[arg].type.is_va_list)
4985 {
23fd0b11 4986 k = -1;
92d715b6 4987 ret = resolve_origin(j, &ops[j].operand[0],
4988 magic + 1, &k, NULL);
5f70a34f 4989 if (ret == 1 && k >= 0)
23fd0b11 4990 {
5f70a34f 4991 if (ops[k].op == OP_LEA) {
acd03176 4992 if (!g_func_pp->is_vararg)
4993 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
4994 g_func_pp->name);
4995
5f70a34f 4996 snprintf(buf, sizeof(buf), "arg_%X",
4997 g_func_pp->argc_stack * 4);
acd03176 4998 if (strstr(ops[k].operand[1].name, buf)
4999 || strstr(ops[k].operand[1].name, "arglist"))
5f70a34f 5000 {
b2bd20c0 5001 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
5002 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
8c83cc48 5003 pp->arg[arg].is_saved = 0;
5f70a34f 5004 reg = -1;
5005 }
5006 else
acd03176 5007 ferr(&ops[k], "va_list arg detection failed\n");
5f70a34f 5008 }
5009 // check for va_list from g_func_pp arg too
5010 else if (ops[k].op == OP_MOV
5011 && is_stack_access(&ops[k], &ops[k].operand[1]))
5012 {
5013 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5014 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5015 if (ret >= 0) {
5e49b270 5016 ops[k].flags |= OPF_RMD | OPF_DONE;
5f70a34f 5017 ops[j].flags |= OPF_RMD;
5018 ops[j].p_argpass = ret + 1;
8c83cc48 5019 pp->arg[arg].is_saved = 0;
5f70a34f 5020 reg = -1;
5021 }
5022 }
23fd0b11 5023 }
5024 }
5025
8c83cc48 5026 if (pp->arg[arg].is_saved) {
5027 ops[j].flags &= ~OPF_RMD;
5028 ops[j].p_argnum = argnum;
5029 }
23fd0b11 5030
5031 // tracking reg usage
5f70a34f 5032 if (reg >= 0)
5033 *regmask |= 1 << reg;
23fd0b11 5034
89ff3147 5035 arg++;
8c83cc48 5036 argnum++;
89ff3147 5037 if (!pp->is_unresolved) {
5038 // next arg
8c83cc48 5039 for (; arg < pp->argc; arg++, argnum++)
89ff3147 5040 if (pp->arg[arg].reg == NULL)
5041 break;
5042 }
a3684be1 5043 magic = (magic & 0xffffff) | (arg << 24);
e56ab892 5044 }
3a5101d7 5045
5046 if (ops[j].p_arggrp > arg_grp_current) {
5047 save_args_seen = 0;
5048 arg_grp_current = ops[j].p_arggrp;
5049 }
5050 if (ops[j].p_argnum > 0)
5051 save_args_seen |= 1 << (ops[j].p_argnum - 1);
e56ab892 5052 }
5053
5054 if (arg < pp->argc) {
5055 ferr(po, "arg collect failed for '%s': %d/%d\n",
5056 pp->name, arg, pp->argc);
89ff3147 5057 return -1;
e56ab892 5058 }
89ff3147 5059
3a5101d7 5060 if (arg_grp_current > *arg_grp)
5061 *arg_grp = arg_grp_current;
5062
89ff3147 5063 return arg;
5064}
5065
5066static int collect_call_args(struct parsed_op *po, int i,
8c83cc48 5067 struct parsed_proto *pp, int *regmask, int magic)
89ff3147 5068{
3a5101d7 5069 // arg group is for cases when pushes for
5070 // multiple funcs are going on
5071 struct parsed_op *po_tmp;
3a5101d7 5072 int arg_grp = 0;
89ff3147 5073 int ret;
5074 int a;
5075
8c83cc48 5076 ret = collect_call_args_r(po, i, pp, regmask, &arg_grp,
5077 0, 1, magic, 0, 0);
89ff3147 5078 if (ret < 0)
5079 return ret;
5080
3a5101d7 5081 if (arg_grp != 0) {
5082 // propagate arg_grp
5083 for (a = 0; a < pp->argc; a++) {
5084 if (pp->arg[a].reg != NULL)
5085 continue;
5086
5087 po_tmp = pp->arg[a].datap;
5088 while (po_tmp != NULL) {
5089 po_tmp->p_arggrp = arg_grp;
8c83cc48 5090 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
3a5101d7 5091 }
5092 }
5093 }
3a5101d7 5094
89ff3147 5095 if (pp->is_unresolved) {
5096 pp->argc += ret;
5097 pp->argc_stack += ret;
5098 for (a = 0; a < pp->argc; a++)
5099 if (pp->arg[a].type.name == NULL)
5100 pp->arg[a].type.name = strdup("int");
5101 }
5102
e56ab892 5103 return ret;
5104}
5105
b2bd20c0 5106static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5107 int regmask_now, int *regmask,
5108 int regmask_save_now, int *regmask_save,
5109 int *regmask_init, int regmask_arg)
5110{
5111 struct parsed_op *po;
5112 int already_saved;
5113 int regmask_new;
5114 int regmask_op;
5115 int flags_set;
5116 int ret, reg;
5117 int j;
5118
5119 for (; i < opcnt; i++)
5120 {
5121 po = &ops[i];
5122 if (cbits[i >> 3] & (1 << (i & 7)))
5123 return;
5124 cbits[i >> 3] |= (1 << (i & 7));
5125
5126 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5127 if (po->flags & (OPF_RMD|OPF_DONE))
5128 continue;
5129 if (po->btj != NULL) {
5130 for (j = 0; j < po->btj->count; j++) {
5131 check_i(po, po->btj->d[j].bt_i);
5132 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5133 regmask_now, regmask, regmask_save_now, regmask_save,
5134 regmask_init, regmask_arg);
5135 }
5136 return;
5137 }
5138
5139 check_i(po, po->bt_i);
5140 if (po->flags & OPF_CJMP)
5141 reg_use_pass(po->bt_i, opcnt, cbits,
5142 regmask_now, regmask, regmask_save_now, regmask_save,
5143 regmask_init, regmask_arg);
5144 else
5145 i = po->bt_i - 1;
5146 continue;
5147 }
5148
5149 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5150 && !g_func_pp->is_userstack
5151 && po->operand[0].type == OPT_REG)
5152 {
5153 reg = po->operand[0].reg;
5154 ferr_assert(po, reg >= 0);
5155
5156 already_saved = 0;
5157 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5158 if (regmask_now & (1 << reg)) {
5159 already_saved = regmask_save_now & (1 << reg);
5160 flags_set = OPF_RSAVE | OPF_DONE;
5161 }
5162
93b5bd18 5163 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, 0);
b2bd20c0 5164 if (ret == 1) {
93b5bd18 5165 scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5166 reg, 0, 0, flags_set);
b2bd20c0 5167 }
5168 else {
5169 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5170 if (ret == 1) {
5171 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5172 flags_set);
5173 }
5174 }
5175 if (ret == 1) {
5176 ferr_assert(po, !already_saved);
5177 po->flags |= flags_set;
5178
5179 if (regmask_now & (1 << reg)) {
5180 regmask_save_now |= (1 << reg);
5181 *regmask_save |= regmask_save_now;
5182 }
5183 continue;
5184 }
5185 }
5186 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5187 reg = po->operand[0].reg;
5188 ferr_assert(po, reg >= 0);
5189
5190 if (regmask_save_now & (1 << reg))
5191 regmask_save_now &= ~(1 << reg);
5192 else
5193 regmask_now &= ~(1 << reg);
5194 continue;
5195 }
5196 else if (po->op == OP_CALL) {
5197 if ((po->regmask_dst & (1 << xAX))
5198 && !(po->regmask_dst & (1 << xDX)))
5199 {
5200 if (po->flags & OPF_TAIL)
5201 // don't need eax, will do "return f();" or "f(); return;"
5202 po->regmask_dst &= ~(1 << xAX);
5203 else {
5204 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
5205 j = -1;
5206 find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
5207 if (j == -1)
5208 // not used
5209 po->regmask_dst &= ~(1 << xAX);
5210 }
5211 }
fe18df39 5212
5213 // not "full stack" mode and have something in stack
5214 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5215 ferr(po, "float stack is not empty on func call\n");
b2bd20c0 5216 }
5217
5218 if (po->flags & OPF_NOREGS)
5219 continue;
5220
acd03176 5221 // if incomplete register is used, clear it on init to avoid
5222 // later use of uninitialized upper part in some situations
5223 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5224 && po->operand[0].lmod != OPLM_DWORD)
5225 {
5226 reg = po->operand[0].reg;
5227 ferr_assert(po, reg >= 0);
5228
5229 if (!(regmask_now & (1 << reg)))
5230 *regmask_init |= 1 << reg;
5231 }
5232
b2bd20c0 5233 regmask_op = po->regmask_src | po->regmask_dst;
5234
5235 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5236 regmask_new &= ~(1 << xSP);
5237 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5238 regmask_new &= ~(1 << xBP);
5239
b2bd20c0 5240 if (regmask_new != 0)
5241 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5242
5243 if (regmask_op & (1 << xBP)) {
5244 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5245 if (po->regmask_dst & (1 << xBP))
5246 // compiler decided to drop bp frame and use ebp as scratch
5247 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5248 else
5249 regmask_op &= ~(1 << xBP);
5250 }
5251 }
5252
622eb2ef 5253 if (po->flags & OPF_FPUSH) {
5254 if (regmask_now & mxST1)
5255 regmask_now |= mxSTa; // switch to "full stack" mode
5256 if (regmask_now & mxSTa)
5257 po->flags |= OPF_FSHIFT;
5258 if (!(regmask_now & mxST7_2)) {
5259 regmask_now =
5260 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5261 }
5262 }
5263
b2bd20c0 5264 regmask_now |= regmask_op;
5265 *regmask |= regmask_now;
5266
d4a985bd 5267 // released regs
5268 if (po->flags & OPF_FPOP) {
fe18df39 5269 if ((regmask_now & mxSTa) == 0)
d4a985bd 5270 ferr(po, "float pop on empty stack?\n");
fe18df39 5271 if (regmask_now & (mxST7_2 | mxST1))
d4a985bd 5272 po->flags |= OPF_FSHIFT;
fe18df39 5273 if (!(regmask_now & mxST7_2)) {
5274 regmask_now =
5275 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5276 }
d4a985bd 5277 }
5278
5279 if (po->flags & OPF_TAIL) {
16057ce1 5280 if (!(regmask_now & mxST7_2)) {
5281 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5282 if (!(regmask_now & mxST0))
5283 ferr(po, "no st0 on float return, mask: %x\n",
5284 regmask_now);
5285 }
5286 else if (regmask_now & mxST1_0)
5287 ferr(po, "float regs on tail: %x\n", regmask_now);
5288 }
4d247254 5289
5290 // there is support for "conditional tailcall", sort of
5291 if (!(po->flags & OPF_CC))
5292 return;
d4a985bd 5293 }
b2bd20c0 5294 }
5295}
5296
89ff3147 5297static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5298{
5299 int i;
5300
5301 for (i = 0; i < pp->argc; i++)
5302 if (pp->arg[i].reg == NULL)
5303 break;
5304
5305 if (pp->argc_stack)
5306 memmove(&pp->arg[i + 1], &pp->arg[i],
5307 sizeof(pp->arg[0]) * pp->argc_stack);
5308 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5309 pp->arg[i].reg = strdup(reg);
5310 pp->arg[i].type.name = strdup("int");
5311 pp->argc++;
5312 pp->argc_reg++;
5313}
5314
04f8a628 5315static void output_std_flags(FILE *fout, struct parsed_op *po,
5316 int *pfomask, const char *dst_opr_text)
5317{
5318 if (*pfomask & (1 << PFO_Z)) {
5319 fprintf(fout, "\n cond_z = (%s%s == 0);",
5320 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5321 *pfomask &= ~(1 << PFO_Z);
5322 }
5323 if (*pfomask & (1 << PFO_S)) {
5324 fprintf(fout, "\n cond_s = (%s%s < 0);",
5325 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5326 *pfomask &= ~(1 << PFO_S);
5327 }
5328}
5329
c0de9015 5330enum {
5331 OPP_FORCE_NORETURN = (1 << 0),
5332 OPP_SIMPLE_ARGS = (1 << 1),
5333 OPP_ALIGN = (1 << 2),
5334};
5335
c0050df6 5336static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
c0de9015 5337 int flags)
c0050df6 5338{
c0de9015 5339 const char *cconv = "";
5340
c0050df6 5341 if (pp->is_fastcall)
c0de9015 5342 cconv = "__fastcall ";
c0050df6 5343 else if (pp->is_stdcall && pp->argc_reg == 0)
c0de9015 5344 cconv = "__stdcall ";
5345
5346 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5347
5348 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
c0050df6 5349 fprintf(fout, "noreturn ");
5350}
5351
c0de9015 5352static void output_pp(FILE *fout, const struct parsed_proto *pp,
5353 int flags)
5354{
5355 int i;
5356
5357 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5358 pp->ret_type.name);
5359 if (pp->is_fptr)
5360 fprintf(fout, "(");
5361 output_pp_attrs(fout, pp, flags);
5362 if (pp->is_fptr)
5363 fprintf(fout, "*");
5364 fprintf(fout, "%s", pp->name);
5365 if (pp->is_fptr)
5366 fprintf(fout, ")");
5367
5368 fprintf(fout, "(");
5369 for (i = 0; i < pp->argc; i++) {
5370 if (i > 0)
5371 fprintf(fout, ", ");
93b5bd18 5372 if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
5373 && !(flags & OPP_SIMPLE_ARGS))
5374 {
c0de9015 5375 // func pointer
93b5bd18 5376 output_pp(fout, pp->arg[i].pp, 0);
c0de9015 5377 }
5378 else if (pp->arg[i].type.is_retreg) {
5379 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
5380 }
5381 else {
5382 fprintf(fout, "%s", pp->arg[i].type.name);
5383 if (!pp->is_fptr)
5384 fprintf(fout, " a%d", i + 1);
5385 }
5386 }
5387 if (pp->is_vararg) {
5388 if (i > 0)
5389 fprintf(fout, ", ");
5390 fprintf(fout, "...");
5391 }
5392 fprintf(fout, ")");
5393}
5394
3a5101d7 5395static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
5396{
5397 char buf1[16];
5398
5399 buf1[0] = 0;
5400 if (grp > 0)
5401 snprintf(buf1, sizeof(buf1), "%d", grp);
5402 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
5403
5404 return buf;
5405}
5406
9af2d373 5407static void gen_x_cleanup(int opcnt);
5408
91977a1c 5409static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
5410{
69a3cdfc 5411 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
850c9265 5412 struct parsed_opr *last_arith_dst = NULL;
3ebea2cf 5413 char buf1[256], buf2[256], buf3[256], cast[64];
ddaf8bd7 5414 struct parsed_proto *pp, *pp_tmp;
4c45fa73 5415 struct parsed_data *pd;
3a5101d7 5416 int save_arg_vars[MAX_ARG_GRP] = { 0, };
b2bd20c0 5417 unsigned char cbits[MAX_OPS / 8];
497a6d6b 5418 const char *float_type;
fe18df39 5419 const char *float_st0;
5420 const char *float_st1;
5421 int need_float_stack = 0;
16057ce1 5422 int need_float_sw = 0; // status word
108e9fe3 5423 int need_tmp_var = 0;
2fe80fdb 5424 int need_tmp64 = 0;
fe18df39 5425 int cond_vars = 0;
91977a1c 5426 int had_decl = 0;
3ebea2cf 5427 int label_pending = 0;
497a6d6b 5428 int need_double = 0;
16057ce1 5429 int regmask_save = 0; // used regs saved/restored in this func
b2bd20c0 5430 int regmask_arg; // regs from this function args (fastcall, etc)
5431 int regmask_ret; // regs needed on ret
25a330eb 5432 int regmask_now; // temp
5433 int regmask_init = 0; // regs that need zero initialization
5434 int regmask_pp = 0; // regs used in complex push-pop graph
30620174 5435 int regmask_ffca = 0; // float function call args
25a330eb 5436 int regmask = 0; // used regs
940e8e66 5437 int pfomask = 0;
64c59faf 5438 int found = 0;
fe18df39 5439 int dead_dst;
91977a1c 5440 int no_output;
4c45fa73 5441 int i, j, l;
91977a1c 5442 int arg;
91977a1c 5443 int reg;
5444 int ret;
5445
1bafb621 5446 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
a2c1d768 5447 g_stack_frame_used = 0;
226e8df1 5448 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
5449 regmask_init = g_regmask_init;
91977a1c 5450
36595fd2 5451 g_func_pp = proto_parse(fhdr, funcn, 0);
bd96f656 5452 if (g_func_pp == NULL)
91977a1c 5453 ferr(ops, "proto_parse failed for '%s'\n", funcn);
5454
b2bd20c0 5455 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
5456 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
5457
91977a1c 5458 // pass1:
87bf6cec 5459 // - resolve all branches
66bdb2b0 5460 // - parse calls with labels
5461 resolve_branches_parse_calls(opcnt);
840257f6 5462
66bdb2b0 5463 // pass2:
5464 // - handle ebp/esp frame, remove ops related to it
5465 scan_prologue_epilogue(opcnt);
87bf6cec 5466
5467 // pass3:
a2c1d768 5468 // - remove dead labels
b2bd20c0 5469 // - set regs needed at ret
1bafb621 5470 for (i = 0; i < opcnt; i++)
5471 {
d7857c3a 5472 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
5473 free(g_labels[i]);
5474 g_labels[i] = NULL;
5475 }
b2bd20c0 5476
5477 if (ops[i].op == OP_RET)
5478 ops[i].regmask_src |= regmask_ret;
66bdb2b0 5479 }
a2c1d768 5480
66bdb2b0 5481 // pass4:
5482 // - process trivial calls
5483 for (i = 0; i < opcnt; i++)
5484 {
69a3cdfc 5485 po = &ops[i];
5e49b270 5486 if (po->flags & (OPF_RMD|OPF_DONE))
91977a1c 5487 continue;
850c9265 5488
d4e3b5db 5489 if (po->op == OP_CALL)
26677139 5490 {
5491 pp = process_call_early(i, opcnt, &j);
5492 if (pp != NULL) {
30620174 5493 if (!(po->flags & OPF_ATAIL)) {
26677139 5494 // since we know the args, try to collect them
30620174 5495 ret = collect_call_args_early(i, pp, &regmask, &regmask_ffca);
5496 if (ret != 0)
26677139 5497 pp = NULL;
30620174 5498 }
26677139 5499 }
5500
5501 if (pp != NULL) {
5502 if (j >= 0) {
5503 // commit esp adjust
5e49b270 5504 if (ops[j].op != OP_POP)
5505 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
bfacdc83 5506 else {
5507 for (l = 0; l < pp->argc_stack; l++)
b2bd20c0 5508 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
bfacdc83 5509 }
26677139 5510 }
5511
5512 if (strstr(pp->ret_type.name, "int64"))
5513 need_tmp64 = 1;
5514
5515 po->flags |= OPF_DONE;
5516 }
5517 }
5518 }
5519
66bdb2b0 5520 // pass5:
b2bd20c0 5521 // - process calls, stage 2
5522 // - handle some push/pop pairs
5523 // - scan for STD/CLD, propagate DF
16057ce1 5524 // - try to resolve needed x87 status word bits
26677139 5525 for (i = 0; i < opcnt; i++)
5526 {
16057ce1 5527 int mask, z_check;
5528
26677139 5529 po = &ops[i];
b2bd20c0 5530 if (po->flags & OPF_RMD)
26677139 5531 continue;
5532
b2bd20c0 5533 if (po->op == OP_CALL)
69a3cdfc 5534 {
b2bd20c0 5535 if (!(po->flags & OPF_DONE)) {
5536 pp = process_call(i, opcnt);
91977a1c 5537
b2bd20c0 5538 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
5539 // since we know the args, collect them
8c83cc48 5540 collect_call_args(po, i, pp, &regmask, i + opcnt * 2);
b2bd20c0 5541 }
5542 // for unresolved, collect after other passes
89ff3147 5543 }
2b43685d 5544
b2bd20c0 5545 pp = po->pp;
5546 ferr_assert(po, pp != NULL);
5547
5548 po->regmask_src |= get_pp_arg_regmask_src(pp);
5549 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
5550
d4a985bd 5551 if (po->regmask_dst & mxST0)
5552 po->flags |= OPF_FPUSH;
5553
2b43685d 5554 if (strstr(pp->ret_type.name, "int64"))
2fe80fdb 5555 need_tmp64 = 1;
b2bd20c0 5556
5557 continue;
91977a1c 5558 }
b2bd20c0 5559
5560 if (po->flags & OPF_DONE)
5561 continue;
5562
16057ce1 5563 switch (po->op) {
5564 case OP_PUSH:
5565 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
5566 && po->operand[0].type == OPT_CONST)
5567 {
5568 scan_for_pop_const(i, opcnt, i + opcnt * 12);
5569 }
5570 break;
5571
5572 case OP_POP:
e83ea7ed 5573 scan_pushes_for_pop(i, opcnt, &regmask_pp);
16057ce1 5574 break;
5575
5576 case OP_STD:
b2bd20c0 5577 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
5578 scan_propagate_df(i + 1, opcnt);
16057ce1 5579 break;
5580
5581 case OP_FNSTSW:
5582 need_float_sw = 1;
5583 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
5584 ferr(po, "TODO: fnstsw to mem\n");
5585 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
5586 if (ret != 0)
5587 ferr(po, "fnstsw resolve failed\n");
5588 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
5589 (void *)(long)(mask | (z_check << 16)));
5590 if (ret != 1)
5591 ferr(po, "failed to find fcom: %d\n", ret);
5592 break;
5593
5594 default:
5595 break;
b2bd20c0 5596 }
d4e3b5db 5597 }
5598
66bdb2b0 5599 // pass6:
d4e3b5db 5600 // - find POPs for PUSHes, rm both
5601 // - scan for all used registers
b2bd20c0 5602 memset(cbits, 0, sizeof(cbits));
226e8df1 5603 reg_use_pass(0, opcnt, cbits, regmask_init, &regmask,
b2bd20c0 5604 0, &regmask_save, &regmask_init, regmask_arg);
5605
11437ea1 5606 need_float_stack = !!(regmask & mxST7_2);
5607
b2bd20c0 5608 // pass7:
d4e3b5db 5609 // - find flag set ops for their users
b2bd20c0 5610 // - do unresolved calls
1bafb621 5611 // - declare indirect functions
16057ce1 5612 // - other op specific processing
26677139 5613 for (i = 0; i < opcnt; i++)
5614 {
d4e3b5db 5615 po = &ops[i];
5e49b270 5616 if (po->flags & (OPF_RMD|OPF_DONE))
d4e3b5db 5617 continue;
5618
d4e3b5db 5619 if (po->flags & OPF_CC)
5620 {
2b43685d 5621 int setters[16], cnt = 0, branched = 0;
5622
7f20f633 5623 ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
04f8a628 5624 &branched, setters, &cnt);
2b43685d 5625 if (ret < 0 || cnt <= 0)
5626 ferr(po, "unable to trace flag setter(s)\n");
5627 if (cnt > ARRAY_SIZE(setters))
5628 ferr(po, "too many flag setters\n");
d4e3b5db 5629
2b43685d 5630 for (j = 0; j < cnt; j++)
5631 {
5632 tmp_op = &ops[setters[j]]; // flag setter
5633 pfomask = 0;
5634
5635 // to get nicer code, we try to delay test and cmp;
5636 // if we can't because of operand modification, or if we
591721d7 5637 // have arith op, or branch, make it calculate flags explicitly
5638 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
5639 {
89ff3147 5640 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
092f64e1 5641 pfomask = 1 << po->pfo;
2b43685d 5642 }
4741fdfe 5643 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
092f64e1 5644 pfomask = 1 << po->pfo;
591721d7 5645 }
2b43685d 5646 else {
04f8a628 5647 // see if we'll be able to handle based on op result
5648 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
092f64e1 5649 && po->pfo != PFO_Z && po->pfo != PFO_S
5650 && po->pfo != PFO_P)
04f8a628 5651 || branched
2b43685d 5652 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
092f64e1 5653 {
5654 pfomask = 1 << po->pfo;
5655 }
2fe80fdb 5656
c8dbc5be 5657 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
5658 propagate_lmod(tmp_op, &tmp_op->operand[0],
5659 &tmp_op->operand[1]);
5660 if (tmp_op->operand[0].lmod == OPLM_DWORD)
5661 need_tmp64 = 1;
5662 }
2b43685d 5663 }
5664 if (pfomask) {
5665 tmp_op->pfomask |= pfomask;
cb090db0 5666 cond_vars |= pfomask;
2b43685d 5667 }
04f8a628 5668 // note: may overwrite, currently not a problem
5669 po->datap = tmp_op;
d4e3b5db 5670 }
5671
cb090db0 5672 if (po->op == OP_RCL || po->op == OP_RCR
5673 || po->op == OP_ADC || po->op == OP_SBB)
5674 cond_vars |= 1 << PFO_C;
d4e3b5db 5675 }
092f64e1 5676
622eb2ef 5677 switch (po->op) {
5678 case OP_CMPS:
5679 case OP_SCAS:
cb090db0 5680 cond_vars |= 1 << PFO_Z;
622eb2ef 5681 break;
5682
5683 case OP_MUL:
c8dbc5be 5684 if (po->operand[0].lmod == OPLM_DWORD)
5685 need_tmp64 = 1;
622eb2ef 5686 break;
5687
5688 case OP_IMUL:
5689 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
5690 need_tmp64 = 1;
5691 break;
5692
5693 case OP_CALL:
26677139 5694 // note: resolved non-reg calls are OPF_DONE already
092f64e1 5695 pp = po->pp;
b2bd20c0 5696 ferr_assert(po, pp != NULL);
89ff3147 5697
5698 if (pp->is_unresolved) {
ddaf8bd7 5699 int regmask_stack = 0;
8c83cc48 5700 collect_call_args(po, i, pp, &regmask, i + opcnt * 2);
89ff3147 5701
b74c31e3 5702 // this is pretty rough guess:
5703 // see ecx and edx were pushed (and not their saved versions)
5704 for (arg = 0; arg < pp->argc; arg++) {
8c83cc48 5705 if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
b74c31e3 5706 continue;
5707
5708 tmp_op = pp->arg[arg].datap;
5709 if (tmp_op == NULL)
5710 ferr(po, "parsed_op missing for arg%d\n", arg);
8c83cc48 5711 if (tmp_op->operand[0].type == OPT_REG)
b74c31e3 5712 regmask_stack |= 1 << tmp_op->operand[0].reg;
5713 }
5714
ddaf8bd7 5715 if (!((regmask_stack & (1 << xCX))
5716 && (regmask_stack & (1 << xDX))))
89ff3147 5717 {
5718 if (pp->argc_stack != 0
c0050df6 5719 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
89ff3147 5720 {
5721 pp_insert_reg_arg(pp, "ecx");
c0050df6 5722 pp->is_fastcall = 1;
ddaf8bd7 5723 regmask_init |= 1 << xCX;
89ff3147 5724 regmask |= 1 << xCX;
5725 }
5726 if (pp->argc_stack != 0
5727 || ((regmask | regmask_arg) & (1 << xDX)))
5728 {
5729 pp_insert_reg_arg(pp, "edx");
ddaf8bd7 5730 regmask_init |= 1 << xDX;
89ff3147 5731 regmask |= 1 << xDX;
5732 }
5733 }
c0050df6 5734
5735 // note: __cdecl doesn't fall into is_unresolved category
5736 if (pp->argc_stack > 0)
5737 pp->is_stdcall = 1;
ddaf8bd7 5738 }
622eb2ef 5739 break;
5740
5741 case OP_MOV:
5742 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
27ebfaed 5743 {
622eb2ef 5744 // <var> = offset <something>
5745 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
5746 && !IS_START(po->operand[1].name, "off_"))
5747 {
5748 if (!po->operand[0].pp->is_fptr)
5749 ferr(po, "%s not declared as fptr when it should be\n",
5750 po->operand[0].name);
5751 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
5752 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
5753 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
5754 fnote(po, "var: %s\n", buf1);
5755 fnote(po, "func: %s\n", buf2);
5756 ferr(po, "^ mismatch\n");
5757 }
27ebfaed 5758 }
5759 }
622eb2ef 5760 break;
5761
5762 case OP_DIV:
5763 case OP_IDIV:
acd03176 5764 if (po->operand[0].lmod == OPLM_DWORD) {
5765 // 32bit division is common, look for it
5766 if (po->op == OP_DIV)
5767 ret = scan_for_reg_clear(i, xDX);
5768 else
5769 ret = scan_for_cdq_edx(i);
5770 if (ret >= 0)
5771 po->flags |= OPF_32BIT;
5772 else
5773 need_tmp64 = 1;
5774 }
cb090db0 5775 else
acd03176 5776 need_tmp_var = 1;
622eb2ef 5777 break;
5778
5779 case OP_CLD:
5e49b270 5780 po->flags |= OPF_RMD | OPF_DONE;
622eb2ef 5781 break;
5782
5783 case OP_RCL:
5784 case OP_RCR:
5785 case OP_XCHG:
5786 need_tmp_var = 1;
5787 break;
5788
5789 case OP_FLD:
5790 if (po->operand[0].lmod == OPLM_QWORD)
5791 need_double = 1;
5792 break;
5793
5794 case OPP_ALLSHL:
5795 case OPP_ALLSHR:
5796 need_tmp64 = 1;
5797 break;
5798
5799 case OPP_FTOL: {
d4a985bd 5800 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
5801 j = -1;
5802 find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
5803 if (j == -1)
5804 po->flags |= OPF_32BIT;
622eb2ef 5805 break;
d4a985bd 5806 }
cb090db0 5807
622eb2ef 5808 default:
5809 break;
5810 }
8c83cc48 5811
5812 // this might need it's own pass...
5813 if (po->op != OP_FST && po->p_argnum > 0)
5814 save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
11437ea1 5815
5816 // correct for "full stack" mode late enable
5817 if ((po->flags & (OPF_PPUSH|OPF_FPOP)) && need_float_stack)
5818 po->flags |= OPF_FSHIFT;
91977a1c 5819 }
5820
497a6d6b 5821 float_type = need_double ? "double" : "float";
fe18df39 5822 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
5823 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
497a6d6b 5824
60fe410c 5825 // output starts here
5826
5827 // define userstack size
5828 if (g_func_pp->is_userstack) {
5829 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
5830 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
5831 fprintf(fout, "#endif\n");
5832 }
5833
5834 // the function itself
c0de9015 5835 ferr_assert(ops, !g_func_pp->is_fptr);
5836 output_pp(fout, g_func_pp,
5837 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
5838 fprintf(fout, "\n{\n");
60fe410c 5839
5840 // declare indirect functions
5841 for (i = 0; i < opcnt; i++) {
5842 po = &ops[i];
5843 if (po->flags & OPF_RMD)
5844 continue;
5845
5846 if (po->op == OP_CALL) {
5847 pp = po->pp;
5848 if (pp == NULL)
5849 ferr(po, "NULL pp\n");
5850
5851 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
5852 if (pp->name[0] != 0) {
5853 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
5854 memcpy(pp->name, "i_", 2);
5855
5856 // might be declared already
5857 found = 0;
5858 for (j = 0; j < i; j++) {
5859 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
5860 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
5861 found = 1;
5862 break;
5863 }
5864 }
5865 }
5866 if (found)
5867 continue;
5868 }
5869 else
5870 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
5871
c0de9015 5872 fprintf(fout, " ");
5873 output_pp(fout, pp, OPP_SIMPLE_ARGS);
5874 fprintf(fout, ";\n");
60fe410c 5875 }
5876 }
5877 }
da87ae38 5878
4c45fa73 5879 // output LUTs/jumptables
5880 for (i = 0; i < g_func_pd_cnt; i++) {
5881 pd = &g_func_pd[i];
5882 fprintf(fout, " static const ");
5883 if (pd->type == OPT_OFFSET) {
5884 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
5885
5886 for (j = 0; j < pd->count; j++) {
5887 if (j > 0)
5888 fprintf(fout, ", ");
5889 fprintf(fout, "&&%s", pd->d[j].u.label);
5890 }
5891 }
5892 else {
5893 fprintf(fout, "%s %s[] =\n { ",
5894 lmod_type_u(ops, pd->lmod), pd->label);
5895
5896 for (j = 0; j < pd->count; j++) {
5897 if (j > 0)
5898 fprintf(fout, ", ");
5899 fprintf(fout, "%u", pd->d[j].u.val);
5900 }
5901 }
5902 fprintf(fout, " };\n");
1f84f6b3 5903 had_decl = 1;
4c45fa73 5904 }
5905
4f12f671 5906 // declare stack frame, va_arg
1f84f6b3 5907 if (g_stack_fsz) {
d4a985bd 5908 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
5909 if (g_func_lmods & (1 << OPLM_WORD))
5910 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
5911 if (g_func_lmods & (1 << OPLM_BYTE))
5912 fprintf(fout, " u8 b[%d];", g_stack_fsz);
5913 if (g_func_lmods & (1 << OPLM_QWORD))
5914 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
5915 fprintf(fout, " } sf;\n");
1f84f6b3 5916 had_decl = 1;
5917 }
5918
5919 if (g_func_pp->is_userstack) {
60fe410c 5920 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
5921 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
1f84f6b3 5922 had_decl = 1;
5923 }
850c9265 5924
1f84f6b3 5925 if (g_func_pp->is_vararg) {
4f12f671 5926 fprintf(fout, " va_list ap;\n");
1f84f6b3 5927 had_decl = 1;
5928 }
4f12f671 5929
940e8e66 5930 // declare arg-registers
bd96f656 5931 for (i = 0; i < g_func_pp->argc; i++) {
5932 if (g_func_pp->arg[i].reg != NULL) {
91977a1c 5933 reg = char_array_i(regs_r32,
bd96f656 5934 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
75ad0378 5935 if (regmask & (1 << reg)) {
1f84f6b3 5936 if (g_func_pp->arg[i].type.is_retreg)
5937 fprintf(fout, " u32 %s = *r_%s;\n",
5938 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
5939 else
5940 fprintf(fout, " u32 %s = (u32)a%d;\n",
5941 g_func_pp->arg[i].reg, i + 1);
75ad0378 5942 }
1f84f6b3 5943 else {
5944 if (g_func_pp->arg[i].type.is_retreg)
5945 ferr(ops, "retreg '%s' is unused?\n",
5946 g_func_pp->arg[i].reg);
75ad0378 5947 fprintf(fout, " // %s = a%d; // unused\n",
5948 g_func_pp->arg[i].reg, i + 1);
1f84f6b3 5949 }
91977a1c 5950 had_decl = 1;
5951 }
5952 }
5953
25a330eb 5954 // declare normal registers
75ad0378 5955 regmask_now = regmask & ~regmask_arg;
5956 regmask_now &= ~(1 << xSP);
90307a99 5957 if (regmask_now & 0x00ff) {
91977a1c 5958 for (reg = 0; reg < 8; reg++) {
75ad0378 5959 if (regmask_now & (1 << reg)) {
ddaf8bd7 5960 fprintf(fout, " u32 %s", regs_r32[reg]);
5961 if (regmask_init & (1 << reg))
5962 fprintf(fout, " = 0");
5963 fprintf(fout, ";\n");
91977a1c 5964 had_decl = 1;
5965 }
5966 }
5967 }
d4a985bd 5968 // ... mmx
90307a99 5969 if (regmask_now & 0xff00) {
5970 for (reg = 8; reg < 16; reg++) {
5971 if (regmask_now & (1 << reg)) {
5972 fprintf(fout, " mmxr %s", regs_r32[reg]);
5973 if (regmask_init & (1 << reg))
5974 fprintf(fout, " = { 0, }");
5975 fprintf(fout, ";\n");
5976 had_decl = 1;
5977 }
5978 }
5979 }
d4a985bd 5980 // ... x87
fe18df39 5981 if (need_float_stack) {
5982 fprintf(fout, " %s f_st[8];\n", float_type);
5983 fprintf(fout, " int f_stp = 0;\n");
5984 had_decl = 1;
5985 }
5986 else {
5987 if (regmask_now & 0xff0000) {
5988 for (reg = 16; reg < 24; reg++) {
5989 if (regmask_now & (1 << reg)) {
5990 fprintf(fout, " %s f_st%d", float_type, reg - 16);
5991 if (regmask_init & (1 << reg))
5992 fprintf(fout, " = 0");
5993 fprintf(fout, ";\n");
5994 had_decl = 1;
5995 }
d4a985bd 5996 }
5997 }
5998 }
91977a1c 5999
16057ce1 6000 if (need_float_sw) {
6001 fprintf(fout, " u16 f_sw;\n");
6002 had_decl = 1;
6003 }
6004
d4e3b5db 6005 if (regmask_save) {
6006 for (reg = 0; reg < 8; reg++) {
6007 if (regmask_save & (1 << reg)) {
6008 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
6009 had_decl = 1;
6010 }
6011 }
6012 }
6013
3a5101d7 6014 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6015 if (save_arg_vars[i] == 0)
6016 continue;
69a3cdfc 6017 for (reg = 0; reg < 32; reg++) {
3a5101d7 6018 if (save_arg_vars[i] & (1 << reg)) {
6019 fprintf(fout, " u32 %s;\n",
6020 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
69a3cdfc 6021 had_decl = 1;
6022 }
6023 }
6024 }
6025
30620174 6026 if (regmask_ffca) {
6027 for (reg = 0; reg < 32; reg++) {
6028 if (regmask_ffca & (1 << reg)) {
6029 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
6030 had_decl = 1;
6031 }
6032 }
6033 }
6034
25a330eb 6035 // declare push-pop temporaries
6036 if (regmask_pp) {
6037 for (reg = 0; reg < 8; reg++) {
6038 if (regmask_pp & (1 << reg)) {
6039 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
6040 had_decl = 1;
6041 }
6042 }
6043 }
6044
cb090db0 6045 if (cond_vars) {
69a3cdfc 6046 for (i = 0; i < 8; i++) {
cb090db0 6047 if (cond_vars & (1 << i)) {
69a3cdfc 6048 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
6049 had_decl = 1;
6050 }
6051 }
6052 }
6053
108e9fe3 6054 if (need_tmp_var) {
6055 fprintf(fout, " u32 tmp;\n");
6056 had_decl = 1;
6057 }
6058
2fe80fdb 6059 if (need_tmp64) {
6060 fprintf(fout, " u64 tmp64;\n");
87bf6cec 6061 had_decl = 1;
6062 }
6063
91977a1c 6064 if (had_decl)
6065 fprintf(fout, "\n");
6066
7e08c224 6067 // do stack clear, if needed
6068 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6069 fprintf(fout, " ");
6070 if (g_stack_clear_len != 0) {
6071 if (g_stack_clear_len <= 4) {
6072 for (i = 0; i < g_stack_clear_len; i++)
6073 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6074 fprintf(fout, "0;\n");
6075 }
6076 else {
6077 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6078 g_stack_clear_start, g_stack_clear_len * 4);
6079 }
6080 }
6081 else
6082 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6083 }
6084
bd96f656 6085 if (g_func_pp->is_vararg) {
6086 if (g_func_pp->argc_stack == 0)
4f12f671 6087 ferr(ops, "vararg func without stack args?\n");
bd96f656 6088 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
4f12f671 6089 }
6090
91977a1c 6091 // output ops
69a3cdfc 6092 for (i = 0; i < opcnt; i++)
6093 {
d7857c3a 6094 if (g_labels[i] != NULL) {
91977a1c 6095 fprintf(fout, "\n%s:\n", g_labels[i]);
3ebea2cf 6096 label_pending = 1;
2b43685d 6097
6098 delayed_flag_op = NULL;
6099 last_arith_dst = NULL;
3ebea2cf 6100 }
91977a1c 6101
69a3cdfc 6102 po = &ops[i];
6103 if (po->flags & OPF_RMD)
91977a1c 6104 continue;
6105
6106 no_output = 0;
6107
91977a1c 6108 #define assert_operand_cnt(n_) \
850c9265 6109 if (po->operand_cnt != n_) \
6110 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6111
69a3cdfc 6112 // conditional/flag using op?
6113 if (po->flags & OPF_CC)
850c9265 6114 {
940e8e66 6115 int is_delayed = 0;
69a3cdfc 6116
04f8a628 6117 tmp_op = po->datap;
850c9265 6118
69a3cdfc 6119 // we go through all this trouble to avoid using parsed_flag_op,
6120 // which makes generated code much nicer
6121 if (delayed_flag_op != NULL)
850c9265 6122 {
092f64e1 6123 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6124 po->pfo, po->pfo_inv);
940e8e66 6125 is_delayed = 1;
91977a1c 6126 }
850c9265 6127 else if (last_arith_dst != NULL
092f64e1 6128 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
04f8a628 6129 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6130 ))
850c9265 6131 {
3ebea2cf 6132 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
092f64e1 6133 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
850c9265 6134 last_arith_dst->lmod, buf3);
940e8e66 6135 is_delayed = 1;
850c9265 6136 }
04f8a628 6137 else if (tmp_op != NULL) {
7ba45c34 6138 // use preprocessed flag calc results
092f64e1 6139 if (!(tmp_op->pfomask & (1 << po->pfo)))
6140 ferr(po, "not prepared for pfo %d\n", po->pfo);
69a3cdfc 6141
092f64e1 6142 // note: pfo_inv was not yet applied
69a3cdfc 6143 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
092f64e1 6144 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
69a3cdfc 6145 }
6146 else {
6147 ferr(po, "all methods of finding comparison failed\n");
6148 }
850c9265 6149
69a3cdfc 6150 if (po->flags & OPF_JMP) {
092f64e1 6151 fprintf(fout, " if %s", buf1);
850c9265 6152 }
cb090db0 6153 else if (po->op == OP_RCL || po->op == OP_RCR
6154 || po->op == OP_ADC || po->op == OP_SBB)
6155 {
940e8e66 6156 if (is_delayed)
6157 fprintf(fout, " cond_%s = %s;\n",
092f64e1 6158 parsed_flag_op_names[po->pfo], buf1);
850c9265 6159 }
5101a5f9 6160 else if (po->flags & OPF_DATA) { // SETcc
850c9265 6161 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6162 fprintf(fout, " %s = %s;", buf2, buf1);
91977a1c 6163 }
69a3cdfc 6164 else {
6165 ferr(po, "unhandled conditional op\n");
6166 }
91977a1c 6167 }
6168
940e8e66 6169 pfomask = po->pfomask;
6170
850c9265 6171 switch (po->op)
91977a1c 6172 {
6173 case OP_MOV:
6174 assert_operand_cnt(2);
850c9265 6175 propagate_lmod(po, &po->operand[0], &po->operand[1]);
de50b98b 6176 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
c7ed83dd 6177 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
de50b98b 6178 fprintf(fout, " %s = %s;", buf1,
3ebea2cf 6179 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
c7ed83dd 6180 buf3, 0));
850c9265 6181 break;
6182
6183 case OP_LEA:
6184 assert_operand_cnt(2);
87bf6cec 6185 po->operand[1].lmod = OPLM_DWORD; // always
850c9265 6186 fprintf(fout, " %s = %s;",
6187 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
3ebea2cf 6188 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6189 NULL, 1));
850c9265 6190 break;
6191
6192 case OP_MOVZX:
6193 assert_operand_cnt(2);
91977a1c 6194 fprintf(fout, " %s = %s;",
850c9265 6195 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
3ebea2cf 6196 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
850c9265 6197 break;
6198
6199 case OP_MOVSX:
6200 assert_operand_cnt(2);
6201 switch (po->operand[1].lmod) {
6202 case OPLM_BYTE:
6203 strcpy(buf3, "(s8)");
6204 break;
6205 case OPLM_WORD:
6206 strcpy(buf3, "(s16)");
6207 break;
6208 default:
6209 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6210 }
a2c1d768 6211 fprintf(fout, " %s = %s;",
850c9265 6212 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
a2c1d768 6213 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6214 buf3, 0));
850c9265 6215 break;
6216
108e9fe3 6217 case OP_XCHG:
6218 assert_operand_cnt(2);
6219 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6220 fprintf(fout, " tmp = %s;",
6221 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6222 fprintf(fout, " %s = %s;",
6223 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
c7ed83dd 6224 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6225 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6226 fprintf(fout, " %s = %stmp;",
6227 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6228 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
108e9fe3 6229 snprintf(g_comment, sizeof(g_comment), "xchg");
6230 break;
6231
850c9265 6232 case OP_NOT:
6233 assert_operand_cnt(1);
6234 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6235 fprintf(fout, " %s = ~%s;", buf1, buf1);
6236 break;
6237
04abc5d6 6238 case OP_XLAT:
6239 assert_operand_cnt(2);
6240 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6241 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6242 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6243 strcpy(g_comment, "xlat");
6244 break;
6245
5101a5f9 6246 case OP_CDQ:
6247 assert_operand_cnt(2);
6248 fprintf(fout, " %s = (s32)%s >> 31;",
6249 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
3ebea2cf 6250 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5101a5f9 6251 strcpy(g_comment, "cdq");
6252 break;
6253
622eb2ef 6254 case OP_BSWAP:
6255 assert_operand_cnt(1);
6256 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6257 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
6258 break;
6259
092f64e1 6260 case OP_LODS:
092f64e1 6261 if (po->flags & OPF_REP) {
acd03176 6262 assert_operand_cnt(3);
092f64e1 6263 // hmh..
6264 ferr(po, "TODO\n");
6265 }
6266 else {
acd03176 6267 assert_operand_cnt(2);
3947cf24 6268 fprintf(fout, " %s = %sesi; esi %c= %d;",
6269 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6270 lmod_cast_u_ptr(po, po->operand[1].lmod),
092f64e1 6271 (po->flags & OPF_DF) ? '-' : '+',
3947cf24 6272 lmod_bytes(po, po->operand[1].lmod));
092f64e1 6273 strcpy(g_comment, "lods");
6274 }
6275 break;
6276
33c35af6 6277 case OP_STOS:
33c35af6 6278 if (po->flags & OPF_REP) {
acd03176 6279 assert_operand_cnt(3);
591721d7 6280 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
6281 (po->flags & OPF_DF) ? '-' : '+',
3947cf24 6282 lmod_bytes(po, po->operand[1].lmod));
d4e3b5db 6283 fprintf(fout, " %sedi = eax;",
3947cf24 6284 lmod_cast_u_ptr(po, po->operand[1].lmod));
33c35af6 6285 strcpy(g_comment, "rep stos");
6286 }
6287 else {
acd03176 6288 assert_operand_cnt(2);
092f64e1 6289 fprintf(fout, " %sedi = eax; edi %c= %d;",
3947cf24 6290 lmod_cast_u_ptr(po, po->operand[1].lmod),
591721d7 6291 (po->flags & OPF_DF) ? '-' : '+',
3947cf24 6292 lmod_bytes(po, po->operand[1].lmod));
33c35af6 6293 strcpy(g_comment, "stos");
6294 }
6295 break;
6296
d4e3b5db 6297 case OP_MOVS:
d4e3b5db 6298 j = lmod_bytes(po, po->operand[0].lmod);
6299 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
591721d7 6300 l = (po->flags & OPF_DF) ? '-' : '+';
d4e3b5db 6301 if (po->flags & OPF_REP) {
acd03176 6302 assert_operand_cnt(3);
d4e3b5db 6303 fprintf(fout,
591721d7 6304 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
6305 l, j, l, j);
d4e3b5db 6306 fprintf(fout,
6307 " %sedi = %sesi;", buf1, buf1);
6308 strcpy(g_comment, "rep movs");
6309 }
6310 else {
acd03176 6311 assert_operand_cnt(2);
092f64e1 6312 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
591721d7 6313 buf1, buf1, l, j, l, j);
d4e3b5db 6314 strcpy(g_comment, "movs");
6315 }
6316 break;
6317
7ba45c34 6318 case OP_CMPS:
7ba45c34 6319 // repe ~ repeat while ZF=1
7ba45c34 6320 j = lmod_bytes(po, po->operand[0].lmod);
6321 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
591721d7 6322 l = (po->flags & OPF_DF) ? '-' : '+';
7ba45c34 6323 if (po->flags & OPF_REP) {
acd03176 6324 assert_operand_cnt(3);
7ba45c34 6325 fprintf(fout,
7f20f633 6326 " while (ecx != 0) {\n");
4741fdfe 6327 if (pfomask & (1 << PFO_C)) {
6328 // ugh..
6329 fprintf(fout,
05381e4a 6330 " cond_c = %sesi < %sedi;\n", buf1, buf1);
4741fdfe 6331 pfomask &= ~(1 << PFO_C);
6332 }
7ba45c34 6333 fprintf(fout,
05381e4a 6334 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
1f84f6b3 6335 buf1, buf1, l, j, l, j);
6336 fprintf(fout,
7f20f633 6337 " ecx--;\n"
1f84f6b3 6338 " if (cond_z %s 0) break;\n",
6339 (po->flags & OPF_REPZ) ? "==" : "!=");
7ba45c34 6340 fprintf(fout,
4741fdfe 6341 " }");
7ba45c34 6342 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
6343 (po->flags & OPF_REPZ) ? "e" : "ne");
6344 }
6345 else {
acd03176 6346 assert_operand_cnt(2);
7ba45c34 6347 fprintf(fout,
05381e4a 6348 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
591721d7 6349 buf1, buf1, l, j, l, j);
7ba45c34 6350 strcpy(g_comment, "cmps");
6351 }
6352 pfomask &= ~(1 << PFO_Z);
6353 last_arith_dst = NULL;
6354 delayed_flag_op = NULL;
6355 break;
6356
591721d7 6357 case OP_SCAS:
6358 // only does ZF (for now)
6359 // repe ~ repeat while ZF=1
3947cf24 6360 j = lmod_bytes(po, po->operand[1].lmod);
591721d7 6361 l = (po->flags & OPF_DF) ? '-' : '+';
6362 if (po->flags & OPF_REP) {
acd03176 6363 assert_operand_cnt(3);
591721d7 6364 fprintf(fout,
7f20f633 6365 " while (ecx != 0) {\n");
591721d7 6366 fprintf(fout,
1f84f6b3 6367 " cond_z = (%seax == %sedi); edi %c= %d;\n",
3947cf24 6368 lmod_cast_u(po, po->operand[1].lmod),
6369 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
1f84f6b3 6370 fprintf(fout,
7f20f633 6371 " ecx--;\n"
1f84f6b3 6372 " if (cond_z %s 0) break;\n",
591721d7 6373 (po->flags & OPF_REPZ) ? "==" : "!=");
6374 fprintf(fout,
1f84f6b3 6375 " }");
591721d7 6376 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
6377 (po->flags & OPF_REPZ) ? "e" : "ne");
6378 }
6379 else {
acd03176 6380 assert_operand_cnt(2);
05381e4a 6381 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
3947cf24 6382 lmod_cast_u(po, po->operand[1].lmod),
6383 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
591721d7 6384 strcpy(g_comment, "scas");
6385 }
6386 pfomask &= ~(1 << PFO_Z);
6387 last_arith_dst = NULL;
6388 delayed_flag_op = NULL;
6389 break;
6390
850c9265 6391 // arithmetic w/flags
850c9265 6392 case OP_AND:
2b70f6d3 6393 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
6394 goto dualop_arith_const;
6395 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6396 goto dualop_arith;
6397
850c9265 6398 case OP_OR:
5101a5f9 6399 propagate_lmod(po, &po->operand[0], &po->operand[1]);
2b70f6d3 6400 if (po->operand[1].type == OPT_CONST) {
6401 j = lmod_bytes(po, po->operand[0].lmod);
6402 if (((1ull << j * 8) - 1) == po->operand[1].val)
6403 goto dualop_arith_const;
6404 }
6405 goto dualop_arith;
6406
850c9265 6407 dualop_arith:
6408 assert_operand_cnt(2);
850c9265 6409 fprintf(fout, " %s %s= %s;",
6410 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6411 op_to_c(po),
3ebea2cf 6412 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
04f8a628 6413 output_std_flags(fout, po, &pfomask, buf1);
6414 last_arith_dst = &po->operand[0];
6415 delayed_flag_op = NULL;
6416 break;
6417
2b70f6d3 6418 dualop_arith_const:
6419 // and 0, or ~0 used instead mov
6420 assert_operand_cnt(2);
6421 fprintf(fout, " %s = %s;",
6422 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6423 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6424 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6425 output_std_flags(fout, po, &pfomask, buf1);
6426 last_arith_dst = &po->operand[0];
6427 delayed_flag_op = NULL;
6428 break;
6429
04f8a628 6430 case OP_SHL:
6431 case OP_SHR:
6432 assert_operand_cnt(2);
6433 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6434 if (pfomask & (1 << PFO_C)) {
6435 if (po->operand[1].type == OPT_CONST) {
6436 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6437 j = po->operand[1].val;
6438 j %= l;
6439 if (j != 0) {
6440 if (po->op == OP_SHL)
6441 j = l - j;
6442 else
6443 j -= 1;
cb090db0 6444 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
6445 buf1, j);
04f8a628 6446 }
6447 else
6448 ferr(po, "zero shift?\n");
6449 }
6450 else
6451 ferr(po, "TODO\n");
6452 pfomask &= ~(1 << PFO_C);
840257f6 6453 }
04abc5d6 6454 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
04f8a628 6455 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
04abc5d6 6456 if (po->operand[1].type != OPT_CONST)
6457 fprintf(fout, " & 0x1f");
6458 fprintf(fout, ";");
04f8a628 6459 output_std_flags(fout, po, &pfomask, buf1);
850c9265 6460 last_arith_dst = &po->operand[0];
69a3cdfc 6461 delayed_flag_op = NULL;
850c9265 6462 break;
6463
d4e3b5db 6464 case OP_SAR:
6465 assert_operand_cnt(2);
6466 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6467 fprintf(fout, " %s = %s%s >> %s;", buf1,
6468 lmod_cast_s(po, po->operand[0].lmod), buf1,
3ebea2cf 6469 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
04f8a628 6470 output_std_flags(fout, po, &pfomask, buf1);
d4e3b5db 6471 last_arith_dst = &po->operand[0];
6472 delayed_flag_op = NULL;
6473 break;
6474
04abc5d6 6475 case OP_SHLD:
3b2f4044 6476 case OP_SHRD:
6477 assert_operand_cnt(3);
6478 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6479 l = lmod_bytes(po, po->operand[0].lmod) * 8;
3b2f4044 6480 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
acd03176 6481 if (po->operand[2].type != OPT_CONST) {
6482 // no handling for "undefined" case, hopefully not needed
6483 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
6484 strcpy(buf3, buf2);
6485 }
6486 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6487 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
04abc5d6 6488 if (po->op == OP_SHLD) {
6489 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
6490 buf1, buf3, buf1, buf2, l, buf3);
6491 strcpy(g_comment, "shld");
6492 }
6493 else {
6494 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
6495 buf1, buf3, buf1, buf2, l, buf3);
6496 strcpy(g_comment, "shrd");
6497 }
3b2f4044 6498 output_std_flags(fout, po, &pfomask, buf1);
6499 last_arith_dst = &po->operand[0];
6500 delayed_flag_op = NULL;
6501 break;
6502
d4e3b5db 6503 case OP_ROL:
6504 case OP_ROR:
6505 assert_operand_cnt(2);
6506 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6507 if (po->operand[1].type == OPT_CONST) {
6508 j = po->operand[1].val;
6509 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
6510 fprintf(fout, po->op == OP_ROL ?
6511 " %s = (%s << %d) | (%s >> %d);" :
6512 " %s = (%s >> %d) | (%s << %d);",
6513 buf1, buf1, j, buf1,
6514 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
6515 }
6516 else
6517 ferr(po, "TODO\n");
04f8a628 6518 output_std_flags(fout, po, &pfomask, buf1);
d4e3b5db 6519 last_arith_dst = &po->operand[0];
6520 delayed_flag_op = NULL;
6521 break;
6522
cb090db0 6523 case OP_RCL:
6524 case OP_RCR:
6525 assert_operand_cnt(2);
6526 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6527 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6528 if (po->operand[1].type == OPT_CONST) {
6529 j = po->operand[1].val % l;
6530 if (j == 0)
6531 ferr(po, "zero rotate\n");
6532 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
6533 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
6534 if (po->op == OP_RCL) {
6535 fprintf(fout,
6536 " %s = (%s << %d) | (cond_c << %d)",
6537 buf1, buf1, j, j - 1);
6538 if (j != 1)
6539 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
6540 }
6541 else {
6542 fprintf(fout,
6543 " %s = (%s >> %d) | (cond_c << %d)",
6544 buf1, buf1, j, l - j);
6545 if (j != 1)
6546 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
6547 }
6548 fprintf(fout, ";\n");
6549 fprintf(fout, " cond_c = tmp;");
6550 }
6551 else
6552 ferr(po, "TODO\n");
6553 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
6554 output_std_flags(fout, po, &pfomask, buf1);
6555 last_arith_dst = &po->operand[0];
6556 delayed_flag_op = NULL;
6557 break;
6558
5101a5f9 6559 case OP_XOR:
850c9265 6560 assert_operand_cnt(2);
6561 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5101a5f9 6562 if (IS(opr_name(po, 0), opr_name(po, 1))) {
6563 // special case for XOR
7f20f633 6564 int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
6565 for (j = 0; j <= PFO_LE; j++) {
6566 if (pfomask & (1 << j)) {
6567 fprintf(fout, " cond_%s = %d;\n",
6568 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
6569 pfomask &= ~(1 << j);
6570 }
2fe80fdb 6571 }
5101a5f9 6572 fprintf(fout, " %s = 0;",
6573 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6574 last_arith_dst = &po->operand[0];
6575 delayed_flag_op = NULL;
850c9265 6576 break;
850c9265 6577 }
5101a5f9 6578 goto dualop_arith;
6579
2fe80fdb 6580 case OP_ADD:
6581 assert_operand_cnt(2);
6582 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6583 if (pfomask & (1 << PFO_C)) {
c8dbc5be 6584 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6585 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6586 if (po->operand[0].lmod == OPLM_DWORD) {
6587 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
6588 fprintf(fout, " cond_c = tmp64 >> 32;\n");
6589 fprintf(fout, " %s = (u32)tmp64;",
6590 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
d4a985bd 6591 strcat(g_comment, " add64");
c8dbc5be 6592 }
6593 else {
6594 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
6595 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
6596 fprintf(fout, " %s += %s;",
6597 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6598 buf2);
6599 }
2fe80fdb 6600 pfomask &= ~(1 << PFO_C);
6601 output_std_flags(fout, po, &pfomask, buf1);
6602 last_arith_dst = &po->operand[0];
6603 delayed_flag_op = NULL;
6604 break;
6605 }
16057ce1 6606 if (pfomask & (1 << PFO_LE)) {
6607 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
6608 fprintf(fout, " cond_%s = %s;\n",
6609 parsed_flag_op_names[PFO_LE], buf1);
6610 pfomask &= ~(1 << PFO_LE);
6611 }
2fe80fdb 6612 goto dualop_arith;
6613
6614 case OP_SUB:
6615 assert_operand_cnt(2);
6616 propagate_lmod(po, &po->operand[0], &po->operand[1]);
3b2f4044 6617 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
6618 for (j = 0; j <= PFO_LE; j++) {
6619 if (!(pfomask & (1 << j)))
6620 continue;
6621 if (j == PFO_Z || j == PFO_S)
6622 continue;
6623
16057ce1 6624 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
3b2f4044 6625 fprintf(fout, " cond_%s = %s;\n",
6626 parsed_flag_op_names[j], buf1);
6627 pfomask &= ~(1 << j);
6628 }
2fe80fdb 6629 }
6630 goto dualop_arith;
6631
5101a5f9 6632 case OP_ADC:
850c9265 6633 case OP_SBB:
5101a5f9 6634 assert_operand_cnt(2);
6635 propagate_lmod(po, &po->operand[0], &po->operand[1]);
a2c1d768 6636 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
840257f6 6637 if (po->op == OP_SBB
6638 && IS(po->operand[0].name, po->operand[1].name))
6639 {
6640 // avoid use of unitialized var
a2c1d768 6641 fprintf(fout, " %s = -cond_c;", buf1);
94d447fb 6642 // carry remains what it was
6643 pfomask &= ~(1 << PFO_C);
840257f6 6644 }
6645 else {
a2c1d768 6646 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
3ebea2cf 6647 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
840257f6 6648 }
a2c1d768 6649 output_std_flags(fout, po, &pfomask, buf1);
5101a5f9 6650 last_arith_dst = &po->operand[0];
6651 delayed_flag_op = NULL;
850c9265 6652 break;
6653
1f84f6b3 6654 case OP_BSF:
6655 assert_operand_cnt(2);
6656 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6657 fprintf(fout, " %s = %s ? __builtin_ffs(%s) - 1 : 0;",
6658 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6659 buf2, buf2);
6660 output_std_flags(fout, po, &pfomask, buf1);
6661 last_arith_dst = &po->operand[0];
6662 delayed_flag_op = NULL;
d4a985bd 6663 strcat(g_comment, " bsf");
1f84f6b3 6664 break;
6665
850c9265 6666 case OP_DEC:
90307a99 6667 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
6668 for (j = 0; j <= PFO_LE; j++) {
6669 if (!(pfomask & (1 << j)))
6670 continue;
6671 if (j == PFO_Z || j == PFO_S || j == PFO_C)
6672 continue;
6673
16057ce1 6674 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
90307a99 6675 fprintf(fout, " cond_%s = %s;\n",
6676 parsed_flag_op_names[j], buf1);
6677 pfomask &= ~(1 << j);
6678 }
6679 }
6680 // fallthrough
6681
6682 case OP_INC:
6683 if (pfomask & (1 << PFO_C))
6684 // carry is unaffected by inc/dec.. wtf?
6685 ferr(po, "carry propagation needed\n");
6686
850c9265 6687 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
1bafb621 6688 if (po->operand[0].type == OPT_REG) {
6689 strcpy(buf2, po->op == OP_INC ? "++" : "--");
6690 fprintf(fout, " %s%s;", buf1, buf2);
6691 }
6692 else {
6693 strcpy(buf2, po->op == OP_INC ? "+" : "-");
6694 fprintf(fout, " %s %s= 1;", buf1, buf2);
6695 }
a2c1d768 6696 output_std_flags(fout, po, &pfomask, buf1);
5101a5f9 6697 last_arith_dst = &po->operand[0];
6698 delayed_flag_op = NULL;
6699 break;
6700
6701 case OP_NEG:
6702 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
3ebea2cf 6703 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
5101a5f9 6704 fprintf(fout, " %s = -%s%s;", buf1,
6705 lmod_cast_s(po, po->operand[0].lmod), buf2);
850c9265 6706 last_arith_dst = &po->operand[0];
69a3cdfc 6707 delayed_flag_op = NULL;
0ea6430c 6708 if (pfomask & PFOB_C) {
940e8e66 6709 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
0ea6430c 6710 pfomask &= ~PFOB_C;
940e8e66 6711 }
0ea6430c 6712 output_std_flags(fout, po, &pfomask, buf1);
850c9265 6713 break;
6714
6715 case OP_IMUL:
de50b98b 6716 if (po->operand_cnt == 2) {
6717 propagate_lmod(po, &po->operand[0], &po->operand[1]);
850c9265 6718 goto dualop_arith;
de50b98b 6719 }
87bf6cec 6720 if (po->operand_cnt == 3)
6721 ferr(po, "TODO imul3\n");
6722 // fallthrough
6723 case OP_MUL:
6724 assert_operand_cnt(1);
c8dbc5be 6725 switch (po->operand[0].lmod) {
6726 case OPLM_DWORD:
6727 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
6728 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
6729 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
6730 fprintf(fout, " edx = tmp64 >> 32;\n");
6731 fprintf(fout, " eax = tmp64;");
6732 break;
6733 case OPLM_BYTE:
6734 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
6735 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
6736 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
6737 buf1, 0));
6738 break;
6739 default:
6740 ferr(po, "TODO: unhandled mul type\n");
6741 break;
6742 }
87bf6cec 6743 last_arith_dst = NULL;
69a3cdfc 6744 delayed_flag_op = NULL;
91977a1c 6745 break;
6746
5101a5f9 6747 case OP_DIV:
6748 case OP_IDIV:
6749 assert_operand_cnt(1);
cb090db0 6750 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
acd03176 6751 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
cb090db0 6752 po->op == OP_IDIV));
6753 switch (po->operand[0].lmod) {
6754 case OPLM_DWORD:
6755 if (po->flags & OPF_32BIT)
acd03176 6756 snprintf(buf2, sizeof(buf2), "%seax", cast);
cb090db0 6757 else {
6758 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
acd03176 6759 snprintf(buf2, sizeof(buf2), "%stmp64",
cb090db0 6760 (po->op == OP_IDIV) ? "(s64)" : "");
6761 }
6762 if (po->operand[0].type == OPT_REG
6763 && po->operand[0].reg == xDX)
6764 {
acd03176 6765 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
6766 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
6767 }
6768 else {
6769 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
6770 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
6771 }
6772 break;
6773 case OPLM_WORD:
6774 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
6775 snprintf(buf2, sizeof(buf2), "%stmp",
6776 (po->op == OP_IDIV) ? "(s32)" : "");
6777 if (po->operand[0].type == OPT_REG
6778 && po->operand[0].reg == xDX)
6779 {
6780 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
6781 buf2, cast, buf1);
6782 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
6783 buf2, cast, buf1);
cb090db0 6784 }
6785 else {
acd03176 6786 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
6787 buf2, cast, buf1);
6788 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
6789 buf2, cast, buf1);
cb090db0 6790 }
d4a985bd 6791 strcat(g_comment, " div16");
cb090db0 6792 break;
6793 default:
acd03176 6794 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
5101a5f9 6795 }
87bf6cec 6796 last_arith_dst = NULL;
6797 delayed_flag_op = NULL;
5101a5f9 6798 break;
6799
91977a1c 6800 case OP_TEST:
6801 case OP_CMP:
850c9265 6802 propagate_lmod(po, &po->operand[0], &po->operand[1]);
940e8e66 6803 if (pfomask != 0) {
69a3cdfc 6804 for (j = 0; j < 8; j++) {
940e8e66 6805 if (pfomask & (1 << j)) {
69a3cdfc 6806 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
6807 fprintf(fout, " cond_%s = %s;",
6808 parsed_flag_op_names[j], buf1);
6809 }
6810 }
940e8e66 6811 pfomask = 0;
69a3cdfc 6812 }
6813 else
6814 no_output = 1;
7ba45c34 6815 last_arith_dst = NULL;
69a3cdfc 6816 delayed_flag_op = po;
91977a1c 6817 break;
6818
092f64e1 6819 case OP_SCC:
6820 // SETcc - should already be handled
6821 break;
6822
69a3cdfc 6823 // note: we reuse OP_Jcc for SETcc, only flags differ
092f64e1 6824 case OP_JCC:
6825 fprintf(fout, "\n goto %s;", po->operand[0].name);
850c9265 6826 break;
6827
5c024ef7 6828 case OP_JECXZ:
6829 fprintf(fout, " if (ecx == 0)\n");
6830 fprintf(fout, " goto %s;", po->operand[0].name);
d4a985bd 6831 strcat(g_comment, " jecxz");
5c024ef7 6832 break;
6833
04abc5d6 6834 case OP_LOOP:
3947cf24 6835 fprintf(fout, " if (--ecx != 0)\n");
04abc5d6 6836 fprintf(fout, " goto %s;", po->operand[0].name);
d4a985bd 6837 strcat(g_comment, " loop");
04abc5d6 6838 break;
6839
850c9265 6840 case OP_JMP:
87bf6cec 6841 assert_operand_cnt(1);
de50b98b 6842 last_arith_dst = NULL;
6843 delayed_flag_op = NULL;
6844
4c45fa73 6845 if (po->operand[0].type == OPT_REGMEM) {
6846 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
6847 buf1, buf2);
6848 if (ret != 2)
6849 ferr(po, "parse failure for jmp '%s'\n",
6850 po->operand[0].name);
6851 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
6852 break;
6853 }
6854 else if (po->operand[0].type != OPT_LABEL)
6855 ferr(po, "unhandled jmp type\n");
87bf6cec 6856
850c9265 6857 fprintf(fout, " goto %s;", po->operand[0].name);
91977a1c 6858 break;
6859
6860 case OP_CALL:
5101a5f9 6861 assert_operand_cnt(1);
092f64e1 6862 pp = po->pp;
89ff3147 6863 my_assert_not(pp, NULL);
91977a1c 6864
092f64e1 6865 strcpy(buf3, " ");
6866 if (po->flags & OPF_CC) {
6867 // we treat conditional branch to another func
6868 // (yes such code exists..) as conditional tailcall
6869 strcat(buf3, " ");
6870 fprintf(fout, " {\n");
6871 }
6872
8eb12e72 6873 if (pp->is_fptr && !pp->is_arg) {
092f64e1 6874 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
1cd4a663 6875 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6876 "(void *)", 0));
8eb12e72 6877 if (pp->is_unresolved)
6878 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
6879 buf3, asmfn, po->asmln, pp->name);
6880 }
1bafb621 6881
092f64e1 6882 fprintf(fout, "%s", buf3);
2b43685d 6883 if (strstr(pp->ret_type.name, "int64")) {
87bf6cec 6884 if (po->flags & OPF_TAIL)
2b43685d 6885 ferr(po, "int64 and tail?\n");
2fe80fdb 6886 fprintf(fout, "tmp64 = ");
2b43685d 6887 }
6888 else if (!IS(pp->ret_type.name, "void")) {
6889 if (po->flags & OPF_TAIL) {
d4a985bd 6890 if (regmask_ret & mxAX) {
840257f6 6891 fprintf(fout, "return ");
6892 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
6893 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
6894 }
d4a985bd 6895 else if (regmask_ret & mxST0)
6896 ferr(po, "float tailcall\n");
2b43685d 6897 }
d4a985bd 6898 else if (po->regmask_dst & mxAX) {
87bf6cec 6899 fprintf(fout, "eax = ");
2b43685d 6900 if (pp->ret_type.is_ptr)
6901 fprintf(fout, "(u32)");
6902 }
d4a985bd 6903 else if (po->regmask_dst & mxST0) {
fe18df39 6904 ferr_assert(po, po->flags & OPF_FPUSH);
6905 if (need_float_stack)
6906 fprintf(fout, "f_st[--f_stp & 7] = ");
6907 else
6908 fprintf(fout, "f_st0 = ");
d4a985bd 6909 }
91977a1c 6910 }
87bf6cec 6911
ddaf8bd7 6912 if (pp->name[0] == 0)
6913 ferr(po, "missing pp->name\n");
6914 fprintf(fout, "%s%s(", pp->name,
6915 pp->has_structarg ? "_sa" : "");
39b168b8 6916
2fe80fdb 6917 if (po->flags & OPF_ATAIL) {
6918 if (pp->argc_stack != g_func_pp->argc_stack
6919 || (pp->argc_stack > 0
6920 && pp->is_stdcall != g_func_pp->is_stdcall))
6921 ferr(po, "incompatible tailcall\n");
1f84f6b3 6922 if (g_func_pp->has_retreg)
6923 ferr(po, "TODO: retreg+tailcall\n");
87bf6cec 6924
2fe80fdb 6925 for (arg = j = 0; arg < pp->argc; arg++) {
6926 if (arg > 0)
6927 fprintf(fout, ", ");
87bf6cec 6928
2fe80fdb 6929 cast[0] = 0;
6930 if (pp->arg[arg].type.is_ptr)
6931 snprintf(cast, sizeof(cast), "(%s)",
6932 pp->arg[arg].type.name);
91977a1c 6933
2fe80fdb 6934 if (pp->arg[arg].reg != NULL) {
6935 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6936 continue;
6937 }
6938 // stack arg
6939 for (; j < g_func_pp->argc; j++)
6940 if (g_func_pp->arg[j].reg == NULL)
6941 break;
6942 fprintf(fout, "%sa%d", cast, j + 1);
6943 j++;
69a3cdfc 6944 }
2fe80fdb 6945 }
6946 else {
6947 for (arg = 0; arg < pp->argc; arg++) {
6948 if (arg > 0)
6949 fprintf(fout, ", ");
6950
6951 cast[0] = 0;
6952 if (pp->arg[arg].type.is_ptr)
6953 snprintf(cast, sizeof(cast), "(%s)",
6954 pp->arg[arg].type.name);
6955
6956 if (pp->arg[arg].reg != NULL) {
1f84f6b3 6957 if (pp->arg[arg].type.is_retreg)
6958 fprintf(fout, "&%s", pp->arg[arg].reg);
8c83cc48 6959 else if (IS(pp->arg[arg].reg, "ebp")
e627c4d0 6960 && g_bp_frame && !(po->flags & OPF_EBP_S))
8c83cc48 6961 {
6962 // rare special case
6963 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
6964 strcat(g_comment, " bp_ref");
6965 }
1f84f6b3 6966 else
6967 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
2fe80fdb 6968 continue;
6969 }
6970
6971 // stack arg
6972 tmp_op = pp->arg[arg].datap;
6973 if (tmp_op == NULL)
6974 ferr(po, "parsed_op missing for arg%d\n", arg);
23fd0b11 6975
6976 if (tmp_op->flags & OPF_VAPUSH) {
6977 fprintf(fout, "ap");
6978 }
30620174 6979 else if (tmp_op->op == OP_FST) {
6980 fprintf(fout, "fs_%d", tmp_op->p_argnum);
6981 if (tmp_op->operand[0].lmod == OPLM_QWORD)
6982 arg++;
6983 }
5f70a34f 6984 else if (tmp_op->p_argpass != 0) {
6985 fprintf(fout, "a%d", tmp_op->p_argpass);
6986 }
8c83cc48 6987 else if (pp->arg[arg].is_saved) {
6988 ferr_assert(po, tmp_op->p_argnum > 0);
3a5101d7 6989 fprintf(fout, "%s%s", cast,
6990 saved_arg_name(buf1, sizeof(buf1),
6991 tmp_op->p_arggrp, tmp_op->p_argnum));
2fe80fdb 6992 }
6993 else {
6994 fprintf(fout, "%s",
6995 out_src_opr(buf1, sizeof(buf1),
6996 tmp_op, &tmp_op->operand[0], cast, 0));
6997 }
69a3cdfc 6998 }
91977a1c 6999 }
7000 fprintf(fout, ");");
87bf6cec 7001
2b43685d 7002 if (strstr(pp->ret_type.name, "int64")) {
7003 fprintf(fout, "\n");
092f64e1 7004 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7005 fprintf(fout, "%seax = tmp64;", buf3);
2b43685d 7006 }
7007
89ff3147 7008 if (pp->is_unresolved) {
8eb12e72 7009 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
89ff3147 7010 pp->argc_reg);
092f64e1 7011 strcat(g_comment, buf2);
89ff3147 7012 }
7013
87bf6cec 7014 if (po->flags & OPF_TAIL) {
840257f6 7015 ret = 0;
ddaf8bd7 7016 if (i == opcnt - 1 || pp->is_noreturn)
840257f6 7017 ret = 0;
7018 else if (IS(pp->ret_type.name, "void"))
7019 ret = 1;
b2bd20c0 7020 else if (!(regmask_ret & (1 << xAX)))
840257f6 7021 ret = 1;
7022 // else already handled as 'return f()'
7023
7024 if (ret) {
acd03176 7025 fprintf(fout, "\n%sreturn;", buf3);
7026 strcat(g_comment, " ^ tailcall");
3ebea2cf 7027 }
89ff3147 7028 else
ddaf8bd7 7029 strcat(g_comment, " tailcall");
acd03176 7030
7031 if ((regmask_ret & (1 << xAX))
7032 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7033 {
7034 ferr(po, "int func -> void func tailcall?\n");
7035 }
87bf6cec 7036 }
ddaf8bd7 7037 if (pp->is_noreturn)
7038 strcat(g_comment, " noreturn");
2fe80fdb 7039 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7040 strcat(g_comment, " argframe");
092f64e1 7041 if (po->flags & OPF_CC)
7042 strcat(g_comment, " cond");
7043
7044 if (po->flags & OPF_CC)
7045 fprintf(fout, "\n }");
7046
87bf6cec 7047 delayed_flag_op = NULL;
7048 last_arith_dst = NULL;
91977a1c 7049 break;
7050
7051 case OP_RET:
bd96f656 7052 if (g_func_pp->is_vararg)
4f12f671 7053 fprintf(fout, " va_end(ap);\n");
1f84f6b3 7054 if (g_func_pp->has_retreg) {
7055 for (arg = 0; arg < g_func_pp->argc; arg++)
7056 if (g_func_pp->arg[arg].type.is_retreg)
7057 fprintf(fout, " *r_%s = %s;\n",
7058 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7059 }
4f12f671 7060
16057ce1 7061 if (regmask_ret & mxST0) {
7062 fprintf(fout, " return %s;", float_st0);
7063 }
7064 else if (!(regmask_ret & mxAX)) {
3ebea2cf 7065 if (i != opcnt - 1 || label_pending)
7066 fprintf(fout, " return;");
7067 }
bd96f656 7068 else if (g_func_pp->ret_type.is_ptr) {
d4e3b5db 7069 fprintf(fout, " return (%s)eax;",
bd96f656 7070 g_func_pp->ret_type.name);
3ebea2cf 7071 }
2fe80fdb 7072 else if (IS(g_func_pp->ret_type.name, "__int64"))
7073 fprintf(fout, " return ((u64)edx << 32) | eax;");
91977a1c 7074 else
7075 fprintf(fout, " return eax;");
de50b98b 7076
7077 last_arith_dst = NULL;
7078 delayed_flag_op = NULL;
91977a1c 7079 break;
7080
7081 case OP_PUSH:
1f84f6b3 7082 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
5f70a34f 7083 if (po->p_argnum != 0) {
69a3cdfc 7084 // special case - saved func arg
3a5101d7 7085 fprintf(fout, " %s = %s;",
7086 saved_arg_name(buf2, sizeof(buf2),
7087 po->p_arggrp, po->p_argnum), buf1);
69a3cdfc 7088 break;
7089 }
d4e3b5db 7090 else if (po->flags & OPF_RSAVE) {
d4e3b5db 7091 fprintf(fout, " s_%s = %s;", buf1, buf1);
7092 break;
7093 }
25a330eb 7094 else if (po->flags & OPF_PPUSH) {
7095 tmp_op = po->datap;
7096 ferr_assert(po, tmp_op != NULL);
7097 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7098 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7099 break;
7100 }
1f84f6b3 7101 else if (g_func_pp->is_userstack) {
7102 fprintf(fout, " *(--esp) = %s;", buf1);
7103 break;
7104 }
e56ab892 7105 if (!(g_ida_func_attr & IDAFA_NORETURN))
7106 ferr(po, "stray push encountered\n");
7107 no_output = 1;
91977a1c 7108 break;
7109
7110 case OP_POP:
25a330eb 7111 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
d4e3b5db 7112 if (po->flags & OPF_RSAVE) {
d4e3b5db 7113 fprintf(fout, " %s = s_%s;", buf1, buf1);
7114 break;
7115 }
25a330eb 7116 else if (po->flags & OPF_PPUSH) {
e83ea7ed 7117 // push/pop graph / non-const
25a330eb 7118 ferr_assert(po, po->datap == NULL);
7119 fprintf(fout, " %s = pp_%s;", buf1, buf1);
7120 break;
7121 }
5c024ef7 7122 else if (po->datap != NULL) {
7123 // push/pop pair
7124 tmp_op = po->datap;
5c024ef7 7125 fprintf(fout, " %s = %s;", buf1,
7126 out_src_opr(buf2, sizeof(buf2),
7127 tmp_op, &tmp_op->operand[0],
c7ed83dd 7128 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
5c024ef7 7129 break;
7130 }
1f84f6b3 7131 else if (g_func_pp->is_userstack) {
25a330eb 7132 fprintf(fout, " %s = *esp++;", buf1);
1f84f6b3 7133 break;
7134 }
7135 else
7136 ferr(po, "stray pop encountered\n");
91977a1c 7137 break;
7138
33c35af6 7139 case OP_NOP:
2b43685d 7140 no_output = 1;
33c35af6 7141 break;
7142
622eb2ef 7143 // pseudo ops
7144 case OPP_ALLSHL:
7145 case OPP_ALLSHR:
7146 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
8c83cc48 7147 fprintf(fout, " tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
622eb2ef 7148 po->op == OPP_ALLSHL ? "<<" : ">>");
7149 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
7150 strcat(g_comment, po->op == OPP_ALLSHL
7151 ? " allshl" : " allshr");
7152 break;
7153
d4a985bd 7154 // x87
7155 case OP_FLD:
fe18df39 7156 if (need_float_stack) {
7157 out_src_opr_float(buf1, sizeof(buf1),
7158 po, &po->operand[0], 1);
7159 if (po->regmask_src & mxSTa) {
7160 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7161 buf1);
7162 }
7163 else
7164 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
7165 }
7166 else {
7167 if (po->flags & OPF_FSHIFT)
7168 fprintf(fout, " f_st1 = f_st0;");
7169 if (po->operand[0].type == OPT_REG
7170 && po->operand[0].reg == xST0)
7171 {
7172 strcat(g_comment, " fld st");
7173 break;
7174 }
7175 fprintf(fout, " f_st0 = %s;",
7176 out_src_opr_float(buf1, sizeof(buf1),
7177 po, &po->operand[0], 0));
d4a985bd 7178 }
d4a985bd 7179 strcat(g_comment, " fld");
7180 break;
7181
7182 case OP_FILD:
fe18df39 7183 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7184 lmod_cast(po, po->operand[0].lmod, 1), 0);
7185 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7186 if (need_float_stack) {
7187 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
7188 }
7189 else {
7190 if (po->flags & OPF_FSHIFT)
7191 fprintf(fout, " f_st1 = f_st0;");
7192 fprintf(fout, " f_st0 = %s;", buf2);
7193 }
d4a985bd 7194 strcat(g_comment, " fild");
7195 break;
7196
7197 case OP_FLDc:
fe18df39 7198 if (need_float_stack)
7199 fprintf(fout, " f_st[--f_stp & 7] = ");
7200 else {
7201 if (po->flags & OPF_FSHIFT)
7202 fprintf(fout, " f_st1 = f_st0;");
7203 fprintf(fout, " f_st0 = ");
7204 }
d4a985bd 7205 switch (po->operand[0].val) {
fe18df39 7206 case X87_CONST_1: fprintf(fout, "1.0;"); break;
7207 case X87_CONST_LN2: fprintf(fout, "0.693147180559945;"); break;
7208 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
d4a985bd 7209 default: ferr(po, "TODO\n"); break;
7210 }
7211 break;
7212
7213 case OP_FST:
30620174 7214 if (po->flags & OPF_FARG) {
7215 // store to stack as func arg
7216 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7217 dead_dst = 0;
7218 }
7219 else {
7220 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7221 need_float_stack);
7222 dead_dst = po->operand[0].type == OPT_REG
7223 && po->operand[0].reg == xST0;
fe18df39 7224 }
30620174 7225 if (!dead_dst)
7226 fprintf(fout, " %s = %s;", buf1, float_st0);
16057ce1 7227 if (po->flags & OPF_FSHIFT) {
7228 if (need_float_stack)
7229 fprintf(fout, " f_stp++;");
7230 else
fe18df39 7231 fprintf(fout, " f_st0 = f_st1;");
d4a985bd 7232 }
fe18df39 7233 if (dead_dst && !(po->flags & OPF_FSHIFT))
7234 no_output = 1;
7235 else
7236 strcat(g_comment, " fst");
d4a985bd 7237 break;
7238
16057ce1 7239 case OP_FIST:
7240 fprintf(fout, " %s = %s%s;",
7241 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7242 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7243 if (po->flags & OPF_FSHIFT) {
7244 if (need_float_stack)
7245 fprintf(fout, " f_stp++;");
7246 else
7247 fprintf(fout, " f_st0 = f_st1;");
7248 }
7249 strcat(g_comment, " fist");
7250 break;
7251
d4a985bd 7252 case OP_FADD:
7253 case OP_FDIV:
7254 case OP_FMUL:
7255 case OP_FSUB:
fe18df39 7256 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7257 need_float_stack);
7258 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7259 need_float_stack);
7260 dead_dst = (po->flags & OPF_FPOP)
7261 && po->operand[0].type == OPT_REG
7262 && po->operand[0].reg == xST0;
d4a985bd 7263 switch (po->op) {
7264 case OP_FADD: j = '+'; break;
7265 case OP_FDIV: j = '/'; break;
7266 case OP_FMUL: j = '*'; break;
7267 case OP_FSUB: j = '-'; break;
7268 default: j = 'x'; break;
7269 }
fe18df39 7270 if (need_float_stack) {
7271 if (!dead_dst)
7272 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7273 if (po->flags & OPF_FSHIFT)
7274 fprintf(fout, " f_stp++;");
d4a985bd 7275 }
7276 else {
fe18df39 7277 if (po->flags & OPF_FSHIFT) {
7278 // note: assumes only 2 regs handled
7279 if (!dead_dst)
7280 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
7281 else
7282 fprintf(fout, " f_st0 = f_st1;");
7283 }
7284 else if (!dead_dst)
7285 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
d4a985bd 7286 }
fe18df39 7287 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
d4a985bd 7288 break;
7289
7290 case OP_FDIVR:
7291 case OP_FSUBR:
fe18df39 7292 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7293 need_float_stack);
7294 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7295 need_float_stack);
7296 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
7297 need_float_stack);
7298 dead_dst = (po->flags & OPF_FPOP)
7299 && po->operand[0].type == OPT_REG
7300 && po->operand[0].reg == xST0;
7301 j = po->op == OP_FDIVR ? '/' : '-';
7302 if (need_float_stack) {
7303 if (!dead_dst)
7304 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7305 if (po->flags & OPF_FSHIFT)
7306 fprintf(fout, " f_stp++;");
7307 }
7308 else {
7309 if (po->flags & OPF_FSHIFT) {
7310 if (!dead_dst)
7311 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
7312 else
7313 fprintf(fout, " f_st0 = f_st1;");
7314 }
7315 else if (!dead_dst)
7316 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7317 }
7318 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
d4a985bd 7319 break;
7320
7321 case OP_FIADD:
7322 case OP_FIDIV:
7323 case OP_FIMUL:
7324 case OP_FISUB:
7325 switch (po->op) {
7326 case OP_FIADD: j = '+'; break;
7327 case OP_FIDIV: j = '/'; break;
7328 case OP_FIMUL: j = '*'; break;
7329 case OP_FISUB: j = '-'; break;
7330 default: j = 'x'; break;
7331 }
fe18df39 7332 fprintf(fout, " %s %c= (%s)%s;", float_st0,
7333 j, float_type,
d4a985bd 7334 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7335 lmod_cast(po, po->operand[0].lmod, 1), 0));
7336 break;
7337
7338 case OP_FIDIVR:
7339 case OP_FISUBR:
fe18df39 7340 fprintf(fout, " %s = %s %c %s;", float_st0,
7341 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7342 need_float_stack),
7343 po->op == OP_FIDIVR ? '/' : '-', float_st0);
7344 break;
7345
16057ce1 7346 case OP_FCOM: {
7347 int mask, z_check;
7348 ferr_assert(po, po->datap != NULL);
7349 mask = (long)po->datap & 0xffff;
7350 z_check = ((long)po->datap >> 16) & 1;
7351 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7352 need_float_stack);
7353 if (mask == 0x0100) { // C0 -> <
7354 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
7355 float_st0, buf1);
7356 }
7357 else if (mask == 0x4000) { // C3 -> =
7358 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
7359 float_st0, buf1);
7360 }
7361 else if (mask == 0x4100) { // C3, C0
7362 if (z_check) {
7363 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
7364 float_st0, buf1);
7365 strcat(g_comment, " z_chk_det");
7366 }
7367 else {
7368 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
7369 "(%s < %s ? 0x0100 : 0);",
7370 float_st0, buf1, float_st0, buf1);
7371 }
7372 }
7373 else
7374 ferr(po, "unhandled sw mask: %x\n", mask);
7375 if (po->flags & OPF_FSHIFT) {
7376 if (need_float_stack)
7377 fprintf(fout, " f_stp++;");
7378 else
7379 fprintf(fout, " f_st0 = f_st1;");
7380 }
7381 break;
7382 }
7383
7384 case OP_FNSTSW:
7385 fprintf(fout, " %s = f_sw;",
7386 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7387 break;
7388
fe18df39 7389 case OP_FCHS:
7390 fprintf(fout, " %s = -%s;", float_st0, float_st0);
d4a985bd 7391 break;
7392
497a6d6b 7393 case OP_FCOS:
fe18df39 7394 fprintf(fout, " %s = cos%s(%s);", float_st0,
7395 need_double ? "" : "f", float_st0);
497a6d6b 7396 break;
7397
7398 case OP_FPATAN:
fe18df39 7399 if (need_float_stack) {
7400 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
7401 need_double ? "" : "f", float_st1, float_st0);
7402 fprintf(fout, " f_stp++;");
7403 }
7404 else {
7405 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
7406 need_double ? "" : "f");
7407 }
7408 break;
7409
7410 case OP_FYL2X:
7411 if (need_float_stack) {
7412 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
7413 float_st1, need_double ? "" : "f", float_st0);
7414 fprintf(fout, " f_stp++;");
7415 }
7416 else {
7417 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
7418 need_double ? "" : "f");
7419 }
8c83cc48 7420 strcat(g_comment, " fyl2x");
497a6d6b 7421 break;
7422
7423 case OP_FSIN:
fe18df39 7424 fprintf(fout, " %s = sin%s(%s);", float_st0,
7425 need_double ? "" : "f", float_st0);
497a6d6b 7426 break;
7427
7428 case OP_FSQRT:
fe18df39 7429 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
7430 need_double ? "" : "f", float_st0);
7431 break;
7432
7433 case OP_FXCH:
7434 dead_dst = po->operand[0].type == OPT_REG
7435 && po->operand[0].reg == xST0;
7436 if (!dead_dst) {
7437 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7438 need_float_stack);
7439 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
7440 float_st0, float_st0, buf1, buf1);
7441 strcat(g_comment, " fxch");
7442 }
7443 else
7444 no_output = 1;
497a6d6b 7445 break;
7446
d4a985bd 7447 case OPP_FTOL:
7448 ferr_assert(po, po->flags & OPF_32BIT);
fe18df39 7449 fprintf(fout, " eax = (s32)%s;", float_st0);
7450 if (po->flags & OPF_FSHIFT) {
7451 if (need_float_stack)
7452 fprintf(fout, " f_stp++;");
7453 else
7454 fprintf(fout, " f_st0 = f_st1;");
7455 }
d4a985bd 7456 strcat(g_comment, " ftol");
7457 break;
7458
8c83cc48 7459 case OPP_CIPOW:
7460 if (need_float_stack) {
7461 fprintf(fout, " %s = pow%s(%s, %s);", float_st1,
7462 need_double ? "" : "f", float_st1, float_st0);
7463 fprintf(fout, " f_stp++;");
7464 }
7465 else {
7466 fprintf(fout, " f_st0 = pow%s(f_st1, f_st0);",
7467 need_double ? "" : "f");
7468 }
7469 strcat(g_comment, " CIpow");
7470 break;
7471
11437ea1 7472 case OPP_ABORT:
7473 fprintf(fout, " do_skip_code_abort();");
7474 break;
7475
90307a99 7476 // mmx
7477 case OP_EMMS:
11437ea1 7478 fprintf(fout, " do_emms();");
90307a99 7479 break;
7480
91977a1c 7481 default:
7482 no_output = 1;
69a3cdfc 7483 ferr(po, "unhandled op type %d, flags %x\n",
7484 po->op, po->flags);
91977a1c 7485 break;
7486 }
7487
7488 if (g_comment[0] != 0) {
ddaf8bd7 7489 char *p = g_comment;
7490 while (my_isblank(*p))
7491 p++;
7492 fprintf(fout, " // %s", p);
91977a1c 7493 g_comment[0] = 0;
7494 no_output = 0;
7495 }
7496 if (!no_output)
7497 fprintf(fout, "\n");
5101a5f9 7498
2b43685d 7499 // some sanity checking
591721d7 7500 if (po->flags & OPF_REP) {
7501 if (po->op != OP_STOS && po->op != OP_MOVS
7502 && po->op != OP_CMPS && po->op != OP_SCAS)
7503 ferr(po, "unexpected rep\n");
7504 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
7505 && (po->op == OP_CMPS || po->op == OP_SCAS))
7506 ferr(po, "cmps/scas with plain rep\n");
7507 }
7508 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
7509 && po->op != OP_CMPS && po->op != OP_SCAS)
2b43685d 7510 ferr(po, "unexpected repz/repnz\n");
7511
940e8e66 7512 if (pfomask != 0)
7ba45c34 7513 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
940e8e66 7514
5101a5f9 7515 // see is delayed flag stuff is still valid
7516 if (delayed_flag_op != NULL && delayed_flag_op != po) {
89ff3147 7517 if (is_any_opr_modified(delayed_flag_op, po, 0))
5101a5f9 7518 delayed_flag_op = NULL;
7519 }
7520
7521 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
7522 if (is_opr_modified(last_arith_dst, po))
7523 last_arith_dst = NULL;
7524 }
3ebea2cf 7525
7526 label_pending = 0;
91977a1c 7527 }
7528
a2c1d768 7529 if (g_stack_fsz && !g_stack_frame_used)
7530 fprintf(fout, " (void)sf;\n");
7531
91977a1c 7532 fprintf(fout, "}\n\n");
7533
9af2d373 7534 gen_x_cleanup(opcnt);
7535}
7536
7537static void gen_x_cleanup(int opcnt)
7538{
7539 int i;
7540
91977a1c 7541 for (i = 0; i < opcnt; i++) {
4c45fa73 7542 struct label_ref *lr, *lr_del;
7543
7544 lr = g_label_refs[i].next;
7545 while (lr != NULL) {
7546 lr_del = lr;
7547 lr = lr->next;
7548 free(lr_del);
7549 }
7550 g_label_refs[i].i = -1;
7551 g_label_refs[i].next = NULL;
7552
91977a1c 7553 if (ops[i].op == OP_CALL) {
092f64e1 7554 if (ops[i].pp)
7555 proto_release(ops[i].pp);
91977a1c 7556 }
7557 }
bd96f656 7558 g_func_pp = NULL;
91977a1c 7559}
c36e914d 7560
92d715b6 7561struct func_proto_dep;
7562
7563struct func_prototype {
7564 char name[NAMELEN];
7565 int id;
7566 int argc_stack;
7567 int regmask_dep;
91ca764a 7568 int has_ret:3; // -1, 0, 1: unresolved, no, yes
92d715b6 7569 unsigned int dep_resolved:1;
7570 unsigned int is_stdcall:1;
7571 struct func_proto_dep *dep_func;
7572 int dep_func_cnt;
91ca764a 7573 const struct parsed_proto *pp; // seed pp, if any
92d715b6 7574};
7575
7576struct func_proto_dep {
7577 char *name;
7578 struct func_prototype *proto;
7579 int regmask_live; // .. at the time of call
7580 unsigned int ret_dep:1; // return from this is caller's return
7581};
7582
7583static struct func_prototype *hg_fp;
7584static int hg_fp_cnt;
7585
5fa1256f 7586static struct scanned_var {
7587 char name[NAMELEN];
7588 enum opr_lenmod lmod;
7589 unsigned int is_seeded:1;
61e29183 7590 unsigned int is_c_str:1;
c0de9015 7591 const struct parsed_proto *pp; // seed pp, if any
5fa1256f 7592} *hg_vars;
7593static int hg_var_cnt;
7594
8c999988 7595static char **hg_refs;
7596static int hg_ref_cnt;
7597
9af2d373 7598static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7599 int count);
7600
8c999988 7601static struct func_prototype *hg_fp_add(const char *funcn)
ebc4dc43 7602{
7603 struct func_prototype *fp;
7604
7605 if ((hg_fp_cnt & 0xff) == 0) {
7606 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
7607 my_assert_not(hg_fp, NULL);
7608 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
7609 }
7610
7611 fp = &hg_fp[hg_fp_cnt];
7612 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
7613 fp->id = hg_fp_cnt;
7614 fp->argc_stack = -1;
7615 hg_fp_cnt++;
7616
7617 return fp;
7618}
7619
92d715b6 7620static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
7621 const char *name)
7622{
7623 int i;
7624
7625 for (i = 0; i < fp->dep_func_cnt; i++)
7626 if (IS(fp->dep_func[i].name, name))
7627 return &fp->dep_func[i];
7628
7629 return NULL;
7630}
7631
7632static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
7633{
7634 // is it a dupe?
7635 if (hg_fp_find_dep(fp, name))
7636 return;
7637
7638 if ((fp->dep_func_cnt & 0xff) == 0) {
7639 fp->dep_func = realloc(fp->dep_func,
7640 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
7641 my_assert_not(fp->dep_func, NULL);
7642 memset(&fp->dep_func[fp->dep_func_cnt], 0,
7643 sizeof(fp->dep_func[0]) * 0x100);
7644 }
7645 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
7646 fp->dep_func_cnt++;
7647}
7648
7649static int hg_fp_cmp_name(const void *p1_, const void *p2_)
7650{
7651 const struct func_prototype *p1 = p1_, *p2 = p2_;
7652 return strcmp(p1->name, p2->name);
7653}
7654
7655#if 0
7656static int hg_fp_cmp_id(const void *p1_, const void *p2_)
7657{
7658 const struct func_prototype *p1 = p1_, *p2 = p2_;
7659 return p1->id - p2->id;
7660}
7661#endif
7662
8c999988 7663static void hg_ref_add(const char *name)
7664{
7665 if ((hg_ref_cnt & 0xff) == 0) {
7666 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
7667 my_assert_not(hg_refs, NULL);
7668 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
7669 }
7670
7671 hg_refs[hg_ref_cnt] = strdup(name);
7672 my_assert_not(hg_refs[hg_ref_cnt], NULL);
7673 hg_ref_cnt++;
7674}
7675
91ca764a 7676// recursive register dep pass
7677// - track saved regs (part 2)
7678// - try to figure out arg-regs
7679// - calculate reg deps
7680static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
7681 struct func_prototype *fp, int regmask_save, int regmask_dst,
7682 int *regmask_dep, int *has_ret)
7683{
7684 struct func_proto_dep *dep;
7685 struct parsed_op *po;
7686 int from_caller = 0;
91ca764a 7687 int j, l;
7688 int reg;
7689 int ret;
7690
7691 for (; i < opcnt; i++)
7692 {
7693 if (cbits[i >> 3] & (1 << (i & 7)))
7694 return;
7695 cbits[i >> 3] |= (1 << (i & 7));
7696
7697 po = &ops[i];
7698
7699 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
04abc5d6 7700 if (po->flags & OPF_RMD)
7701 continue;
7702
91ca764a 7703 if (po->btj != NULL) {
7704 // jumptable
7705 for (j = 0; j < po->btj->count; j++) {
db63af51 7706 check_i(po, po->btj->d[j].bt_i);
91ca764a 7707 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
7708 regmask_save, regmask_dst, regmask_dep, has_ret);
7709 }
7710 return;
7711 }
7712
db63af51 7713 check_i(po, po->bt_i);
91ca764a 7714 if (po->flags & OPF_CJMP) {
7715 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
7716 regmask_save, regmask_dst, regmask_dep, has_ret);
7717 }
7718 else {
7719 i = po->bt_i - 1;
7720 }
7721 continue;
7722 }
7723
7724 if (po->flags & OPF_FARG)
7725 /* (just calculate register deps) */;
7726 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
7727 {
7728 reg = po->operand[0].reg;
b2bd20c0 7729 ferr_assert(po, reg >= 0);
91ca764a 7730
7731 if (po->flags & OPF_RSAVE) {
7732 regmask_save |= 1 << reg;
7733 continue;
7734 }
7735 if (po->flags & OPF_DONE)
7736 continue;
7737
93b5bd18 7738 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0, 0);
91ca764a 7739 if (ret == 1) {
7740 regmask_save |= 1 << reg;
7741 po->flags |= OPF_RMD;
93b5bd18 7742 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, OPF_RMD);
91ca764a 7743 continue;
7744 }
7745 }
7746 else if (po->flags & OPF_RMD)
7747 continue;
7748 else if (po->op == OP_CALL) {
7749 po->regmask_dst |= 1 << xAX;
7750
7751 dep = hg_fp_find_dep(fp, po->operand[0].name);
e627c4d0 7752 if (dep != NULL) {
91ca764a 7753 dep->regmask_live = regmask_save | regmask_dst;
e627c4d0 7754 if (g_bp_frame && !(po->flags & OPF_EBP_S))
7755 dep->regmask_live |= 1 << xBP;
7756 }
91ca764a 7757 }
7758 else if (po->op == OP_RET) {
7759 if (po->operand_cnt > 0) {
7760 fp->is_stdcall = 1;
7761 if (fp->argc_stack >= 0
7762 && fp->argc_stack != po->operand[0].val / 4)
7763 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
7764 fp->argc_stack = po->operand[0].val / 4;
7765 }
7766 }
7767
ebc4dc43 7768 // if has_ret is 0, there is uninitialized eax path,
7769 // which means it's most likely void func
91ca764a 7770 if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
7771 if (po->op == OP_CALL) {
7772 j = i;
7773 ret = 1;
7774 }
7775 else {
b2bd20c0 7776 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
91ca764a 7777 j = -1;
7778 from_caller = 0;
7779 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
7780 }
7781
ebc4dc43 7782 if (ret != 1 && from_caller) {
91ca764a 7783 // unresolved eax - probably void func
7784 *has_ret = 0;
7785 }
7786 else {
ebc4dc43 7787 if (j >= 0 && ops[j].op == OP_CALL) {
7788 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
91ca764a 7789 if (dep != NULL)
7790 dep->ret_dep = 1;
7791 else
7792 *has_ret = 1;
7793 }
7794 else
7795 *has_ret = 1;
7796 }
7797 }
7798
7799 l = regmask_save | regmask_dst;
7800 if (g_bp_frame && !(po->flags & OPF_EBP_S))
7801 l |= 1 << xBP;
7802
7803 l = po->regmask_src & ~l;
7804#if 0
7805 if (l)
7806 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
7807 l, regmask_dst, regmask_save, po->flags);
7808#endif
7809 *regmask_dep |= l;
7810 regmask_dst |= po->regmask_dst;
7811
7812 if (po->flags & OPF_TAIL)
7813 return;
7814 }
7815}
7816
92d715b6 7817static void gen_hdr(const char *funcn, int opcnt)
7818{
91ca764a 7819 unsigned char cbits[MAX_OPS / 8];
ebc4dc43 7820 const struct parsed_proto *pp_c;
9af2d373 7821 struct parsed_proto *pp;
92d715b6 7822 struct func_prototype *fp;
92d715b6 7823 struct parsed_op *po;
26677139 7824 int regmask_dummy = 0;
91ca764a 7825 int regmask_dep;
92d715b6 7826 int max_bp_offset = 0;
91ca764a 7827 int has_ret;
bfacdc83 7828 int i, j, l;
7829 int ret;
92d715b6 7830
ebc4dc43 7831 pp_c = proto_parse(g_fhdr, funcn, 1);
7832 if (pp_c != NULL)
7833 // already in seed, will add to hg_fp later
9af2d373 7834 return;
ebc4dc43 7835
7836 fp = hg_fp_add(funcn);
9af2d373 7837
7838 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
7839 g_stack_frame_used = 0;
7840
92d715b6 7841 // pass1:
66bdb2b0 7842 // - resolve all branches
7843 // - parse calls with labels
7844 resolve_branches_parse_calls(opcnt);
7845
7846 // pass2:
9af2d373 7847 // - handle ebp/esp frame, remove ops related to it
7848 scan_prologue_epilogue(opcnt);
7849
66bdb2b0 7850 // pass3:
7851 // - remove dead labels
92d715b6 7852 // - collect calls
92d715b6 7853 for (i = 0; i < opcnt; i++)
7854 {
66bdb2b0 7855 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7856 free(g_labels[i]);
7857 g_labels[i] = NULL;
7858 }
92d715b6 7859
66bdb2b0 7860 po = &ops[i];
5e49b270 7861 if (po->flags & (OPF_RMD|OPF_DONE))
92d715b6 7862 continue;
7863
7864 if (po->op == OP_CALL) {
66bdb2b0 7865 if (po->operand[0].type == OPT_LABEL)
7866 hg_fp_add_dep(fp, opr_name(po, 0));
7867 else if (po->pp != NULL)
7868 hg_fp_add_dep(fp, po->pp->name);
92d715b6 7869 }
92d715b6 7870 }
7871
66bdb2b0 7872 // pass4:
92d715b6 7873 // - remove dead labels
9af2d373 7874 // - handle push <const>/pop pairs
92d715b6 7875 for (i = 0; i < opcnt; i++)
7876 {
d7857c3a 7877 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7878 free(g_labels[i]);
7879 g_labels[i] = NULL;
7880 }
9af2d373 7881
91ca764a 7882 po = &ops[i];
7883 if (po->flags & (OPF_RMD|OPF_DONE))
7884 continue;
7885
7886 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
e83ea7ed 7887 scan_for_pop_const(i, opcnt, i + opcnt * 13);
91ca764a 7888 }
7889
66bdb2b0 7890 // pass5:
91ca764a 7891 // - process trivial calls
7892 for (i = 0; i < opcnt; i++)
7893 {
9af2d373 7894 po = &ops[i];
5e49b270 7895 if (po->flags & (OPF_RMD|OPF_DONE))
9af2d373 7896 continue;
7897
26677139 7898 if (po->op == OP_CALL)
7899 {
7900 pp = process_call_early(i, opcnt, &j);
7901 if (pp != NULL) {
7902 if (!(po->flags & OPF_ATAIL))
7903 // since we know the args, try to collect them
30620174 7904 if (collect_call_args_early(i, pp, NULL, NULL) != 0)
26677139 7905 pp = NULL;
7906 }
7907
7908 if (pp != NULL) {
7909 if (j >= 0) {
7910 // commit esp adjust
5e49b270 7911 if (ops[j].op != OP_POP)
7912 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
bfacdc83 7913 else {
7914 for (l = 0; l < pp->argc_stack; l++)
b2bd20c0 7915 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
bfacdc83 7916 }
26677139 7917 }
7918
7919 po->flags |= OPF_DONE;
7920 }
7921 }
26677139 7922 }
7923
66bdb2b0 7924 // pass6:
5e49b270 7925 // - track saved regs (simple)
26677139 7926 // - process calls
7927 for (i = 0; i < opcnt; i++)
7928 {
7929 po = &ops[i];
5e49b270 7930 if (po->flags & (OPF_RMD|OPF_DONE))
26677139 7931 continue;
7932
e83ea7ed 7933 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
7934 && po->operand[0].reg != xCX)
5e49b270 7935 {
e83ea7ed 7936 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
b2bd20c0 7937 if (ret == 1) {
91ca764a 7938 // regmask_save |= 1 << po->operand[0].reg; // do it later
7939 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
e83ea7ed 7940 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
5e49b270 7941 }
7942 }
e83ea7ed 7943 else if (po->op == OP_CALL)
26677139 7944 {
9af2d373 7945 pp = process_call(i, opcnt);
7946
7947 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
9af2d373 7948 // since we know the args, collect them
8c83cc48 7949 ret = collect_call_args(po, i, pp, &regmask_dummy,
7950 i + opcnt * 1);
9af2d373 7951 }
7952 }
92d715b6 7953 }
7954
66bdb2b0 7955 // pass7
91ca764a 7956 memset(cbits, 0, sizeof(cbits));
7957 regmask_dep = 0;
7958 has_ret = -1;
7959
7960 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, &regmask_dep, &has_ret);
7961
7962 // find unreachable code - must be fixed in IDA
92d715b6 7963 for (i = 0; i < opcnt; i++)
7964 {
91ca764a 7965 if (cbits[i >> 3] & (1 << (i & 7)))
9af2d373 7966 continue;
92d715b6 7967
04abc5d6 7968 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
7969 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
7970 {
7971 // the compiler sometimes still generates code after
7972 // noreturn OS functions
7973 break;
7974 }
ea43585b 7975 if (ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
91ca764a 7976 ferr(&ops[i], "unreachable code\n");
92d715b6 7977 }
7978
9af2d373 7979 for (i = 0; i < g_eqcnt; i++) {
92d715b6 7980 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
7981 max_bp_offset = g_eqs[i].offset;
9af2d373 7982 }
92d715b6 7983
9af2d373 7984 if (fp->argc_stack < 0) {
92d715b6 7985 max_bp_offset = (max_bp_offset + 3) & ~3;
9af2d373 7986 fp->argc_stack = max_bp_offset / 4;
7987 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
92d715b6 7988 fp->argc_stack--;
7989 }
7990
622eb2ef 7991 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
92d715b6 7992 fp->has_ret = has_ret;
91ca764a 7993#if 0
7994 printf("// has_ret %d, regmask_dep %x\n",
7995 fp->has_ret, fp->regmask_dep);
7996 output_hdr_fp(stdout, fp, 1);
ebc4dc43 7997 if (IS(funcn, "sub_10007F72")) exit(1);
91ca764a 7998#endif
9af2d373 7999
8000 gen_x_cleanup(opcnt);
92d715b6 8001}
8002
8003static void hg_fp_resolve_deps(struct func_prototype *fp)
8004{
8005 struct func_prototype fp_s;
91ca764a 8006 int dep;
92d715b6 8007 int i;
8008
8009 // this thing is recursive, so mark first..
8010 fp->dep_resolved = 1;
8011
8012 for (i = 0; i < fp->dep_func_cnt; i++) {
8013 strcpy(fp_s.name, fp->dep_func[i].name);
8014 fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8015 sizeof(hg_fp[0]), hg_fp_cmp_name);
8016 if (fp->dep_func[i].proto != NULL) {
8017 if (!fp->dep_func[i].proto->dep_resolved)
8018 hg_fp_resolve_deps(fp->dep_func[i].proto);
8019
91ca764a 8020 dep = ~fp->dep_func[i].regmask_live
8021 & fp->dep_func[i].proto->regmask_dep;
8022 fp->regmask_dep |= dep;
8023 // printf("dep %s %s |= %x\n", fp->name,
8024 // fp->dep_func[i].name, dep);
92d715b6 8025
ebc4dc43 8026 if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
92d715b6 8027 fp->has_ret = fp->dep_func[i].proto->has_ret;
8028 }
8029 }
8030}
8031
8c999988 8032// make all thiscall/edx arg functions referenced from .data fastcall
8033static void do_func_refs_from_data(void)
8034{
8035 struct func_prototype *fp, fp_s;
8036 int i;
8037
8038 for (i = 0; i < hg_ref_cnt; i++) {
8039 strcpy(fp_s.name, hg_refs[i]);
8040 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8041 sizeof(hg_fp[0]), hg_fp_cmp_name);
8042 if (fp == NULL)
8043 continue;
8044
8045 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
8046 fp->regmask_dep |= mxCX | mxDX;
8047 }
8048}
8049
9af2d373 8050static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8051 int count)
92d715b6 8052{
61e29183 8053 const struct parsed_proto *pp;
8054 char *p, namebuf[NAMELEN];
8055 const char *name;
92d715b6 8056 int regmask_dep;
226e8df1 8057 int argc_normal;
9af2d373 8058 int j, arg;
92d715b6 8059
9af2d373 8060 for (; count > 0; count--, fp++) {
92d715b6 8061 if (fp->has_ret == -1)
8062 fprintf(fout, "// ret unresolved\n");
8063#if 0
8064 fprintf(fout, "// dep:");
8065 for (j = 0; j < fp->dep_func_cnt; j++) {
8066 fprintf(fout, " %s/", fp->dep_func[j].name);
8067 if (fp->dep_func[j].proto != NULL)
8068 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8069 fp->dep_func[j].proto->has_ret);
8070 }
8071 fprintf(fout, "\n");
8072#endif
8073
61e29183 8074 p = strchr(fp->name, '@');
8075 if (p != NULL) {
8076 memcpy(namebuf, fp->name, p - fp->name);
8077 namebuf[p - fp->name] = 0;
8078 name = namebuf;
8079 }
8080 else
8081 name = fp->name;
8082 if (name[0] == '_')
8083 name++;
8084
8085 pp = proto_parse(g_fhdr, name, 1);
8086 if (pp != NULL && pp->is_include)
8087 continue;
8088
c0de9015 8089 if (fp->pp != NULL) {
4e81a3a2 8090 // part of seed, output later
8091 continue;
c0de9015 8092 }
8093
92d715b6 8094 regmask_dep = fp->regmask_dep;
226e8df1 8095 argc_normal = fp->argc_stack;
92d715b6 8096
91ca764a 8097 fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
8098 (fp->has_ret ? "int" : "void"));
226e8df1 8099 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
8100 && (regmask_dep & ~mxCX) == 0)
8101 {
8102 fprintf(fout, "/*__thiscall*/ ");
8103 argc_normal++;
8104 regmask_dep = 0;
8105 }
8106 else if (regmask_dep && (fp->is_stdcall || fp->argc_stack == 0)
8107 && (regmask_dep & ~(mxCX | mxDX)) == 0)
92d715b6 8108 {
9af2d373 8109 fprintf(fout, " __fastcall ");
226e8df1 8110 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8111 argc_normal = 1;
92d715b6 8112 else
226e8df1 8113 argc_normal += 2;
92d715b6 8114 regmask_dep = 0;
8115 }
8116 else if (regmask_dep && !fp->is_stdcall) {
8117 fprintf(fout, "/*__usercall*/ ");
92d715b6 8118 }
8119 else if (regmask_dep) {
8120 fprintf(fout, "/*__userpurge*/ ");
92d715b6 8121 }
8122 else if (fp->is_stdcall)
9af2d373 8123 fprintf(fout, " __stdcall ");
92d715b6 8124 else
9af2d373 8125 fprintf(fout, " __cdecl ");
92d715b6 8126
61e29183 8127 fprintf(fout, "%s(", name);
92d715b6 8128
8129 arg = 0;
8130 for (j = 0; j < xSP; j++) {
8131 if (regmask_dep & (1 << j)) {
8132 arg++;
8133 if (arg != 1)
8134 fprintf(fout, ", ");
91ca764a 8135 if (fp->pp != NULL)
8136 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8137 else
8138 fprintf(fout, "int");
8139 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
92d715b6 8140 }
8141 }
8142
226e8df1 8143 for (j = 0; j < argc_normal; j++) {
92d715b6 8144 arg++;
8145 if (arg != 1)
8146 fprintf(fout, ", ");
91ca764a 8147 if (fp->pp != NULL) {
8148 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8149 if (!fp->pp->arg[arg - 1].type.is_ptr)
8150 fprintf(fout, " ");
8151 }
8152 else
8153 fprintf(fout, "int ");
8154 fprintf(fout, "a%d", arg);
92d715b6 8155 }
8156
8157 fprintf(fout, ");\n");
8158 }
8159}
8160
9af2d373 8161static void output_hdr(FILE *fout)
8162{
5fa1256f 8163 static const char *lmod_c_names[] = {
8164 [OPLM_UNSPEC] = "???",
8165 [OPLM_BYTE] = "uint8_t",
8166 [OPLM_WORD] = "uint16_t",
8167 [OPLM_DWORD] = "uint32_t",
8168 [OPLM_QWORD] = "uint64_t",
8169 };
8170 const struct scanned_var *var;
ebc4dc43 8171 struct func_prototype *fp;
c0de9015 8172 char line[256] = { 0, };
ebc4dc43 8173 char name[256];
9af2d373 8174 int i;
8175
ebc4dc43 8176 // add stuff from headers
8177 for (i = 0; i < pp_cache_size; i++) {
8178 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
8179 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
8180 else
8181 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
8182 fp = hg_fp_add(name);
8183 fp->pp = &pp_cache[i];
8184 fp->argc_stack = fp->pp->argc_stack;
8185 fp->is_stdcall = fp->pp->is_stdcall;
b2bd20c0 8186 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
ebc4dc43 8187 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
8188 }
8189
9af2d373 8190 // resolve deps
8191 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
8192 for (i = 0; i < hg_fp_cnt; i++)
8193 hg_fp_resolve_deps(&hg_fp[i]);
8194
8c999988 8195 // adjust functions referenced from data segment
8196 do_func_refs_from_data();
8197
9af2d373 8198 // note: messes up .proto ptr, don't use
8199 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
8200
5fa1256f 8201 // output variables
8202 for (i = 0; i < hg_var_cnt; i++) {
8203 var = &hg_vars[i];
8204
4e81a3a2 8205 if (var->pp != NULL)
8206 // part of seed
8207 continue;
c0de9015 8208 else if (var->is_c_str)
61e29183 8209 fprintf(fout, "extern %-8s %s[];", "char", var->name);
8210 else
8211 fprintf(fout, "extern %-8s %s;",
8212 lmod_c_names[var->lmod], var->name);
5fa1256f 8213
8214 if (var->is_seeded)
8215 fprintf(fout, " // seeded");
8216 fprintf(fout, "\n");
8217 }
8218
8219 fprintf(fout, "\n");
8220
8221 // output function prototypes
9af2d373 8222 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
c0de9015 8223
4e81a3a2 8224 // seed passthrough
8225 fprintf(fout, "\n// - seed -\n");
c0de9015 8226
8227 rewind(g_fhdr);
4e81a3a2 8228 while (fgets(line, sizeof(line), g_fhdr))
8229 fwrite(line, 1, strlen(line), fout);
9af2d373 8230}
8231
61e29183 8232// '=' needs special treatment
8233// also ' quote
bfa4a6ee 8234static char *next_word_s(char *w, size_t wsize, char *s)
8235{
61e29183 8236 size_t i;
bfa4a6ee 8237
61e29183 8238 s = sskip(s);
bfa4a6ee 8239
61e29183 8240 i = 0;
8c999988 8241 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
61e29183 8242 w[0] = s[0];
8243 for (i = 1; i < wsize - 1; i++) {
8244 if (s[i] == 0) {
8245 printf("warning: missing closing quote: \"%s\"\n", s);
8246 break;
8247 }
8248 if (s[i] == '\'')
8249 break;
8250 w[i] = s[i];
8251 }
8252 }
bfa4a6ee 8253
61e29183 8254 for (; i < wsize - 1; i++) {
8255 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
8256 break;
8257 w[i] = s[i];
8258 }
8259 w[i] = 0;
8260
8261 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
8262 printf("warning: '%s' truncated\n", w);
bfa4a6ee 8263
61e29183 8264 return s + i;
bfa4a6ee 8265}
8266
4c20744d 8267static int cmpstringp(const void *p1, const void *p2)
8268{
8269 return strcmp(*(char * const *)p1, *(char * const *)p2);
8270}
8271
8272static int is_xref_needed(char *p, char **rlist, int rlist_len)
8273{
8274 char *p2;
8275
8276 p = sskip(p);
8277 if (strstr(p, "..."))
8278 // unable to determine, assume needed
8279 return 1;
8280
8281 if (*p == '.') // .text, .data, ...
8282 // ref from other data or non-function -> no
8283 return 0;
8284
8285 p2 = strpbrk(p, "+:\r\n\x18");
8286 if (p2 != NULL)
8287 *p2 = 0;
8288 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8289 // referenced from removed code
8290 return 0;
8291
8292 return 1;
8293}
8294
8c999988 8295static int ida_xrefs_show_need(FILE *fasm, char *p,
4c20744d 8296 char **rlist, int rlist_len)
8297{
8298 int found_need = 0;
8299 char line[256];
8300 long pos;
8301
8302 p = strrchr(p, ';');
ea43585b 8303 if (p != NULL && *p == ';') {
8304 if (IS_START(p + 2, "sctref"))
4c20744d 8305 return 1;
ea43585b 8306 if (IS_START(p + 2, "DATA XREF: ")) {
8307 p += 13;
8308 if (is_xref_needed(p, rlist, rlist_len))
8309 return 1;
8310 }
4c20744d 8311 }
8312
8313 pos = ftell(fasm);
8314 while (1)
8315 {
8316 if (!my_fgets(line, sizeof(line), fasm))
8317 break;
8318 // non-first line is always indented
8319 if (!my_isblank(line[0]))
8320 break;
8321
8322 // should be no content, just comment
8323 p = sskip(line);
8324 if (*p != ';')
8325 break;
8326
8327 p = strrchr(p, ';');
8328 p += 2;
ea43585b 8329
8330 if (IS_START(p, "sctref")) {
8331 found_need = 1;
8332 break;
8333 }
8334
4c20744d 8335 // it's printed once, but no harm to check again
8336 if (IS_START(p, "DATA XREF: "))
8337 p += 11;
8338
8339 if (is_xref_needed(p, rlist, rlist_len)) {
8340 found_need = 1;
8341 break;
8342 }
8343 }
8344 fseek(fasm, pos, SEEK_SET);
8345 return found_need;
8346}
8347
8348static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
5fa1256f 8349{
5fa1256f 8350 struct scanned_var *var;
8351 char line[256] = { 0, };
8c999988 8352 char words[4][256];
8353 int no_identifier;
5fa1256f 8354 char *p = NULL;
8355 int wordc;
61e29183 8356 int l;
5fa1256f 8357
8358 while (!feof(fasm))
8359 {
8360 // skip to next data section
8361 while (my_fgets(line, sizeof(line), fasm))
8362 {
8363 asmln++;
8364
8365 p = sskip(line);
8366 if (*p == 0 || *p == ';')
8367 continue;
8368
8369 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
8370 if (*p == 0 || *p == ';')
8371 continue;
8372
8373 if (*p != 's' || !IS_START(p, "segment para public"))
8374 continue;
8375
8376 break;
8377 }
8378
8379 if (p == NULL || !IS_START(p, "segment para public"))
8380 break;
8381 p = sskip(p + 19);
8382
8383 if (!IS_START(p, "'DATA'"))
8384 continue;
8385
8386 // now process it
8387 while (my_fgets(line, sizeof(line), fasm))
8388 {
8389 asmln++;
8390
8391 p = line;
8c999988 8392 no_identifier = my_isblank(*p);
5fa1256f 8393
8394 p = sskip(p);
8395 if (*p == 0 || *p == ';')
8396 continue;
8397
8398 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8399 words[wordc][0] = 0;
8400 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8401 if (*p == 0 || *p == ';') {
8402 wordc++;
8403 break;
8404 }
8405 }
8406
8407 if (wordc == 2 && IS(words[1], "ends"))
8408 break;
61e29183 8409 if (wordc < 2)
8410 continue;
5fa1256f 8411
8c999988 8412 if (no_identifier) {
8413 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
8414 hg_ref_add(words[2]);
8415 continue;
8416 }
8417
9ea60b8d 8418 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
8419 // when this starts, we don't need anything from this section
8420 break;
8421 }
8422
4c20744d 8423 // check refs comment(s)
8c999988 8424 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
4c20744d 8425 continue;
8426
5fa1256f 8427 if ((hg_var_cnt & 0xff) == 0) {
8428 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
8429 * (hg_var_cnt + 0x100));
8430 my_assert_not(hg_vars, NULL);
8431 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
8432 }
8433
8434 var = &hg_vars[hg_var_cnt++];
8435 snprintf(var->name, sizeof(var->name), "%s", words[0]);
8436
8437 // maybe already in seed header?
c0de9015 8438 var->pp = proto_parse(g_fhdr, var->name, 1);
8439 if (var->pp != NULL) {
8440 if (var->pp->is_fptr) {
5fa1256f 8441 var->lmod = OPLM_DWORD;
8442 //var->is_ptr = 1;
8443 }
c0de9015 8444 else if (var->pp->is_func)
8445 aerr("func?\n");
8446 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
5fa1256f 8447 aerr("unhandled C type '%s' for '%s'\n",
c0de9015 8448 var->pp->type.name, var->name);
5fa1256f 8449
8450 var->is_seeded = 1;
8451 continue;
8452 }
8453
8c999988 8454 if (IS(words[1], "dd")) {
5fa1256f 8455 var->lmod = OPLM_DWORD;
8c999988 8456 if (wordc >= 4 && IS(words[2], "offset"))
8457 hg_ref_add(words[3]);
8458 }
5fa1256f 8459 else if (IS(words[1], "dw"))
8460 var->lmod = OPLM_WORD;
61e29183 8461 else if (IS(words[1], "db")) {
5fa1256f 8462 var->lmod = OPLM_BYTE;
61e29183 8463 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
8464 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
8465 var->is_c_str = 1;
8466 }
8467 }
5fa1256f 8468 else if (IS(words[1], "dq"))
8469 var->lmod = OPLM_QWORD;
8470 //else if (IS(words[1], "dt"))
8471 else
8472 aerr("type '%s' not known\n", words[1]);
8473 }
8474 }
8475
8476 rewind(fasm);
8477 asmln = 0;
8478}
8479
8480static void set_label(int i, const char *name)
8481{
8482 const char *p;
8483 int len;
8484
8485 len = strlen(name);
8486 p = strchr(name, ':');
8487 if (p != NULL)
8488 len = p - name;
8489
8490 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
8491 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
8492 g_labels[i] = realloc(g_labels[i], len + 1);
8493 my_assert_not(g_labels[i], NULL);
8494 memcpy(g_labels[i], name, len);
8495 g_labels[i][len] = 0;
8496}
8497
e56ab892 8498struct chunk_item {
8499 char *name;
8500 long fptr;
de50b98b 8501 int asmln;
e56ab892 8502};
8503
cdfaeed7 8504static struct chunk_item *func_chunks;
8505static int func_chunk_cnt;
8506static int func_chunk_alloc;
8507
8508static void add_func_chunk(FILE *fasm, const char *name, int line)
8509{
8510 if (func_chunk_cnt >= func_chunk_alloc) {
8511 func_chunk_alloc *= 2;
8512 func_chunks = realloc(func_chunks,
8513 func_chunk_alloc * sizeof(func_chunks[0]));
8514 my_assert_not(func_chunks, NULL);
8515 }
8516 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
8517 func_chunks[func_chunk_cnt].name = strdup(name);
8518 func_chunks[func_chunk_cnt].asmln = line;
8519 func_chunk_cnt++;
8520}
8521
e56ab892 8522static int cmp_chunks(const void *p1, const void *p2)
8523{
8524 const struct chunk_item *c1 = p1, *c2 = p2;
8525 return strcmp(c1->name, c2->name);
8526}
8527
ea43585b 8528static void scan_ahead_for_chunks(FILE *fasm)
cdfaeed7 8529{
8530 char words[2][256];
8531 char line[256];
8532 long oldpos;
8533 int oldasmln;
8534 int wordc;
8535 char *p;
8536 int i;
8537
8538 oldpos = ftell(fasm);
8539 oldasmln = asmln;
8540
5fa1256f 8541 while (my_fgets(line, sizeof(line), fasm))
cdfaeed7 8542 {
8543 wordc = 0;
8544 asmln++;
8545
8546 p = sskip(line);
8547 if (*p == 0)
8548 continue;
8549
8550 if (*p == ';')
8551 {
8552 // get rid of random tabs
8553 for (i = 0; line[i] != 0; i++)
8554 if (line[i] == '\t')
8555 line[i] = ' ';
8556
8557 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8558 {
8559 p += 30;
8560 next_word(words[0], sizeof(words[0]), p);
8561 if (words[0][0] == 0)
8562 aerr("missing name for func chunk?\n");
8563
8564 add_func_chunk(fasm, words[0], asmln);
8565 }
46b388c2 8566 else if (IS_START(p, "; sctend"))
8567 break;
8568
cdfaeed7 8569 continue;
8570 } // *p == ';'
8571
8572 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8573 words[wordc][0] = 0;
8574 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8575 if (*p == 0 || *p == ';') {
8576 wordc++;
8577 break;
8578 }
8579 }
8580
8581 if (wordc == 2 && IS(words[1], "ends"))
8582 break;
8583 }
8584
8585 fseek(fasm, oldpos, SEEK_SET);
8586 asmln = oldasmln;
8587}
8588
91977a1c 8589int main(int argc, char *argv[])
8590{
06c5d854 8591 FILE *fout, *fasm, *frlist;
4c45fa73 8592 struct parsed_data *pd = NULL;
8593 int pd_alloc = 0;
8594 char **rlist = NULL;
8595 int rlist_len = 0;
8596 int rlist_alloc = 0;
e56ab892 8597 int func_chunks_used = 0;
8598 int func_chunks_sorted = 0;
e56ab892 8599 int func_chunk_i = -1;
8600 long func_chunk_ret = 0;
de50b98b 8601 int func_chunk_ret_ln = 0;
cdfaeed7 8602 int scanned_ahead = 0;
91977a1c 8603 char line[256];
a2c1d768 8604 char words[20][256];
4c45fa73 8605 enum opr_lenmod lmod;
ddaf8bd7 8606 char *sctproto = NULL;
91977a1c 8607 int in_func = 0;
4c45fa73 8608 int pending_endp = 0;
11437ea1 8609 int skip_code = 0;
8610 int skip_code_end = 0;
940e8e66 8611 int skip_warned = 0;
91977a1c 8612 int eq_alloc;
bfa4a6ee 8613 int verbose = 0;
1f84f6b3 8614 int multi_seg = 0;
46b388c2 8615 int end = 0;
bfa4a6ee 8616 int arg_out;
89ff3147 8617 int arg;
91977a1c 8618 int pi = 0;
e56ab892 8619 int i, j;
8620 int ret, len;
91977a1c 8621 char *p;
8622 int wordc;
8623
89ff3147 8624 for (arg = 1; arg < argc; arg++) {
8625 if (IS(argv[arg], "-v"))
8626 verbose = 1;
8627 else if (IS(argv[arg], "-rf"))
8628 g_allow_regfunc = 1;
8c83cc48 8629 else if (IS(argv[arg], "-uc"))
8630 g_allow_user_icall = 1;
1f84f6b3 8631 else if (IS(argv[arg], "-m"))
8632 multi_seg = 1;
92d715b6 8633 else if (IS(argv[arg], "-hdr"))
9af2d373 8634 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
89ff3147 8635 else
8636 break;
bfa4a6ee 8637 }
8638
8639 if (argc < arg + 3) {
315b77eb 8640 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
8641 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
8642 "options:\n"
8643 " -hdr - header generation mode\n"
8644 " -rf - allow unannotated indirect calls\n"
8c83cc48 8645 " -uc - allow ind. calls/refs to __usercall\n"
315b77eb 8646 " -m - allow multiple .text sections\n"
8647 "[rlist] is a file with function names to skip,"
8648 " one per line\n",
92d715b6 8649 argv[0], argv[0]);
91977a1c 8650 return 1;
8651 }
8652
bfa4a6ee 8653 arg_out = arg++;
91977a1c 8654
bfa4a6ee 8655 asmfn = argv[arg++];
91977a1c 8656 fasm = fopen(asmfn, "r");
8657 my_assert_not(fasm, NULL);
8658
bfa4a6ee 8659 hdrfn = argv[arg++];
06c5d854 8660 g_fhdr = fopen(hdrfn, "r");
8661 my_assert_not(g_fhdr, NULL);
bfa4a6ee 8662
8663 rlist_alloc = 64;
8664 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
8665 my_assert_not(rlist, NULL);
8666 // needs special handling..
8667 rlist[rlist_len++] = "__alloca_probe";
8668
e56ab892 8669 func_chunk_alloc = 32;
8670 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
8671 my_assert_not(func_chunks, NULL);
8672
a2c1d768 8673 memset(words, 0, sizeof(words));
8674
bfa4a6ee 8675 for (; arg < argc; arg++) {
11437ea1 8676 int skip_func = 0;
8677
bfa4a6ee 8678 frlist = fopen(argv[arg], "r");
8679 my_assert_not(frlist, NULL);
8680
5fa1256f 8681 while (my_fgets(line, sizeof(line), frlist)) {
bfa4a6ee 8682 p = sskip(line);
1cd4a663 8683 if (*p == 0 || *p == ';')
8684 continue;
8685 if (*p == '#') {
89ff3147 8686 if (IS_START(p, "#if 0")
8687 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
8688 {
1cd4a663 8689 skip_func = 1;
89ff3147 8690 }
1cd4a663 8691 else if (IS_START(p, "#endif"))
8692 skip_func = 0;
8693 continue;
8694 }
8695 if (skip_func)
bfa4a6ee 8696 continue;
8697
8698 p = next_word(words[0], sizeof(words[0]), p);
8699 if (words[0][0] == 0)
8700 continue;
8701
8702 if (rlist_len >= rlist_alloc) {
8703 rlist_alloc = rlist_alloc * 2 + 64;
8704 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
8705 my_assert_not(rlist, NULL);
8706 }
8707 rlist[rlist_len++] = strdup(words[0]);
8708 }
8709
8710 fclose(frlist);
8711 frlist = NULL;
8712 }
8713
8714 if (rlist_len > 0)
8715 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
8716
8717 fout = fopen(argv[arg_out], "w");
91977a1c 8718 my_assert_not(fout, NULL);
8719
8720 eq_alloc = 128;
8721 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
8722 my_assert_not(g_eqs, NULL);
8723
4c45fa73 8724 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
8725 g_label_refs[i].i = -1;
8726 g_label_refs[i].next = NULL;
8727 }
8728
5fa1256f 8729 if (g_header_mode)
4c20744d 8730 scan_variables(fasm, rlist, rlist_len);
5fa1256f 8731
8732 while (my_fgets(line, sizeof(line), fasm))
91977a1c 8733 {
4c45fa73 8734 wordc = 0;
91977a1c 8735 asmln++;
8736
8737 p = sskip(line);
1bafb621 8738 if (*p == 0)
91977a1c 8739 continue;
8740
de50b98b 8741 // get rid of random tabs
8742 for (i = 0; line[i] != 0; i++)
8743 if (line[i] == '\t')
8744 line[i] = ' ';
8745
e56ab892 8746 if (*p == ';')
8747 {
e56ab892 8748 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
8749 goto do_pending_endp; // eww..
8750
8751 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
8752 {
8753 static const char *attrs[] = {
8754 "bp-based frame",
8755 "library function",
8756 "static",
8757 "noreturn",
8758 "thunk",
8759 "fpd=",
8760 };
8761
8762 // parse IDA's attribute-list comment
8763 g_ida_func_attr = 0;
8764 p = sskip(p + 13);
8765
8766 for (; *p != 0; p = sskip(p)) {
8767 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8768 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8769 g_ida_func_attr |= 1 << i;
8770 p += strlen(attrs[i]);
8771 break;
8772 }
8773 }
8774 if (i == ARRAY_SIZE(attrs)) {
8775 anote("unparsed IDA attr: %s\n", p);
1bafb621 8776 break;
8777 }
e56ab892 8778 if (IS(attrs[i], "fpd=")) {
8779 p = next_word(words[0], sizeof(words[0]), p);
8780 // ignore for now..
8781 }
1bafb621 8782 }
e56ab892 8783 }
7e08c224 8784 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
8785 {
8786 static const char *attrs[] = {
8787 "clear_sf",
226e8df1 8788 "clear_regmask",
7e08c224 8789 };
8790
8791 // parse manual attribute-list comment
8792 g_sct_func_attr = 0;
8793 p = sskip(p + 10);
8794
8795 for (; *p != 0; p = sskip(p)) {
8796 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8797 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8798 g_sct_func_attr |= 1 << i;
8799 p += strlen(attrs[i]);
8800 break;
8801 }
8802 }
226e8df1 8803 if (*p == '=') {
8804 j = ret = 0;
8805 if (i == 0)
8806 // clear_sf=start,len (in dwords)
8807 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
8808 &g_stack_clear_len, &j);
8809 else if (i == 1)
8810 // clear_regmask=<mask>
6135d8e6 8811 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
7e08c224 8812 if (ret < 2) {
226e8df1 8813 anote("unparsed attr value: %s\n", p);
7e08c224 8814 break;
8815 }
8816 p += j;
8817 }
8818 else if (i == ARRAY_SIZE(attrs)) {
8819 anote("unparsed sct attr: %s\n", p);
8820 break;
8821 }
8822 }
8823 }
e56ab892 8824 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8825 {
8826 p += 30;
8827 next_word(words[0], sizeof(words[0]), p);
8828 if (words[0][0] == 0)
cdfaeed7 8829 aerr("missing name for func chunk?\n");
8830
8831 if (!scanned_ahead) {
8832 add_func_chunk(fasm, words[0], asmln);
8833 func_chunks_sorted = 0;
e56ab892 8834 }
e56ab892 8835 }
8836 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
8837 {
8838 if (func_chunk_i >= 0) {
8839 if (func_chunk_i < func_chunk_cnt
8840 && IS(func_chunks[func_chunk_i].name, g_func))
8841 {
8842 // move on to next chunk
8843 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
8844 if (ret)
8845 aerr("seek failed for '%s' chunk #%d\n",
8846 g_func, func_chunk_i);
de50b98b 8847 asmln = func_chunks[func_chunk_i].asmln;
e56ab892 8848 func_chunk_i++;
8849 }
8850 else {
8851 if (func_chunk_ret == 0)
8852 aerr("no return from chunk?\n");
8853 fseek(fasm, func_chunk_ret, SEEK_SET);
de50b98b 8854 asmln = func_chunk_ret_ln;
e56ab892 8855 func_chunk_ret = 0;
8856 pending_endp = 1;
8857 }
1bafb621 8858 }
e56ab892 8859 }
8860 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
8861 func_chunks_used = 1;
8862 p += 20;
8863 if (IS_START(g_func, "sub_")) {
8864 unsigned long addr = strtoul(p, NULL, 16);
8865 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
cdfaeed7 8866 if (addr > f_addr && !scanned_ahead) {
b2bd20c0 8867 //anote("scan_ahead caused by '%s', addr %lx\n",
8868 // g_func, addr);
ea43585b 8869 scan_ahead_for_chunks(fasm);
cdfaeed7 8870 scanned_ahead = 1;
8871 func_chunks_sorted = 0;
8872 }
1bafb621 8873 }
8874 }
8875 continue;
e56ab892 8876 } // *p == ';'
1bafb621 8877
06c5d854 8878parse_words:
a2c1d768 8879 for (i = wordc; i < ARRAY_SIZE(words); i++)
8880 words[i][0] = 0;
cdfaeed7 8881 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
bfa4a6ee 8882 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
91977a1c 8883 if (*p == 0 || *p == ';') {
8884 wordc++;
8885 break;
8886 }
8887 }
a2c1d768 8888 if (*p != 0 && *p != ';')
8889 aerr("too many words\n");
91977a1c 8890
11437ea1 8891 if (skip_code_end) {
8892 skip_code_end = 0;
8893 skip_code = 0;
8894 }
8895
8896 // allow asm patches in comments
ddaf8bd7 8897 if (*p == ';') {
8898 if (IS_START(p, "; sctpatch:")) {
8899 p = sskip(p + 11);
8900 if (*p == 0 || *p == ';')
8901 continue;
8902 goto parse_words; // lame
8903 }
8904 if (IS_START(p, "; sctproto:")) {
8905 sctproto = strdup(p + 11);
8906 }
46b388c2 8907 else if (IS_START(p, "; sctend")) {
8908 end = 1;
8909 if (!pending_endp)
8910 break;
8911 }
11437ea1 8912 else if (IS_START(p, "; sctskip_start")) {
8913 if (in_func && !g_skip_func) {
8914 if (!skip_code) {
8915 ops[pi].op = OPP_ABORT;
8916 ops[pi].asmln = asmln;
8917 pi++;
8918 }
8919 skip_code = 1;
8920 }
8921 }
8922 else if (IS_START(p, "; sctskip_end")) {
8923 if (skip_code)
8924 skip_code_end = 1;
8925 }
06c5d854 8926 }
8927
91977a1c 8928 if (wordc == 0) {
8929 // shouldn't happen
8930 awarn("wordc == 0?\n");
8931 continue;
8932 }
8933
8934 // don't care about this:
8935 if (words[0][0] == '.'
8936 || IS(words[0], "include")
8937 || IS(words[0], "assume") || IS(words[1], "segment")
8938 || IS(words[0], "align"))
8939 {
8940 continue;
8941 }
8942
4c45fa73 8943do_pending_endp:
8944 // do delayed endp processing to collect switch jumptables
8945 if (pending_endp) {
30c8c549 8946 if (in_func && !g_skip_func && !end && wordc >= 2
4c45fa73 8947 && ((words[0][0] == 'd' && words[0][2] == 0)
8948 || (words[1][0] == 'd' && words[1][2] == 0)))
8949 {
8950 i = 1;
8951 if (words[1][0] == 'd' && words[1][2] == 0) {
8952 // label
8953 if (g_func_pd_cnt >= pd_alloc) {
8954 pd_alloc = pd_alloc * 2 + 16;
8955 g_func_pd = realloc(g_func_pd,
8956 sizeof(g_func_pd[0]) * pd_alloc);
8957 my_assert_not(g_func_pd, NULL);
8958 }
8959 pd = &g_func_pd[g_func_pd_cnt];
8960 g_func_pd_cnt++;
8961 memset(pd, 0, sizeof(*pd));
8962 strcpy(pd->label, words[0]);
8963 pd->type = OPT_CONST;
8964 pd->lmod = lmod_from_directive(words[1]);
8965 i = 2;
8966 }
8967 else {
da87ae38 8968 if (pd == NULL) {
8969 if (verbose)
8970 anote("skipping alignment byte?\n");
8971 continue;
8972 }
4c45fa73 8973 lmod = lmod_from_directive(words[0]);
8974 if (lmod != pd->lmod)
8975 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
8976 }
8977
8978 if (pd->count_alloc < pd->count + wordc) {
8979 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
8980 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
8981 my_assert_not(pd->d, NULL);
8982 }
8983 for (; i < wordc; i++) {
8984 if (IS(words[i], "offset")) {
8985 pd->type = OPT_OFFSET;
8986 i++;
8987 }
8988 p = strchr(words[i], ',');
8989 if (p != NULL)
8990 *p = 0;
8991 if (pd->type == OPT_OFFSET)
8992 pd->d[pd->count].u.label = strdup(words[i]);
8993 else
8994 pd->d[pd->count].u.val = parse_number(words[i]);
8995 pd->d[pd->count].bt_i = -1;
8996 pd->count++;
8997 }
8998 continue;
8999 }
9000
30c8c549 9001 if (in_func && !g_skip_func) {
9af2d373 9002 if (g_header_mode)
92d715b6 9003 gen_hdr(g_func, pi);
9004 else
9005 gen_func(fout, g_fhdr, g_func, pi);
9006 }
4c45fa73 9007
9008 pending_endp = 0;
9009 in_func = 0;
9010 g_ida_func_attr = 0;
7e08c224 9011 g_sct_func_attr = 0;
9012 g_stack_clear_start = 0;
9013 g_stack_clear_len = 0;
226e8df1 9014 g_regmask_init = 0;
4c45fa73 9015 skip_warned = 0;
30c8c549 9016 g_skip_func = 0;
4c45fa73 9017 g_func[0] = 0;
e56ab892 9018 func_chunks_used = 0;
9019 func_chunk_i = -1;
4c45fa73 9020 if (pi != 0) {
9021 memset(&ops, 0, pi * sizeof(ops[0]));
d7857c3a 9022 clear_labels(pi);
4c45fa73 9023 pi = 0;
9024 }
9025 g_eqcnt = 0;
9026 for (i = 0; i < g_func_pd_cnt; i++) {
9027 pd = &g_func_pd[i];
9028 if (pd->type == OPT_OFFSET) {
9029 for (j = 0; j < pd->count; j++)
9030 free(pd->d[j].u.label);
9031 }
9032 free(pd->d);
9033 pd->d = NULL;
9034 }
9035 g_func_pd_cnt = 0;
d4a985bd 9036 g_func_lmods = 0;
4c45fa73 9037 pd = NULL;
46b388c2 9038
9039 if (end)
9040 break;
4c45fa73 9041 if (wordc == 0)
9042 continue;
9043 }
9044
91977a1c 9045 if (IS(words[1], "proc")) {
9046 if (in_func)
9047 aerr("proc '%s' while in_func '%s'?\n",
9048 words[0], g_func);
bfa4a6ee 9049 p = words[0];
ddaf8bd7 9050 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
30c8c549 9051 g_skip_func = 1;
91977a1c 9052 strcpy(g_func, words[0]);
d4e3b5db 9053 set_label(0, words[0]);
91977a1c 9054 in_func = 1;
9055 continue;
9056 }
9057
e56ab892 9058 if (IS(words[1], "endp"))
9059 {
91977a1c 9060 if (!in_func)
9061 aerr("endp '%s' while not in_func?\n", words[0]);
9062 if (!IS(g_func, words[0]))
9063 aerr("endp '%s' while in_func '%s'?\n",
9064 words[0], g_func);
11437ea1 9065 if (skip_code)
9066 aerr("endp '%s' while skipping code\n", words[0]);
bfa4a6ee 9067
ddaf8bd7 9068 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
9069 && ops[0].op == OP_JMP && ops[0].operand[0].had_ds)
9070 {
9071 // import jump
30c8c549 9072 g_skip_func = 1;
ddaf8bd7 9073 }
9074
30c8c549 9075 if (!g_skip_func && func_chunks_used) {
e56ab892 9076 // start processing chunks
9077 struct chunk_item *ci, key = { g_func, 0 };
9078
9079 func_chunk_ret = ftell(fasm);
de50b98b 9080 func_chunk_ret_ln = asmln;
e56ab892 9081 if (!func_chunks_sorted) {
9082 qsort(func_chunks, func_chunk_cnt,
9083 sizeof(func_chunks[0]), cmp_chunks);
9084 func_chunks_sorted = 1;
9085 }
9086 ci = bsearch(&key, func_chunks, func_chunk_cnt,
9087 sizeof(func_chunks[0]), cmp_chunks);
9088 if (ci == NULL)
9089 aerr("'%s' needs chunks, but none found\n", g_func);
9090 func_chunk_i = ci - func_chunks;
9091 for (; func_chunk_i > 0; func_chunk_i--)
9092 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
9093 break;
9094
9095 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9096 if (ret)
9097 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
de50b98b 9098 asmln = func_chunks[func_chunk_i].asmln;
e56ab892 9099 func_chunk_i++;
9100 continue;
9101 }
4c45fa73 9102 pending_endp = 1;
91977a1c 9103 continue;
9104 }
9105
1f84f6b3 9106 if (wordc == 2 && IS(words[1], "ends")) {
46b388c2 9107 if (!multi_seg) {
9108 end = 1;
9109 if (pending_endp)
9110 goto do_pending_endp;
1f84f6b3 9111 break;
46b388c2 9112 }
1f84f6b3 9113
9114 // scan for next text segment
5fa1256f 9115 while (my_fgets(line, sizeof(line), fasm)) {
1f84f6b3 9116 asmln++;
9117 p = sskip(line);
9118 if (*p == 0 || *p == ';')
9119 continue;
9120
9121 if (strstr(p, "segment para public 'CODE' use32"))
9122 break;
9123 }
9124
9125 continue;
9126 }
a2c1d768 9127
bfa4a6ee 9128 p = strchr(words[0], ':');
9129 if (p != NULL) {
d4e3b5db 9130 set_label(pi, words[0]);
bfa4a6ee 9131 continue;
9132 }
9133
11437ea1 9134 if (!in_func || g_skip_func || skip_code) {
30c8c549 9135 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
bfa4a6ee 9136 if (verbose)
9137 anote("skipping from '%s'\n", g_labels[pi]);
9138 skip_warned = 1;
9139 }
d7857c3a 9140 free(g_labels[pi]);
9141 g_labels[pi] = NULL;
bfa4a6ee 9142 continue;
9143 }
9144
ddaf8bd7 9145 if (wordc > 1 && IS(words[1], "="))
9146 {
91977a1c 9147 if (wordc != 5)
9148 aerr("unhandled equ, wc=%d\n", wordc);
9149 if (g_eqcnt >= eq_alloc) {
9150 eq_alloc *= 2;
9151 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
9152 my_assert_not(g_eqs, NULL);
9153 }
9154
9155 len = strlen(words[0]);
9156 if (len > sizeof(g_eqs[0].name) - 1)
9157 aerr("equ name too long: %d\n", len);
9158 strcpy(g_eqs[g_eqcnt].name, words[0]);
9159
9160 if (!IS(words[3], "ptr"))
9161 aerr("unhandled equ\n");
9162 if (IS(words[2], "dword"))
9163 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
9164 else if (IS(words[2], "word"))
9165 g_eqs[g_eqcnt].lmod = OPLM_WORD;
9166 else if (IS(words[2], "byte"))
9167 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
90307a99 9168 else if (IS(words[2], "qword"))
9169 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
91977a1c 9170 else
9171 aerr("bad lmod: '%s'\n", words[2]);
9172
9173 g_eqs[g_eqcnt].offset = parse_number(words[4]);
9174 g_eqcnt++;
9175 continue;
9176 }
9177
9178 if (pi >= ARRAY_SIZE(ops))
9179 aerr("too many ops\n");
9180
91977a1c 9181 parse_op(&ops[pi], words, wordc);
ddaf8bd7 9182
865f1aca 9183 ops[pi].datap = sctproto;
9184 sctproto = NULL;
91977a1c 9185 pi++;
91977a1c 9186 }
9187
9af2d373 9188 if (g_header_mode)
92d715b6 9189 output_hdr(fout);
9190
91977a1c 9191 fclose(fout);
9192 fclose(fasm);
06c5d854 9193 fclose(g_fhdr);
91977a1c 9194
9195 return 0;
c36e914d 9196}
91977a1c 9197
9198// vim:ts=2:shiftwidth=2:expandtab