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