translate: add fptr-arg checking
[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,
17ed469e 3633 int magic, int is_call_op, const struct parsed_proto **pp_found,
3634 int *pp_i, 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);
17ed469e 3647 scan_for_call_type(lr->i, opr, magic, is_call_op,
3648 pp_found, pp_i, multi);
92d715b6 3649 }
46411e6c 3650 if (i > 0 && LAST_OP(i - 1))
3651 return;
1cd4a663 3652 }
037f4971 3653
1cd4a663 3654 i--;
037f4971 3655 if (i < 0)
3656 break;
3657
3658 if (ops[i].cc_scratch == magic)
3659 return;
3660 ops[i].cc_scratch = magic;
1cd4a663 3661
3662 if (!(ops[i].flags & OPF_DATA))
3663 continue;
3664 if (!is_opr_modified(opr, &ops[i]))
3665 continue;
3666 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3667 // most probably trashed by some processing
3668 *pp_found = NULL;
3669 return;
3670 }
3671
3672 opr = &ops[i].operand[1];
3673 if (opr->type != OPT_REG)
3674 break;
3675 }
3676
3677 po = (i >= 0) ? &ops[i] : ops;
3678
3679 if (i < 0) {
3680 // reached the top - can only be an arg-reg
04abc5d6 3681 if (opr->type != OPT_REG || g_func_pp == NULL)
1cd4a663 3682 return;
3683
3684 for (i = 0; i < g_func_pp->argc; i++) {
3685 if (g_func_pp->arg[i].reg == NULL)
3686 continue;
3687 if (IS(opr->name, g_func_pp->arg[i].reg))
3688 break;
3689 }
3690 if (i == g_func_pp->argc)
3691 return;
93b5bd18 3692 pp = g_func_pp->arg[i].pp;
17ed469e 3693 if (pp == NULL) {
3694 if (is_call_op)
3695 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3696 i + 1, g_func_pp->arg[i].reg);
3697 return;
3698 }
89ff3147 3699 check_func_pp(po, pp, "icall reg-arg");
1cd4a663 3700 }
3701 else
17ed469e 3702 pp = try_recover_pp(po, opr, is_call_op, NULL);
1cd4a663 3703
89ff3147 3704 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
17ed469e 3705 if (pp_cmp_func(*pp_found, pp)) {
3706 if (pp_i != NULL && *pp_i != -1)
3707 fnote(&ops[*pp_i], "(other ref)\n");
1cd4a663 3708 ferr(po, "icall: parsed_proto mismatch\n");
3709 }
17ed469e 3710 if (multi != NULL)
3711 *multi = 1;
1cd4a663 3712 }
db63af51 3713 if (pp != NULL) {
1cd4a663 3714 *pp_found = pp;
17ed469e 3715 if (pp_i != NULL)
3716 *pp_i = po - ops;
db63af51 3717 }
1cd4a663 3718}
3719
66bdb2b0 3720static void add_label_ref(struct label_ref *lr, int op_i)
9af2d373 3721{
66bdb2b0 3722 struct label_ref *lr_new;
9af2d373 3723
66bdb2b0 3724 if (lr->i == -1) {
3725 lr->i = op_i;
3726 return;
3727 }
9af2d373 3728
66bdb2b0 3729 lr_new = calloc(1, sizeof(*lr_new));
3730 lr_new->i = op_i;
3731 lr_new->next = lr->next;
3732 lr->next = lr_new;
3733}
3734
3735static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3736{
3737 struct parsed_op *po = &ops[i];
3738 struct parsed_data *pd;
3739 char label[NAMELEN], *p;
3740 int len, j, l;
3741
3742 p = strchr(po->operand[0].name, '[');
3743 if (p == NULL)
3744 return NULL;
3745
3746 len = p - po->operand[0].name;
3747 strncpy(label, po->operand[0].name, len);
3748 label[len] = 0;
3749
3750 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3751 if (IS(g_func_pd[j].label, label)) {
3752 pd = &g_func_pd[j];
3753 break;
3754 }
3755 }
3756 if (pd == NULL)
3757 //ferr(po, "label '%s' not parsed?\n", label);
3758 return NULL;
3759
3760 if (pd->type != OPT_OFFSET)
3761 ferr(po, "label '%s' with non-offset data?\n", label);
3762
3763 // find all labels, link
3764 for (j = 0; j < pd->count; j++) {
3765 for (l = 0; l < opcnt; l++) {
3766 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3767 add_label_ref(&g_label_refs[l], i);
3768 pd->d[j].bt_i = l;
3769 break;
3770 }
3771 }
3772 }
3773
3774 return pd;
3775}
3776
3777static void clear_labels(int count)
3778{
3779 int i;
3780
3781 for (i = 0; i < count; i++) {
3782 if (g_labels[i] != NULL) {
3783 free(g_labels[i]);
3784 g_labels[i] = NULL;
3785 }
3786 }
3787}
3788
b2bd20c0 3789static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3790{
3791 int regmask = 0;
3792 int i, reg;
3793
3794 for (i = 0; i < pp->argc; i++) {
3795 if (pp->arg[i].reg != NULL) {
3796 reg = char_array_i(regs_r32,
3797 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3798 if (reg < 0)
3799 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3800 pp->arg[i].reg, pp->name);
3801 regmask |= 1 << reg;
3802 }
3803 }
3804
3805 return regmask;
3806}
3807
3808static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3809{
4d247254 3810 int regmask = 0;
3811 int i, reg;
3812
3813 if (pp->has_retreg) {
3814 for (i = 0; i < pp->argc; i++) {
3815 if (pp->arg[i].type.is_retreg) {
3816 reg = char_array_i(regs_r32,
3817 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3818 ferr_assert(ops, reg >= 0);
3819 regmask |= 1 << reg;
3820 }
3821 }
3822 }
3823
b2bd20c0 3824 if (strstr(pp->ret_type.name, "int64"))
4d247254 3825 return regmask | (1 << xAX) | (1 << xDX);
d4a985bd 3826 if (IS(pp->ret_type.name, "float")
3827 || IS(pp->ret_type.name, "double"))
3828 {
4d247254 3829 return regmask | mxST0;
d4a985bd 3830 }
b2bd20c0 3831 if (strcasecmp(pp->ret_type.name, "void") == 0)
4d247254 3832 return regmask;
b2bd20c0 3833
4d247254 3834 return regmask | mxAX;
b2bd20c0 3835}
3836
93b5bd18 3837static int are_ops_same(struct parsed_op *po1, struct parsed_op *po2)
3838{
3839 return po1->op == po2->op && po1->operand_cnt == po2->operand_cnt
3840 && memcmp(po1->operand, po2->operand,
3841 sizeof(po1->operand[0]) * po1->operand_cnt) == 0;
3842}
3843
66bdb2b0 3844static void resolve_branches_parse_calls(int opcnt)
3845{
d4a985bd 3846 static const struct {
3847 const char *name;
3848 enum op_op op;
3849 unsigned int flags;
3850 unsigned int regmask_src;
3851 unsigned int regmask_dst;
3852 } pseudo_ops[] = {
622eb2ef 3853 { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3854 { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3855 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
f9327ad4 3856 // more precise? Wine gets away with just __ftol handler
3857 { "__ftol2", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
8c83cc48 3858 { "__CIpow", OPP_CIPOW, OPF_FPOP, mxST0|mxST1, mxST0 },
d4a985bd 3859 };
66bdb2b0 3860 const struct parsed_proto *pp_c;
3861 struct parsed_proto *pp;
3862 struct parsed_data *pd;
3863 struct parsed_op *po;
3864 const char *tmpname;
56b49358 3865 enum op_op prev_op;
b2bd20c0 3866 int i, l;
3867 int ret;
66bdb2b0 3868
3869 for (i = 0; i < opcnt; i++)
3870 {
3871 po = &ops[i];
3872 po->bt_i = -1;
3873 po->btj = NULL;
3874
865f1aca 3875 if (po->datap != NULL) {
3876 pp = calloc(1, sizeof(*pp));
3877 my_assert_not(pp, NULL);
3878
3879 ret = parse_protostr(po->datap, pp);
3880 if (ret < 0)
3881 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3882 free(po->datap);
3883 po->datap = NULL;
3884 po->pp = pp;
3885 }
3886
66bdb2b0 3887 if (po->op == OP_CALL) {
3888 pp = NULL;
3889
865f1aca 3890 if (po->pp != NULL)
3891 pp = po->pp;
3892 else if (po->operand[0].type == OPT_LABEL)
3893 {
66bdb2b0 3894 tmpname = opr_name(po, 0);
0a2c6da1 3895 if (IS_START(tmpname, "loc_")) {
3896 if (!g_seh_found)
3897 ferr(po, "call to loc_*\n");
3898 // eliminate_seh() must take care of it
3899 continue;
3900 }
16057ce1 3901 if (IS(tmpname, "__alloca_probe"))
3902 continue;
2eae9f23 3903 if (IS(tmpname, "__SEH_prolog")) {
3904 ferr_assert(po, g_seh_found == 0);
3905 g_seh_found = 2;
3906 continue;
3907 }
3908 if (IS(tmpname, "__SEH_epilog"))
3909 continue;
d4a985bd 3910
3911 // convert some calls to pseudo-ops
3912 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3913 if (!IS(tmpname, pseudo_ops[l].name))
3914 continue;
3915
3916 po->op = pseudo_ops[l].op;
3917 po->operand_cnt = 0;
3918 po->regmask_src = pseudo_ops[l].regmask_src;
3919 po->regmask_dst = pseudo_ops[l].regmask_dst;
3920 po->flags = pseudo_ops[l].flags;
3921 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3922 break;
3923 }
3924 if (l < ARRAY_SIZE(pseudo_ops))
3925 continue;
3926
66bdb2b0 3927 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3928 if (!g_header_mode && pp_c == NULL)
3929 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3930
3931 if (pp_c != NULL) {
3932 pp = proto_clone(pp_c);
3933 my_assert_not(pp, NULL);
3934 }
3935 }
66bdb2b0 3936
3937 if (pp != NULL) {
3938 if (pp->is_fptr)
3939 check_func_pp(po, pp, "fptr var call");
56b49358 3940 if (pp->is_noreturn) {
66bdb2b0 3941 po->flags |= OPF_TAIL;
56b49358 3942 po->flags &= ~OPF_ATAIL; // most likely...
3943 }
66bdb2b0 3944 }
3945 po->pp = pp;
3946 continue;
3947 }
3948
3949 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3950 continue;
3951
3952 if (po->operand[0].type == OPT_REGMEM) {
3953 pd = try_resolve_jumptab(i, opcnt);
3954 if (pd == NULL)
3955 goto tailcall;
3956
3957 po->btj = pd;
3958 continue;
3959 }
3960
3961 for (l = 0; l < opcnt; l++) {
3962 if (g_labels[l] != NULL
3963 && IS(po->operand[0].name, g_labels[l]))
3964 {
3965 if (l == i + 1 && po->op == OP_JMP) {
9bbecbfb 3966 // yet another alignment type...
3967 po->flags |= OPF_RMD | OPF_DONE;
3968 po->flags &= ~OPF_JMP;
3969 po->op = OP_NOP;
66bdb2b0 3970 break;
3971 }
3972 add_label_ref(&g_label_refs[l], i);
3973 po->bt_i = l;
3974 break;
3975 }
3976 }
3977
3978 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3979 continue;
3980
3981 if (po->operand[0].type == OPT_LABEL)
3982 // assume tail call
3983 goto tailcall;
3984
3985 ferr(po, "unhandled branch\n");
3986
3987tailcall:
3988 po->op = OP_CALL;
3989 po->flags |= OPF_TAIL;
56b49358 3990 prev_op = i > 0 ? ops[i - 1].op : OP_UD2;
3991 if (prev_op == OP_POP)
66bdb2b0 3992 po->flags |= OPF_ATAIL;
56b49358 3993 if (g_stack_fsz + g_bp_frame == 0 && prev_op != OP_PUSH
3994 && (g_func_pp == NULL || g_func_pp->argc_stack > 0))
3995 {
3996 po->flags |= OPF_ATAIL;
3997 }
66bdb2b0 3998 i--; // reprocess
3999 }
9af2d373 4000}
4001
ba93cc12 4002static int resolve_origin(int i, const struct parsed_opr *opr,
4003 int magic, int *op_i, int *is_caller);
0a2c6da1 4004static void set_label(int i, const char *name);
ba93cc12 4005
2eae9f23 4006static void eliminate_seh_writes(int opcnt)
4007{
4008 const struct parsed_opr *opr;
4009 char ofs_reg[16];
4010 int offset;
4011 int i;
4012
4013 // assume all sf writes above g_seh_size to be seh related
4014 // (probably unsafe but oh well)
4015 for (i = 0; i < opcnt; i++) {
4016 if (ops[i].op != OP_MOV)
4017 continue;
4018 opr = &ops[i].operand[0];
4019 if (opr->type != OPT_REGMEM)
4020 continue;
4021 if (!is_stack_access(&ops[i], opr))
4022 continue;
4023
4024 offset = 0;
4025 parse_stack_access(&ops[i], opr->name, ofs_reg, &offset,
4026 NULL, NULL, 0);
4027 if (offset < 0 && offset >= -g_seh_size)
4028 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4029 }
4030}
4031
0a2c6da1 4032static void eliminate_seh_finally(int opcnt)
4033{
4034 const char *target_name = NULL;
4035 const char *return_name = NULL;
4036 int exits[MAX_EXITS];
4037 int exit_count = 0;
4038 int call_i = -1;
4039 int target_i = -1;
4040 int return_i = -1;
4041 int tgend_i = -1;
4042 int i;
4043
4044 for (i = 0; i < opcnt; i++) {
4045 if (ops[i].op != OP_CALL)
4046 continue;
4047 if (!IS_START(opr_name(&ops[i], 0), "loc_"))
4048 continue;
4049 if (target_name != NULL)
4050 ferr(&ops[i], "multiple finally calls? (last was %s)\n",
4051 target_name);
4052 target_name = opr_name(&ops[i], 0);
4053 call_i = i;
4054
4055 if (g_labels[i + 1] == NULL)
4056 set_label(i + 1, "seh_fin_done");
4057 return_name = g_labels[i + 1];
4058 return_i = i + 1;
4059 }
4060
4061 if (call_i == -1)
4062 // no finally block
4063 return;
4064
4065 // find finally code (bt_i is not set because it's call)
4066 for (i = 0; i < opcnt; i++) {
4067 if (g_labels[i] == NULL)
4068 continue;
4069 if (!IS(g_labels[i], target_name))
4070 continue;
4071
4072 ferr_assert(&ops[i], target_i == -1);
4073 target_i = i;
4074 }
4075 ferr_assert(&ops[0], target_i != -1);
4076
4077 find_reachable_exits(target_i, opcnt, target_i + opcnt * 24,
4078 exits, &exit_count);
4079 ferr_assert(&ops[target_i], exit_count == 1);
4080 ferr_assert(&ops[target_i], ops[exits[0]].op == OP_RET);
4081 tgend_i = exits[0];
4082
4083 // convert to jumps, link
4084 ops[call_i].op = OP_JMP;
4085 ops[call_i].bt_i = target_i;
4086 add_label_ref(&g_label_refs[target_i], call_i);
4087
4088 ops[tgend_i].op = OP_JMP;
4089 ops[tgend_i].flags &= ~OPF_TAIL;
4090 ops[tgend_i].flags |= OPF_JMP;
4091 ops[tgend_i].bt_i = return_i;
4092 ops[tgend_i].operand_cnt = 1;
4093 ops[tgend_i].operand[0].type = OPT_LABEL;
4094 snprintf(ops[tgend_i].operand[0].name, NAMELEN, "%s", return_name);
4095 add_label_ref(&g_label_refs[return_i], tgend_i);
4096
4097 // rm seh finally entry code
4098 for (i = target_i - 1; i >= 0; i--) {
4099 if (g_labels[i] != NULL && g_label_refs[i].i != -1)
4100 return;
4101 if (ops[i].flags & OPF_CJMP)
4102 return;
4103 if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4104 break;
4105 }
4106 for (i = target_i - 1; i >= 0; i--) {
4107 if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4108 break;
4109 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4110 }
4111}
4112
ba93cc12 4113static void eliminate_seh(int opcnt)
4114{
4115 int i, j, k, ret;
4116
4117 for (i = 0; i < opcnt; i++) {
4118 if (ops[i].op != OP_MOV)
4119 continue;
4120 if (ops[i].operand[0].segment != SEG_FS)
4121 continue;
4122 if (!IS(opr_name(&ops[i], 0), "0"))
4123 continue;
4124
4125 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4126 if (ops[i].operand[1].reg == xSP) {
4127 for (j = i - 1; j >= 0; j--) {
4128 if (ops[j].op != OP_PUSH)
4129 continue;
4130 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4131 g_seh_size += 4;
4132 if (ops[j].operand[0].val == ~0)
4133 break;
4134 if (ops[j].operand[0].type == OPT_REG) {
4135 k = -1;
4136 ret = resolve_origin(j, &ops[j].operand[0],
4137 j + opcnt * 22, &k, NULL);
4138 if (ret == 1)
4139 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4140 }
4141 }
4142 if (j < 0)
4143 ferr(ops, "missing seh terminator\n");
4144 }
4145 else {
4146 k = -1;
4147 ret = resolve_origin(i, &ops[i].operand[1],
4148 i + opcnt * 23, &k, NULL);
4149 if (ret == 1)
4150 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4151 }
4152 }
4153
2eae9f23 4154 eliminate_seh_writes(opcnt);
0a2c6da1 4155 eliminate_seh_finally(opcnt);
2eae9f23 4156}
ba93cc12 4157
2eae9f23 4158static void eliminate_seh_calls(int opcnt)
4159{
4160 int epilog_found = 0;
4161 int i;
4162
4163 g_bp_frame = 1;
4164 g_seh_size = 0x10;
4165
4166 i = 0;
4167 ferr_assert(&ops[i], ops[i].op == OP_PUSH
4168 && ops[i].operand[0].type == OPT_CONST);
4169 g_stack_fsz = g_seh_size + ops[i].operand[0].val;
4170 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4171
4172 i++;
4173 ferr_assert(&ops[i], ops[i].op == OP_PUSH
4174 && ops[i].operand[0].type == OPT_OFFSET);
4175 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4176
4177 i++;
4178 ferr_assert(&ops[i], ops[i].op == OP_CALL
4179 && IS(opr_name(&ops[i], 0), "__SEH_prolog"));
4180 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4181
4182 for (i++; i < opcnt; i++) {
4183 if (ops[i].op != OP_CALL)
ba93cc12 4184 continue;
2eae9f23 4185 if (!IS(opr_name(&ops[i], 0), "__SEH_epilog"))
ba93cc12 4186 continue;
4187
2eae9f23 4188 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4189 epilog_found = 1;
4190 }
4191 ferr_assert(ops, epilog_found);
4192
4193 eliminate_seh_writes(opcnt);
0a2c6da1 4194 eliminate_seh_finally(opcnt);
2eae9f23 4195}
4196
f9d7b461 4197// check for prologue of many pushes and epilogue with pops
4198static void check_simple_sequence(int opcnt, int *fsz)
4199{
4200 int found = 0;
4201 int seq_len;
4202 int seq_p;
4203 int seq[4];
4204 int reg;
4205 int i, j;
4206
4207 for (i = 0; i < opcnt && i < ARRAY_SIZE(seq); i++) {
4208 if (ops[i].op != OP_PUSH || ops[i].operand[0].type != OPT_REG)
4209 break;
4210 reg = ops[i].operand[0].reg;
4211 if (reg != xBX && reg != xSI && reg != xDI && reg != xBP)
4212 break;
4213 for (j = 0; j < i; j++)
4214 if (seq[j] == reg)
4215 break;
4216 if (j != i)
4217 // probably something else is going on here
4218 break;
4219 seq[i] = reg;
4220 }
4221 seq_len = i;
4222 if (seq_len == 0)
4223 return;
4224
4225 for (; i < opcnt && seq_len > 0; i++) {
4226 if (!(ops[i].flags & OPF_TAIL))
4227 continue;
4228
4229 for (j = i - 1, seq_p = 0; j >= 0 && seq_p < seq_len; j--) {
4230 if (ops[j].op != OP_POP || ops[j].operand[0].type != OPT_REG)
4231 break;
4232 if (ops[j].operand[0].reg != seq[seq_p])
4233 break;
4234 seq_p++;
4235 }
4236 found = seq_len = seq_p;
4237 }
4238 if (!found)
4239 return;
4240
4241 for (i = 0; i < seq_len; i++)
4242 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4243
4244 for (; i < opcnt && seq_len > 0; i++) {
4245 if (!(ops[i].flags & OPF_TAIL))
4246 continue;
4247
4248 for (j = i - 1, seq_p = 0; j >= 0 && seq_p < seq_len; j--) {
4249 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4250 seq_p++;
4251 }
4252 }
4253
4254 // unlike pushes after sub esp,
57b1b785 4255 // IDA treats pushes like this as part of var area
f9d7b461 4256 *fsz += seq_len * 4;
4257}
4258
2eae9f23 4259static int scan_prologue(int i, int opcnt, int *ecx_push, int *esp_sub)
4260{
f9d7b461 4261 const char *name;
4262 int j, len, ret;
2eae9f23 4263
4264 for (; i < opcnt; i++)
4265 if (!(ops[i].flags & OPF_DONE))
4266 break;
4267
4268 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4269 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4270 g_stack_fsz += 4;
4271 (*ecx_push)++;
4272 i++;
4273 }
4274
4275 for (; i < opcnt; i++) {
4276 if (i > 0 && g_labels[i] != NULL)
4277 break;
57b1b785 4278 if (ops[i].flags & (OPF_JMP|OPF_TAIL))
4279 break;
4280 if (ops[i].flags & OPF_DONE)
4281 continue;
4282 if (ops[i].op == OP_PUSH)
2eae9f23 4283 break;
4284 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
4285 && ops[i].operand[1].type == OPT_CONST)
4286 {
4287 g_stack_fsz += opr_const(&ops[i], 1);
ba93cc12 4288 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
2eae9f23 4289 i++;
4290 *esp_sub = 1;
4291 break;
4292 }
f9d7b461 4293 if (ops[i].op == OP_LEA && ops[i].operand[0].reg == xSP
4294 && ops[i].operand[1].type == OPT_REGMEM
4295 && IS_START(ops[i].operand[1].name, "esp-"))
4296 {
4297 name = ops[i].operand[1].name;
4298 ret = sscanf(name, "esp-%x%n", &j, &len);
4299 ferr_assert(&ops[i], ret == 1 && len == strlen(name));
4300 g_stack_fsz += j;
4301 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4302 i++;
4303 *esp_sub = 1;
4304 break;
4305 }
2eae9f23 4306 if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
4307 && ops[i].operand[1].type == OPT_CONST)
4308 {
4309 for (j = i + 1; j < opcnt; j++)
4310 if (!(ops[j].flags & OPF_DONE))
4311 break;
4312 if (ops[j].op == OP_CALL
4313 && IS(opr_name(&ops[j], 0), "__alloca_probe"))
4314 {
4315 g_stack_fsz += opr_const(&ops[i], 1);
4316 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4317 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4318 i = j + 1;
4319 *esp_sub = 1;
57b1b785 4320 break;
2eae9f23 4321 }
2eae9f23 4322 }
ba93cc12 4323 }
2eae9f23 4324
4325 return i;
ba93cc12 4326}
4327
f9327ad4 4328static void scan_prologue_epilogue(int opcnt, int *stack_align)
9af2d373 4329{
16057ce1 4330 int ecx_push = 0, esp_sub = 0, pusha = 0;
4331 int sandard_epilogue;
f9d7b461 4332 int found, ret, len;
4333 int push_fsz = 0;
9af2d373 4334 int i, j, l;
4335
2eae9f23 4336 if (g_seh_found == 2) {
4337 eliminate_seh_calls(opcnt);
4338 return;
4339 }
ba93cc12 4340 if (g_seh_found) {
4341 eliminate_seh(opcnt);
4342 // ida treats seh as part of sf
4343 g_stack_fsz = g_seh_size;
4344 esp_sub = 1;
4345 }
4346
9af2d373 4347 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
4348 && ops[1].op == OP_MOV
4349 && IS(opr_name(&ops[1], 0), "ebp")
4350 && IS(opr_name(&ops[1], 1), "esp"))
4351 {
4352 g_bp_frame = 1;
b2bd20c0 4353 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4354 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
ba93cc12 4355
4356 for (i = 2; i < opcnt; i++)
4357 if (!(ops[i].flags & OPF_DONE))
4358 break;
9af2d373 4359
16057ce1 4360 if (ops[i].op == OP_PUSHA) {
4361 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4362 pusha = 1;
4363 i++;
4364 }
4365
f9327ad4 4366 if (ops[i].op == OP_AND && ops[i].operand[0].reg == xSP
4367 && ops[i].operand[1].type == OPT_CONST)
4368 {
4369 l = ops[i].operand[1].val;
4370 j = ffs(l) - 1;
4371 if (j == -1 || (l >> j) != -1)
4372 ferr(&ops[i], "unhandled esp align: %x\n", l);
4373 if (stack_align != NULL)
4374 *stack_align = 1 << j;
4375 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4376 i++;
4377 }
4378
2eae9f23 4379 i = scan_prologue(i, opcnt, &ecx_push, &esp_sub);
9af2d373 4380
4381 found = 0;
4382 do {
4383 for (; i < opcnt; i++)
66bdb2b0 4384 if (ops[i].flags & OPF_TAIL)
9af2d373 4385 break;
4386 j = i - 1;
4387 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
66bdb2b0 4388 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4389 break;
4390 i--;
9af2d373 4391 j--;
4392 }
4393
16057ce1 4394 sandard_epilogue = 0;
4395 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
4396 {
4397 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4398 // the standard epilogue is sometimes even used without a sf
4399 if (ops[j - 1].op == OP_MOV
4400 && IS(opr_name(&ops[j - 1], 0), "esp")
4401 && IS(opr_name(&ops[j - 1], 1), "ebp"))
4402 sandard_epilogue = 1;
4403 }
4404 else if (ops[j].op == OP_LEAVE)
9af2d373 4405 {
b2bd20c0 4406 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
16057ce1 4407 sandard_epilogue = 1;
9af2d373 4408 }
66bdb2b0 4409 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
4410 && ops[i].pp->is_noreturn)
4411 {
4412 // on noreturn, msvc sometimes cleans stack, sometimes not
4413 i++;
4414 found = 1;
4415 continue;
4416 }
9af2d373 4417 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4418 ferr(&ops[j], "'pop ebp' expected\n");
4419
16057ce1 4420 if (g_stack_fsz != 0 || sandard_epilogue) {
bfacdc83 4421 if (ops[j].op == OP_LEAVE)
4422 j--;
16057ce1 4423 else if (sandard_epilogue) // mov esp, ebp
9af2d373 4424 {
b2bd20c0 4425 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
bfacdc83 4426 j -= 2;
9af2d373 4427 }
bfacdc83 4428 else if (!(g_ida_func_attr & IDAFA_NORETURN))
9af2d373 4429 {
bfacdc83 4430 ferr(&ops[j], "esp restore expected\n");
9af2d373 4431 }
4432
bfacdc83 4433 if (ecx_push && j >= 0 && ops[j].op == OP_POP
4434 && IS(opr_name(&ops[j], 0), "ecx"))
9af2d373 4435 {
bfacdc83 4436 ferr(&ops[j], "unexpected ecx pop\n");
9af2d373 4437 }
4438 }
4439
16057ce1 4440 if (pusha) {
4441 if (ops[j].op == OP_POPA)
4442 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4443 else
4444 ferr(&ops[j], "popa expected\n");
4445 }
4446
9af2d373 4447 found = 1;
4448 i++;
4449 } while (i < opcnt);
4450
66bdb2b0 4451 if (!found)
4452 ferr(ops, "missing ebp epilogue\n");
9af2d373 4453 return;
4454 }
4455
4456 // non-bp frame
f9d7b461 4457 check_simple_sequence(opcnt, &push_fsz);
2eae9f23 4458 i = scan_prologue(0, opcnt, &ecx_push, &esp_sub);
9af2d373 4459
4460 if (ecx_push && !esp_sub) {
4461 // could actually be args for a call..
4462 for (; i < opcnt; i++)
4463 if (ops[i].op != OP_PUSH)
4464 break;
4465
4466 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
4467 const struct parsed_proto *pp;
4468 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
4469 j = pp ? pp->argc_stack : 0;
4470 while (i > 0 && j > 0) {
4471 i--;
4472 if (ops[i].op == OP_PUSH) {
b2bd20c0 4473 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
9af2d373 4474 j--;
4475 }
4476 }
4477 if (j != 0)
4478 ferr(&ops[i], "unhandled prologue\n");
4479
4480 // recheck
ba93cc12 4481 i = ecx_push = 0;
4482 g_stack_fsz = g_seh_size;
9af2d373 4483 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4484 if (!(ops[i].flags & OPF_RMD))
4485 break;
4486 g_stack_fsz += 4;
4487 ecx_push++;
4488 i++;
4489 }
4490 }
4491 }
4492
4493 found = 0;
4494 if (ecx_push || esp_sub)
4495 {
4496 g_sp_frame = 1;
4497
9af2d373 4498 do {
4499 for (; i < opcnt; i++)
66bdb2b0 4500 if (ops[i].flags & OPF_TAIL)
9af2d373 4501 break;
fe18df39 4502
9af2d373 4503 j = i - 1;
4504 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
66bdb2b0 4505 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4506 break;
4507 i--;
9af2d373 4508 j--;
4509 }
2eae9f23 4510 else if (i < opcnt && (ops[i].flags & OPF_ATAIL)) {
4511 // skip arg updates for arg-reuse tailcall
4512 for (; j >= 0; j--) {
4513 if (ops[j].op != OP_MOV)
4514 break;
57b1b785 4515 if (ops[j].operand[0].type == OPT_REGMEM
4516 && strstr(ops[j].operand[0].name, "arg_") != NULL)
4517 continue;
4518 if (ops[j].operand[0].type == OPT_REG)
4519 continue; // assume arg-reg mov
4520 break;
2eae9f23 4521 }
4522 }
9af2d373 4523
f9d7b461 4524 for (; j >= 0; j--) {
4525 if ((ops[j].flags & (OPF_RMD | OPF_DONE | OPF_NOREGS)) !=
4526 (OPF_RMD | OPF_DONE | OPF_NOREGS))
4527 break;
4528 }
4529
ba93cc12 4530 if (ecx_push > 0 && !esp_sub) {
2eae9f23 4531 for (l = 0; l < ecx_push && j >= 0; l++) {
9af2d373 4532 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
4533 /* pop ecx */;
4534 else if (ops[j].op == OP_ADD
4535 && IS(opr_name(&ops[j], 0), "esp")
4536 && ops[j].operand[1].type == OPT_CONST)
4537 {
4538 /* add esp, N */
5e49b270 4539 l += ops[j].operand[1].val / 4 - 1;
9af2d373 4540 }
4541 else
56b49358 4542 break;
9af2d373 4543
b2bd20c0 4544 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
9af2d373 4545 j--;
4546 }
56b49358 4547 if (l != ecx_push) {
4548 if (i < opcnt && ops[i].op == OP_CALL
4549 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4550 {
4551 // noreturn tailcall with no epilogue
4552 i++;
4553 found = 1;
4554 continue;
4555 }
9af2d373 4556 ferr(&ops[j], "epilogue scan failed\n");
56b49358 4557 }
9af2d373 4558
4559 found = 1;
4560 }
4561
4562 if (esp_sub) {
f9d7b461 4563 if (ops[j].op == OP_ADD
4564 && IS(opr_name(&ops[j], 0), "esp")
4565 && ops[j].operand[1].type == OPT_CONST)
622eb2ef 4566 {
f9d7b461 4567 if (ops[j].operand[1].val < g_stack_fsz)
4568 ferr(&ops[j], "esp adj is too low (need %d)\n", g_stack_fsz);
71d50aa7 4569
f9d7b461 4570 ops[j].operand[1].val -= g_stack_fsz; // for stack arg scanner
4571 if (ops[j].operand[1].val == 0)
4572 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4573 found = 1;
4574 }
4575 else if (ops[j].op == OP_LEA && ops[j].operand[0].reg == xSP
4576 && ops[j].operand[1].type == OPT_REGMEM
4577 && IS_START(ops[j].operand[1].name, "esp+"))
4578 {
4579 const char *name = ops[j].operand[1].name;
4580 ret = sscanf(name, "esp+%x%n", &l, &len);
4581 ferr_assert(&ops[j], ret == 1 && len == strlen(name));
4582 ferr_assert(&ops[j], l <= g_stack_fsz);
71d50aa7 4583 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
f9d7b461 4584 found = 1;
4585 }
4586 else if (i < opcnt && ops[i].op == OP_CALL
4587 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4588 {
4589 // noreturn tailcall with no epilogue
4590 found = 1;
4591 }
4592 else
4593 ferr(&ops[j], "'add esp' expected\n");
9af2d373 4594 }
4595
4596 i++;
4597 } while (i < opcnt);
66bdb2b0 4598
4599 if (!found)
4600 ferr(ops, "missing esp epilogue\n");
9af2d373 4601 }
f9d7b461 4602
4603 if (g_stack_fsz != 0)
4604 // see check_simple_sequence
4605 g_stack_fsz += push_fsz;
9af2d373 4606}
4607
23fd0b11 4608// find an instruction that changed opr before i op
db63af51 4609// *op_i must be set to -1 by the caller
865f1aca 4610// *is_caller is set to 1 if one source is determined to be g_func arg
92d715b6 4611// returns 1 if found, *op_i is then set to origin
865f1aca 4612// returns -1 if multiple origins are found
23fd0b11 4613static int resolve_origin(int i, const struct parsed_opr *opr,
92d715b6 4614 int magic, int *op_i, int *is_caller)
1f84f6b3 4615{
4616 struct label_ref *lr;
4617 int ret = 0;
4618
1f84f6b3 4619 while (1) {
d7857c3a 4620 if (g_labels[i] != NULL) {
1f84f6b3 4621 lr = &g_label_refs[i];
92d715b6 4622 for (; lr != NULL; lr = lr->next) {
4623 check_i(&ops[i], lr->i);
4624 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4625 }
1f84f6b3 4626 if (i > 0 && LAST_OP(i - 1))
4627 return ret;
4628 }
4629
4630 i--;
92d715b6 4631 if (i < 0) {
4632 if (is_caller != NULL)
4633 *is_caller = 1;
1f84f6b3 4634 return -1;
92d715b6 4635 }
1f84f6b3 4636
4637 if (ops[i].cc_scratch == magic)
ebc4dc43 4638 return ret;
1f84f6b3 4639 ops[i].cc_scratch = magic;
4640
4641 if (!(ops[i].flags & OPF_DATA))
4642 continue;
4643 if (!is_opr_modified(opr, &ops[i]))
4644 continue;
23fd0b11 4645
4646 if (*op_i >= 0) {
93b5bd18 4647 if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
ebc4dc43 4648 return ret | 1;
4649
23fd0b11 4650 return -1;
4651 }
4652
4653 *op_i = i;
ebc4dc43 4654 return ret | 1;
23fd0b11 4655 }
4656}
4657
17ed469e 4658static int resolve_origin_reg(int i, int reg, int magic, int *op_i,
4659 int *is_caller)
4660{
4661 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, reg);
4662
4663 *op_i = -1;
4664 if (is_caller != NULL)
4665 *is_caller = 0;
4666 return resolve_origin(i, &opr, magic, op_i, is_caller);
4667}
4668
db63af51 4669// find an instruction that previously referenced opr
4670// if multiple results are found - fail
4671// *op_i must be set to -1 by the caller
4672// returns 1 if found, *op_i is then set to referencer insn
4673static int resolve_last_ref(int i, const struct parsed_opr *opr,
4674 int magic, int *op_i)
4675{
4676 struct label_ref *lr;
4677 int ret = 0;
4678
db63af51 4679 while (1) {
4680 if (g_labels[i] != NULL) {
4681 lr = &g_label_refs[i];
4682 for (; lr != NULL; lr = lr->next) {
4683 check_i(&ops[i], lr->i);
4684 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4685 }
4686 if (i > 0 && LAST_OP(i - 1))
4687 return ret;
4688 }
4689
4690 i--;
4691 if (i < 0)
4692 return -1;
4693
4694 if (ops[i].cc_scratch == magic)
4695 return 0;
4696 ops[i].cc_scratch = magic;
4697
4698 if (!is_opr_referenced(opr, &ops[i]))
4699 continue;
4700
4701 if (*op_i >= 0)
4702 return -1;
4703
4704 *op_i = i;
4705 return 1;
4706 }
4707}
4708
16057ce1 4709// adjust datap of all reachable 'op' insns when moving back
4710// returns 1 if at least 1 op was found
4711// returns -1 if path without an op was found
4712static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4713{
4714 struct label_ref *lr;
4715 int ret = 0;
4716
4717 if (ops[i].cc_scratch == magic)
4718 return 0;
4719 ops[i].cc_scratch = magic;
4720
4721 while (1) {
4722 if (g_labels[i] != NULL) {
4723 lr = &g_label_refs[i];
4724 for (; lr != NULL; lr = lr->next) {
4725 check_i(&ops[i], lr->i);
4726 ret |= adjust_prev_op(lr->i, op, magic, datap);
4727 }
4728 if (i > 0 && LAST_OP(i - 1))
4729 return ret;
4730 }
4731
4732 i--;
4733 if (i < 0)
4734 return -1;
4735
4736 if (ops[i].cc_scratch == magic)
4737 return 0;
4738 ops[i].cc_scratch = magic;
4739
4740 if (ops[i].op != op)
4741 continue;
4742
4743 ops[i].datap = datap;
4744 return 1;
4745 }
4746}
4747
db63af51 4748// find next instruction that reads opr
db63af51 4749// *op_i must be set to -1 by the caller
b2bd20c0 4750// on return, *op_i is set to first referencer insn
4751// returns 1 if exactly 1 referencer is found
db63af51 4752static int find_next_read(int i, int opcnt,
4753 const struct parsed_opr *opr, int magic, int *op_i)
4754{
4755 struct parsed_op *po;
4756 int j, ret = 0;
4757
4758 for (; i < opcnt; i++)
4759 {
4760 if (ops[i].cc_scratch == magic)
b2bd20c0 4761 return ret;
db63af51 4762 ops[i].cc_scratch = magic;
4763
4764 po = &ops[i];
4765 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4766 if (po->btj != NULL) {
4767 // jumptable
4768 for (j = 0; j < po->btj->count; j++) {
4769 check_i(po, po->btj->d[j].bt_i);
4770 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4771 magic, op_i);
4772 }
4773 return ret;
4774 }
4775
4776 if (po->flags & OPF_RMD)
4777 continue;
4778 check_i(po, po->bt_i);
4779 if (po->flags & OPF_CJMP) {
b2bd20c0 4780 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
db63af51 4781 if (ret < 0)
4782 return ret;
4783 }
b2bd20c0 4784 else
4785 i = po->bt_i - 1;
db63af51 4786 continue;
4787 }
4788
4789 if (!is_opr_read(opr, po)) {
16057ce1 4790 int full_opr = 1;
4791 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4792 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
acd03176 4793 {
16057ce1 4794 full_opr = po->operand[0].lmod >= opr->lmod;
4795 }
4796 if (is_opr_modified(opr, po) && full_opr) {
db63af51 4797 // it's overwritten
b2bd20c0 4798 return ret;
acd03176 4799 }
db63af51 4800 if (po->flags & OPF_TAIL)
b2bd20c0 4801 return ret;
db63af51 4802 continue;
4803 }
4804
4805 if (*op_i >= 0)
4806 return -1;
4807
4808 *op_i = i;
4809 return 1;
4810 }
4811
4812 return 0;
4813}
4814
427da1c9 4815static int find_next_read_reg(int i, int opcnt, int reg,
4816 enum opr_lenmod lmod, int magic, int *op_i)
4817{
4818 struct parsed_opr opr = OPR_INIT(OPT_REG, lmod, reg);
4819
4820 *op_i = -1;
4821 return find_next_read(i, opcnt, &opr, magic, op_i);
4822}
4823
16057ce1 4824// find next instruction that reads opr
4825// *op_i must be set to -1 by the caller
4826// on return, *op_i is set to first flag user insn
4827// returns 1 if exactly 1 flag user is found
4828static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4829{
4830 struct parsed_op *po;
4831 int j, ret = 0;
4832
4833 for (; i < opcnt; i++)
4834 {
4835 if (ops[i].cc_scratch == magic)
4836 return ret;
4837 ops[i].cc_scratch = magic;
4838
4839 po = &ops[i];
4840 if (po->op == OP_CALL)
4841 return -1;
4842 if (po->flags & OPF_JMP) {
4843 if (po->btj != NULL) {
4844 // jumptable
4845 for (j = 0; j < po->btj->count; j++) {
4846 check_i(po, po->btj->d[j].bt_i);
4847 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4848 magic, op_i);
4849 }
4850 return ret;
4851 }
4852
4853 if (po->flags & OPF_RMD)
4854 continue;
4855 check_i(po, po->bt_i);
4856 if (po->flags & OPF_CJMP)
4857 goto found;
4858 else
4859 i = po->bt_i - 1;
4860 continue;
4861 }
4862
4863 if (!(po->flags & OPF_CC)) {
4864 if (po->flags & OPF_FLAGS)
4865 // flags changed
4866 return ret;
4867 if (po->flags & OPF_TAIL)
4868 return ret;
4869 continue;
4870 }
4871
4872found:
4873 if (*op_i >= 0)
4874 return -1;
4875
4876 *op_i = i;
4877 return 1;
4878 }
4879
4880 return 0;
4881}
4882
23fd0b11 4883static int try_resolve_const(int i, const struct parsed_opr *opr,
4884 int magic, unsigned int *val)
4885{
4886 int s_i = -1;
92d715b6 4887 int ret;
23fd0b11 4888
92d715b6 4889 ret = resolve_origin(i, opr, magic, &s_i, NULL);
23fd0b11 4890 if (ret == 1) {
4891 i = s_i;
1f84f6b3 4892 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4893 return -1;
4894
4895 *val = ops[i].operand[1].val;
4896 return 1;
4897 }
23fd0b11 4898
4899 return -1;
1f84f6b3 4900}
4901
16057ce1 4902static int resolve_used_bits(int i, int opcnt, int reg,
4903 int *mask, int *is_z_check)
4904{
4905 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4906 int j = -1, k = -1;
4907 int ret;
4908
4909 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4910 if (ret != 1)
4911 return -1;
4912
4913 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4914 if (k != -1) {
4915 fnote(&ops[j], "(first read)\n");
4916 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4917 }
4918
4919 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4920 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4921
4922 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4923 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4924
4925 *mask = ops[j].operand[1].val;
4926 if (ops[j].operand[0].lmod == OPLM_BYTE
4927 && ops[j].operand[0].name[1] == 'h')
4928 {
4929 *mask <<= 8;
4930 }
4931 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4932
4933 *is_z_check = 0;
4934 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4935 if (ret == 1)
4936 *is_z_check = ops[k].pfo == PFO_Z;
4937
4938 return 0;
4939}
4940
93b5bd18 4941static const struct parsed_proto *resolve_deref(int i, int magic,
17ed469e 4942 const struct parsed_opr *opr, int level)
93b5bd18 4943{
93b5bd18 4944 const struct parsed_proto *pp = NULL;
4945 int from_caller = 0;
4946 char s_reg[4];
4947 int offset = 0;
4948 int len = 0;
4949 int j = -1;
4950 int k = -1;
4951 int reg;
4952 int ret;
4953
4954 ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4955 if (ret != 2 || len != strlen(opr->name)) {
4956 ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4957 if (ret != 1 || len != strlen(opr->name))
4958 return NULL;
4959 }
4960
4961 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4962 if (reg < 0)
4963 return NULL;
4964
17ed469e 4965 ret = resolve_origin_reg(i, reg, i + magic, &j, NULL);
93b5bd18 4966 if (ret != 1)
4967 return NULL;
4968
4969 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4970 && strlen(ops[j].operand[1].name) == 3
4971 && ops[j].operand[0].lmod == OPLM_DWORD
4972 && ops[j].pp == NULL // no hint
4973 && level == 0)
4974 {
4975 // allow one simple dereference (com/directx)
4976 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4977 ops[j].operand[1].name);
4978 if (reg < 0)
4979 return NULL;
17ed469e 4980 ret = resolve_origin_reg(j, reg, j + magic, &k, NULL);
93b5bd18 4981 if (ret != 1)
4982 return NULL;
4983 j = k;
4984 }
4985 if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
4986 return NULL;
4987
4988 if (ops[j].pp != NULL) {
4989 // type hint in asm
4990 pp = ops[j].pp;
4991 }
4992 else if (ops[j].operand[1].type == OPT_REGMEM) {
4993 pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
4994 if (pp == NULL) {
4995 // maybe structure ptr in structure
4996 pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
4997 }
4998 }
4999 else if (ops[j].operand[1].type == OPT_LABEL)
5000 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
5001 else if (ops[j].operand[1].type == OPT_REG) {
5002 // maybe arg reg?
5003 k = -1;
5004 ret = resolve_origin(j, &ops[j].operand[1], i + magic,
5005 &k, &from_caller);
5006 if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
5007 for (k = 0; k < g_func_pp->argc; k++) {
5008 if (g_func_pp->arg[k].reg == NULL)
5009 continue;
5010 if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
5011 pp = g_func_pp->arg[k].pp;
5012 break;
5013 }
5014 }
5015 }
5016 }
5017
5018 if (pp == NULL)
5019 return NULL;
5020 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
5021 if (offset != 0)
5022 ferr(&ops[j], "expected struct, got '%s %s'\n",
5023 pp->type.name, pp->name);
5024 return NULL;
5025 }
5026
5027 return proto_lookup_struct(g_fhdr, pp->type.name, offset);
5028}
5029
17ed469e 5030static const struct parsed_proto *resolve_func_ptr(int i, int opcnt,
5031 int is_call_op, const struct parsed_opr *opr,
865f1aca 5032 int *pp_i, int *multi_src)
5033{
5034 const struct parsed_proto *pp = NULL;
5035 int search_advice = 0;
865f1aca 5036
17ed469e 5037 if (multi_src != NULL)
5038 *multi_src = 0;
5039 if (pp_i != NULL)
5040 *pp_i = -1;
865f1aca 5041
17ed469e 5042 switch (opr->type) {
865f1aca 5043 case OPT_REGMEM:
5044 // try to resolve struct member calls
17ed469e 5045 pp = resolve_deref(i, i + opcnt * 19, opr, 0);
93b5bd18 5046 if (pp != NULL)
865f1aca 5047 break;
865f1aca 5048 // fallthrough
5049 case OPT_LABEL:
5050 case OPT_OFFSET:
17ed469e 5051 pp = try_recover_pp(&ops[i], opr, is_call_op, &search_advice);
865f1aca 5052 if (!search_advice)
5053 break;
5054 // fallthrough
5055 default:
17ed469e 5056 scan_for_call_type(i, opr, i + opcnt * 9, is_call_op,
5057 &pp, pp_i, multi_src);
865f1aca 5058 break;
5059 }
5060
5061 return pp;
5062}
5063
26677139 5064static struct parsed_proto *process_call_early(int i, int opcnt,
5065 int *adj_i)
5066{
5067 struct parsed_op *po = &ops[i];
5068 struct parsed_proto *pp;
5069 int multipath = 0;
5070 int adj = 0;
bfacdc83 5071 int j, ret;
26677139 5072
5073 pp = po->pp;
5074 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
5075 // leave for later
5076 return NULL;
5077
5078 // look for and make use of esp adjust
5079 *adj_i = ret = -1;
5080 if (!pp->is_stdcall && pp->argc_stack > 0)
5081 ret = scan_for_esp_adjust(i + 1, opcnt,
ee2361b9 5082 pp->argc_stack * 4, &adj, &multipath, 0);
26677139 5083 if (ret >= 0) {
5084 if (pp->argc_stack > adj / 4)
5085 return NULL;
5086 if (multipath)
5087 return NULL;
bfacdc83 5088 if (ops[ret].op == OP_POP) {
5089 for (j = 1; j < adj / 4; j++) {
5090 if (ops[ret + j].op != OP_POP
5091 || ops[ret + j].operand[0].reg != xCX)
5092 {
5093 return NULL;
5094 }
5095 }
5096 }
26677139 5097 }
5098
5099 *adj_i = ret;
5100 return pp;
5101}
5102
9af2d373 5103static struct parsed_proto *process_call(int i, int opcnt)
5104{
5105 struct parsed_op *po = &ops[i];
5106 const struct parsed_proto *pp_c;
5107 struct parsed_proto *pp;
5108 const char *tmpname;
db63af51 5109 int call_i = -1, ref_i = -1;
26677139 5110 int adj = 0, multipath = 0;
9af2d373 5111 int ret, arg;
5112
5113 tmpname = opr_name(po, 0);
5114 pp = po->pp;
5115 if (pp == NULL)
5116 {
5117 // indirect call
17ed469e 5118 pp_c = resolve_func_ptr(i, opcnt, 1, &ops[i].operand[0],
5119 &call_i, &multipath);
9af2d373 5120 if (pp_c != NULL) {
5121 if (!pp_c->is_func && !pp_c->is_fptr)
5122 ferr(po, "call to non-func: %s\n", pp_c->name);
5123 pp = proto_clone(pp_c);
5124 my_assert_not(pp, NULL);
26677139 5125 if (multipath)
9af2d373 5126 // not resolved just to single func
5127 pp->is_fptr = 1;
5128
5129 switch (po->operand[0].type) {
5130 case OPT_REG:
5131 // we resolved this call and no longer need the register
5132 po->regmask_src &= ~(1 << po->operand[0].reg);
db63af51 5133
5134 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
5135 && ops[call_i].operand[1].type == OPT_LABEL)
5136 {
5137 // no other source users?
e83ea7ed 5138 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
db63af51 5139 &ref_i);
5140 if (ret == 1 && call_i == ref_i) {
5141 // and nothing uses it after us?
5142 ref_i = -1;
b2bd20c0 5143 find_next_read(i + 1, opcnt, &po->operand[0],
5144 i + opcnt * 11, &ref_i);
5145 if (ref_i == -1)
db63af51 5146 // then also don't need the source mov
b2bd20c0 5147 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
db63af51 5148 }
5149 }
9af2d373 5150 break;
5151 case OPT_REGMEM:
5152 pp->is_fptr = 1;
5153 break;
5154 default:
5155 break;
5156 }
5157 }
5158 if (pp == NULL) {
5159 pp = calloc(1, sizeof(*pp));
5160 my_assert_not(pp, NULL);
5161
5162 pp->is_fptr = 1;
ee2361b9 5163 ret = scan_for_esp_adjust(i + 1, opcnt,
bfacdc83 5164 -1, &adj, &multipath, 0);
26677139 5165 if (ret < 0 || adj < 0) {
9af2d373 5166 if (!g_allow_regfunc)
5167 ferr(po, "non-__cdecl indirect call unhandled yet\n");
5168 pp->is_unresolved = 1;
26677139 5169 adj = 0;
9af2d373 5170 }
26677139 5171 adj /= 4;
5172 if (adj > ARRAY_SIZE(pp->arg))
5173 ferr(po, "esp adjust too large: %d\n", adj);
9af2d373 5174 pp->ret_type.name = strdup("int");
26677139 5175 pp->argc = pp->argc_stack = adj;
9af2d373 5176 for (arg = 0; arg < pp->argc; arg++)
5177 pp->arg[arg].type.name = strdup("int");
5178 }
5179 po->pp = pp;
5180 }
5181
5182 // look for and make use of esp adjust
91ca764a 5183 multipath = 0;
9af2d373 5184 ret = -1;
bfacdc83 5185 if (!pp->is_stdcall && pp->argc_stack > 0) {
5186 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
9af2d373 5187 ret = scan_for_esp_adjust(i + 1, opcnt,
bfacdc83 5188 adj_expect, &adj, &multipath, 0);
5189 }
9af2d373 5190 if (ret >= 0) {
5191 if (pp->is_vararg) {
26677139 5192 if (adj / 4 < pp->argc_stack) {
5193 fnote(po, "(this call)\n");
5194 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
5195 adj, pp->argc_stack * 4);
5196 }
9af2d373 5197 // modify pp to make it have varargs as normal args
5198 arg = pp->argc;
26677139 5199 pp->argc += adj / 4 - pp->argc_stack;
9af2d373 5200 for (; arg < pp->argc; arg++) {
5201 pp->arg[arg].type.name = strdup("int");
5202 pp->argc_stack++;
5203 }
5204 if (pp->argc > ARRAY_SIZE(pp->arg))
5205 ferr(po, "too many args for '%s'\n", tmpname);
5206 }
26677139 5207 if (pp->argc_stack > adj / 4) {
56b49358 5208 if (pp->is_noreturn)
5209 // assume no stack adjust was emited
5210 goto out;
9af2d373 5211 fnote(po, "(this call)\n");
5212 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
26677139 5213 tmpname, pp->argc_stack * 4, adj);
9af2d373 5214 }
5215
ee2361b9 5216 scan_for_esp_adjust(i + 1, opcnt,
5217 pp->argc_stack * 4, &adj, &multipath, 1);
9af2d373 5218 }
5219 else if (pp->is_vararg)
5220 ferr(po, "missing esp_adjust for vararg func '%s'\n",
5221 pp->name);
5222
56b49358 5223out:
9af2d373 5224 return pp;
5225}
5226
17ed469e 5227static void check_fptr_args(int i, int opcnt, struct parsed_proto *pp)
5228{
5229 struct parsed_opr s_opr = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
5230 const struct parsed_proto *pp_arg, *pp_cmp;
5231 const struct parsed_op *po_a;
5232 const char *s_reg;
5233 int pp_cmp_i;
5234 int arg, reg;
5235
5236 for (arg = 0; arg < pp->argc; arg++) {
5237 pp_cmp = NULL;
5238 pp_cmp_i = -1;
5239
5240 pp_arg = pp->arg[arg].pp;
5241 if (pp_arg == NULL || !pp_arg->is_func)
5242 continue;
5243
5244 s_reg = pp->arg[arg].reg;
5245 if (s_reg != NULL) {
5246 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
5247 ferr_assert(&ops[i], reg >= 0);
5248 s_opr.reg = reg;
5249 scan_for_call_type(i, &s_opr, i + arg + opcnt * 28, 0,
5250 &pp_cmp, &pp_cmp_i, NULL);
5251 }
5252 else {
5253 po_a = pp->arg[arg].datap;
5254 if (po_a != NULL && po_a->op == OP_PUSH)
5255 pp_cmp = resolve_func_ptr(po_a - ops, opcnt, 0,
5256 &po_a->operand[0], &pp_cmp_i, NULL);
5257 if (pp_cmp_i < 0)
5258 pp_cmp_i = po_a - ops;
5259 }
5260
5261 if (pp_cmp != NULL && !pp_compatible_func(pp_arg, pp_cmp)) {
5262 if (pp_cmp_i >= 0)
5263 fnote(&ops[pp_cmp_i], "(referenced here)\n");
5264 ferr(&ops[i], "incompatible fptr arg %d\n", arg + 1);
5265 }
5266 }
5267}
5268
b62264bc 5269static void mark_float_arg(struct parsed_op *po,
5270 struct parsed_proto *pp, int arg, int *regmask_ffca)
5271{
5272 po->p_argnext = -1;
5273 po->p_argnum = arg + 1;
5274 ferr_assert(po, pp->arg[arg].datap == NULL);
5275 pp->arg[arg].datap = po;
5276 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
5277 if (regmask_ffca != NULL)
5278 *regmask_ffca |= 1 << arg;
5279}
5280
5281static int check_for_stp(int i, int i_to)
5282{
5283 struct parsed_op *po;
5284
5285 for (; i < i_to; i++) {
5286 po = &ops[i];
5287 if (po->op == OP_FST)
5288 return i;
5289 if (g_labels[i] != NULL || (po->flags & OPF_JMP))
5290 return -1;
5291 if (po->op == OP_CALL || po->op == OP_PUSH || po->op == OP_POP)
5292 return -1;
5293 if (po->op == OP_ADD && po->operand[0].reg == xSP)
5294 return -1;
5295 }
5296
5297 return -1;
5298}
5299
30620174 5300static int collect_call_args_no_push(int i, struct parsed_proto *pp,
5301 int *regmask_ffca)
5302{
5303 struct parsed_op *po;
5304 int offset = 0;
5305 int base_arg;
5306 int j, arg;
5307 int ret;
5308
5309 for (base_arg = 0; base_arg < pp->argc; base_arg++)
5310 if (pp->arg[base_arg].reg == NULL)
5311 break;
5312
5313 for (j = i; j > 0; )
5314 {
5315 ferr_assert(&ops[j], g_labels[j] == NULL);
5316 j--;
5317
5318 po = &ops[j];
5319 ferr_assert(po, po->op != OP_PUSH);
5320 if (po->op == OP_FST)
5321 {
5322 if (po->operand[0].type != OPT_REGMEM)
5323 continue;
5324 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
5325 if (ret != 0)
5326 continue;
71d50aa7 5327 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3)) {
5328 //ferr(po, "offset %d, %d args\n", offset, pp->argc_stack);
5329 continue;
5330 }
30620174 5331
5332 arg = base_arg + offset / 4;
b62264bc 5333 mark_float_arg(po, pp, arg, regmask_ffca);
30620174 5334 }
5335 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5336 && po->operand[1].type == OPT_CONST)
5337 {
5338 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5339 break;
5340 }
5341 }
5342
5343 for (arg = base_arg; arg < pp->argc; arg++) {
5344 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
5345 po = pp->arg[arg].datap;
5346 if (po == NULL)
5347 ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
5348 if (po->operand[0].lmod == OPLM_QWORD)
5349 arg++;
5350 }
5351
5352 return 0;
5353}
5354
17ed469e 5355static int collect_call_args_early(int i, int opcnt,
5356 struct parsed_proto *pp, int *regmask, int *regmask_ffca)
26677139 5357{
30620174 5358 struct parsed_op *po;
26677139 5359 int arg, ret;
b62264bc 5360 int offset;
5361 int j, k;
26677139 5362
5363 for (arg = 0; arg < pp->argc; arg++)
5364 if (pp->arg[arg].reg == NULL)
5365 break;
5366
5367 // first see if it can be easily done
5368 for (j = i; j > 0 && arg < pp->argc; )
5369 {
5370 if (g_labels[j] != NULL)
5371 return -1;
5372 j--;
5373
30620174 5374 po = &ops[j];
5375 if (po->op == OP_CALL)
26677139 5376 return -1;
30620174 5377 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
26677139 5378 return -1;
30620174 5379 else if (po->op == OP_POP)
26677139 5380 return -1;
30620174 5381 else if (po->flags & OPF_CJMP)
26677139 5382 return -1;
30620174 5383 else if (po->op == OP_PUSH) {
5384 if (po->flags & (OPF_FARG|OPF_FARGNR))
26677139 5385 return -1;
622eb2ef 5386 if (!g_header_mode) {
30620174 5387 ret = scan_for_mod(po, j + 1, i, 1);
622eb2ef 5388 if (ret >= 0)
5389 return -1;
5390 }
26677139 5391
5392 if (pp->arg[arg].type.is_va_list)
5393 return -1;
5394
5395 // next arg
5396 for (arg++; arg < pp->argc; arg++)
5397 if (pp->arg[arg].reg == NULL)
5398 break;
5399 }
30620174 5400 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5401 && po->operand[1].type == OPT_CONST)
5402 {
5403 if (po->flags & (OPF_RMD|OPF_DONE))
5404 return -1;
5405 if (po->operand[1].val != pp->argc_stack * 4)
5406 ferr(po, "unexpected esp adjust: %d\n",
5407 po->operand[1].val * 4);
5408 ferr_assert(po, pp->argc - arg == pp->argc_stack);
5409 return collect_call_args_no_push(i, pp, regmask_ffca);
5410 }
26677139 5411 }
5412
5413 if (arg < pp->argc)
5414 return -1;
5415
5416 // now do it
5417 for (arg = 0; arg < pp->argc; arg++)
5418 if (pp->arg[arg].reg == NULL)
5419 break;
5420
5421 for (j = i; j > 0 && arg < pp->argc; )
5422 {
5423 j--;
5424
5425 if (ops[j].op == OP_PUSH)
5426 {
5427 ops[j].p_argnext = -1;
5428 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
26677139 5429
b62264bc 5430 k = check_for_stp(j + 1, i);
5431 if (k != -1) {
5432 // push ecx; fstp dword ptr [esp]
5433 ret = parse_stack_esp_offset(&ops[k],
5434 ops[k].operand[0].name, &offset);
5435 if (ret == 0 && offset == 0) {
5436 if (!pp->arg[arg].type.is_float)
5437 ferr(&ops[i], "arg %d should be float\n", arg + 1);
5438 mark_float_arg(&ops[k], pp, arg, regmask_ffca);
5439 }
5440 }
5441
5442 if (pp->arg[arg].datap == NULL) {
5443 pp->arg[arg].datap = &ops[j];
5444 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
5445 *regmask |= 1 << ops[j].operand[0].reg;
5446 }
26677139 5447
5e49b270 5448 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
26677139 5449 ops[j].flags &= ~OPF_RSAVE;
5450
5451 // next arg
5452 for (arg++; arg < pp->argc; arg++)
5453 if (pp->arg[arg].reg == NULL)
5454 break;
5455 }
5456 }
5457
17ed469e 5458 if (!g_header_mode)
5459 check_fptr_args(i, opcnt, pp);
5460
26677139 5461 return 0;
5462}
5463
8c83cc48 5464static int sync_argnum(struct parsed_op *po, int argnum)
5465{
5466 struct parsed_op *po_tmp;
5467
5468 // see if other branches don't have higher argnum
5469 for (po_tmp = po; po_tmp != NULL; ) {
5470 if (argnum < po_tmp->p_argnum)
5471 argnum = po_tmp->p_argnum;
5472 // note: p_argnext is active on current collect_call_args only
5473 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5474 }
5475
5476 // make all argnums consistent
5477 for (po_tmp = po; po_tmp != NULL; ) {
5478 if (po_tmp->p_argnum != 0)
5479 po_tmp->p_argnum = argnum;
5480 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5481 }
5482
5483 return argnum;
5484}
5485
89ff3147 5486static int collect_call_args_r(struct parsed_op *po, int i,
8c83cc48 5487 struct parsed_proto *pp, int *regmask, int *arg_grp,
5488 int arg, int argnum, int magic, int need_op_saving, int may_reuse)
e56ab892 5489{
5490 struct parsed_proto *pp_tmp;
3a5101d7 5491 struct parsed_op *po_tmp;
e56ab892 5492 struct label_ref *lr;
2b43685d 5493 int need_to_save_current;
3a5101d7 5494 int arg_grp_current = 0;
5495 int save_args_seen = 0;
e56ab892 5496 int ret = 0;
5f70a34f 5497 int reg;
23fd0b11 5498 char buf[32];
5499 int j, k;
e56ab892 5500
a3684be1 5501 if (i < 0) {
a2c1d768 5502 ferr(po, "dead label encountered\n");
a3684be1 5503 return -1;
5504 }
e56ab892 5505
8c83cc48 5506 for (; arg < pp->argc; arg++, argnum++)
e56ab892 5507 if (pp->arg[arg].reg == NULL)
5508 break;
a3684be1 5509 magic = (magic & 0xffffff) | (arg << 24);
e56ab892 5510
89ff3147 5511 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
e56ab892 5512 {
a3684be1 5513 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
5514 if (ops[j].cc_scratch != magic) {
5515 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
5516 pp->name);
5517 return -1;
5518 }
5519 // ok: have already been here
5520 return 0;
5521 }
5522 ops[j].cc_scratch = magic;
5523
d7857c3a 5524 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
e56ab892 5525 lr = &g_label_refs[j];
5526 if (lr->next != NULL)
5527 need_op_saving = 1;
a652aa9f 5528 for (; lr->next; lr = lr->next) {
92d715b6 5529 check_i(&ops[j], lr->i);
5c024ef7 5530 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
a652aa9f 5531 may_reuse = 1;
8c83cc48 5532 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5533 arg, argnum, magic, need_op_saving, may_reuse);
a3684be1 5534 if (ret < 0)
5535 return ret;
a652aa9f 5536 }
e56ab892 5537
92d715b6 5538 check_i(&ops[j], lr->i);
5c024ef7 5539 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
a652aa9f 5540 may_reuse = 1;
de50b98b 5541 if (j > 0 && LAST_OP(j - 1)) {
e56ab892 5542 // follow last branch in reverse
5543 j = lr->i;
5544 continue;
5545 }
5546 need_op_saving = 1;
8c83cc48 5547 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5548 arg, argnum, magic, need_op_saving, may_reuse);
a3684be1 5549 if (ret < 0)
5550 return ret;
e56ab892 5551 }
5552 j--;
5553
5554 if (ops[j].op == OP_CALL)
5555 {
89ff3147 5556 if (pp->is_unresolved)
5557 break;
5558
092f64e1 5559 pp_tmp = ops[j].pp;
e56ab892 5560 if (pp_tmp == NULL)
56b49358 5561 ferr(po, "arg collect %d/%d hit unparsed call '%s'\n",
5562 arg, pp->argc, ops[j].operand[0].name);
a652aa9f 5563 if (may_reuse && pp_tmp->argc_stack > 0)
de50b98b 5564 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
5565 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
e56ab892 5566 }
fdd5548a 5567 // esp adjust of 0 means we collected it before
5568 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
5569 && (ops[j].operand[1].type != OPT_CONST
5570 || ops[j].operand[1].val != 0))
5571 {
89ff3147 5572 if (pp->is_unresolved)
5573 break;
5574
2b70f6d3 5575 fnote(po, "(this call)\n");
5576 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
fdd5548a 5577 arg, pp->argc, ops[j].operand[1].val);
de50b98b 5578 }
5e49b270 5579 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
9af2d373 5580 {
89ff3147 5581 if (pp->is_unresolved)
5582 break;
5583
2b70f6d3 5584 fnote(po, "(this call)\n");
5585 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
de50b98b 5586 }
5c024ef7 5587 else if (ops[j].flags & OPF_CJMP)
de50b98b 5588 {
89ff3147 5589 if (pp->is_unresolved)
5590 break;
5591
a652aa9f 5592 may_reuse = 1;
de50b98b 5593 }
91ca764a 5594 else if (ops[j].op == OP_PUSH
5595 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
e56ab892 5596 {
89ff3147 5597 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
5598 break;
5599
3a5101d7 5600 ops[j].p_argnext = -1;
5601 po_tmp = pp->arg[arg].datap;
5602 if (po_tmp != NULL)
5603 ops[j].p_argnext = po_tmp - ops;
e56ab892 5604 pp->arg[arg].datap = &ops[j];
3a5101d7 5605
8c83cc48 5606 argnum = sync_argnum(&ops[j], argnum);
5607
2b43685d 5608 need_to_save_current = 0;
5f70a34f 5609 reg = -1;
5610 if (ops[j].operand[0].type == OPT_REG)
5611 reg = ops[j].operand[0].reg;
5612
e56ab892 5613 if (!need_op_saving) {
89ff3147 5614 ret = scan_for_mod(&ops[j], j + 1, i, 1);
2b43685d 5615 need_to_save_current = (ret >= 0);
e56ab892 5616 }
2b43685d 5617 if (need_op_saving || need_to_save_current) {
8c83cc48 5618 // mark this arg as one that needs operand saving
5619 pp->arg[arg].is_saved = 1;
3a5101d7 5620
8c83cc48 5621 if (save_args_seen & (1 << (argnum - 1))) {
3a5101d7 5622 save_args_seen = 0;
5623 arg_grp_current++;
5624 if (arg_grp_current >= MAX_ARG_GRP)
5625 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
8c83cc48 5626 argnum, pp->name);
3a5101d7 5627 }
e56ab892 5628 }
5f70a34f 5629 else if (ops[j].p_argnum == 0)
e56ab892 5630 ops[j].flags |= OPF_RMD;
5631
a652aa9f 5632 // some PUSHes are reused by different calls on other branches,
de50b98b 5633 // but that can't happen if we didn't branch, so they
5634 // can be removed from future searches (handles nested calls)
a652aa9f 5635 if (!may_reuse)
9af2d373 5636 ops[j].flags |= OPF_FARGNR;
de50b98b 5637
9af2d373 5638 ops[j].flags |= OPF_FARG;
da87ae38 5639 ops[j].flags &= ~OPF_RSAVE;
5640
23fd0b11 5641 // check for __VALIST
04abc5d6 5642 if (!pp->is_unresolved && g_func_pp != NULL
5643 && pp->arg[arg].type.is_va_list)
5644 {
23fd0b11 5645 k = -1;
92d715b6 5646 ret = resolve_origin(j, &ops[j].operand[0],
5647 magic + 1, &k, NULL);
5f70a34f 5648 if (ret == 1 && k >= 0)
23fd0b11 5649 {
5f70a34f 5650 if (ops[k].op == OP_LEA) {
acd03176 5651 if (!g_func_pp->is_vararg)
5652 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
5653 g_func_pp->name);
5654
5f70a34f 5655 snprintf(buf, sizeof(buf), "arg_%X",
5656 g_func_pp->argc_stack * 4);
acd03176 5657 if (strstr(ops[k].operand[1].name, buf)
5658 || strstr(ops[k].operand[1].name, "arglist"))
5f70a34f 5659 {
b2bd20c0 5660 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
5661 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
8c83cc48 5662 pp->arg[arg].is_saved = 0;
5f70a34f 5663 reg = -1;
5664 }
5665 else
acd03176 5666 ferr(&ops[k], "va_list arg detection failed\n");
5f70a34f 5667 }
5668 // check for va_list from g_func_pp arg too
5669 else if (ops[k].op == OP_MOV
5670 && is_stack_access(&ops[k], &ops[k].operand[1]))
5671 {
5672 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5673 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5674 if (ret >= 0) {
5e49b270 5675 ops[k].flags |= OPF_RMD | OPF_DONE;
5f70a34f 5676 ops[j].flags |= OPF_RMD;
5677 ops[j].p_argpass = ret + 1;
8c83cc48 5678 pp->arg[arg].is_saved = 0;
5f70a34f 5679 reg = -1;
5680 }
5681 }
23fd0b11 5682 }
5683 }
5684
8c83cc48 5685 if (pp->arg[arg].is_saved) {
5686 ops[j].flags &= ~OPF_RMD;
5687 ops[j].p_argnum = argnum;
5688 }
23fd0b11 5689
5690 // tracking reg usage
5f70a34f 5691 if (reg >= 0)
5692 *regmask |= 1 << reg;
23fd0b11 5693
89ff3147 5694 arg++;
8c83cc48 5695 argnum++;
89ff3147 5696 if (!pp->is_unresolved) {
5697 // next arg
8c83cc48 5698 for (; arg < pp->argc; arg++, argnum++)
89ff3147 5699 if (pp->arg[arg].reg == NULL)
5700 break;
5701 }
a3684be1 5702 magic = (magic & 0xffffff) | (arg << 24);
e56ab892 5703 }
3a5101d7 5704
5705 if (ops[j].p_arggrp > arg_grp_current) {
5706 save_args_seen = 0;
5707 arg_grp_current = ops[j].p_arggrp;
5708 }
5709 if (ops[j].p_argnum > 0)
5710 save_args_seen |= 1 << (ops[j].p_argnum - 1);
e56ab892 5711 }
5712
5713 if (arg < pp->argc) {
5714 ferr(po, "arg collect failed for '%s': %d/%d\n",
5715 pp->name, arg, pp->argc);
89ff3147 5716 return -1;
e56ab892 5717 }
89ff3147 5718
3a5101d7 5719 if (arg_grp_current > *arg_grp)
5720 *arg_grp = arg_grp_current;
5721
89ff3147 5722 return arg;
5723}
5724
17ed469e 5725static int collect_call_args(struct parsed_op *po, int i, int opcnt,
8c83cc48 5726 struct parsed_proto *pp, int *regmask, int magic)
89ff3147 5727{
3a5101d7 5728 // arg group is for cases when pushes for
5729 // multiple funcs are going on
5730 struct parsed_op *po_tmp;
3a5101d7 5731 int arg_grp = 0;
89ff3147 5732 int ret;
5733 int a;
5734
8c83cc48 5735 ret = collect_call_args_r(po, i, pp, regmask, &arg_grp,
5736 0, 1, magic, 0, 0);
89ff3147 5737 if (ret < 0)
5738 return ret;
5739
57b1b785 5740 if (pp->is_unresolved) {
5741 pp->argc += ret;
5742 pp->argc_stack += ret;
5743 for (a = 0; a < pp->argc; a++)
5744 if (pp->arg[a].type.name == NULL)
5745 pp->arg[a].type.name = strdup("int");
5746 }
5747
3a5101d7 5748 if (arg_grp != 0) {
5749 // propagate arg_grp
5750 for (a = 0; a < pp->argc; a++) {
5751 if (pp->arg[a].reg != NULL)
5752 continue;
5753
5754 po_tmp = pp->arg[a].datap;
5755 while (po_tmp != NULL) {
5756 po_tmp->p_arggrp = arg_grp;
8c83cc48 5757 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
3a5101d7 5758 }
5759 }
5760 }
3a5101d7 5761
17ed469e 5762 if (!g_header_mode)
5763 check_fptr_args(i, opcnt, pp);
5764
e56ab892 5765 return ret;
5766}
5767
b2bd20c0 5768static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5769 int regmask_now, int *regmask,
5770 int regmask_save_now, int *regmask_save,
5771 int *regmask_init, int regmask_arg)
5772{
5773 struct parsed_op *po;
5774 int already_saved;
5775 int regmask_new;
5776 int regmask_op;
5777 int flags_set;
5778 int ret, reg;
5779 int j;
5780
5781 for (; i < opcnt; i++)
5782 {
5783 po = &ops[i];
5784 if (cbits[i >> 3] & (1 << (i & 7)))
5785 return;
5786 cbits[i >> 3] |= (1 << (i & 7));
5787
5788 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5789 if (po->flags & (OPF_RMD|OPF_DONE))
5790 continue;
5791 if (po->btj != NULL) {
5792 for (j = 0; j < po->btj->count; j++) {
5793 check_i(po, po->btj->d[j].bt_i);
5794 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5795 regmask_now, regmask, regmask_save_now, regmask_save,
5796 regmask_init, regmask_arg);
5797 }
5798 return;
5799 }
5800
5801 check_i(po, po->bt_i);
5802 if (po->flags & OPF_CJMP)
5803 reg_use_pass(po->bt_i, opcnt, cbits,
5804 regmask_now, regmask, regmask_save_now, regmask_save,
5805 regmask_init, regmask_arg);
5806 else
5807 i = po->bt_i - 1;
5808 continue;
5809 }
5810
5811 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5812 && !g_func_pp->is_userstack
5813 && po->operand[0].type == OPT_REG)
5814 {
7a3c5555 5815 int save_level = 0;
5816
b2bd20c0 5817 reg = po->operand[0].reg;
5818 ferr_assert(po, reg >= 0);
5819
5820 already_saved = 0;
5821 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5822 if (regmask_now & (1 << reg)) {
5823 already_saved = regmask_save_now & (1 << reg);
5824 flags_set = OPF_RSAVE | OPF_DONE;
7a3c5555 5825 save_level++;
b2bd20c0 5826 }
5827
7a3c5555 5828 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3,
5829 reg, 0, 0, save_level, 0);
b2bd20c0 5830 if (ret == 1) {
93b5bd18 5831 scan_for_pop(i + 1, opcnt, i + opcnt * 4,
7a3c5555 5832 reg, 0, 0, save_level, flags_set);
b2bd20c0 5833 }
5834 else {
5835 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5836 if (ret == 1) {
5837 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5838 flags_set);
5839 }
5840 }
5841 if (ret == 1) {
5842 ferr_assert(po, !already_saved);
5843 po->flags |= flags_set;
5844
5845 if (regmask_now & (1 << reg)) {
5846 regmask_save_now |= (1 << reg);
5847 *regmask_save |= regmask_save_now;
5848 }
5849 continue;
5850 }
5851 }
5852 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5853 reg = po->operand[0].reg;
5854 ferr_assert(po, reg >= 0);
5855
5856 if (regmask_save_now & (1 << reg))
5857 regmask_save_now &= ~(1 << reg);
5858 else
5859 regmask_now &= ~(1 << reg);
5860 continue;
5861 }
5862 else if (po->op == OP_CALL) {
5863 if ((po->regmask_dst & (1 << xAX))
5864 && !(po->regmask_dst & (1 << xDX)))
5865 {
5866 if (po->flags & OPF_TAIL)
5867 // don't need eax, will do "return f();" or "f(); return;"
5868 po->regmask_dst &= ~(1 << xAX);
5869 else {
427da1c9 5870 find_next_read_reg(i + 1, opcnt, xAX, OPLM_DWORD,
5871 i + opcnt * 17, &j);
b2bd20c0 5872 if (j == -1)
5873 // not used
5874 po->regmask_dst &= ~(1 << xAX);
5875 }
5876 }
fe18df39 5877
5878 // not "full stack" mode and have something in stack
5879 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5880 ferr(po, "float stack is not empty on func call\n");
b2bd20c0 5881 }
5882
5883 if (po->flags & OPF_NOREGS)
5884 continue;
5885
acd03176 5886 // if incomplete register is used, clear it on init to avoid
5887 // later use of uninitialized upper part in some situations
5888 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5889 && po->operand[0].lmod != OPLM_DWORD)
5890 {
5891 reg = po->operand[0].reg;
5892 ferr_assert(po, reg >= 0);
5893
5894 if (!(regmask_now & (1 << reg)))
5895 *regmask_init |= 1 << reg;
5896 }
5897
b2bd20c0 5898 regmask_op = po->regmask_src | po->regmask_dst;
5899
5900 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5901 regmask_new &= ~(1 << xSP);
5902 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5903 regmask_new &= ~(1 << xBP);
5904
b2bd20c0 5905 if (regmask_new != 0)
5906 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5907
5908 if (regmask_op & (1 << xBP)) {
5909 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5910 if (po->regmask_dst & (1 << xBP))
5911 // compiler decided to drop bp frame and use ebp as scratch
5912 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5913 else
5914 regmask_op &= ~(1 << xBP);
5915 }
5916 }
5917
622eb2ef 5918 if (po->flags & OPF_FPUSH) {
5919 if (regmask_now & mxST1)
5920 regmask_now |= mxSTa; // switch to "full stack" mode
5921 if (regmask_now & mxSTa)
5922 po->flags |= OPF_FSHIFT;
5923 if (!(regmask_now & mxST7_2)) {
5924 regmask_now =
5925 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5926 }
5927 }
5928
b2bd20c0 5929 regmask_now |= regmask_op;
5930 *regmask |= regmask_now;
5931
d4a985bd 5932 // released regs
88eed95d 5933 if (po->flags & OPF_FPOPP) {
5934 if ((regmask_now & mxSTa) == 0)
5935 ferr(po, "float pop on empty stack?\n");
5936 if (regmask_now & mxST7_2)
5937 po->flags |= OPF_FSHIFT;
5938 if (!(regmask_now & mxST7_2))
5939 regmask_now &= ~mxST1_0;
5940 }
5941 else if (po->flags & OPF_FPOP) {
fe18df39 5942 if ((regmask_now & mxSTa) == 0)
d4a985bd 5943 ferr(po, "float pop on empty stack?\n");
fe18df39 5944 if (regmask_now & (mxST7_2 | mxST1))
d4a985bd 5945 po->flags |= OPF_FSHIFT;
fe18df39 5946 if (!(regmask_now & mxST7_2)) {
5947 regmask_now =
5948 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5949 }
d4a985bd 5950 }
5951
5952 if (po->flags & OPF_TAIL) {
16057ce1 5953 if (!(regmask_now & mxST7_2)) {
5954 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5955 if (!(regmask_now & mxST0))
5956 ferr(po, "no st0 on float return, mask: %x\n",
5957 regmask_now);
5958 }
5959 else if (regmask_now & mxST1_0)
5960 ferr(po, "float regs on tail: %x\n", regmask_now);
5961 }
4d247254 5962
5963 // there is support for "conditional tailcall", sort of
5964 if (!(po->flags & OPF_CC))
5965 return;
d4a985bd 5966 }
b2bd20c0 5967 }
5968}
5969
89ff3147 5970static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5971{
5972 int i;
5973
5974 for (i = 0; i < pp->argc; i++)
5975 if (pp->arg[i].reg == NULL)
5976 break;
5977
5978 if (pp->argc_stack)
5979 memmove(&pp->arg[i + 1], &pp->arg[i],
5980 sizeof(pp->arg[0]) * pp->argc_stack);
5981 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5982 pp->arg[i].reg = strdup(reg);
5983 pp->arg[i].type.name = strdup("int");
5984 pp->argc++;
5985 pp->argc_reg++;
5986}
5987
f9327ad4 5988static void output_std_flag_z(FILE *fout, struct parsed_op *po,
04f8a628 5989 int *pfomask, const char *dst_opr_text)
5990{
5991 if (*pfomask & (1 << PFO_Z)) {
5992 fprintf(fout, "\n cond_z = (%s%s == 0);",
5993 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5994 *pfomask &= ~(1 << PFO_Z);
5995 }
f9327ad4 5996}
5997
5998static void output_std_flag_s(FILE *fout, struct parsed_op *po,
5999 int *pfomask, const char *dst_opr_text)
6000{
04f8a628 6001 if (*pfomask & (1 << PFO_S)) {
6002 fprintf(fout, "\n cond_s = (%s%s < 0);",
6003 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
6004 *pfomask &= ~(1 << PFO_S);
6005 }
6006}
6007
f9327ad4 6008static void output_std_flags(FILE *fout, struct parsed_op *po,
6009 int *pfomask, const char *dst_opr_text)
6010{
6011 output_std_flag_z(fout, po, pfomask, dst_opr_text);
6012 output_std_flag_s(fout, po, pfomask, dst_opr_text);
6013}
6014
c0de9015 6015enum {
6016 OPP_FORCE_NORETURN = (1 << 0),
6017 OPP_SIMPLE_ARGS = (1 << 1),
6018 OPP_ALIGN = (1 << 2),
6019};
6020
c0050df6 6021static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
c0de9015 6022 int flags)
c0050df6 6023{
c0de9015 6024 const char *cconv = "";
6025
c0050df6 6026 if (pp->is_fastcall)
c0de9015 6027 cconv = "__fastcall ";
c0050df6 6028 else if (pp->is_stdcall && pp->argc_reg == 0)
c0de9015 6029 cconv = "__stdcall ";
6030
6031 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
6032
6033 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
c0050df6 6034 fprintf(fout, "noreturn ");
6035}
6036
c0de9015 6037static void output_pp(FILE *fout, const struct parsed_proto *pp,
6038 int flags)
6039{
6040 int i;
6041
6042 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
6043 pp->ret_type.name);
6044 if (pp->is_fptr)
6045 fprintf(fout, "(");
6046 output_pp_attrs(fout, pp, flags);
6047 if (pp->is_fptr)
6048 fprintf(fout, "*");
6049 fprintf(fout, "%s", pp->name);
6050 if (pp->is_fptr)
6051 fprintf(fout, ")");
6052
6053 fprintf(fout, "(");
6054 for (i = 0; i < pp->argc; i++) {
6055 if (i > 0)
6056 fprintf(fout, ", ");
93b5bd18 6057 if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
6058 && !(flags & OPP_SIMPLE_ARGS))
6059 {
c0de9015 6060 // func pointer
93b5bd18 6061 output_pp(fout, pp->arg[i].pp, 0);
c0de9015 6062 }
6063 else if (pp->arg[i].type.is_retreg) {
6064 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
6065 }
6066 else {
6067 fprintf(fout, "%s", pp->arg[i].type.name);
6068 if (!pp->is_fptr)
6069 fprintf(fout, " a%d", i + 1);
6070 }
2c31fb4c 6071
6072 if (pp->arg[i].type.is_64bit)
6073 i++;
c0de9015 6074 }
6075 if (pp->is_vararg) {
6076 if (i > 0)
6077 fprintf(fout, ", ");
6078 fprintf(fout, "...");
6079 }
6080 fprintf(fout, ")");
6081}
6082
3a5101d7 6083static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
6084{
6085 char buf1[16];
6086
6087 buf1[0] = 0;
6088 if (grp > 0)
6089 snprintf(buf1, sizeof(buf1), "%d", grp);
6090 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
6091
6092 return buf;
6093}
6094
9af2d373 6095static void gen_x_cleanup(int opcnt);
6096
91977a1c 6097static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
6098{
69a3cdfc 6099 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
850c9265 6100 struct parsed_opr *last_arith_dst = NULL;
3ebea2cf 6101 char buf1[256], buf2[256], buf3[256], cast[64];
ddaf8bd7 6102 struct parsed_proto *pp, *pp_tmp;
4c45fa73 6103 struct parsed_data *pd;
3a5101d7 6104 int save_arg_vars[MAX_ARG_GRP] = { 0, };
b2bd20c0 6105 unsigned char cbits[MAX_OPS / 8];
497a6d6b 6106 const char *float_type;
fe18df39 6107 const char *float_st0;
6108 const char *float_st1;
6109 int need_float_stack = 0;
16057ce1 6110 int need_float_sw = 0; // status word
108e9fe3 6111 int need_tmp_var = 0;
2fe80fdb 6112 int need_tmp64 = 0;
fe18df39 6113 int cond_vars = 0;
91977a1c 6114 int had_decl = 0;
3ebea2cf 6115 int label_pending = 0;
497a6d6b 6116 int need_double = 0;
f9327ad4 6117 int stack_align = 0;
2c31fb4c 6118 int stack_fsz_adj = 0;
193c11bf 6119 int lock_handled = 0;
16057ce1 6120 int regmask_save = 0; // used regs saved/restored in this func
b2bd20c0 6121 int regmask_arg; // regs from this function args (fastcall, etc)
6122 int regmask_ret; // regs needed on ret
25a330eb 6123 int regmask_now; // temp
6124 int regmask_init = 0; // regs that need zero initialization
6125 int regmask_pp = 0; // regs used in complex push-pop graph
30620174 6126 int regmask_ffca = 0; // float function call args
25a330eb 6127 int regmask = 0; // used regs
940e8e66 6128 int pfomask = 0;
64c59faf 6129 int found = 0;
fe18df39 6130 int dead_dst;
91977a1c 6131 int no_output;
4c45fa73 6132 int i, j, l;
91977a1c 6133 int arg;
91977a1c 6134 int reg;
6135 int ret;
6136
1bafb621 6137 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
a2c1d768 6138 g_stack_frame_used = 0;
ba93cc12 6139 g_seh_size = 0;
226e8df1 6140 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
6141 regmask_init = g_regmask_init;
91977a1c 6142
36595fd2 6143 g_func_pp = proto_parse(fhdr, funcn, 0);
bd96f656 6144 if (g_func_pp == NULL)
91977a1c 6145 ferr(ops, "proto_parse failed for '%s'\n", funcn);
6146
b2bd20c0 6147 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
6148 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
6149
91977a1c 6150 // pass1:
87bf6cec 6151 // - resolve all branches
66bdb2b0 6152 // - parse calls with labels
6153 resolve_branches_parse_calls(opcnt);
840257f6 6154
66bdb2b0 6155 // pass2:
6156 // - handle ebp/esp frame, remove ops related to it
f9327ad4 6157 scan_prologue_epilogue(opcnt, &stack_align);
87bf6cec 6158
2c31fb4c 6159 // handle a case where sf size is unalignment, but is
6160 // placed in a way that elements are still aligned
6161 if (g_stack_fsz & 4) {
6162 for (i = 0; i < g_eqcnt; i++) {
6163 if (g_eqs[i].lmod != OPLM_QWORD)
6164 continue;
6165 if (!(g_eqs[i].offset & 4)) {
6166 g_stack_fsz += 4;
6167 stack_fsz_adj = 4;
6168 }
6169 break;
6170 }
6171 }
6172
87bf6cec 6173 // pass3:
a2c1d768 6174 // - remove dead labels
b2bd20c0 6175 // - set regs needed at ret
1bafb621 6176 for (i = 0; i < opcnt; i++)
6177 {
d7857c3a 6178 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
6179 free(g_labels[i]);
6180 g_labels[i] = NULL;
6181 }
b2bd20c0 6182
6183 if (ops[i].op == OP_RET)
6184 ops[i].regmask_src |= regmask_ret;
66bdb2b0 6185 }
a2c1d768 6186
66bdb2b0 6187 // pass4:
6188 // - process trivial calls
6189 for (i = 0; i < opcnt; i++)
6190 {
69a3cdfc 6191 po = &ops[i];
5e49b270 6192 if (po->flags & (OPF_RMD|OPF_DONE))
91977a1c 6193 continue;
850c9265 6194
d4e3b5db 6195 if (po->op == OP_CALL)
26677139 6196 {
6197 pp = process_call_early(i, opcnt, &j);
6198 if (pp != NULL) {
30620174 6199 if (!(po->flags & OPF_ATAIL)) {
26677139 6200 // since we know the args, try to collect them
17ed469e 6201 ret = collect_call_args_early(i, opcnt, pp,
6202 &regmask, &regmask_ffca);
30620174 6203 if (ret != 0)
26677139 6204 pp = NULL;
30620174 6205 }
26677139 6206 }
6207
6208 if (pp != NULL) {
6209 if (j >= 0) {
6210 // commit esp adjust
5e49b270 6211 if (ops[j].op != OP_POP)
6212 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
bfacdc83 6213 else {
6214 for (l = 0; l < pp->argc_stack; l++)
b2bd20c0 6215 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
bfacdc83 6216 }
26677139 6217 }
6218
6219 if (strstr(pp->ret_type.name, "int64"))
6220 need_tmp64 = 1;
6221
6222 po->flags |= OPF_DONE;
6223 }
6224 }
6225 }
6226
66bdb2b0 6227 // pass5:
b2bd20c0 6228 // - process calls, stage 2
6229 // - handle some push/pop pairs
6230 // - scan for STD/CLD, propagate DF
16057ce1 6231 // - try to resolve needed x87 status word bits
26677139 6232 for (i = 0; i < opcnt; i++)
6233 {
16057ce1 6234 int mask, z_check;
6235
26677139 6236 po = &ops[i];
b2bd20c0 6237 if (po->flags & OPF_RMD)
26677139 6238 continue;
6239
b2bd20c0 6240 if (po->op == OP_CALL)
69a3cdfc 6241 {
b2bd20c0 6242 if (!(po->flags & OPF_DONE)) {
6243 pp = process_call(i, opcnt);
91977a1c 6244
b2bd20c0 6245 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
6246 // since we know the args, collect them
17ed469e 6247 collect_call_args(po, i, opcnt, pp, &regmask, i + opcnt * 2);
b2bd20c0 6248 }
6249 // for unresolved, collect after other passes
89ff3147 6250 }
2b43685d 6251
b2bd20c0 6252 pp = po->pp;
6253 ferr_assert(po, pp != NULL);
6254
6255 po->regmask_src |= get_pp_arg_regmask_src(pp);
6256 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
6257
d4a985bd 6258 if (po->regmask_dst & mxST0)
6259 po->flags |= OPF_FPUSH;
6260
2b43685d 6261 if (strstr(pp->ret_type.name, "int64"))
2fe80fdb 6262 need_tmp64 = 1;
b2bd20c0 6263
6264 continue;
91977a1c 6265 }
b2bd20c0 6266
6267 if (po->flags & OPF_DONE)
6268 continue;
6269
16057ce1 6270 switch (po->op) {
6271 case OP_PUSH:
6272 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
6273 && po->operand[0].type == OPT_CONST)
6274 {
6275 scan_for_pop_const(i, opcnt, i + opcnt * 12);
6276 }
6277 break;
6278
6279 case OP_POP:
e83ea7ed 6280 scan_pushes_for_pop(i, opcnt, &regmask_pp);
16057ce1 6281 break;
6282
6283 case OP_STD:
b2bd20c0 6284 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
6285 scan_propagate_df(i + 1, opcnt);
16057ce1 6286 break;
6287
6288 case OP_FNSTSW:
6289 need_float_sw = 1;
6290 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
6291 ferr(po, "TODO: fnstsw to mem\n");
6292 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
6293 if (ret != 0)
6294 ferr(po, "fnstsw resolve failed\n");
6295 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
6296 (void *)(long)(mask | (z_check << 16)));
6297 if (ret != 1)
6298 ferr(po, "failed to find fcom: %d\n", ret);
6299 break;
6300
6301 default:
6302 break;
b2bd20c0 6303 }
d4e3b5db 6304 }
6305
66bdb2b0 6306 // pass6:
d4e3b5db 6307 // - find POPs for PUSHes, rm both
6308 // - scan for all used registers
b2bd20c0 6309 memset(cbits, 0, sizeof(cbits));
226e8df1 6310 reg_use_pass(0, opcnt, cbits, regmask_init, &regmask,
b2bd20c0 6311 0, &regmask_save, &regmask_init, regmask_arg);
6312
11437ea1 6313 need_float_stack = !!(regmask & mxST7_2);
6314
b2bd20c0 6315 // pass7:
d4e3b5db 6316 // - find flag set ops for their users
b2bd20c0 6317 // - do unresolved calls
1bafb621 6318 // - declare indirect functions
16057ce1 6319 // - other op specific processing
26677139 6320 for (i = 0; i < opcnt; i++)
6321 {
d4e3b5db 6322 po = &ops[i];
5e49b270 6323 if (po->flags & (OPF_RMD|OPF_DONE))
d4e3b5db 6324 continue;
6325
d4e3b5db 6326 if (po->flags & OPF_CC)
6327 {
2b43685d 6328 int setters[16], cnt = 0, branched = 0;
6329
7f20f633 6330 ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
04f8a628 6331 &branched, setters, &cnt);
2b43685d 6332 if (ret < 0 || cnt <= 0)
6333 ferr(po, "unable to trace flag setter(s)\n");
6334 if (cnt > ARRAY_SIZE(setters))
6335 ferr(po, "too many flag setters\n");
d4e3b5db 6336
2b43685d 6337 for (j = 0; j < cnt; j++)
6338 {
6339 tmp_op = &ops[setters[j]]; // flag setter
6340 pfomask = 0;
6341
6342 // to get nicer code, we try to delay test and cmp;
6343 // if we can't because of operand modification, or if we
591721d7 6344 // have arith op, or branch, make it calculate flags explicitly
6345 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
6346 {
89ff3147 6347 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
092f64e1 6348 pfomask = 1 << po->pfo;
2b43685d 6349 }
4741fdfe 6350 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
092f64e1 6351 pfomask = 1 << po->pfo;
591721d7 6352 }
2b43685d 6353 else {
04f8a628 6354 // see if we'll be able to handle based on op result
6355 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
092f64e1 6356 && po->pfo != PFO_Z && po->pfo != PFO_S
6357 && po->pfo != PFO_P)
04f8a628 6358 || branched
2b43685d 6359 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
092f64e1 6360 {
6361 pfomask = 1 << po->pfo;
6362 }
2fe80fdb 6363
c8dbc5be 6364 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
6365 propagate_lmod(tmp_op, &tmp_op->operand[0],
6366 &tmp_op->operand[1]);
6367 if (tmp_op->operand[0].lmod == OPLM_DWORD)
6368 need_tmp64 = 1;
6369 }
2b43685d 6370 }
6371 if (pfomask) {
6372 tmp_op->pfomask |= pfomask;
cb090db0 6373 cond_vars |= pfomask;
2b43685d 6374 }
04f8a628 6375 // note: may overwrite, currently not a problem
6376 po->datap = tmp_op;
d4e3b5db 6377 }
6378
cb090db0 6379 if (po->op == OP_RCL || po->op == OP_RCR
6380 || po->op == OP_ADC || po->op == OP_SBB)
6381 cond_vars |= 1 << PFO_C;
d4e3b5db 6382 }
092f64e1 6383
622eb2ef 6384 switch (po->op) {
6385 case OP_CMPS:
6386 case OP_SCAS:
cb090db0 6387 cond_vars |= 1 << PFO_Z;
622eb2ef 6388 break;
6389
6390 case OP_MUL:
c8dbc5be 6391 if (po->operand[0].lmod == OPLM_DWORD)
6392 need_tmp64 = 1;
622eb2ef 6393 break;
6394
6395 case OP_IMUL:
6396 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
6397 need_tmp64 = 1;
6398 break;
6399
6400 case OP_CALL:
26677139 6401 // note: resolved non-reg calls are OPF_DONE already
092f64e1 6402 pp = po->pp;
b2bd20c0 6403 ferr_assert(po, pp != NULL);
89ff3147 6404
6405 if (pp->is_unresolved) {
ddaf8bd7 6406 int regmask_stack = 0;
17ed469e 6407 collect_call_args(po, i, opcnt, pp, &regmask, i + opcnt * 2);
89ff3147 6408
b74c31e3 6409 // this is pretty rough guess:
6410 // see ecx and edx were pushed (and not their saved versions)
6411 for (arg = 0; arg < pp->argc; arg++) {
8c83cc48 6412 if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
b74c31e3 6413 continue;
6414
6415 tmp_op = pp->arg[arg].datap;
6416 if (tmp_op == NULL)
6417 ferr(po, "parsed_op missing for arg%d\n", arg);
8c83cc48 6418 if (tmp_op->operand[0].type == OPT_REG)
b74c31e3 6419 regmask_stack |= 1 << tmp_op->operand[0].reg;
6420 }
6421
57b1b785 6422 // quick dumb check for potential reg-args
6423 for (j = i - 1; j >= 0 && ops[j].op == OP_MOV; j--)
6424 if (ops[j].operand[0].type == OPT_REG)
6425 regmask_stack &= ~(1 << ops[j].operand[0].reg);
6426
6427 if ((regmask_stack & (mxCX|mxDX)) != (mxCX|mxDX)
6428 && ((regmask | regmask_arg) & (mxCX|mxDX)))
89ff3147 6429 {
6430 if (pp->argc_stack != 0
57b1b785 6431 || ((regmask | regmask_arg) & (mxCX|mxDX)))
89ff3147 6432 {
6433 pp_insert_reg_arg(pp, "ecx");
c0050df6 6434 pp->is_fastcall = 1;
ddaf8bd7 6435 regmask_init |= 1 << xCX;
89ff3147 6436 regmask |= 1 << xCX;
6437 }
6438 if (pp->argc_stack != 0
57b1b785 6439 || ((regmask | regmask_arg) & mxDX))
89ff3147 6440 {
6441 pp_insert_reg_arg(pp, "edx");
ddaf8bd7 6442 regmask_init |= 1 << xDX;
89ff3147 6443 regmask |= 1 << xDX;
6444 }
6445 }
c0050df6 6446
6447 // note: __cdecl doesn't fall into is_unresolved category
6448 if (pp->argc_stack > 0)
6449 pp->is_stdcall = 1;
ddaf8bd7 6450 }
427da1c9 6451 if (!(po->flags & OPF_TAIL)
615dbae1 6452 && !(g_sct_func_attr & SCTFA_NOWARN) && !g_nowarn_reguse)
427da1c9 6453 {
6454 // treat al write as overwrite to avoid many false positives
6455 if (IS(pp->ret_type.name, "void") || pp->ret_type.is_float) {
6456 find_next_read_reg(i + 1, opcnt, xAX, OPLM_BYTE,
6457 i + opcnt * 25, &j);
6458 if (j != -1) {
6459 fnote(po, "eax used after void/float ret call\n");
6460 fnote(&ops[j], "(used here)\n");
6461 }
6462 }
6463 if (!strstr(pp->ret_type.name, "int64")) {
6464 find_next_read_reg(i + 1, opcnt, xDX, OPLM_BYTE,
6465 i + opcnt * 26, &j);
6466 // indirect calls are often guessed, don't warn
6467 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j])) {
6468 fnote(po, "edx used after 32bit ret call\n");
6469 fnote(&ops[j], "(used here)\n");
6470 }
6471 }
6472 j = 1;
6473 // msvc often relies on callee not modifying 'this'
6474 for (arg = 0; arg < pp->argc; arg++) {
6475 if (pp->arg[arg].reg && IS(pp->arg[arg].reg, "ecx")) {
6476 j = 0;
6477 break;
6478 }
6479 }
6480 if (j != 0) {
6481 find_next_read_reg(i + 1, opcnt, xCX, OPLM_BYTE,
6482 i + opcnt * 27, &j);
6483 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j])) {
6484 fnote(po, "ecx used after call\n");
6485 fnote(&ops[j], "(used here)\n");
6486 }
6487 }
6488 }
622eb2ef 6489 break;
6490
6491 case OP_MOV:
6492 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
27ebfaed 6493 {
622eb2ef 6494 // <var> = offset <something>
6495 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
6496 && !IS_START(po->operand[1].name, "off_"))
6497 {
6498 if (!po->operand[0].pp->is_fptr)
6499 ferr(po, "%s not declared as fptr when it should be\n",
6500 po->operand[0].name);
6501 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
6502 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
6503 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
6504 fnote(po, "var: %s\n", buf1);
6505 fnote(po, "func: %s\n", buf2);
6506 ferr(po, "^ mismatch\n");
6507 }
27ebfaed 6508 }
6509 }
622eb2ef 6510 break;
6511
6512 case OP_DIV:
6513 case OP_IDIV:
acd03176 6514 if (po->operand[0].lmod == OPLM_DWORD) {
6515 // 32bit division is common, look for it
6516 if (po->op == OP_DIV)
6517 ret = scan_for_reg_clear(i, xDX);
6518 else
6519 ret = scan_for_cdq_edx(i);
6520 if (ret >= 0)
6521 po->flags |= OPF_32BIT;
6522 else
6523 need_tmp64 = 1;
6524 }
cb090db0 6525 else
acd03176 6526 need_tmp_var = 1;
622eb2ef 6527 break;
6528
6529 case OP_CLD:
5e49b270 6530 po->flags |= OPF_RMD | OPF_DONE;
622eb2ef 6531 break;
6532
6533 case OP_RCL:
6534 case OP_RCR:
6535 case OP_XCHG:
6536 need_tmp_var = 1;
6537 break;
6538
6539 case OP_FLD:
6540 if (po->operand[0].lmod == OPLM_QWORD)
6541 need_double = 1;
6542 break;
6543
193c11bf 6544 case OP_RDTSC:
622eb2ef 6545 case OPP_ALLSHL:
6546 case OPP_ALLSHR:
6547 need_tmp64 = 1;
6548 break;
6549
427da1c9 6550 case OPP_FTOL:
6551 find_next_read_reg(i + 1, opcnt, xDX, OPLM_DWORD,
6552 i + opcnt * 18, &j);
d4a985bd 6553 if (j == -1)
6554 po->flags |= OPF_32BIT;
622eb2ef 6555 break;
cb090db0 6556
622eb2ef 6557 default:
6558 break;
6559 }
57b1b785 6560 }
6561
6562 // pass8: final adjustments
6563 for (i = 0; i < opcnt; i++)
6564 {
6565 po = &ops[i];
6566 if (po->flags & (OPF_RMD|OPF_DONE))
6567 continue;
8c83cc48 6568
8c83cc48 6569 if (po->op != OP_FST && po->p_argnum > 0)
6570 save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
11437ea1 6571
6572 // correct for "full stack" mode late enable
88eed95d 6573 if ((po->flags & (OPF_PPUSH|OPF_FPOP|OPF_FPOPP))
6574 && need_float_stack)
11437ea1 6575 po->flags |= OPF_FSHIFT;
91977a1c 6576 }
6577
497a6d6b 6578 float_type = need_double ? "double" : "float";
fe18df39 6579 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
6580 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
497a6d6b 6581
60fe410c 6582 // output starts here
6583
ba93cc12 6584 if (g_seh_found)
6585 fprintf(fout, "// had SEH\n");
6586
60fe410c 6587 // define userstack size
6588 if (g_func_pp->is_userstack) {
6589 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
6590 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
6591 fprintf(fout, "#endif\n");
6592 }
6593
6594 // the function itself
c0de9015 6595 ferr_assert(ops, !g_func_pp->is_fptr);
6596 output_pp(fout, g_func_pp,
6597 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
6598 fprintf(fout, "\n{\n");
60fe410c 6599
6600 // declare indirect functions
6601 for (i = 0; i < opcnt; i++) {
6602 po = &ops[i];
6603 if (po->flags & OPF_RMD)
6604 continue;
6605
6606 if (po->op == OP_CALL) {
6607 pp = po->pp;
6608 if (pp == NULL)
6609 ferr(po, "NULL pp\n");
6610
6611 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
6612 if (pp->name[0] != 0) {
1fe8d40e 6613 if (IS_START(pp->name, "guess"))
6614 pp->is_guessed = 1;
6615
60fe410c 6616 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
6617 memcpy(pp->name, "i_", 2);
6618
6619 // might be declared already
6620 found = 0;
6621 for (j = 0; j < i; j++) {
6622 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
6623 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
6624 found = 1;
6625 break;
6626 }
6627 }
6628 }
6629 if (found)
6630 continue;
6631 }
6632 else
6633 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
6634
c0de9015 6635 fprintf(fout, " ");
6636 output_pp(fout, pp, OPP_SIMPLE_ARGS);
6637 fprintf(fout, ";\n");
60fe410c 6638 }
6639 }
6640 }
da87ae38 6641
4c45fa73 6642 // output LUTs/jumptables
6643 for (i = 0; i < g_func_pd_cnt; i++) {
6644 pd = &g_func_pd[i];
6645 fprintf(fout, " static const ");
6646 if (pd->type == OPT_OFFSET) {
6647 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
6648
6649 for (j = 0; j < pd->count; j++) {
6650 if (j > 0)
6651 fprintf(fout, ", ");
6652 fprintf(fout, "&&%s", pd->d[j].u.label);
6653 }
6654 }
6655 else {
6656 fprintf(fout, "%s %s[] =\n { ",
6657 lmod_type_u(ops, pd->lmod), pd->label);
6658
6659 for (j = 0; j < pd->count; j++) {
6660 if (j > 0)
6661 fprintf(fout, ", ");
6662 fprintf(fout, "%u", pd->d[j].u.val);
6663 }
6664 }
6665 fprintf(fout, " };\n");
1f84f6b3 6666 had_decl = 1;
4c45fa73 6667 }
6668
4f12f671 6669 // declare stack frame, va_arg
1f84f6b3 6670 if (g_stack_fsz) {
2c31fb4c 6671 if (stack_fsz_adj)
6672 fprintf(fout, " // stack_fsz_adj %d\n", stack_fsz_adj);
6673
d4a985bd 6674 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
6675 if (g_func_lmods & (1 << OPLM_WORD))
6676 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
6677 if (g_func_lmods & (1 << OPLM_BYTE))
6678 fprintf(fout, " u8 b[%d];", g_stack_fsz);
6679 if (g_func_lmods & (1 << OPLM_QWORD))
6680 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
2c31fb4c 6681
f9327ad4 6682 if (stack_align > 8)
6683 ferr(ops, "unhandled stack align of %d\n", stack_align);
6684 else if (stack_align == 8)
6685 fprintf(fout, " u64 align;");
d4a985bd 6686 fprintf(fout, " } sf;\n");
1f84f6b3 6687 had_decl = 1;
6688 }
6689
193c11bf 6690 if ((g_sct_func_attr & SCTFA_ARGFRAME) && g_func_pp->argc_stack) {
6691 fprintf(fout, " struct { u32 ");
6692 for (i = j = 0; i < g_func_pp->argc; i++) {
6693 if (g_func_pp->arg[i].reg != NULL)
6694 continue;
6695 if (j++ != 0)
6696 fprintf(fout, ", ");
6697 fprintf(fout, "a%d", i + 1);
6698 }
6699 fprintf(fout, "; } af = {\n ");
6700 for (i = j = 0; i < g_func_pp->argc; i++) {
6701 if (g_func_pp->arg[i].reg != NULL)
6702 continue;
6703 if (j++ != 0)
6704 fprintf(fout, ", ");
6705 if (g_func_pp->arg[i].type.is_ptr)
6706 fprintf(fout, "(u32)");
6707 fprintf(fout, "a%d", i + 1);
6708 }
6709 fprintf(fout, "\n };\n");
6710 }
6711
1f84f6b3 6712 if (g_func_pp->is_userstack) {
60fe410c 6713 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
6714 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
1f84f6b3 6715 had_decl = 1;
6716 }
850c9265 6717
1f84f6b3 6718 if (g_func_pp->is_vararg) {
4f12f671 6719 fprintf(fout, " va_list ap;\n");
1f84f6b3 6720 had_decl = 1;
6721 }
4f12f671 6722
940e8e66 6723 // declare arg-registers
bd96f656 6724 for (i = 0; i < g_func_pp->argc; i++) {
6725 if (g_func_pp->arg[i].reg != NULL) {
91977a1c 6726 reg = char_array_i(regs_r32,
bd96f656 6727 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
75ad0378 6728 if (regmask & (1 << reg)) {
1f84f6b3 6729 if (g_func_pp->arg[i].type.is_retreg)
6730 fprintf(fout, " u32 %s = *r_%s;\n",
6731 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
6732 else
6733 fprintf(fout, " u32 %s = (u32)a%d;\n",
6734 g_func_pp->arg[i].reg, i + 1);
75ad0378 6735 }
1f84f6b3 6736 else {
6737 if (g_func_pp->arg[i].type.is_retreg)
6738 ferr(ops, "retreg '%s' is unused?\n",
6739 g_func_pp->arg[i].reg);
75ad0378 6740 fprintf(fout, " // %s = a%d; // unused\n",
6741 g_func_pp->arg[i].reg, i + 1);
1f84f6b3 6742 }
91977a1c 6743 had_decl = 1;
6744 }
6745 }
6746
25a330eb 6747 // declare normal registers
383dff16 6748 regmask_now = regmask & ~regmask_arg & ~g_regmask_rm;
75ad0378 6749 regmask_now &= ~(1 << xSP);
90307a99 6750 if (regmask_now & 0x00ff) {
91977a1c 6751 for (reg = 0; reg < 8; reg++) {
75ad0378 6752 if (regmask_now & (1 << reg)) {
ddaf8bd7 6753 fprintf(fout, " u32 %s", regs_r32[reg]);
6754 if (regmask_init & (1 << reg))
6755 fprintf(fout, " = 0");
6756 fprintf(fout, ";\n");
91977a1c 6757 had_decl = 1;
6758 }
6759 }
6760 }
d4a985bd 6761 // ... mmx
90307a99 6762 if (regmask_now & 0xff00) {
6763 for (reg = 8; reg < 16; reg++) {
6764 if (regmask_now & (1 << reg)) {
6765 fprintf(fout, " mmxr %s", regs_r32[reg]);
6766 if (regmask_init & (1 << reg))
6767 fprintf(fout, " = { 0, }");
6768 fprintf(fout, ";\n");
6769 had_decl = 1;
6770 }
6771 }
6772 }
d4a985bd 6773 // ... x87
fe18df39 6774 if (need_float_stack) {
6775 fprintf(fout, " %s f_st[8];\n", float_type);
6776 fprintf(fout, " int f_stp = 0;\n");
6777 had_decl = 1;
6778 }
6779 else {
6780 if (regmask_now & 0xff0000) {
6781 for (reg = 16; reg < 24; reg++) {
6782 if (regmask_now & (1 << reg)) {
6783 fprintf(fout, " %s f_st%d", float_type, reg - 16);
6784 if (regmask_init & (1 << reg))
6785 fprintf(fout, " = 0");
6786 fprintf(fout, ";\n");
6787 had_decl = 1;
6788 }
d4a985bd 6789 }
6790 }
6791 }
91977a1c 6792
16057ce1 6793 if (need_float_sw) {
6794 fprintf(fout, " u16 f_sw;\n");
6795 had_decl = 1;
6796 }
6797
d4e3b5db 6798 if (regmask_save) {
6799 for (reg = 0; reg < 8; reg++) {
6800 if (regmask_save & (1 << reg)) {
6801 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
6802 had_decl = 1;
6803 }
6804 }
6805 }
6806
3a5101d7 6807 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6808 if (save_arg_vars[i] == 0)
6809 continue;
69a3cdfc 6810 for (reg = 0; reg < 32; reg++) {
3a5101d7 6811 if (save_arg_vars[i] & (1 << reg)) {
6812 fprintf(fout, " u32 %s;\n",
6813 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
69a3cdfc 6814 had_decl = 1;
6815 }
6816 }
6817 }
6818
30620174 6819 if (regmask_ffca) {
6820 for (reg = 0; reg < 32; reg++) {
6821 if (regmask_ffca & (1 << reg)) {
6822 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
6823 had_decl = 1;
6824 }
6825 }
6826 }
6827
25a330eb 6828 // declare push-pop temporaries
6829 if (regmask_pp) {
6830 for (reg = 0; reg < 8; reg++) {
6831 if (regmask_pp & (1 << reg)) {
6832 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
6833 had_decl = 1;
6834 }
6835 }
6836 }
6837
cb090db0 6838 if (cond_vars) {
69a3cdfc 6839 for (i = 0; i < 8; i++) {
cb090db0 6840 if (cond_vars & (1 << i)) {
69a3cdfc 6841 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
6842 had_decl = 1;
6843 }
6844 }
6845 }
6846
108e9fe3 6847 if (need_tmp_var) {
6848 fprintf(fout, " u32 tmp;\n");
6849 had_decl = 1;
6850 }
6851
2fe80fdb 6852 if (need_tmp64) {
6853 fprintf(fout, " u64 tmp64;\n");
87bf6cec 6854 had_decl = 1;
6855 }
6856
91977a1c 6857 if (had_decl)
6858 fprintf(fout, "\n");
6859
7e08c224 6860 // do stack clear, if needed
6861 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6862 fprintf(fout, " ");
6863 if (g_stack_clear_len != 0) {
6864 if (g_stack_clear_len <= 4) {
6865 for (i = 0; i < g_stack_clear_len; i++)
6866 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6867 fprintf(fout, "0;\n");
6868 }
6869 else {
6870 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6871 g_stack_clear_start, g_stack_clear_len * 4);
6872 }
6873 }
6874 else
6875 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6876 }
6877
bd96f656 6878 if (g_func_pp->is_vararg) {
6879 if (g_func_pp->argc_stack == 0)
4f12f671 6880 ferr(ops, "vararg func without stack args?\n");
bd96f656 6881 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
4f12f671 6882 }
6883
91977a1c 6884 // output ops
69a3cdfc 6885 for (i = 0; i < opcnt; i++)
6886 {
d7857c3a 6887 if (g_labels[i] != NULL) {
91977a1c 6888 fprintf(fout, "\n%s:\n", g_labels[i]);
3ebea2cf 6889 label_pending = 1;
2b43685d 6890
6891 delayed_flag_op = NULL;
6892 last_arith_dst = NULL;
3ebea2cf 6893 }
91977a1c 6894
69a3cdfc 6895 po = &ops[i];
6896 if (po->flags & OPF_RMD)
91977a1c 6897 continue;
6898
193c11bf 6899 lock_handled = 0;
91977a1c 6900 no_output = 0;
6901
91977a1c 6902 #define assert_operand_cnt(n_) \
850c9265 6903 if (po->operand_cnt != n_) \
6904 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6905
69a3cdfc 6906 // conditional/flag using op?
6907 if (po->flags & OPF_CC)
850c9265 6908 {
940e8e66 6909 int is_delayed = 0;
69a3cdfc 6910
04f8a628 6911 tmp_op = po->datap;
850c9265 6912
69a3cdfc 6913 // we go through all this trouble to avoid using parsed_flag_op,
6914 // which makes generated code much nicer
6915 if (delayed_flag_op != NULL)
850c9265 6916 {
092f64e1 6917 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6918 po->pfo, po->pfo_inv);
940e8e66 6919 is_delayed = 1;
91977a1c 6920 }
850c9265 6921 else if (last_arith_dst != NULL
092f64e1 6922 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
04f8a628 6923 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6924 ))
850c9265 6925 {
3ebea2cf 6926 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
092f64e1 6927 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
850c9265 6928 last_arith_dst->lmod, buf3);
940e8e66 6929 is_delayed = 1;
850c9265 6930 }
04f8a628 6931 else if (tmp_op != NULL) {
7ba45c34 6932 // use preprocessed flag calc results
092f64e1 6933 if (!(tmp_op->pfomask & (1 << po->pfo)))
6934 ferr(po, "not prepared for pfo %d\n", po->pfo);
69a3cdfc 6935
092f64e1 6936 // note: pfo_inv was not yet applied
69a3cdfc 6937 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
092f64e1 6938 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
69a3cdfc 6939 }
6940 else {
6941 ferr(po, "all methods of finding comparison failed\n");
6942 }
850c9265 6943
69a3cdfc 6944 if (po->flags & OPF_JMP) {
092f64e1 6945 fprintf(fout, " if %s", buf1);
850c9265 6946 }
cb090db0 6947 else if (po->op == OP_RCL || po->op == OP_RCR
6948 || po->op == OP_ADC || po->op == OP_SBB)
6949 {
940e8e66 6950 if (is_delayed)
6951 fprintf(fout, " cond_%s = %s;\n",
092f64e1 6952 parsed_flag_op_names[po->pfo], buf1);
850c9265 6953 }
5101a5f9 6954 else if (po->flags & OPF_DATA) { // SETcc
850c9265 6955 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6956 fprintf(fout, " %s = %s;", buf2, buf1);
91977a1c 6957 }
69a3cdfc 6958 else {
6959 ferr(po, "unhandled conditional op\n");
6960 }
91977a1c 6961 }
6962
940e8e66 6963 pfomask = po->pfomask;
6964
850c9265 6965 switch (po->op)
91977a1c 6966 {
6967 case OP_MOV:
6968 assert_operand_cnt(2);
850c9265 6969 propagate_lmod(po, &po->operand[0], &po->operand[1]);
de50b98b 6970 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
c7ed83dd 6971 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
de50b98b 6972 fprintf(fout, " %s = %s;", buf1,
3ebea2cf 6973 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
c7ed83dd 6974 buf3, 0));
850c9265 6975 break;
6976
6977 case OP_LEA:
6978 assert_operand_cnt(2);
87bf6cec 6979 po->operand[1].lmod = OPLM_DWORD; // always
850c9265 6980 fprintf(fout, " %s = %s;",
6981 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
3ebea2cf 6982 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6983 NULL, 1));
850c9265 6984 break;
6985
6986 case OP_MOVZX:
6987 assert_operand_cnt(2);
91977a1c 6988 fprintf(fout, " %s = %s;",
850c9265 6989 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
3ebea2cf 6990 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
850c9265 6991 break;
6992
6993 case OP_MOVSX:
6994 assert_operand_cnt(2);
6995 switch (po->operand[1].lmod) {
6996 case OPLM_BYTE:
6997 strcpy(buf3, "(s8)");
6998 break;
6999 case OPLM_WORD:
7000 strcpy(buf3, "(s16)");
7001 break;
7002 default:
7003 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
7004 }
a2c1d768 7005 fprintf(fout, " %s = %s;",
850c9265 7006 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
a2c1d768 7007 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
7008 buf3, 0));
850c9265 7009 break;
7010
108e9fe3 7011 case OP_XCHG:
7012 assert_operand_cnt(2);
7013 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7014 fprintf(fout, " tmp = %s;",
7015 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
7016 fprintf(fout, " %s = %s;",
7017 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
c7ed83dd 7018 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
7019 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7020 fprintf(fout, " %s = %stmp;",
7021 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
7022 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
108e9fe3 7023 snprintf(g_comment, sizeof(g_comment), "xchg");
7024 break;
7025
850c9265 7026 case OP_NOT:
7027 assert_operand_cnt(1);
7028 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7029 fprintf(fout, " %s = ~%s;", buf1, buf1);
7030 break;
7031
04abc5d6 7032 case OP_XLAT:
7033 assert_operand_cnt(2);
7034 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7035 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7036 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
7037 strcpy(g_comment, "xlat");
7038 break;
7039
5101a5f9 7040 case OP_CDQ:
7041 assert_operand_cnt(2);
7042 fprintf(fout, " %s = (s32)%s >> 31;",
7043 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
3ebea2cf 7044 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5101a5f9 7045 strcpy(g_comment, "cdq");
7046 break;
7047
622eb2ef 7048 case OP_BSWAP:
7049 assert_operand_cnt(1);
7050 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7051 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
7052 break;
7053
092f64e1 7054 case OP_LODS:
092f64e1 7055 if (po->flags & OPF_REP) {
acd03176 7056 assert_operand_cnt(3);
092f64e1 7057 // hmh..
7058 ferr(po, "TODO\n");
7059 }
7060 else {
acd03176 7061 assert_operand_cnt(2);
3947cf24 7062 fprintf(fout, " %s = %sesi; esi %c= %d;",
7063 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
7064 lmod_cast_u_ptr(po, po->operand[1].lmod),
092f64e1 7065 (po->flags & OPF_DF) ? '-' : '+',
3947cf24 7066 lmod_bytes(po, po->operand[1].lmod));
092f64e1 7067 strcpy(g_comment, "lods");
7068 }
7069 break;
7070
33c35af6 7071 case OP_STOS:
33c35af6 7072 if (po->flags & OPF_REP) {
acd03176 7073 assert_operand_cnt(3);
591721d7 7074 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
7075 (po->flags & OPF_DF) ? '-' : '+',
3947cf24 7076 lmod_bytes(po, po->operand[1].lmod));
193c11bf 7077 fprintf(fout, " %sedi = eax;\n",
3947cf24 7078 lmod_cast_u_ptr(po, po->operand[1].lmod));
193c11bf 7079 fprintf(fout, " barrier();");
7080 strcpy(g_comment, "^ rep stos");
33c35af6 7081 }
7082 else {
acd03176 7083 assert_operand_cnt(2);
092f64e1 7084 fprintf(fout, " %sedi = eax; edi %c= %d;",
3947cf24 7085 lmod_cast_u_ptr(po, po->operand[1].lmod),
591721d7 7086 (po->flags & OPF_DF) ? '-' : '+',
3947cf24 7087 lmod_bytes(po, po->operand[1].lmod));
33c35af6 7088 strcpy(g_comment, "stos");
7089 }
7090 break;
7091
d4e3b5db 7092 case OP_MOVS:
d4e3b5db 7093 j = lmod_bytes(po, po->operand[0].lmod);
7094 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
591721d7 7095 l = (po->flags & OPF_DF) ? '-' : '+';
d4e3b5db 7096 if (po->flags & OPF_REP) {
acd03176 7097 assert_operand_cnt(3);
d4e3b5db 7098 fprintf(fout,
591721d7 7099 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
7100 l, j, l, j);
d4e3b5db 7101 fprintf(fout,
193c11bf 7102 " %sedi = %sesi;\n", buf1, buf1);
7103 // this can overwrite many variables
7104 fprintf(fout, " barrier();");
7105 strcpy(g_comment, "^ rep movs");
d4e3b5db 7106 }
7107 else {
acd03176 7108 assert_operand_cnt(2);
092f64e1 7109 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
591721d7 7110 buf1, buf1, l, j, l, j);
d4e3b5db 7111 strcpy(g_comment, "movs");
7112 }
7113 break;
7114
7ba45c34 7115 case OP_CMPS:
7ba45c34 7116 // repe ~ repeat while ZF=1
7ba45c34 7117 j = lmod_bytes(po, po->operand[0].lmod);
7118 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
591721d7 7119 l = (po->flags & OPF_DF) ? '-' : '+';
7ba45c34 7120 if (po->flags & OPF_REP) {
acd03176 7121 assert_operand_cnt(3);
7ba45c34 7122 fprintf(fout,
7f20f633 7123 " while (ecx != 0) {\n");
4741fdfe 7124 if (pfomask & (1 << PFO_C)) {
7125 // ugh..
7126 fprintf(fout,
05381e4a 7127 " cond_c = %sesi < %sedi;\n", buf1, buf1);
4741fdfe 7128 pfomask &= ~(1 << PFO_C);
7129 }
7ba45c34 7130 fprintf(fout,
05381e4a 7131 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
1f84f6b3 7132 buf1, buf1, l, j, l, j);
7133 fprintf(fout,
7f20f633 7134 " ecx--;\n"
1f84f6b3 7135 " if (cond_z %s 0) break;\n",
7136 (po->flags & OPF_REPZ) ? "==" : "!=");
7ba45c34 7137 fprintf(fout,
4741fdfe 7138 " }");
7ba45c34 7139 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
7140 (po->flags & OPF_REPZ) ? "e" : "ne");
7141 }
7142 else {
acd03176 7143 assert_operand_cnt(2);
7ba45c34 7144 fprintf(fout,
05381e4a 7145 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
591721d7 7146 buf1, buf1, l, j, l, j);
7ba45c34 7147 strcpy(g_comment, "cmps");
7148 }
7149 pfomask &= ~(1 << PFO_Z);
7150 last_arith_dst = NULL;
7151 delayed_flag_op = NULL;
7152 break;
7153
591721d7 7154 case OP_SCAS:
7155 // only does ZF (for now)
7156 // repe ~ repeat while ZF=1
3947cf24 7157 j = lmod_bytes(po, po->operand[1].lmod);
591721d7 7158 l = (po->flags & OPF_DF) ? '-' : '+';
7159 if (po->flags & OPF_REP) {
acd03176 7160 assert_operand_cnt(3);
591721d7 7161 fprintf(fout,
7f20f633 7162 " while (ecx != 0) {\n");
591721d7 7163 fprintf(fout,
1f84f6b3 7164 " cond_z = (%seax == %sedi); edi %c= %d;\n",
3947cf24 7165 lmod_cast_u(po, po->operand[1].lmod),
7166 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
1f84f6b3 7167 fprintf(fout,
7f20f633 7168 " ecx--;\n"
1f84f6b3 7169 " if (cond_z %s 0) break;\n",
591721d7 7170 (po->flags & OPF_REPZ) ? "==" : "!=");
7171 fprintf(fout,
1f84f6b3 7172 " }");
591721d7 7173 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
7174 (po->flags & OPF_REPZ) ? "e" : "ne");
7175 }
7176 else {
acd03176 7177 assert_operand_cnt(2);
05381e4a 7178 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
3947cf24 7179 lmod_cast_u(po, po->operand[1].lmod),
7180 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
591721d7 7181 strcpy(g_comment, "scas");
7182 }
7183 pfomask &= ~(1 << PFO_Z);
7184 last_arith_dst = NULL;
7185 delayed_flag_op = NULL;
7186 break;
7187
193c11bf 7188 case OP_RDTSC:
7189 fprintf(fout, " tmp64 = ext_rdtsc();\n");
7190 fprintf(fout, " edx = tmp64 >> 32;\n");
7191 fprintf(fout, " eax = tmp64;");
7192 break;
7193
7194 case OP_CPUID:
7195 fprintf(fout, " ext_cpuid(&eax, &ebx, &ecx, &edx);");
7196 break;
7197
850c9265 7198 // arithmetic w/flags
850c9265 7199 case OP_AND:
2b70f6d3 7200 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
7201 goto dualop_arith_const;
7202 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7203 goto dualop_arith;
7204
850c9265 7205 case OP_OR:
5101a5f9 7206 propagate_lmod(po, &po->operand[0], &po->operand[1]);
2b70f6d3 7207 if (po->operand[1].type == OPT_CONST) {
7208 j = lmod_bytes(po, po->operand[0].lmod);
7209 if (((1ull << j * 8) - 1) == po->operand[1].val)
7210 goto dualop_arith_const;
7211 }
7212 goto dualop_arith;
7213
850c9265 7214 dualop_arith:
7215 assert_operand_cnt(2);
850c9265 7216 fprintf(fout, " %s %s= %s;",
7217 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7218 op_to_c(po),
3ebea2cf 7219 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
04f8a628 7220 output_std_flags(fout, po, &pfomask, buf1);
7221 last_arith_dst = &po->operand[0];
7222 delayed_flag_op = NULL;
7223 break;
7224
2b70f6d3 7225 dualop_arith_const:
7226 // and 0, or ~0 used instead mov
7227 assert_operand_cnt(2);
7228 fprintf(fout, " %s = %s;",
7229 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7230 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
7231 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7232 output_std_flags(fout, po, &pfomask, buf1);
7233 last_arith_dst = &po->operand[0];
7234 delayed_flag_op = NULL;
7235 break;
7236
04f8a628 7237 case OP_SHL:
7238 case OP_SHR:
7239 assert_operand_cnt(2);
7240 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7241 if (pfomask & (1 << PFO_C)) {
7242 if (po->operand[1].type == OPT_CONST) {
7243 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7244 j = po->operand[1].val;
7245 j %= l;
7246 if (j != 0) {
7247 if (po->op == OP_SHL)
7248 j = l - j;
7249 else
7250 j -= 1;
cb090db0 7251 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
7252 buf1, j);
04f8a628 7253 }
7254 else
7255 ferr(po, "zero shift?\n");
7256 }
7257 else
7258 ferr(po, "TODO\n");
7259 pfomask &= ~(1 << PFO_C);
840257f6 7260 }
04abc5d6 7261 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
04f8a628 7262 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
04abc5d6 7263 if (po->operand[1].type != OPT_CONST)
7264 fprintf(fout, " & 0x1f");
7265 fprintf(fout, ";");
04f8a628 7266 output_std_flags(fout, po, &pfomask, buf1);
850c9265 7267 last_arith_dst = &po->operand[0];
69a3cdfc 7268 delayed_flag_op = NULL;
850c9265 7269 break;
7270
d4e3b5db 7271 case OP_SAR:
7272 assert_operand_cnt(2);
7273 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7274 fprintf(fout, " %s = %s%s >> %s;", buf1,
7275 lmod_cast_s(po, po->operand[0].lmod), buf1,
3ebea2cf 7276 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
04f8a628 7277 output_std_flags(fout, po, &pfomask, buf1);
d4e3b5db 7278 last_arith_dst = &po->operand[0];
7279 delayed_flag_op = NULL;
7280 break;
7281
04abc5d6 7282 case OP_SHLD:
3b2f4044 7283 case OP_SHRD:
7284 assert_operand_cnt(3);
7285 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7286 l = lmod_bytes(po, po->operand[0].lmod) * 8;
3b2f4044 7287 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
acd03176 7288 if (po->operand[2].type != OPT_CONST) {
7289 // no handling for "undefined" case, hopefully not needed
7290 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
7291 strcpy(buf3, buf2);
7292 }
7293 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7294 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
04abc5d6 7295 if (po->op == OP_SHLD) {
7296 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
7297 buf1, buf3, buf1, buf2, l, buf3);
7298 strcpy(g_comment, "shld");
7299 }
7300 else {
7301 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
7302 buf1, buf3, buf1, buf2, l, buf3);
7303 strcpy(g_comment, "shrd");
7304 }
3b2f4044 7305 output_std_flags(fout, po, &pfomask, buf1);
7306 last_arith_dst = &po->operand[0];
7307 delayed_flag_op = NULL;
7308 break;
7309
d4e3b5db 7310 case OP_ROL:
7311 case OP_ROR:
7312 assert_operand_cnt(2);
7313 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7314 if (po->operand[1].type == OPT_CONST) {
7315 j = po->operand[1].val;
7316 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
7317 fprintf(fout, po->op == OP_ROL ?
7318 " %s = (%s << %d) | (%s >> %d);" :
7319 " %s = (%s >> %d) | (%s << %d);",
7320 buf1, buf1, j, buf1,
7321 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
7322 }
7323 else
7324 ferr(po, "TODO\n");
04f8a628 7325 output_std_flags(fout, po, &pfomask, buf1);
d4e3b5db 7326 last_arith_dst = &po->operand[0];
7327 delayed_flag_op = NULL;
7328 break;
7329
cb090db0 7330 case OP_RCL:
7331 case OP_RCR:
7332 assert_operand_cnt(2);
7333 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7334 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7335 if (po->operand[1].type == OPT_CONST) {
7336 j = po->operand[1].val % l;
7337 if (j == 0)
7338 ferr(po, "zero rotate\n");
7339 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
7340 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
7341 if (po->op == OP_RCL) {
7342 fprintf(fout,
7343 " %s = (%s << %d) | (cond_c << %d)",
7344 buf1, buf1, j, j - 1);
7345 if (j != 1)
7346 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
7347 }
7348 else {
7349 fprintf(fout,
7350 " %s = (%s >> %d) | (cond_c << %d)",
7351 buf1, buf1, j, l - j);
7352 if (j != 1)
7353 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
7354 }
7355 fprintf(fout, ";\n");
7356 fprintf(fout, " cond_c = tmp;");
7357 }
7358 else
7359 ferr(po, "TODO\n");
7360 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
7361 output_std_flags(fout, po, &pfomask, buf1);
7362 last_arith_dst = &po->operand[0];
7363 delayed_flag_op = NULL;
7364 break;
7365
5101a5f9 7366 case OP_XOR:
850c9265 7367 assert_operand_cnt(2);
7368 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5101a5f9 7369 if (IS(opr_name(po, 0), opr_name(po, 1))) {
7370 // special case for XOR
7f20f633 7371 int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
7372 for (j = 0; j <= PFO_LE; j++) {
7373 if (pfomask & (1 << j)) {
7374 fprintf(fout, " cond_%s = %d;\n",
7375 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
7376 pfomask &= ~(1 << j);
7377 }
2fe80fdb 7378 }
5101a5f9 7379 fprintf(fout, " %s = 0;",
7380 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7381 last_arith_dst = &po->operand[0];
7382 delayed_flag_op = NULL;
850c9265 7383 break;
850c9265 7384 }
5101a5f9 7385 goto dualop_arith;
7386
2fe80fdb 7387 case OP_ADD:
7388 assert_operand_cnt(2);
7389 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7390 if (pfomask & (1 << PFO_C)) {
c8dbc5be 7391 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7392 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7393 if (po->operand[0].lmod == OPLM_DWORD) {
7394 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
7395 fprintf(fout, " cond_c = tmp64 >> 32;\n");
7396 fprintf(fout, " %s = (u32)tmp64;",
7397 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
d4a985bd 7398 strcat(g_comment, " add64");
c8dbc5be 7399 }
7400 else {
7401 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
7402 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
7403 fprintf(fout, " %s += %s;",
7404 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7405 buf2);
7406 }
2fe80fdb 7407 pfomask &= ~(1 << PFO_C);
7408 output_std_flags(fout, po, &pfomask, buf1);
7409 last_arith_dst = &po->operand[0];
7410 delayed_flag_op = NULL;
7411 break;
7412 }
16057ce1 7413 if (pfomask & (1 << PFO_LE)) {
7414 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
7415 fprintf(fout, " cond_%s = %s;\n",
7416 parsed_flag_op_names[PFO_LE], buf1);
7417 pfomask &= ~(1 << PFO_LE);
7418 }
2fe80fdb 7419 goto dualop_arith;
7420
7421 case OP_SUB:
7422 assert_operand_cnt(2);
7423 propagate_lmod(po, &po->operand[0], &po->operand[1]);
3b2f4044 7424 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
7425 for (j = 0; j <= PFO_LE; j++) {
7426 if (!(pfomask & (1 << j)))
7427 continue;
7428 if (j == PFO_Z || j == PFO_S)
7429 continue;
7430
16057ce1 7431 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
3b2f4044 7432 fprintf(fout, " cond_%s = %s;\n",
7433 parsed_flag_op_names[j], buf1);
7434 pfomask &= ~(1 << j);
7435 }
2fe80fdb 7436 }
7437 goto dualop_arith;
7438
5101a5f9 7439 case OP_ADC:
850c9265 7440 case OP_SBB:
5101a5f9 7441 assert_operand_cnt(2);
7442 propagate_lmod(po, &po->operand[0], &po->operand[1]);
a2c1d768 7443 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
840257f6 7444 if (po->op == OP_SBB
7445 && IS(po->operand[0].name, po->operand[1].name))
7446 {
7447 // avoid use of unitialized var
a2c1d768 7448 fprintf(fout, " %s = -cond_c;", buf1);
94d447fb 7449 // carry remains what it was
7450 pfomask &= ~(1 << PFO_C);
840257f6 7451 }
7452 else {
a2c1d768 7453 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
3ebea2cf 7454 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
840257f6 7455 }
a2c1d768 7456 output_std_flags(fout, po, &pfomask, buf1);
5101a5f9 7457 last_arith_dst = &po->operand[0];
7458 delayed_flag_op = NULL;
850c9265 7459 break;
7460
1f84f6b3 7461 case OP_BSF:
f9327ad4 7462 case OP_BSR:
7463 // on SKL, if src is 0, dst is left unchanged
1f84f6b3 7464 assert_operand_cnt(2);
f9327ad4 7465 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
1f84f6b3 7466 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
f9327ad4 7467 output_std_flag_z(fout, po, &pfomask, buf2);
7468 if (po->op == OP_BSF)
7469 snprintf(buf3, sizeof(buf3), "__builtin_ffs(%s) - 1", buf2);
7470 else
7471 snprintf(buf3, sizeof(buf3), "31 - __builtin_clz(%s)", buf2);
7472 fprintf(fout, " if (%s) %s = %s;", buf2, buf1, buf3);
1f84f6b3 7473 last_arith_dst = &po->operand[0];
7474 delayed_flag_op = NULL;
f9327ad4 7475 strcat(g_comment, po->op == OP_BSF ? " bsf" : " bsr");
1f84f6b3 7476 break;
7477
850c9265 7478 case OP_DEC:
90307a99 7479 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
7480 for (j = 0; j <= PFO_LE; j++) {
7481 if (!(pfomask & (1 << j)))
7482 continue;
7483 if (j == PFO_Z || j == PFO_S || j == PFO_C)
7484 continue;
7485
16057ce1 7486 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
90307a99 7487 fprintf(fout, " cond_%s = %s;\n",
7488 parsed_flag_op_names[j], buf1);
7489 pfomask &= ~(1 << j);
7490 }
7491 }
7492 // fallthrough
7493
7494 case OP_INC:
7495 if (pfomask & (1 << PFO_C))
7496 // carry is unaffected by inc/dec.. wtf?
7497 ferr(po, "carry propagation needed\n");
7498
850c9265 7499 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
1bafb621 7500 if (po->operand[0].type == OPT_REG) {
193c11bf 7501 ferr_assert(po, !(po->flags & OPF_LOCK));
1bafb621 7502 strcpy(buf2, po->op == OP_INC ? "++" : "--");
7503 fprintf(fout, " %s%s;", buf1, buf2);
7504 }
193c11bf 7505 else if (po->flags & OPF_LOCK) {
7506 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0], "", 1);
7507 fprintf(fout, " __sync_fetch_and_%s((%s *)(%s), 1);",
7508 po->op == OP_INC ? "add" : "sub",
7509 lmod_type_u(po, po->operand[0].lmod), buf2);
7510 strcat(g_comment, " lock");
7511 lock_handled = 1;
7512 }
1bafb621 7513 else {
7514 strcpy(buf2, po->op == OP_INC ? "+" : "-");
7515 fprintf(fout, " %s %s= 1;", buf1, buf2);
7516 }
a2c1d768 7517 output_std_flags(fout, po, &pfomask, buf1);
5101a5f9 7518 last_arith_dst = &po->operand[0];
7519 delayed_flag_op = NULL;
7520 break;
7521
7522 case OP_NEG:
7523 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
3ebea2cf 7524 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
5101a5f9 7525 fprintf(fout, " %s = -%s%s;", buf1,
7526 lmod_cast_s(po, po->operand[0].lmod), buf2);
850c9265 7527 last_arith_dst = &po->operand[0];
69a3cdfc 7528 delayed_flag_op = NULL;
0ea6430c 7529 if (pfomask & PFOB_C) {
940e8e66 7530 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
0ea6430c 7531 pfomask &= ~PFOB_C;
940e8e66 7532 }
0ea6430c 7533 output_std_flags(fout, po, &pfomask, buf1);
850c9265 7534 break;
7535
7536 case OP_IMUL:
de50b98b 7537 if (po->operand_cnt == 2) {
7538 propagate_lmod(po, &po->operand[0], &po->operand[1]);
850c9265 7539 goto dualop_arith;
de50b98b 7540 }
87bf6cec 7541 if (po->operand_cnt == 3)
7542 ferr(po, "TODO imul3\n");
7543 // fallthrough
7544 case OP_MUL:
7545 assert_operand_cnt(1);
c8dbc5be 7546 switch (po->operand[0].lmod) {
7547 case OPLM_DWORD:
7548 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
7549 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
7550 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
7551 fprintf(fout, " edx = tmp64 >> 32;\n");
7552 fprintf(fout, " eax = tmp64;");
7553 break;
7554 case OPLM_BYTE:
7555 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
7556 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
7557 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
7558 buf1, 0));
7559 break;
7560 default:
7561 ferr(po, "TODO: unhandled mul type\n");
7562 break;
7563 }
87bf6cec 7564 last_arith_dst = NULL;
69a3cdfc 7565 delayed_flag_op = NULL;
91977a1c 7566 break;
7567
5101a5f9 7568 case OP_DIV:
7569 case OP_IDIV:
7570 assert_operand_cnt(1);
cb090db0 7571 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
acd03176 7572 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
cb090db0 7573 po->op == OP_IDIV));
7574 switch (po->operand[0].lmod) {
7575 case OPLM_DWORD:
7576 if (po->flags & OPF_32BIT)
acd03176 7577 snprintf(buf2, sizeof(buf2), "%seax", cast);
cb090db0 7578 else {
7579 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
acd03176 7580 snprintf(buf2, sizeof(buf2), "%stmp64",
cb090db0 7581 (po->op == OP_IDIV) ? "(s64)" : "");
7582 }
7583 if (po->operand[0].type == OPT_REG
7584 && po->operand[0].reg == xDX)
7585 {
acd03176 7586 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
7587 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
7588 }
7589 else {
7590 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
7591 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
7592 }
7593 break;
7594 case OPLM_WORD:
7595 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
7596 snprintf(buf2, sizeof(buf2), "%stmp",
7597 (po->op == OP_IDIV) ? "(s32)" : "");
7598 if (po->operand[0].type == OPT_REG
7599 && po->operand[0].reg == xDX)
7600 {
7601 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
7602 buf2, cast, buf1);
7603 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
7604 buf2, cast, buf1);
cb090db0 7605 }
7606 else {
acd03176 7607 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
7608 buf2, cast, buf1);
7609 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
7610 buf2, cast, buf1);
cb090db0 7611 }
d4a985bd 7612 strcat(g_comment, " div16");
cb090db0 7613 break;
7614 default:
acd03176 7615 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
5101a5f9 7616 }
87bf6cec 7617 last_arith_dst = NULL;
7618 delayed_flag_op = NULL;
5101a5f9 7619 break;
7620
91977a1c 7621 case OP_TEST:
7622 case OP_CMP:
850c9265 7623 propagate_lmod(po, &po->operand[0], &po->operand[1]);
940e8e66 7624 if (pfomask != 0) {
69a3cdfc 7625 for (j = 0; j < 8; j++) {
940e8e66 7626 if (pfomask & (1 << j)) {
69a3cdfc 7627 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
7628 fprintf(fout, " cond_%s = %s;",
7629 parsed_flag_op_names[j], buf1);
7630 }
7631 }
940e8e66 7632 pfomask = 0;
69a3cdfc 7633 }
7634 else
7635 no_output = 1;
7ba45c34 7636 last_arith_dst = NULL;
69a3cdfc 7637 delayed_flag_op = po;
91977a1c 7638 break;
7639
092f64e1 7640 case OP_SCC:
7641 // SETcc - should already be handled
7642 break;
7643
69a3cdfc 7644 // note: we reuse OP_Jcc for SETcc, only flags differ
092f64e1 7645 case OP_JCC:
7646 fprintf(fout, "\n goto %s;", po->operand[0].name);
850c9265 7647 break;
7648
5c024ef7 7649 case OP_JECXZ:
7650 fprintf(fout, " if (ecx == 0)\n");
7651 fprintf(fout, " goto %s;", po->operand[0].name);
d4a985bd 7652 strcat(g_comment, " jecxz");
5c024ef7 7653 break;
7654
04abc5d6 7655 case OP_LOOP:
3947cf24 7656 fprintf(fout, " if (--ecx != 0)\n");
04abc5d6 7657 fprintf(fout, " goto %s;", po->operand[0].name);
d4a985bd 7658 strcat(g_comment, " loop");
04abc5d6 7659 break;
7660
850c9265 7661 case OP_JMP:
87bf6cec 7662 assert_operand_cnt(1);
de50b98b 7663 last_arith_dst = NULL;
7664 delayed_flag_op = NULL;
7665
4c45fa73 7666 if (po->operand[0].type == OPT_REGMEM) {
7667 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
7668 buf1, buf2);
7669 if (ret != 2)
7670 ferr(po, "parse failure for jmp '%s'\n",
7671 po->operand[0].name);
7672 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
7673 break;
7674 }
7675 else if (po->operand[0].type != OPT_LABEL)
7676 ferr(po, "unhandled jmp type\n");
87bf6cec 7677
850c9265 7678 fprintf(fout, " goto %s;", po->operand[0].name);
91977a1c 7679 break;
7680
7681 case OP_CALL:
5101a5f9 7682 assert_operand_cnt(1);
092f64e1 7683 pp = po->pp;
89ff3147 7684 my_assert_not(pp, NULL);
91977a1c 7685
092f64e1 7686 strcpy(buf3, " ");
7687 if (po->flags & OPF_CC) {
7688 // we treat conditional branch to another func
7689 // (yes such code exists..) as conditional tailcall
7690 strcat(buf3, " ");
7691 fprintf(fout, " {\n");
7692 }
7693
8eb12e72 7694 if (pp->is_fptr && !pp->is_arg) {
092f64e1 7695 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
1cd4a663 7696 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7697 "(void *)", 0));
1fe8d40e 7698 }
7699 if (pp->is_fptr && (pp->is_unresolved || pp->is_guessed)) {
7700 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
7701 buf3, asmfn, po->asmln, pp->name);
8eb12e72 7702 }
1bafb621 7703
092f64e1 7704 fprintf(fout, "%s", buf3);
2b43685d 7705 if (strstr(pp->ret_type.name, "int64")) {
87bf6cec 7706 if (po->flags & OPF_TAIL)
2b43685d 7707 ferr(po, "int64 and tail?\n");
2fe80fdb 7708 fprintf(fout, "tmp64 = ");
2b43685d 7709 }
7710 else if (!IS(pp->ret_type.name, "void")) {
7711 if (po->flags & OPF_TAIL) {
d4a985bd 7712 if (regmask_ret & mxAX) {
840257f6 7713 fprintf(fout, "return ");
7714 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
7715 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
7716 }
d4a985bd 7717 else if (regmask_ret & mxST0)
7718 ferr(po, "float tailcall\n");
2b43685d 7719 }
d4a985bd 7720 else if (po->regmask_dst & mxAX) {
87bf6cec 7721 fprintf(fout, "eax = ");
2b43685d 7722 if (pp->ret_type.is_ptr)
7723 fprintf(fout, "(u32)");
7724 }
d4a985bd 7725 else if (po->regmask_dst & mxST0) {
fe18df39 7726 ferr_assert(po, po->flags & OPF_FPUSH);
7727 if (need_float_stack)
7728 fprintf(fout, "f_st[--f_stp & 7] = ");
7729 else
7730 fprintf(fout, "f_st0 = ");
d4a985bd 7731 }
91977a1c 7732 }
87bf6cec 7733
ddaf8bd7 7734 if (pp->name[0] == 0)
7735 ferr(po, "missing pp->name\n");
7736 fprintf(fout, "%s%s(", pp->name,
7737 pp->has_structarg ? "_sa" : "");
39b168b8 7738
2fe80fdb 7739 if (po->flags & OPF_ATAIL) {
56b49358 7740 int check_compat =
7741 g_func_pp->is_stdcall && g_func_pp->argc_stack > 0;
7742 check_compat |= pp->argc_stack > 0;
7743 if (check_compat
7744 && (pp->argc_stack != g_func_pp->argc_stack
7745 || pp->is_stdcall != g_func_pp->is_stdcall))
7746 ferr(po, "incompatible arg-reuse tailcall\n");
1f84f6b3 7747 if (g_func_pp->has_retreg)
7748 ferr(po, "TODO: retreg+tailcall\n");
87bf6cec 7749
2fe80fdb 7750 for (arg = j = 0; arg < pp->argc; arg++) {
7751 if (arg > 0)
7752 fprintf(fout, ", ");
87bf6cec 7753
2fe80fdb 7754 cast[0] = 0;
7755 if (pp->arg[arg].type.is_ptr)
7756 snprintf(cast, sizeof(cast), "(%s)",
7757 pp->arg[arg].type.name);
91977a1c 7758
2fe80fdb 7759 if (pp->arg[arg].reg != NULL) {
7760 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7761 continue;
7762 }
7763 // stack arg
7764 for (; j < g_func_pp->argc; j++)
7765 if (g_func_pp->arg[j].reg == NULL)
7766 break;
7767 fprintf(fout, "%sa%d", cast, j + 1);
7768 j++;
69a3cdfc 7769 }
2fe80fdb 7770 }
7771 else {
7772 for (arg = 0; arg < pp->argc; arg++) {
7773 if (arg > 0)
7774 fprintf(fout, ", ");
7775
7776 cast[0] = 0;
7777 if (pp->arg[arg].type.is_ptr)
7778 snprintf(cast, sizeof(cast), "(%s)",
7779 pp->arg[arg].type.name);
7780
7781 if (pp->arg[arg].reg != NULL) {
1f84f6b3 7782 if (pp->arg[arg].type.is_retreg)
7783 fprintf(fout, "&%s", pp->arg[arg].reg);
8c83cc48 7784 else if (IS(pp->arg[arg].reg, "ebp")
e627c4d0 7785 && g_bp_frame && !(po->flags & OPF_EBP_S))
8c83cc48 7786 {
7787 // rare special case
7788 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
7789 strcat(g_comment, " bp_ref");
7790 }
1f84f6b3 7791 else
7792 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
2fe80fdb 7793 continue;
7794 }
7795
7796 // stack arg
7797 tmp_op = pp->arg[arg].datap;
7798 if (tmp_op == NULL)
7799 ferr(po, "parsed_op missing for arg%d\n", arg);
23fd0b11 7800
7801 if (tmp_op->flags & OPF_VAPUSH) {
7802 fprintf(fout, "ap");
7803 }
30620174 7804 else if (tmp_op->op == OP_FST) {
7805 fprintf(fout, "fs_%d", tmp_op->p_argnum);
7806 if (tmp_op->operand[0].lmod == OPLM_QWORD)
7807 arg++;
7808 }
57860365 7809 else if (pp->arg[arg].type.is_64bit) {
7810 ferr_assert(po, tmp_op->p_argpass == 0);
7811 ferr_assert(po, !pp->arg[arg].is_saved);
b62264bc 7812 ferr_assert(po, !pp->arg[arg].type.is_float);
57860365 7813 ferr_assert(po, cast[0] == 0);
7814 out_src_opr(buf1, sizeof(buf1),
7815 tmp_op, &tmp_op->operand[0], cast, 0);
7816 tmp_op = pp->arg[++arg].datap;
7817 ferr_assert(po, tmp_op != NULL);
7818 out_src_opr(buf2, sizeof(buf2),
7819 tmp_op, &tmp_op->operand[0], cast, 0);
7820 fprintf(fout, "((u64)(%s) << 32) | (%s)",
7821 buf2, buf1);
7822 }
5f70a34f 7823 else if (tmp_op->p_argpass != 0) {
b62264bc 7824 ferr_assert(po, !pp->arg[arg].type.is_float);
5f70a34f 7825 fprintf(fout, "a%d", tmp_op->p_argpass);
7826 }
8c83cc48 7827 else if (pp->arg[arg].is_saved) {
7828 ferr_assert(po, tmp_op->p_argnum > 0);
b62264bc 7829 ferr_assert(po, !pp->arg[arg].type.is_float);
3a5101d7 7830 fprintf(fout, "%s%s", cast,
7831 saved_arg_name(buf1, sizeof(buf1),
7832 tmp_op->p_arggrp, tmp_op->p_argnum));
2fe80fdb 7833 }
b62264bc 7834 else if (pp->arg[arg].type.is_float) {
7835 ferr_assert(po, !pp->arg[arg].type.is_64bit);
7836 fprintf(fout, "%s",
7837 out_src_opr_float(buf1, sizeof(buf1),
7838 tmp_op, &tmp_op->operand[0], need_float_stack));
7839 }
2fe80fdb 7840 else {
7841 fprintf(fout, "%s",
7842 out_src_opr(buf1, sizeof(buf1),
7843 tmp_op, &tmp_op->operand[0], cast, 0));
7844 }
69a3cdfc 7845 }
91977a1c 7846 }
7847 fprintf(fout, ");");
87bf6cec 7848
2b43685d 7849 if (strstr(pp->ret_type.name, "int64")) {
7850 fprintf(fout, "\n");
092f64e1 7851 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7852 fprintf(fout, "%seax = tmp64;", buf3);
2b43685d 7853 }
7854
89ff3147 7855 if (pp->is_unresolved) {
8eb12e72 7856 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
89ff3147 7857 pp->argc_reg);
092f64e1 7858 strcat(g_comment, buf2);
89ff3147 7859 }
7860
87bf6cec 7861 if (po->flags & OPF_TAIL) {
840257f6 7862 ret = 0;
ddaf8bd7 7863 if (i == opcnt - 1 || pp->is_noreturn)
840257f6 7864 ret = 0;
7865 else if (IS(pp->ret_type.name, "void"))
7866 ret = 1;
b2bd20c0 7867 else if (!(regmask_ret & (1 << xAX)))
840257f6 7868 ret = 1;
7869 // else already handled as 'return f()'
7870
7871 if (ret) {
acd03176 7872 fprintf(fout, "\n%sreturn;", buf3);
7873 strcat(g_comment, " ^ tailcall");
3ebea2cf 7874 }
89ff3147 7875 else
ddaf8bd7 7876 strcat(g_comment, " tailcall");
acd03176 7877
7878 if ((regmask_ret & (1 << xAX))
7879 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7880 {
7881 ferr(po, "int func -> void func tailcall?\n");
7882 }
87bf6cec 7883 }
ddaf8bd7 7884 if (pp->is_noreturn)
7885 strcat(g_comment, " noreturn");
2fe80fdb 7886 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7887 strcat(g_comment, " argframe");
092f64e1 7888 if (po->flags & OPF_CC)
7889 strcat(g_comment, " cond");
7890
7891 if (po->flags & OPF_CC)
7892 fprintf(fout, "\n }");
7893
87bf6cec 7894 delayed_flag_op = NULL;
7895 last_arith_dst = NULL;
91977a1c 7896 break;
7897
7898 case OP_RET:
bd96f656 7899 if (g_func_pp->is_vararg)
4f12f671 7900 fprintf(fout, " va_end(ap);\n");
1f84f6b3 7901 if (g_func_pp->has_retreg) {
7902 for (arg = 0; arg < g_func_pp->argc; arg++)
7903 if (g_func_pp->arg[arg].type.is_retreg)
7904 fprintf(fout, " *r_%s = %s;\n",
7905 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7906 }
4f12f671 7907
16057ce1 7908 if (regmask_ret & mxST0) {
7909 fprintf(fout, " return %s;", float_st0);
7910 }
7911 else if (!(regmask_ret & mxAX)) {
3ebea2cf 7912 if (i != opcnt - 1 || label_pending)
7913 fprintf(fout, " return;");
7914 }
bd96f656 7915 else if (g_func_pp->ret_type.is_ptr) {
d4e3b5db 7916 fprintf(fout, " return (%s)eax;",
bd96f656 7917 g_func_pp->ret_type.name);
3ebea2cf 7918 }
2fe80fdb 7919 else if (IS(g_func_pp->ret_type.name, "__int64"))
7920 fprintf(fout, " return ((u64)edx << 32) | eax;");
91977a1c 7921 else
7922 fprintf(fout, " return eax;");
de50b98b 7923
7924 last_arith_dst = NULL;
7925 delayed_flag_op = NULL;
91977a1c 7926 break;
7927
7928 case OP_PUSH:
1f84f6b3 7929 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
5f70a34f 7930 if (po->p_argnum != 0) {
69a3cdfc 7931 // special case - saved func arg
3a5101d7 7932 fprintf(fout, " %s = %s;",
7933 saved_arg_name(buf2, sizeof(buf2),
7934 po->p_arggrp, po->p_argnum), buf1);
69a3cdfc 7935 break;
7936 }
d4e3b5db 7937 else if (po->flags & OPF_RSAVE) {
d4e3b5db 7938 fprintf(fout, " s_%s = %s;", buf1, buf1);
7939 break;
7940 }
25a330eb 7941 else if (po->flags & OPF_PPUSH) {
7942 tmp_op = po->datap;
7943 ferr_assert(po, tmp_op != NULL);
7944 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7945 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7946 break;
7947 }
1f84f6b3 7948 else if (g_func_pp->is_userstack) {
7949 fprintf(fout, " *(--esp) = %s;", buf1);
7950 break;
7951 }
e56ab892 7952 if (!(g_ida_func_attr & IDAFA_NORETURN))
7953 ferr(po, "stray push encountered\n");
7954 no_output = 1;
91977a1c 7955 break;
7956
7957 case OP_POP:
25a330eb 7958 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
d4e3b5db 7959 if (po->flags & OPF_RSAVE) {
d4e3b5db 7960 fprintf(fout, " %s = s_%s;", buf1, buf1);
7961 break;
7962 }
25a330eb 7963 else if (po->flags & OPF_PPUSH) {
e83ea7ed 7964 // push/pop graph / non-const
25a330eb 7965 ferr_assert(po, po->datap == NULL);
7966 fprintf(fout, " %s = pp_%s;", buf1, buf1);
7967 break;
7968 }
5c024ef7 7969 else if (po->datap != NULL) {
7970 // push/pop pair
7971 tmp_op = po->datap;
5c024ef7 7972 fprintf(fout, " %s = %s;", buf1,
7973 out_src_opr(buf2, sizeof(buf2),
7974 tmp_op, &tmp_op->operand[0],
c7ed83dd 7975 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
5c024ef7 7976 break;
7977 }
1f84f6b3 7978 else if (g_func_pp->is_userstack) {
25a330eb 7979 fprintf(fout, " %s = *esp++;", buf1);
1f84f6b3 7980 break;
7981 }
7982 else
7983 ferr(po, "stray pop encountered\n");
91977a1c 7984 break;
7985
33c35af6 7986 case OP_NOP:
2b43685d 7987 no_output = 1;
33c35af6 7988 break;
7989
622eb2ef 7990 // pseudo ops
7991 case OPP_ALLSHL:
7992 case OPP_ALLSHR:
7993 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
8c83cc48 7994 fprintf(fout, " tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
622eb2ef 7995 po->op == OPP_ALLSHL ? "<<" : ">>");
7996 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
7997 strcat(g_comment, po->op == OPP_ALLSHL
7998 ? " allshl" : " allshr");
7999 break;
8000
d4a985bd 8001 // x87
8002 case OP_FLD:
fe18df39 8003 if (need_float_stack) {
8004 out_src_opr_float(buf1, sizeof(buf1),
8005 po, &po->operand[0], 1);
8006 if (po->regmask_src & mxSTa) {
8007 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
8008 buf1);
8009 }
8010 else
8011 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
8012 }
8013 else {
8014 if (po->flags & OPF_FSHIFT)
8015 fprintf(fout, " f_st1 = f_st0;");
8016 if (po->operand[0].type == OPT_REG
8017 && po->operand[0].reg == xST0)
8018 {
8019 strcat(g_comment, " fld st");
8020 break;
8021 }
8022 fprintf(fout, " f_st0 = %s;",
8023 out_src_opr_float(buf1, sizeof(buf1),
8024 po, &po->operand[0], 0));
d4a985bd 8025 }
d4a985bd 8026 strcat(g_comment, " fld");
8027 break;
8028
8029 case OP_FILD:
fe18df39 8030 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
8031 lmod_cast(po, po->operand[0].lmod, 1), 0);
8032 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
8033 if (need_float_stack) {
8034 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
8035 }
8036 else {
8037 if (po->flags & OPF_FSHIFT)
8038 fprintf(fout, " f_st1 = f_st0;");
8039 fprintf(fout, " f_st0 = %s;", buf2);
8040 }
d4a985bd 8041 strcat(g_comment, " fild");
8042 break;
8043
8044 case OP_FLDc:
fe18df39 8045 if (need_float_stack)
8046 fprintf(fout, " f_st[--f_stp & 7] = ");
8047 else {
8048 if (po->flags & OPF_FSHIFT)
8049 fprintf(fout, " f_st1 = f_st0;");
8050 fprintf(fout, " f_st0 = ");
8051 }
d4a985bd 8052 switch (po->operand[0].val) {
fe18df39 8053 case X87_CONST_1: fprintf(fout, "1.0;"); break;
b62264bc 8054 case X87_CONST_L2T: fprintf(fout, "3.321928094887362;"); break;
8055 case X87_CONST_L2E: fprintf(fout, "M_LOG2E;"); break;
8056 case X87_CONST_PI: fprintf(fout, "M_PI;"); break;
8057 case X87_CONST_LG2: fprintf(fout, "0.301029995663981;"); break;
8058 case X87_CONST_LN2: fprintf(fout, "M_LN2;"); break;
fe18df39 8059 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
b62264bc 8060 default: ferr_assert(po, 0); break;
d4a985bd 8061 }
8062 break;
8063
8064 case OP_FST:
30620174 8065 if (po->flags & OPF_FARG) {
8066 // store to stack as func arg
8067 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
8068 dead_dst = 0;
8069 }
8070 else {
8071 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8072 need_float_stack);
8073 dead_dst = po->operand[0].type == OPT_REG
8074 && po->operand[0].reg == xST0;
fe18df39 8075 }
30620174 8076 if (!dead_dst)
8077 fprintf(fout, " %s = %s;", buf1, float_st0);
16057ce1 8078 if (po->flags & OPF_FSHIFT) {
8079 if (need_float_stack)
8080 fprintf(fout, " f_stp++;");
8081 else
fe18df39 8082 fprintf(fout, " f_st0 = f_st1;");
d4a985bd 8083 }
fe18df39 8084 if (dead_dst && !(po->flags & OPF_FSHIFT))
8085 no_output = 1;
8086 else
8087 strcat(g_comment, " fst");
d4a985bd 8088 break;
8089
16057ce1 8090 case OP_FIST:
8091 fprintf(fout, " %s = %s%s;",
8092 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
8093 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
8094 if (po->flags & OPF_FSHIFT) {
8095 if (need_float_stack)
8096 fprintf(fout, " f_stp++;");
8097 else
8098 fprintf(fout, " f_st0 = f_st1;");
8099 }
8100 strcat(g_comment, " fist");
8101 break;
8102
d4a985bd 8103 case OP_FADD:
8104 case OP_FDIV:
8105 case OP_FMUL:
8106 case OP_FSUB:
fe18df39 8107 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8108 need_float_stack);
8109 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
8110 need_float_stack);
8111 dead_dst = (po->flags & OPF_FPOP)
8112 && po->operand[0].type == OPT_REG
8113 && po->operand[0].reg == xST0;
d4a985bd 8114 switch (po->op) {
8115 case OP_FADD: j = '+'; break;
8116 case OP_FDIV: j = '/'; break;
8117 case OP_FMUL: j = '*'; break;
8118 case OP_FSUB: j = '-'; break;
8119 default: j = 'x'; break;
8120 }
fe18df39 8121 if (need_float_stack) {
8122 if (!dead_dst)
8123 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
8124 if (po->flags & OPF_FSHIFT)
8125 fprintf(fout, " f_stp++;");
d4a985bd 8126 }
8127 else {
fe18df39 8128 if (po->flags & OPF_FSHIFT) {
8129 // note: assumes only 2 regs handled
8130 if (!dead_dst)
8131 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
8132 else
8133 fprintf(fout, " f_st0 = f_st1;");
8134 }
8135 else if (!dead_dst)
8136 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
d4a985bd 8137 }
fe18df39 8138 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
d4a985bd 8139 break;
8140
8141 case OP_FDIVR:
8142 case OP_FSUBR:
fe18df39 8143 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8144 need_float_stack);
8145 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
8146 need_float_stack);
8147 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
8148 need_float_stack);
8149 dead_dst = (po->flags & OPF_FPOP)
8150 && po->operand[0].type == OPT_REG
8151 && po->operand[0].reg == xST0;
8152 j = po->op == OP_FDIVR ? '/' : '-';
8153 if (need_float_stack) {
8154 if (!dead_dst)
8155 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
8156 if (po->flags & OPF_FSHIFT)
8157 fprintf(fout, " f_stp++;");
8158 }
8159 else {
8160 if (po->flags & OPF_FSHIFT) {
8161 if (!dead_dst)
8162 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
8163 else
8164 fprintf(fout, " f_st0 = f_st1;");
8165 }
8166 else if (!dead_dst)
8167 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
8168 }
8169 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
d4a985bd 8170 break;
8171
8172 case OP_FIADD:
8173 case OP_FIDIV:
8174 case OP_FIMUL:
8175 case OP_FISUB:
8176 switch (po->op) {
8177 case OP_FIADD: j = '+'; break;
8178 case OP_FIDIV: j = '/'; break;
8179 case OP_FIMUL: j = '*'; break;
8180 case OP_FISUB: j = '-'; break;
8181 default: j = 'x'; break;
8182 }
fe18df39 8183 fprintf(fout, " %s %c= (%s)%s;", float_st0,
8184 j, float_type,
d4a985bd 8185 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
8186 lmod_cast(po, po->operand[0].lmod, 1), 0));
8187 break;
8188
8189 case OP_FIDIVR:
8190 case OP_FISUBR:
fe18df39 8191 fprintf(fout, " %s = %s %c %s;", float_st0,
8192 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
8193 need_float_stack),
8194 po->op == OP_FIDIVR ? '/' : '-', float_st0);
8195 break;
8196
16057ce1 8197 case OP_FCOM: {
8198 int mask, z_check;
8199 ferr_assert(po, po->datap != NULL);
8200 mask = (long)po->datap & 0xffff;
8201 z_check = ((long)po->datap >> 16) & 1;
8202 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8203 need_float_stack);
2c31fb4c 8204 if (mask == 0x0100 || mask == 0x0500) { // C0 -> <
16057ce1 8205 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
8206 float_st0, buf1);
8207 }
88eed95d 8208 else if (mask == 0x4000 || mask == 0x4400) { // C3 -> =
16057ce1 8209 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
8210 float_st0, buf1);
8211 }
8212 else if (mask == 0x4100) { // C3, C0
8213 if (z_check) {
8214 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
8215 float_st0, buf1);
8216 strcat(g_comment, " z_chk_det");
8217 }
8218 else {
8219 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
8220 "(%s < %s ? 0x0100 : 0);",
8221 float_st0, buf1, float_st0, buf1);
8222 }
8223 }
8224 else
8225 ferr(po, "unhandled sw mask: %x\n", mask);
8226 if (po->flags & OPF_FSHIFT) {
88eed95d 8227 if (need_float_stack) {
8228 if (po->flags & OPF_FPOPP)
8229 fprintf(fout, " f_stp += 2;");
8230 else
8231 fprintf(fout, " f_stp++;");
8232 }
8233 else {
8234 ferr_assert(po, !(po->flags & OPF_FPOPP));
16057ce1 8235 fprintf(fout, " f_st0 = f_st1;");
88eed95d 8236 }
16057ce1 8237 }
8238 break;
8239 }
8240
8241 case OP_FNSTSW:
8242 fprintf(fout, " %s = f_sw;",
8243 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
8244 break;
8245
fe18df39 8246 case OP_FCHS:
8247 fprintf(fout, " %s = -%s;", float_st0, float_st0);
d4a985bd 8248 break;
8249
497a6d6b 8250 case OP_FCOS:
fe18df39 8251 fprintf(fout, " %s = cos%s(%s);", float_st0,
8252 need_double ? "" : "f", float_st0);
497a6d6b 8253 break;
8254
8255 case OP_FPATAN:
fe18df39 8256 if (need_float_stack) {
8257 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
8258 need_double ? "" : "f", float_st1, float_st0);
8259 fprintf(fout, " f_stp++;");
8260 }
8261 else {
8262 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
8263 need_double ? "" : "f");
8264 }
8265 break;
8266
8267 case OP_FYL2X:
8268 if (need_float_stack) {
8269 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
8270 float_st1, need_double ? "" : "f", float_st0);
8271 fprintf(fout, " f_stp++;");
8272 }
8273 else {
8274 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
8275 need_double ? "" : "f");
8276 }
8c83cc48 8277 strcat(g_comment, " fyl2x");
497a6d6b 8278 break;
8279
8280 case OP_FSIN:
fe18df39 8281 fprintf(fout, " %s = sin%s(%s);", float_st0,
8282 need_double ? "" : "f", float_st0);
497a6d6b 8283 break;
8284
8285 case OP_FSQRT:
fe18df39 8286 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
8287 need_double ? "" : "f", float_st0);
8288 break;
8289
8290 case OP_FXCH:
8291 dead_dst = po->operand[0].type == OPT_REG
8292 && po->operand[0].reg == xST0;
8293 if (!dead_dst) {
8294 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8295 need_float_stack);
8296 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
8297 float_st0, float_st0, buf1, buf1);
8298 strcat(g_comment, " fxch");
8299 }
8300 else
8301 no_output = 1;
497a6d6b 8302 break;
8303
d4a985bd 8304 case OPP_FTOL:
8305 ferr_assert(po, po->flags & OPF_32BIT);
fe18df39 8306 fprintf(fout, " eax = (s32)%s;", float_st0);
8307 if (po->flags & OPF_FSHIFT) {
8308 if (need_float_stack)
8309 fprintf(fout, " f_stp++;");
8310 else
8311 fprintf(fout, " f_st0 = f_st1;");
8312 }
d4a985bd 8313 strcat(g_comment, " ftol");
8314 break;
8315
8c83cc48 8316 case OPP_CIPOW:
8317 if (need_float_stack) {
8318 fprintf(fout, " %s = pow%s(%s, %s);", float_st1,
8319 need_double ? "" : "f", float_st1, float_st0);
8320 fprintf(fout, " f_stp++;");
8321 }
8322 else {
8323 fprintf(fout, " f_st0 = pow%s(f_st1, f_st0);",
8324 need_double ? "" : "f");
8325 }
8326 strcat(g_comment, " CIpow");
8327 break;
8328
11437ea1 8329 case OPP_ABORT:
8330 fprintf(fout, " do_skip_code_abort();");
8331 break;
8332
90307a99 8333 // mmx
8334 case OP_EMMS:
11437ea1 8335 fprintf(fout, " do_emms();");
90307a99 8336 break;
8337
91977a1c 8338 default:
8339 no_output = 1;
69a3cdfc 8340 ferr(po, "unhandled op type %d, flags %x\n",
8341 po->op, po->flags);
91977a1c 8342 break;
8343 }
8344
8345 if (g_comment[0] != 0) {
ddaf8bd7 8346 char *p = g_comment;
8347 while (my_isblank(*p))
8348 p++;
8349 fprintf(fout, " // %s", p);
91977a1c 8350 g_comment[0] = 0;
8351 no_output = 0;
8352 }
8353 if (!no_output)
8354 fprintf(fout, "\n");
5101a5f9 8355
2b43685d 8356 // some sanity checking
591721d7 8357 if (po->flags & OPF_REP) {
8358 if (po->op != OP_STOS && po->op != OP_MOVS
8359 && po->op != OP_CMPS && po->op != OP_SCAS)
8360 ferr(po, "unexpected rep\n");
8361 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
8362 && (po->op == OP_CMPS || po->op == OP_SCAS))
8363 ferr(po, "cmps/scas with plain rep\n");
8364 }
8365 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
8366 && po->op != OP_CMPS && po->op != OP_SCAS)
2b43685d 8367 ferr(po, "unexpected repz/repnz\n");
8368
940e8e66 8369 if (pfomask != 0)
7ba45c34 8370 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
940e8e66 8371
193c11bf 8372 if ((po->flags & OPF_LOCK) && !lock_handled)
8373 ferr(po, "unhandled lock\n");
8374
5101a5f9 8375 // see is delayed flag stuff is still valid
8376 if (delayed_flag_op != NULL && delayed_flag_op != po) {
89ff3147 8377 if (is_any_opr_modified(delayed_flag_op, po, 0))
5101a5f9 8378 delayed_flag_op = NULL;
8379 }
8380
8381 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
8382 if (is_opr_modified(last_arith_dst, po))
8383 last_arith_dst = NULL;
8384 }
3ebea2cf 8385
2c31fb4c 8386 if (!no_output)
8387 label_pending = 0;
91977a1c 8388 }
8389
a2c1d768 8390 if (g_stack_fsz && !g_stack_frame_used)
8391 fprintf(fout, " (void)sf;\n");
8392
91977a1c 8393 fprintf(fout, "}\n\n");
8394
9af2d373 8395 gen_x_cleanup(opcnt);
8396}
8397
8398static void gen_x_cleanup(int opcnt)
8399{
8400 int i;
8401
91977a1c 8402 for (i = 0; i < opcnt; i++) {
4c45fa73 8403 struct label_ref *lr, *lr_del;
8404
8405 lr = g_label_refs[i].next;
8406 while (lr != NULL) {
8407 lr_del = lr;
8408 lr = lr->next;
8409 free(lr_del);
8410 }
8411 g_label_refs[i].i = -1;
8412 g_label_refs[i].next = NULL;
8413
91977a1c 8414 if (ops[i].op == OP_CALL) {
092f64e1 8415 if (ops[i].pp)
8416 proto_release(ops[i].pp);
91977a1c 8417 }
8418 }
bd96f656 8419 g_func_pp = NULL;
91977a1c 8420}
c36e914d 8421
92d715b6 8422struct func_proto_dep;
8423
8424struct func_prototype {
8425 char name[NAMELEN];
8426 int id;
8427 int argc_stack;
427da1c9 8428 int regmask_dep; // likely register args
8429 int regmask_use; // used registers
91ca764a 8430 int has_ret:3; // -1, 0, 1: unresolved, no, yes
427da1c9 8431 unsigned int has_ret64:1;
92d715b6 8432 unsigned int dep_resolved:1;
8433 unsigned int is_stdcall:1;
087ced53 8434 unsigned int eax_pass:1; // returns without touching eax
615dbae1 8435 unsigned int ptr_taken:1; // pointer taken of this func
92d715b6 8436 struct func_proto_dep *dep_func;
8437 int dep_func_cnt;
91ca764a 8438 const struct parsed_proto *pp; // seed pp, if any
92d715b6 8439};
8440
8441struct func_proto_dep {
8442 char *name;
8443 struct func_prototype *proto;
8444 int regmask_live; // .. at the time of call
8445 unsigned int ret_dep:1; // return from this is caller's return
427da1c9 8446 unsigned int has_ret:1; // found from eax use after return
8447 unsigned int has_ret64:1;
615dbae1 8448 unsigned int ptr_taken:1; // pointer taken, not a call
92d715b6 8449};
8450
8451static struct func_prototype *hg_fp;
8452static int hg_fp_cnt;
8453
5fa1256f 8454static struct scanned_var {
8455 char name[NAMELEN];
8456 enum opr_lenmod lmod;
8457 unsigned int is_seeded:1;
61e29183 8458 unsigned int is_c_str:1;
c0de9015 8459 const struct parsed_proto *pp; // seed pp, if any
5fa1256f 8460} *hg_vars;
8461static int hg_var_cnt;
8462
8c999988 8463static char **hg_refs;
8464static int hg_ref_cnt;
8465
9af2d373 8466static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8467 int count);
8468
8c999988 8469static struct func_prototype *hg_fp_add(const char *funcn)
ebc4dc43 8470{
8471 struct func_prototype *fp;
8472
8473 if ((hg_fp_cnt & 0xff) == 0) {
8474 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
8475 my_assert_not(hg_fp, NULL);
8476 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
8477 }
8478
8479 fp = &hg_fp[hg_fp_cnt];
8480 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
8481 fp->id = hg_fp_cnt;
8482 fp->argc_stack = -1;
8483 hg_fp_cnt++;
8484
8485 return fp;
8486}
8487
92d715b6 8488static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
8489 const char *name)
8490{
8491 int i;
8492
8493 for (i = 0; i < fp->dep_func_cnt; i++)
8494 if (IS(fp->dep_func[i].name, name))
8495 return &fp->dep_func[i];
8496
8497 return NULL;
8498}
8499
615dbae1 8500static void hg_fp_add_dep(struct func_prototype *fp, const char *name,
8501 unsigned int ptr_taken)
92d715b6 8502{
615dbae1 8503 struct func_proto_dep * dep;
8504
92d715b6 8505 // is it a dupe?
615dbae1 8506 dep = hg_fp_find_dep(fp, name);
8507 if (dep != NULL && dep->ptr_taken == ptr_taken)
92d715b6 8508 return;
8509
8510 if ((fp->dep_func_cnt & 0xff) == 0) {
8511 fp->dep_func = realloc(fp->dep_func,
8512 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
8513 my_assert_not(fp->dep_func, NULL);
8514 memset(&fp->dep_func[fp->dep_func_cnt], 0,
8515 sizeof(fp->dep_func[0]) * 0x100);
8516 }
8517 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
615dbae1 8518 fp->dep_func[fp->dep_func_cnt].ptr_taken = ptr_taken;
92d715b6 8519 fp->dep_func_cnt++;
8520}
8521
8522static int hg_fp_cmp_name(const void *p1_, const void *p2_)
8523{
8524 const struct func_prototype *p1 = p1_, *p2 = p2_;
8525 return strcmp(p1->name, p2->name);
8526}
8527
8528#if 0
8529static int hg_fp_cmp_id(const void *p1_, const void *p2_)
8530{
8531 const struct func_prototype *p1 = p1_, *p2 = p2_;
8532 return p1->id - p2->id;
8533}
8534#endif
8535
8c999988 8536static void hg_ref_add(const char *name)
8537{
8538 if ((hg_ref_cnt & 0xff) == 0) {
8539 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
8540 my_assert_not(hg_refs, NULL);
8541 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
8542 }
8543
8544 hg_refs[hg_ref_cnt] = strdup(name);
8545 my_assert_not(hg_refs[hg_ref_cnt], NULL);
8546 hg_ref_cnt++;
8547}
8548
91ca764a 8549// recursive register dep pass
8550// - track saved regs (part 2)
8551// - try to figure out arg-regs
8552// - calculate reg deps
8553static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
8554 struct func_prototype *fp, int regmask_save, int regmask_dst,
427da1c9 8555 int *regmask_dep, int *regmask_use, int *has_ret)
91ca764a 8556{
8557 struct func_proto_dep *dep;
8558 struct parsed_op *po;
8559 int from_caller = 0;
91ca764a 8560 int j, l;
8561 int reg;
8562 int ret;
8563
8564 for (; i < opcnt; i++)
8565 {
8566 if (cbits[i >> 3] & (1 << (i & 7)))
8567 return;
8568 cbits[i >> 3] |= (1 << (i & 7));
8569
8570 po = &ops[i];
8571
8572 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
04abc5d6 8573 if (po->flags & OPF_RMD)
8574 continue;
8575
91ca764a 8576 if (po->btj != NULL) {
8577 // jumptable
8578 for (j = 0; j < po->btj->count; j++) {
db63af51 8579 check_i(po, po->btj->d[j].bt_i);
91ca764a 8580 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
427da1c9 8581 regmask_save, regmask_dst, regmask_dep, regmask_use,
8582 has_ret);
91ca764a 8583 }
8584 return;
8585 }
8586
db63af51 8587 check_i(po, po->bt_i);
91ca764a 8588 if (po->flags & OPF_CJMP) {
8589 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
427da1c9 8590 regmask_save, regmask_dst, regmask_dep, regmask_use,
8591 has_ret);
91ca764a 8592 }
8593 else {
8594 i = po->bt_i - 1;
8595 }
8596 continue;
8597 }
8598
8599 if (po->flags & OPF_FARG)
8600 /* (just calculate register deps) */;
8601 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
8602 {
8603 reg = po->operand[0].reg;
b2bd20c0 8604 ferr_assert(po, reg >= 0);
91ca764a 8605
8606 if (po->flags & OPF_RSAVE) {
8607 regmask_save |= 1 << reg;
8608 continue;
8609 }
8610 if (po->flags & OPF_DONE)
8611 continue;
8612
7a3c5555 8613 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2,
8614 reg, 0, 0, 0, 0);
91ca764a 8615 if (ret == 1) {
8616 regmask_save |= 1 << reg;
8617 po->flags |= OPF_RMD;
7a3c5555 8618 scan_for_pop(i + 1, opcnt, i + opcnt * 3,
8619 reg, 0, 0, 0, OPF_RMD);
91ca764a 8620 continue;
8621 }
8622 }
8623 else if (po->flags & OPF_RMD)
8624 continue;
8625 else if (po->op == OP_CALL) {
8626 po->regmask_dst |= 1 << xAX;
8627
8628 dep = hg_fp_find_dep(fp, po->operand[0].name);
e627c4d0 8629 if (dep != NULL) {
91ca764a 8630 dep->regmask_live = regmask_save | regmask_dst;
e627c4d0 8631 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8632 dep->regmask_live |= 1 << xBP;
8633 }
91ca764a 8634 }
8635 else if (po->op == OP_RET) {
8636 if (po->operand_cnt > 0) {
8637 fp->is_stdcall = 1;
8638 if (fp->argc_stack >= 0
8639 && fp->argc_stack != po->operand[0].val / 4)
8640 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
8641 fp->argc_stack = po->operand[0].val / 4;
8642 }
8643 }
8644
427da1c9 8645 if (!fp->eax_pass && (po->flags & OPF_TAIL)) {
91ca764a 8646 if (po->op == OP_CALL) {
8647 j = i;
8648 ret = 1;
8649 }
8650 else {
91ca764a 8651 j = -1;
8652 from_caller = 0;
17ed469e 8653 ret = resolve_origin_reg(i, xAX, i + opcnt * 4, &j, &from_caller);
91ca764a 8654 }
8655
ebc4dc43 8656 if (ret != 1 && from_caller) {
91ca764a 8657 // unresolved eax - probably void func
8658 *has_ret = 0;
087ced53 8659 fp->eax_pass = 1;
91ca764a 8660 }
8661 else {
ebc4dc43 8662 if (j >= 0 && ops[j].op == OP_CALL) {
427da1c9 8663 if (ops[j].pp != NULL && !ops[j].pp->is_unresolved) {
8664 int call_has_ret = !IS(ops[j].pp->ret_type.name, "void");
8665 if (ops[j].pp->is_noreturn) {
8666 // could be some fail path
8667 if (*has_ret == -1)
8668 *has_ret = call_has_ret;
8669 }
8670 else
8671 *has_ret = call_has_ret;
8672 }
8673 else {
8674 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
8675 if (dep != NULL)
8676 dep->ret_dep = 1;
8677 else
8678 *has_ret = 1;
8679 }
91ca764a 8680 }
8681 else
8682 *has_ret = 1;
8683 }
8684 }
8685
8686 l = regmask_save | regmask_dst;
8687 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8688 l |= 1 << xBP;
8689
8690 l = po->regmask_src & ~l;
8691#if 0
8692 if (l)
8693 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
8694 l, regmask_dst, regmask_save, po->flags);
8695#endif
8696 *regmask_dep |= l;
427da1c9 8697 *regmask_use |= (po->regmask_src | po->regmask_dst)
8698 & ~regmask_save;
91ca764a 8699 regmask_dst |= po->regmask_dst;
8700
354f5504 8701 if (po->flags & OPF_TAIL) {
8702 if (!(po->flags & OPF_CC)) // not cond. tailcall
8703 return;
8704 }
91ca764a 8705 }
8706}
8707
92d715b6 8708static void gen_hdr(const char *funcn, int opcnt)
8709{
91ca764a 8710 unsigned char cbits[MAX_OPS / 8];
ebc4dc43 8711 const struct parsed_proto *pp_c;
9af2d373 8712 struct parsed_proto *pp;
92d715b6 8713 struct func_prototype *fp;
427da1c9 8714 struct func_proto_dep *dep;
92d715b6 8715 struct parsed_op *po;
615dbae1 8716 const char *tmpname;
26677139 8717 int regmask_dummy = 0;
91ca764a 8718 int regmask_dep;
427da1c9 8719 int regmask_use;
92d715b6 8720 int max_bp_offset = 0;
91ca764a 8721 int has_ret;
bfacdc83 8722 int i, j, l;
8723 int ret;
92d715b6 8724
ebc4dc43 8725 pp_c = proto_parse(g_fhdr, funcn, 1);
8726 if (pp_c != NULL)
8727 // already in seed, will add to hg_fp later
9af2d373 8728 return;
ebc4dc43 8729
8730 fp = hg_fp_add(funcn);
9af2d373 8731
8732 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
8733 g_stack_frame_used = 0;
ba93cc12 8734 g_seh_size = 0;
9af2d373 8735
92d715b6 8736 // pass1:
66bdb2b0 8737 // - resolve all branches
8738 // - parse calls with labels
8739 resolve_branches_parse_calls(opcnt);
8740
8741 // pass2:
9af2d373 8742 // - handle ebp/esp frame, remove ops related to it
f9327ad4 8743 scan_prologue_epilogue(opcnt, NULL);
9af2d373 8744
66bdb2b0 8745 // pass3:
8746 // - remove dead labels
92d715b6 8747 // - collect calls
615dbae1 8748 // - collect function ptr refs
92d715b6 8749 for (i = 0; i < opcnt; i++)
8750 {
66bdb2b0 8751 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8752 free(g_labels[i]);
8753 g_labels[i] = NULL;
8754 }
92d715b6 8755
66bdb2b0 8756 po = &ops[i];
5e49b270 8757 if (po->flags & (OPF_RMD|OPF_DONE))
92d715b6 8758 continue;
8759
8760 if (po->op == OP_CALL) {
66bdb2b0 8761 if (po->operand[0].type == OPT_LABEL)
615dbae1 8762 hg_fp_add_dep(fp, opr_name(po, 0), 0);
66bdb2b0 8763 else if (po->pp != NULL)
615dbae1 8764 hg_fp_add_dep(fp, po->pp->name, 0);
8765 }
8766 else if (po->op == OP_MOV && po->operand[1].type == OPT_OFFSET) {
8767 tmpname = opr_name(po, 1);
8768 if (IS_START(tmpname, "p_") || IS_START(tmpname, "sub_"))
8769 hg_fp_add_dep(fp, tmpname, 1);
8770 }
8771 else if (po->op == OP_PUSH && po->operand[0].type == OPT_OFFSET) {
8772 tmpname = opr_name(po, 0);
8773 if (IS_START(tmpname, "p_") || IS_START(tmpname, "sub_"))
8774 hg_fp_add_dep(fp, tmpname, 1);
92d715b6 8775 }
92d715b6 8776 }
8777
66bdb2b0 8778 // pass4:
9af2d373 8779 // - handle push <const>/pop pairs
92d715b6 8780 for (i = 0; i < opcnt; i++)
8781 {
91ca764a 8782 po = &ops[i];
8783 if (po->flags & (OPF_RMD|OPF_DONE))
8784 continue;
8785
8786 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
e83ea7ed 8787 scan_for_pop_const(i, opcnt, i + opcnt * 13);
91ca764a 8788 }
8789
66bdb2b0 8790 // pass5:
91ca764a 8791 // - process trivial calls
8792 for (i = 0; i < opcnt; i++)
8793 {
9af2d373 8794 po = &ops[i];
5e49b270 8795 if (po->flags & (OPF_RMD|OPF_DONE))
9af2d373 8796 continue;
8797
26677139 8798 if (po->op == OP_CALL)
8799 {
8800 pp = process_call_early(i, opcnt, &j);
8801 if (pp != NULL) {
8802 if (!(po->flags & OPF_ATAIL))
8803 // since we know the args, try to collect them
17ed469e 8804 if (collect_call_args_early(i, opcnt, pp, NULL, NULL) != 0)
26677139 8805 pp = NULL;
8806 }
8807
8808 if (pp != NULL) {
8809 if (j >= 0) {
8810 // commit esp adjust
5e49b270 8811 if (ops[j].op != OP_POP)
8812 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
bfacdc83 8813 else {
8814 for (l = 0; l < pp->argc_stack; l++)
b2bd20c0 8815 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
bfacdc83 8816 }
26677139 8817 }
8818
8819 po->flags |= OPF_DONE;
8820 }
8821 }
26677139 8822 }
8823
66bdb2b0 8824 // pass6:
5e49b270 8825 // - track saved regs (simple)
26677139 8826 // - process calls
8827 for (i = 0; i < opcnt; i++)
8828 {
8829 po = &ops[i];
5e49b270 8830 if (po->flags & (OPF_RMD|OPF_DONE))
26677139 8831 continue;
8832
e83ea7ed 8833 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
8834 && po->operand[0].reg != xCX)
5e49b270 8835 {
e83ea7ed 8836 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
b2bd20c0 8837 if (ret == 1) {
91ca764a 8838 // regmask_save |= 1 << po->operand[0].reg; // do it later
8839 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
e83ea7ed 8840 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
5e49b270 8841 }
8842 }
e83ea7ed 8843 else if (po->op == OP_CALL)
26677139 8844 {
9af2d373 8845 pp = process_call(i, opcnt);
8846
8847 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
9af2d373 8848 // since we know the args, collect them
17ed469e 8849 ret = collect_call_args(po, i, opcnt, pp, &regmask_dummy,
8c83cc48 8850 i + opcnt * 1);
9af2d373 8851 }
427da1c9 8852 if (!(po->flags & OPF_TAIL)
8853 && po->operand[0].type == OPT_LABEL)
8854 {
8855 dep = hg_fp_find_dep(fp, opr_name(po, 0));
8856 ferr_assert(po, dep != NULL);
8857 // treat al write as overwrite to avoid many false positives
8858 find_next_read_reg(i + 1, opcnt, xAX, OPLM_BYTE,
8859 i + opcnt * 25, &j);
8860 if (j != -1)
8861 dep->has_ret = 1;
8862 find_next_read_reg(i + 1, opcnt, xDX, OPLM_BYTE,
8863 i + opcnt * 26, &j);
8864 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j]))
8865 dep->has_ret64 = 1;
8866 }
9af2d373 8867 }
92d715b6 8868 }
8869
66bdb2b0 8870 // pass7
354f5504 8871 memset(cbits, 0, (opcnt + 7) / 8);
427da1c9 8872 regmask_dep = regmask_use = 0;
91ca764a 8873 has_ret = -1;
8874
427da1c9 8875 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0,
8876 &regmask_dep, &regmask_use, &has_ret);
91ca764a 8877
8878 // find unreachable code - must be fixed in IDA
92d715b6 8879 for (i = 0; i < opcnt; i++)
8880 {
91ca764a 8881 if (cbits[i >> 3] & (1 << (i & 7)))
9af2d373 8882 continue;
92d715b6 8883
04abc5d6 8884 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
8885 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
8886 {
8887 // the compiler sometimes still generates code after
8888 // noreturn OS functions
8889 break;
8890 }
0a2c6da1 8891 if (!(ops[i].flags & OPF_RMD)
8892 && ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
8893 {
91ca764a 8894 ferr(&ops[i], "unreachable code\n");
0a2c6da1 8895 }
92d715b6 8896 }
8897
9af2d373 8898 for (i = 0; i < g_eqcnt; i++) {
92d715b6 8899 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
8900 max_bp_offset = g_eqs[i].offset;
9af2d373 8901 }
92d715b6 8902
9af2d373 8903 if (fp->argc_stack < 0) {
92d715b6 8904 max_bp_offset = (max_bp_offset + 3) & ~3;
9af2d373 8905 fp->argc_stack = max_bp_offset / 4;
8906 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
92d715b6 8907 fp->argc_stack--;
8908 }
8909
622eb2ef 8910 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
427da1c9 8911 fp->regmask_use = regmask_use;
92d715b6 8912 fp->has_ret = has_ret;
91ca764a 8913#if 0
8914 printf("// has_ret %d, regmask_dep %x\n",
8915 fp->has_ret, fp->regmask_dep);
8916 output_hdr_fp(stdout, fp, 1);
ebc4dc43 8917 if (IS(funcn, "sub_10007F72")) exit(1);
91ca764a 8918#endif
9af2d373 8919
8920 gen_x_cleanup(opcnt);
92d715b6 8921}
8922
8923static void hg_fp_resolve_deps(struct func_prototype *fp)
8924{
8925 struct func_prototype fp_s;
427da1c9 8926 struct func_proto_dep *dep;
8927 int regmask_dep;
92d715b6 8928 int i;
8929
8930 // this thing is recursive, so mark first..
8931 fp->dep_resolved = 1;
8932
8933 for (i = 0; i < fp->dep_func_cnt; i++) {
427da1c9 8934 dep = &fp->dep_func[i];
8935
8936 strcpy(fp_s.name, dep->name);
8937 dep->proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
92d715b6 8938 sizeof(hg_fp[0]), hg_fp_cmp_name);
427da1c9 8939 if (dep->proto != NULL) {
615dbae1 8940 if (dep->ptr_taken) {
8941 dep->proto->ptr_taken = 1;
8942 continue;
8943 }
8944
427da1c9 8945 if (!dep->proto->dep_resolved)
8946 hg_fp_resolve_deps(dep->proto);
92d715b6 8947
427da1c9 8948 regmask_dep = ~dep->regmask_live
8949 & dep->proto->regmask_dep;
8950 fp->regmask_dep |= regmask_dep;
91ca764a 8951 // printf("dep %s %s |= %x\n", fp->name,
427da1c9 8952 // fp->dep_func[i].name, regmask_dep);
92d715b6 8953
427da1c9 8954 if (dep->has_ret && (dep->proto->regmask_use & mxAX))
8955 dep->proto->has_ret = 1;
8956 if (dep->has_ret64 && (dep->proto->regmask_use & mxDX))
8957 dep->proto->has_ret64 = 1;
8958 if (fp->has_ret == -1 && dep->ret_dep)
8959 fp->has_ret = dep->proto->has_ret;
92d715b6 8960 }
8961 }
8962}
8963
8c999988 8964// make all thiscall/edx arg functions referenced from .data fastcall
8965static void do_func_refs_from_data(void)
8966{
8967 struct func_prototype *fp, fp_s;
8968 int i;
8969
8970 for (i = 0; i < hg_ref_cnt; i++) {
8971 strcpy(fp_s.name, hg_refs[i]);
8972 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8973 sizeof(hg_fp[0]), hg_fp_cmp_name);
615dbae1 8974 if (fp != NULL)
8975 fp->ptr_taken = 1;
8c999988 8976 }
8977}
8978
9af2d373 8979static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8980 int count)
92d715b6 8981{
61e29183 8982 const struct parsed_proto *pp;
8983 char *p, namebuf[NAMELEN];
8984 const char *name;
92d715b6 8985 int regmask_dep;
226e8df1 8986 int argc_normal;
9af2d373 8987 int j, arg;
92d715b6 8988
9af2d373 8989 for (; count > 0; count--, fp++) {
92d715b6 8990 if (fp->has_ret == -1)
8991 fprintf(fout, "// ret unresolved\n");
8992#if 0
8993 fprintf(fout, "// dep:");
8994 for (j = 0; j < fp->dep_func_cnt; j++) {
8995 fprintf(fout, " %s/", fp->dep_func[j].name);
8996 if (fp->dep_func[j].proto != NULL)
8997 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8998 fp->dep_func[j].proto->has_ret);
8999 }
9000 fprintf(fout, "\n");
9001#endif
9002
61e29183 9003 p = strchr(fp->name, '@');
9004 if (p != NULL) {
9005 memcpy(namebuf, fp->name, p - fp->name);
9006 namebuf[p - fp->name] = 0;
9007 name = namebuf;
9008 }
9009 else
9010 name = fp->name;
9011 if (name[0] == '_')
9012 name++;
9013
9014 pp = proto_parse(g_fhdr, name, 1);
9015 if (pp != NULL && pp->is_include)
9016 continue;
9017
c0de9015 9018 if (fp->pp != NULL) {
4e81a3a2 9019 // part of seed, output later
9020 continue;
c0de9015 9021 }
9022
92d715b6 9023 regmask_dep = fp->regmask_dep;
226e8df1 9024 argc_normal = fp->argc_stack;
615dbae1 9025 if (fp->ptr_taken && regmask_dep
9026 && (regmask_dep & ~(mxCX|mxDX)) == 0)
9027 {
9028 if ((regmask_dep & mxDX) || fp->argc_stack > 0)
9029 regmask_dep |= mxCX | mxDX;
9030 }
92d715b6 9031
427da1c9 9032 fprintf(fout, "%-5s",
9033 fp->pp ? fp->pp->ret_type.name :
9034 fp->has_ret64 ? "__int64" :
9035 fp->has_ret ? "int" : "void");
226e8df1 9036 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
9037 && (regmask_dep & ~mxCX) == 0)
9038 {
9039 fprintf(fout, "/*__thiscall*/ ");
9040 argc_normal++;
9041 regmask_dep = 0;
9042 }
236c23eb 9043 else if ((regmask_dep == (mxCX | mxDX)
9044 && (fp->is_stdcall || fp->argc_stack == 0))
9045 || (regmask_dep == mxCX && fp->argc_stack == 0))
92d715b6 9046 {
9af2d373 9047 fprintf(fout, " __fastcall ");
226e8df1 9048 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
9049 argc_normal = 1;
92d715b6 9050 else
226e8df1 9051 argc_normal += 2;
92d715b6 9052 regmask_dep = 0;
9053 }
9054 else if (regmask_dep && !fp->is_stdcall) {
9055 fprintf(fout, "/*__usercall*/ ");
92d715b6 9056 }
9057 else if (regmask_dep) {
9058 fprintf(fout, "/*__userpurge*/ ");
92d715b6 9059 }
9060 else if (fp->is_stdcall)
9af2d373 9061 fprintf(fout, " __stdcall ");
92d715b6 9062 else
9af2d373 9063 fprintf(fout, " __cdecl ");
92d715b6 9064
61e29183 9065 fprintf(fout, "%s(", name);
92d715b6 9066
9067 arg = 0;
9068 for (j = 0; j < xSP; j++) {
9069 if (regmask_dep & (1 << j)) {
9070 arg++;
9071 if (arg != 1)
9072 fprintf(fout, ", ");
91ca764a 9073 if (fp->pp != NULL)
9074 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
9075 else
9076 fprintf(fout, "int");
9077 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
92d715b6 9078 }
9079 }
9080
226e8df1 9081 for (j = 0; j < argc_normal; j++) {
92d715b6 9082 arg++;
9083 if (arg != 1)
9084 fprintf(fout, ", ");
91ca764a 9085 if (fp->pp != NULL) {
9086 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
9087 if (!fp->pp->arg[arg - 1].type.is_ptr)
9088 fprintf(fout, " ");
9089 }
9090 else
9091 fprintf(fout, "int ");
9092 fprintf(fout, "a%d", arg);
92d715b6 9093 }
9094
9095 fprintf(fout, ");\n");
9096 }
9097}
9098
9af2d373 9099static void output_hdr(FILE *fout)
9100{
5fa1256f 9101 static const char *lmod_c_names[] = {
9102 [OPLM_UNSPEC] = "???",
9103 [OPLM_BYTE] = "uint8_t",
9104 [OPLM_WORD] = "uint16_t",
9105 [OPLM_DWORD] = "uint32_t",
9106 [OPLM_QWORD] = "uint64_t",
9107 };
9108 const struct scanned_var *var;
ebc4dc43 9109 struct func_prototype *fp;
c0de9015 9110 char line[256] = { 0, };
ebc4dc43 9111 char name[256];
9af2d373 9112 int i;
9113
ebc4dc43 9114 // add stuff from headers
9115 for (i = 0; i < pp_cache_size; i++) {
9116 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
9117 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
9118 else
9119 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
9120 fp = hg_fp_add(name);
9121 fp->pp = &pp_cache[i];
9122 fp->argc_stack = fp->pp->argc_stack;
9123 fp->is_stdcall = fp->pp->is_stdcall;
b2bd20c0 9124 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
ebc4dc43 9125 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
9126 }
9127
9af2d373 9128 // resolve deps
9129 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
9130 for (i = 0; i < hg_fp_cnt; i++)
9131 hg_fp_resolve_deps(&hg_fp[i]);
9132
8c999988 9133 // adjust functions referenced from data segment
9134 do_func_refs_from_data();
9135
087ced53 9136 // final adjustments
9137 for (i = 0; i < hg_fp_cnt; i++) {
9138 if (hg_fp[i].eax_pass && (hg_fp[i].regmask_dep & mxAX))
9139 hg_fp[i].has_ret = 1;
9140 }
9141
9af2d373 9142 // note: messes up .proto ptr, don't use
9143 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
9144
5fa1256f 9145 // output variables
9146 for (i = 0; i < hg_var_cnt; i++) {
9147 var = &hg_vars[i];
9148
4e81a3a2 9149 if (var->pp != NULL)
9150 // part of seed
9151 continue;
c0de9015 9152 else if (var->is_c_str)
61e29183 9153 fprintf(fout, "extern %-8s %s[];", "char", var->name);
9154 else
9155 fprintf(fout, "extern %-8s %s;",
9156 lmod_c_names[var->lmod], var->name);
5fa1256f 9157
9158 if (var->is_seeded)
9159 fprintf(fout, " // seeded");
9160 fprintf(fout, "\n");
9161 }
9162
9163 fprintf(fout, "\n");
9164
9165 // output function prototypes
9af2d373 9166 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
c0de9015 9167
4e81a3a2 9168 // seed passthrough
9169 fprintf(fout, "\n// - seed -\n");
c0de9015 9170
9171 rewind(g_fhdr);
4e81a3a2 9172 while (fgets(line, sizeof(line), g_fhdr))
9173 fwrite(line, 1, strlen(line), fout);
9af2d373 9174}
9175
61e29183 9176// '=' needs special treatment
9177// also ' quote
bfa4a6ee 9178static char *next_word_s(char *w, size_t wsize, char *s)
9179{
61e29183 9180 size_t i;
bfa4a6ee 9181
61e29183 9182 s = sskip(s);
bfa4a6ee 9183
61e29183 9184 i = 0;
8c999988 9185 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
61e29183 9186 w[0] = s[0];
9187 for (i = 1; i < wsize - 1; i++) {
9188 if (s[i] == 0) {
9189 printf("warning: missing closing quote: \"%s\"\n", s);
9190 break;
9191 }
9192 if (s[i] == '\'')
9193 break;
9194 w[i] = s[i];
9195 }
9196 }
bfa4a6ee 9197
61e29183 9198 for (; i < wsize - 1; i++) {
9199 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
9200 break;
9201 w[i] = s[i];
9202 }
9203 w[i] = 0;
9204
9205 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
9206 printf("warning: '%s' truncated\n", w);
bfa4a6ee 9207
61e29183 9208 return s + i;
bfa4a6ee 9209}
9210
4c20744d 9211static int cmpstringp(const void *p1, const void *p2)
9212{
9213 return strcmp(*(char * const *)p1, *(char * const *)p2);
9214}
9215
9216static int is_xref_needed(char *p, char **rlist, int rlist_len)
9217{
9218 char *p2;
9219
9220 p = sskip(p);
9221 if (strstr(p, "..."))
9222 // unable to determine, assume needed
9223 return 1;
9224
9225 if (*p == '.') // .text, .data, ...
9226 // ref from other data or non-function -> no
9227 return 0;
9228
9229 p2 = strpbrk(p, "+:\r\n\x18");
9230 if (p2 != NULL)
9231 *p2 = 0;
9232 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9233 // referenced from removed code
9234 return 0;
9235
9236 return 1;
9237}
9238
8c999988 9239static int ida_xrefs_show_need(FILE *fasm, char *p,
4c20744d 9240 char **rlist, int rlist_len)
9241{
9242 int found_need = 0;
9243 char line[256];
9244 long pos;
9245
9246 p = strrchr(p, ';');
ea43585b 9247 if (p != NULL && *p == ';') {
9248 if (IS_START(p + 2, "sctref"))
4c20744d 9249 return 1;
ea43585b 9250 if (IS_START(p + 2, "DATA XREF: ")) {
9251 p += 13;
9252 if (is_xref_needed(p, rlist, rlist_len))
9253 return 1;
9254 }
4c20744d 9255 }
9256
9257 pos = ftell(fasm);
9258 while (1)
9259 {
9260 if (!my_fgets(line, sizeof(line), fasm))
9261 break;
9262 // non-first line is always indented
9263 if (!my_isblank(line[0]))
9264 break;
9265
9266 // should be no content, just comment
9267 p = sskip(line);
9268 if (*p != ';')
9269 break;
9270
9271 p = strrchr(p, ';');
9272 p += 2;
ea43585b 9273
9274 if (IS_START(p, "sctref")) {
9275 found_need = 1;
9276 break;
9277 }
9278
4c20744d 9279 // it's printed once, but no harm to check again
9280 if (IS_START(p, "DATA XREF: "))
9281 p += 11;
9282
9283 if (is_xref_needed(p, rlist, rlist_len)) {
9284 found_need = 1;
9285 break;
9286 }
9287 }
9288 fseek(fasm, pos, SEEK_SET);
9289 return found_need;
9290}
9291
9292static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
5fa1256f 9293{
5fa1256f 9294 struct scanned_var *var;
9295 char line[256] = { 0, };
8c999988 9296 char words[4][256];
9297 int no_identifier;
5fa1256f 9298 char *p = NULL;
9299 int wordc;
61e29183 9300 int l;
5fa1256f 9301
9302 while (!feof(fasm))
9303 {
9304 // skip to next data section
9305 while (my_fgets(line, sizeof(line), fasm))
9306 {
9307 asmln++;
9308
9309 p = sskip(line);
9310 if (*p == 0 || *p == ';')
9311 continue;
9312
9313 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
9314 if (*p == 0 || *p == ';')
9315 continue;
9316
9317 if (*p != 's' || !IS_START(p, "segment para public"))
9318 continue;
9319
9320 break;
9321 }
9322
9323 if (p == NULL || !IS_START(p, "segment para public"))
9324 break;
9325 p = sskip(p + 19);
9326
9327 if (!IS_START(p, "'DATA'"))
9328 continue;
9329
9330 // now process it
9331 while (my_fgets(line, sizeof(line), fasm))
9332 {
9333 asmln++;
9334
9335 p = line;
8c999988 9336 no_identifier = my_isblank(*p);
5fa1256f 9337
9338 p = sskip(p);
9339 if (*p == 0 || *p == ';')
9340 continue;
9341
9342 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9343 words[wordc][0] = 0;
9344 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9345 if (*p == 0 || *p == ';') {
9346 wordc++;
9347 break;
9348 }
9349 }
9350
9351 if (wordc == 2 && IS(words[1], "ends"))
9352 break;
61e29183 9353 if (wordc < 2)
9354 continue;
5fa1256f 9355
8c999988 9356 if (no_identifier) {
9357 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
9358 hg_ref_add(words[2]);
9359 continue;
9360 }
9361
9ea60b8d 9362 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
9363 // when this starts, we don't need anything from this section
9364 break;
9365 }
9366
4c20744d 9367 // check refs comment(s)
8c999988 9368 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
4c20744d 9369 continue;
9370
5fa1256f 9371 if ((hg_var_cnt & 0xff) == 0) {
9372 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
9373 * (hg_var_cnt + 0x100));
9374 my_assert_not(hg_vars, NULL);
9375 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
9376 }
9377
9378 var = &hg_vars[hg_var_cnt++];
9379 snprintf(var->name, sizeof(var->name), "%s", words[0]);
9380
9381 // maybe already in seed header?
c0de9015 9382 var->pp = proto_parse(g_fhdr, var->name, 1);
9383 if (var->pp != NULL) {
9384 if (var->pp->is_fptr) {
5fa1256f 9385 var->lmod = OPLM_DWORD;
9386 //var->is_ptr = 1;
9387 }
c0de9015 9388 else if (var->pp->is_func)
9389 aerr("func?\n");
9390 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
5fa1256f 9391 aerr("unhandled C type '%s' for '%s'\n",
c0de9015 9392 var->pp->type.name, var->name);
5fa1256f 9393
9394 var->is_seeded = 1;
9395 continue;
9396 }
9397
8c999988 9398 if (IS(words[1], "dd")) {
5fa1256f 9399 var->lmod = OPLM_DWORD;
8c999988 9400 if (wordc >= 4 && IS(words[2], "offset"))
9401 hg_ref_add(words[3]);
9402 }
5fa1256f 9403 else if (IS(words[1], "dw"))
9404 var->lmod = OPLM_WORD;
61e29183 9405 else if (IS(words[1], "db")) {
5fa1256f 9406 var->lmod = OPLM_BYTE;
61e29183 9407 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
9408 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
9409 var->is_c_str = 1;
9410 }
9411 }
5fa1256f 9412 else if (IS(words[1], "dq"))
9413 var->lmod = OPLM_QWORD;
9414 //else if (IS(words[1], "dt"))
9415 else
9416 aerr("type '%s' not known\n", words[1]);
9417 }
9418 }
9419
9420 rewind(fasm);
9421 asmln = 0;
9422}
9423
9424static void set_label(int i, const char *name)
9425{
9426 const char *p;
9427 int len;
9428
9429 len = strlen(name);
9430 p = strchr(name, ':');
9431 if (p != NULL)
9432 len = p - name;
9433
9434 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
9435 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
9436 g_labels[i] = realloc(g_labels[i], len + 1);
9437 my_assert_not(g_labels[i], NULL);
9438 memcpy(g_labels[i], name, len);
9439 g_labels[i][len] = 0;
9440}
9441
e56ab892 9442struct chunk_item {
9443 char *name;
9444 long fptr;
de50b98b 9445 int asmln;
e56ab892 9446};
9447
cdfaeed7 9448static struct chunk_item *func_chunks;
9449static int func_chunk_cnt;
9450static int func_chunk_alloc;
9451
9452static void add_func_chunk(FILE *fasm, const char *name, int line)
9453{
9454 if (func_chunk_cnt >= func_chunk_alloc) {
9455 func_chunk_alloc *= 2;
9456 func_chunks = realloc(func_chunks,
9457 func_chunk_alloc * sizeof(func_chunks[0]));
9458 my_assert_not(func_chunks, NULL);
9459 }
9460 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
9461 func_chunks[func_chunk_cnt].name = strdup(name);
9462 func_chunks[func_chunk_cnt].asmln = line;
9463 func_chunk_cnt++;
9464}
9465
e56ab892 9466static int cmp_chunks(const void *p1, const void *p2)
9467{
9468 const struct chunk_item *c1 = p1, *c2 = p2;
9469 return strcmp(c1->name, c2->name);
9470}
9471
ea43585b 9472static void scan_ahead_for_chunks(FILE *fasm)
cdfaeed7 9473{
9474 char words[2][256];
9475 char line[256];
9476 long oldpos;
9477 int oldasmln;
9478 int wordc;
9479 char *p;
9480 int i;
9481
9482 oldpos = ftell(fasm);
9483 oldasmln = asmln;
9484
5fa1256f 9485 while (my_fgets(line, sizeof(line), fasm))
cdfaeed7 9486 {
9487 wordc = 0;
9488 asmln++;
9489
9490 p = sskip(line);
9491 if (*p == 0)
9492 continue;
9493
9494 if (*p == ';')
9495 {
9496 // get rid of random tabs
9497 for (i = 0; line[i] != 0; i++)
9498 if (line[i] == '\t')
9499 line[i] = ' ';
9500
9501 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9502 {
9503 p += 30;
9504 next_word(words[0], sizeof(words[0]), p);
9505 if (words[0][0] == 0)
9506 aerr("missing name for func chunk?\n");
9507
9508 add_func_chunk(fasm, words[0], asmln);
9509 }
46b388c2 9510 else if (IS_START(p, "; sctend"))
9511 break;
9512
cdfaeed7 9513 continue;
9514 } // *p == ';'
9515
9516 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9517 words[wordc][0] = 0;
9518 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9519 if (*p == 0 || *p == ';') {
9520 wordc++;
9521 break;
9522 }
9523 }
9524
9525 if (wordc == 2 && IS(words[1], "ends"))
9526 break;
9527 }
9528
9529 fseek(fasm, oldpos, SEEK_SET);
9530 asmln = oldasmln;
9531}
9532
91977a1c 9533int main(int argc, char *argv[])
9534{
06c5d854 9535 FILE *fout, *fasm, *frlist;
4c45fa73 9536 struct parsed_data *pd = NULL;
9537 int pd_alloc = 0;
9538 char **rlist = NULL;
9539 int rlist_len = 0;
9540 int rlist_alloc = 0;
e56ab892 9541 int func_chunks_used = 0;
9542 int func_chunks_sorted = 0;
e56ab892 9543 int func_chunk_i = -1;
9544 long func_chunk_ret = 0;
de50b98b 9545 int func_chunk_ret_ln = 0;
cdfaeed7 9546 int scanned_ahead = 0;
91977a1c 9547 char line[256];
a2c1d768 9548 char words[20][256];
4c45fa73 9549 enum opr_lenmod lmod;
ddaf8bd7 9550 char *sctproto = NULL;
91977a1c 9551 int in_func = 0;
4c45fa73 9552 int pending_endp = 0;
11437ea1 9553 int skip_code = 0;
9554 int skip_code_end = 0;
940e8e66 9555 int skip_warned = 0;
91977a1c 9556 int eq_alloc;
bfa4a6ee 9557 int verbose = 0;
1f84f6b3 9558 int multi_seg = 0;
46b388c2 9559 int end = 0;
bfa4a6ee 9560 int arg_out;
89ff3147 9561 int arg;
91977a1c 9562 int pi = 0;
e56ab892 9563 int i, j;
9564 int ret, len;
087ced53 9565 char *p, *p2;
91977a1c 9566 int wordc;
9567
89ff3147 9568 for (arg = 1; arg < argc; arg++) {
9569 if (IS(argv[arg], "-v"))
9570 verbose = 1;
9571 else if (IS(argv[arg], "-rf"))
9572 g_allow_regfunc = 1;
8c83cc48 9573 else if (IS(argv[arg], "-uc"))
9574 g_allow_user_icall = 1;
615dbae1 9575 else if (IS(argv[arg], "-wu"))
9576 g_nowarn_reguse = 1;
1f84f6b3 9577 else if (IS(argv[arg], "-m"))
9578 multi_seg = 1;
92d715b6 9579 else if (IS(argv[arg], "-hdr"))
9af2d373 9580 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
89ff3147 9581 else
9582 break;
bfa4a6ee 9583 }
9584
9585 if (argc < arg + 3) {
615dbae1 9586 printf("usage:\n%s [options] <.c> <.asm> <hdr.h> [rlist]*\n"
315b77eb 9587 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
9588 "options:\n"
9589 " -hdr - header generation mode\n"
9590 " -rf - allow unannotated indirect calls\n"
8c83cc48 9591 " -uc - allow ind. calls/refs to __usercall\n"
315b77eb 9592 " -m - allow multiple .text sections\n"
615dbae1 9593 " -wu - don't warn about bad reg use\n"
315b77eb 9594 "[rlist] is a file with function names to skip,"
9595 " one per line\n",
92d715b6 9596 argv[0], argv[0]);
91977a1c 9597 return 1;
9598 }
9599
bfa4a6ee 9600 arg_out = arg++;
91977a1c 9601
bfa4a6ee 9602 asmfn = argv[arg++];
91977a1c 9603 fasm = fopen(asmfn, "r");
9604 my_assert_not(fasm, NULL);
9605
bfa4a6ee 9606 hdrfn = argv[arg++];
06c5d854 9607 g_fhdr = fopen(hdrfn, "r");
9608 my_assert_not(g_fhdr, NULL);
bfa4a6ee 9609
9610 rlist_alloc = 64;
9611 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
9612 my_assert_not(rlist, NULL);
9613 // needs special handling..
9614 rlist[rlist_len++] = "__alloca_probe";
9615
e56ab892 9616 func_chunk_alloc = 32;
9617 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
9618 my_assert_not(func_chunks, NULL);
9619
a2c1d768 9620 memset(words, 0, sizeof(words));
9621
bfa4a6ee 9622 for (; arg < argc; arg++) {
11437ea1 9623 int skip_func = 0;
9624
bfa4a6ee 9625 frlist = fopen(argv[arg], "r");
9626 my_assert_not(frlist, NULL);
9627
5fa1256f 9628 while (my_fgets(line, sizeof(line), frlist)) {
bfa4a6ee 9629 p = sskip(line);
1cd4a663 9630 if (*p == 0 || *p == ';')
9631 continue;
9632 if (*p == '#') {
89ff3147 9633 if (IS_START(p, "#if 0")
9634 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
9635 {
1cd4a663 9636 skip_func = 1;
89ff3147 9637 }
1cd4a663 9638 else if (IS_START(p, "#endif"))
9639 skip_func = 0;
9640 continue;
9641 }
9642 if (skip_func)
bfa4a6ee 9643 continue;
9644
9645 p = next_word(words[0], sizeof(words[0]), p);
9646 if (words[0][0] == 0)
9647 continue;
9648
9649 if (rlist_len >= rlist_alloc) {
9650 rlist_alloc = rlist_alloc * 2 + 64;
9651 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
9652 my_assert_not(rlist, NULL);
9653 }
9654 rlist[rlist_len++] = strdup(words[0]);
9655 }
9656
9657 fclose(frlist);
9658 frlist = NULL;
9659 }
9660
9661 if (rlist_len > 0)
9662 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
9663
9664 fout = fopen(argv[arg_out], "w");
91977a1c 9665 my_assert_not(fout, NULL);
9666
9667 eq_alloc = 128;
9668 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
9669 my_assert_not(g_eqs, NULL);
9670
4c45fa73 9671 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
9672 g_label_refs[i].i = -1;
9673 g_label_refs[i].next = NULL;
9674 }
9675
5fa1256f 9676 if (g_header_mode)
4c20744d 9677 scan_variables(fasm, rlist, rlist_len);
5fa1256f 9678
9679 while (my_fgets(line, sizeof(line), fasm))
91977a1c 9680 {
4c45fa73 9681 wordc = 0;
91977a1c 9682 asmln++;
9683
9684 p = sskip(line);
1bafb621 9685 if (*p == 0)
91977a1c 9686 continue;
9687
de50b98b 9688 // get rid of random tabs
9689 for (i = 0; line[i] != 0; i++)
9690 if (line[i] == '\t')
9691 line[i] = ' ';
9692
e56ab892 9693 if (*p == ';')
9694 {
e56ab892 9695 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
9696 goto do_pending_endp; // eww..
9697
9698 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
9699 {
9700 static const char *attrs[] = {
9701 "bp-based frame",
9702 "library function",
9703 "static",
9704 "noreturn",
9705 "thunk",
9706 "fpd=",
9707 };
9708
9709 // parse IDA's attribute-list comment
9710 g_ida_func_attr = 0;
9711 p = sskip(p + 13);
9712
9713 for (; *p != 0; p = sskip(p)) {
9714 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9715 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9716 g_ida_func_attr |= 1 << i;
9717 p += strlen(attrs[i]);
9718 break;
9719 }
9720 }
9721 if (i == ARRAY_SIZE(attrs)) {
9722 anote("unparsed IDA attr: %s\n", p);
1bafb621 9723 break;
9724 }
e56ab892 9725 if (IS(attrs[i], "fpd=")) {
9726 p = next_word(words[0], sizeof(words[0]), p);
9727 // ignore for now..
9728 }
1bafb621 9729 }
e56ab892 9730 }
7e08c224 9731 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
9732 {
9733 static const char *attrs[] = {
9734 "clear_sf",
226e8df1 9735 "clear_regmask",
383dff16 9736 "rm_regmask",
427da1c9 9737 "nowarn",
193c11bf 9738 "argframe",
7e08c224 9739 };
9740
9741 // parse manual attribute-list comment
9742 g_sct_func_attr = 0;
9743 p = sskip(p + 10);
9744
9745 for (; *p != 0; p = sskip(p)) {
9746 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9747 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9748 g_sct_func_attr |= 1 << i;
9749 p += strlen(attrs[i]);
9750 break;
9751 }
9752 }
226e8df1 9753 if (*p == '=') {
9754 j = ret = 0;
9755 if (i == 0)
9756 // clear_sf=start,len (in dwords)
9757 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
9758 &g_stack_clear_len, &j);
9759 else if (i == 1)
9760 // clear_regmask=<mask>
6135d8e6 9761 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
383dff16 9762 else if (i == 2)
9763 // rm_regmask=<mask>
9764 ret = sscanf(p, "=%x%n", &g_regmask_rm, &j) + 1;
7e08c224 9765 if (ret < 2) {
226e8df1 9766 anote("unparsed attr value: %s\n", p);
7e08c224 9767 break;
9768 }
9769 p += j;
9770 }
9771 else if (i == ARRAY_SIZE(attrs)) {
9772 anote("unparsed sct attr: %s\n", p);
9773 break;
9774 }
9775 }
9776 }
e56ab892 9777 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9778 {
9779 p += 30;
9780 next_word(words[0], sizeof(words[0]), p);
9781 if (words[0][0] == 0)
cdfaeed7 9782 aerr("missing name for func chunk?\n");
9783
9784 if (!scanned_ahead) {
9785 add_func_chunk(fasm, words[0], asmln);
9786 func_chunks_sorted = 0;
e56ab892 9787 }
e56ab892 9788 }
9789 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
9790 {
9791 if (func_chunk_i >= 0) {
9792 if (func_chunk_i < func_chunk_cnt
9793 && IS(func_chunks[func_chunk_i].name, g_func))
9794 {
9795 // move on to next chunk
9796 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9797 if (ret)
9798 aerr("seek failed for '%s' chunk #%d\n",
9799 g_func, func_chunk_i);
de50b98b 9800 asmln = func_chunks[func_chunk_i].asmln;
e56ab892 9801 func_chunk_i++;
9802 }
9803 else {
9804 if (func_chunk_ret == 0)
9805 aerr("no return from chunk?\n");
9806 fseek(fasm, func_chunk_ret, SEEK_SET);
de50b98b 9807 asmln = func_chunk_ret_ln;
e56ab892 9808 func_chunk_ret = 0;
9809 pending_endp = 1;
9810 }
1bafb621 9811 }
e56ab892 9812 }
9813 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
9814 func_chunks_used = 1;
9815 p += 20;
9816 if (IS_START(g_func, "sub_")) {
9817 unsigned long addr = strtoul(p, NULL, 16);
9818 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
cdfaeed7 9819 if (addr > f_addr && !scanned_ahead) {
b2bd20c0 9820 //anote("scan_ahead caused by '%s', addr %lx\n",
9821 // g_func, addr);
ea43585b 9822 scan_ahead_for_chunks(fasm);
cdfaeed7 9823 scanned_ahead = 1;
9824 func_chunks_sorted = 0;
9825 }
1bafb621 9826 }
9827 }
9828 continue;
e56ab892 9829 } // *p == ';'
1bafb621 9830
06c5d854 9831parse_words:
a2c1d768 9832 for (i = wordc; i < ARRAY_SIZE(words); i++)
9833 words[i][0] = 0;
cdfaeed7 9834 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
bfa4a6ee 9835 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
91977a1c 9836 if (*p == 0 || *p == ';') {
9837 wordc++;
9838 break;
9839 }
9840 }
a2c1d768 9841 if (*p != 0 && *p != ';')
9842 aerr("too many words\n");
91977a1c 9843
11437ea1 9844 if (skip_code_end) {
9845 skip_code_end = 0;
9846 skip_code = 0;
9847 }
9848
9849 // allow asm patches in comments
ddaf8bd7 9850 if (*p == ';') {
087ced53 9851 // skip IDA's forced non-removable comment
9852 if (!IS_START(p, "; sct") && (p2 = strchr(p + 1, ';')))
9853 p = p2;
9854 }
9855 if (*p == ';' && IS_START(p, "; sct")) {
ddaf8bd7 9856 if (IS_START(p, "; sctpatch:")) {
9857 p = sskip(p + 11);
9858 if (*p == 0 || *p == ';')
9859 continue;
9860 goto parse_words; // lame
9861 }
46b388c2 9862 else if (IS_START(p, "; sctend")) {
9863 end = 1;
9864 if (!pending_endp)
9865 break;
9866 }
eadfb2b6 9867 else if (g_skip_func)
9868 /* ignore remaining attrs */;
9869 else if (IS_START(p, "; sctproto:")) {
9870 sctproto = strdup(p + 11);
9871 }
11437ea1 9872 else if (IS_START(p, "; sctskip_start")) {
eadfb2b6 9873 if (in_func) {
11437ea1 9874 if (!skip_code) {
9875 ops[pi].op = OPP_ABORT;
9876 ops[pi].asmln = asmln;
9877 pi++;
9878 }
9879 skip_code = 1;
9880 }
9881 }
9882 else if (IS_START(p, "; sctskip_end")) {
9883 if (skip_code)
9884 skip_code_end = 1;
9885 }
06c5d854 9886 }
9887
91977a1c 9888 if (wordc == 0) {
9889 // shouldn't happen
9890 awarn("wordc == 0?\n");
9891 continue;
9892 }
9893
9894 // don't care about this:
9895 if (words[0][0] == '.'
9896 || IS(words[0], "include")
9897 || IS(words[0], "assume") || IS(words[1], "segment")
9898 || IS(words[0], "align"))
9899 {
9900 continue;
9901 }
9902
4c45fa73 9903do_pending_endp:
9904 // do delayed endp processing to collect switch jumptables
9905 if (pending_endp) {
30c8c549 9906 if (in_func && !g_skip_func && !end && wordc >= 2
4c45fa73 9907 && ((words[0][0] == 'd' && words[0][2] == 0)
9908 || (words[1][0] == 'd' && words[1][2] == 0)))
9909 {
9910 i = 1;
9911 if (words[1][0] == 'd' && words[1][2] == 0) {
9912 // label
9913 if (g_func_pd_cnt >= pd_alloc) {
9914 pd_alloc = pd_alloc * 2 + 16;
9915 g_func_pd = realloc(g_func_pd,
9916 sizeof(g_func_pd[0]) * pd_alloc);
9917 my_assert_not(g_func_pd, NULL);
9918 }
9919 pd = &g_func_pd[g_func_pd_cnt];
9920 g_func_pd_cnt++;
9921 memset(pd, 0, sizeof(*pd));
9922 strcpy(pd->label, words[0]);
9923 pd->type = OPT_CONST;
9924 pd->lmod = lmod_from_directive(words[1]);
9925 i = 2;
9926 }
9927 else {
da87ae38 9928 if (pd == NULL) {
9929 if (verbose)
9930 anote("skipping alignment byte?\n");
9931 continue;
9932 }
4c45fa73 9933 lmod = lmod_from_directive(words[0]);
9934 if (lmod != pd->lmod)
9935 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
9936 }
9937
9938 if (pd->count_alloc < pd->count + wordc) {
9939 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
9940 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
9941 my_assert_not(pd->d, NULL);
9942 }
9943 for (; i < wordc; i++) {
9944 if (IS(words[i], "offset")) {
9945 pd->type = OPT_OFFSET;
9946 i++;
9947 }
9948 p = strchr(words[i], ',');
9949 if (p != NULL)
9950 *p = 0;
9951 if (pd->type == OPT_OFFSET)
9952 pd->d[pd->count].u.label = strdup(words[i]);
9953 else
e27467d0 9954 pd->d[pd->count].u.val = parse_number(words[i], 0);
4c45fa73 9955 pd->d[pd->count].bt_i = -1;
9956 pd->count++;
9957 }
9958 continue;
9959 }
9960
30c8c549 9961 if (in_func && !g_skip_func) {
9af2d373 9962 if (g_header_mode)
92d715b6 9963 gen_hdr(g_func, pi);
9964 else
9965 gen_func(fout, g_fhdr, g_func, pi);
9966 }
4c45fa73 9967
9968 pending_endp = 0;
9969 in_func = 0;
9970 g_ida_func_attr = 0;
7e08c224 9971 g_sct_func_attr = 0;
9972 g_stack_clear_start = 0;
9973 g_stack_clear_len = 0;
226e8df1 9974 g_regmask_init = 0;
383dff16 9975 g_regmask_rm = 0;
4c45fa73 9976 skip_warned = 0;
30c8c549 9977 g_skip_func = 0;
4c45fa73 9978 g_func[0] = 0;
ba93cc12 9979 g_seh_found = 0;
e56ab892 9980 func_chunks_used = 0;
9981 func_chunk_i = -1;
4c45fa73 9982 if (pi != 0) {
9983 memset(&ops, 0, pi * sizeof(ops[0]));
d7857c3a 9984 clear_labels(pi);
4c45fa73 9985 pi = 0;
9986 }
9987 g_eqcnt = 0;
9988 for (i = 0; i < g_func_pd_cnt; i++) {
9989 pd = &g_func_pd[i];
9990 if (pd->type == OPT_OFFSET) {
9991 for (j = 0; j < pd->count; j++)
9992 free(pd->d[j].u.label);
9993 }
9994 free(pd->d);
9995 pd->d = NULL;
9996 }
9997 g_func_pd_cnt = 0;
d4a985bd 9998 g_func_lmods = 0;
4c45fa73 9999 pd = NULL;
46b388c2 10000
10001 if (end)
10002 break;
4c45fa73 10003 if (wordc == 0)
10004 continue;
10005 }
10006
91977a1c 10007 if (IS(words[1], "proc")) {
10008 if (in_func)
10009 aerr("proc '%s' while in_func '%s'?\n",
10010 words[0], g_func);
bfa4a6ee 10011 p = words[0];
ddaf8bd7 10012 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
30c8c549 10013 g_skip_func = 1;
91977a1c 10014 strcpy(g_func, words[0]);
d4e3b5db 10015 set_label(0, words[0]);
91977a1c 10016 in_func = 1;
10017 continue;
10018 }
10019
e56ab892 10020 if (IS(words[1], "endp"))
10021 {
91977a1c 10022 if (!in_func)
10023 aerr("endp '%s' while not in_func?\n", words[0]);
10024 if (!IS(g_func, words[0]))
10025 aerr("endp '%s' while in_func '%s'?\n",
10026 words[0], g_func);
11437ea1 10027 if (skip_code)
10028 aerr("endp '%s' while skipping code\n", words[0]);
bfa4a6ee 10029
ddaf8bd7 10030 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
ba93cc12 10031 && ops[0].op == OP_JMP && ops[0].operand[0].segment)
ddaf8bd7 10032 {
10033 // import jump
30c8c549 10034 g_skip_func = 1;
ddaf8bd7 10035 }
10036
30c8c549 10037 if (!g_skip_func && func_chunks_used) {
e56ab892 10038 // start processing chunks
10039 struct chunk_item *ci, key = { g_func, 0 };
10040
10041 func_chunk_ret = ftell(fasm);
de50b98b 10042 func_chunk_ret_ln = asmln;
e56ab892 10043 if (!func_chunks_sorted) {
10044 qsort(func_chunks, func_chunk_cnt,
10045 sizeof(func_chunks[0]), cmp_chunks);
10046 func_chunks_sorted = 1;
10047 }
10048 ci = bsearch(&key, func_chunks, func_chunk_cnt,
10049 sizeof(func_chunks[0]), cmp_chunks);
10050 if (ci == NULL)
10051 aerr("'%s' needs chunks, but none found\n", g_func);
10052 func_chunk_i = ci - func_chunks;
10053 for (; func_chunk_i > 0; func_chunk_i--)
10054 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
10055 break;
10056
10057 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
10058 if (ret)
10059 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
de50b98b 10060 asmln = func_chunks[func_chunk_i].asmln;
e56ab892 10061 func_chunk_i++;
10062 continue;
10063 }
4c45fa73 10064 pending_endp = 1;
91977a1c 10065 continue;
10066 }
10067
1f84f6b3 10068 if (wordc == 2 && IS(words[1], "ends")) {
46b388c2 10069 if (!multi_seg) {
10070 end = 1;
10071 if (pending_endp)
10072 goto do_pending_endp;
1f84f6b3 10073 break;
46b388c2 10074 }
1f84f6b3 10075
10076 // scan for next text segment
5fa1256f 10077 while (my_fgets(line, sizeof(line), fasm)) {
1f84f6b3 10078 asmln++;
10079 p = sskip(line);
10080 if (*p == 0 || *p == ';')
10081 continue;
10082
10083 if (strstr(p, "segment para public 'CODE' use32"))
10084 break;
10085 }
10086
10087 continue;
10088 }
a2c1d768 10089
bfa4a6ee 10090 p = strchr(words[0], ':');
10091 if (p != NULL) {
d4e3b5db 10092 set_label(pi, words[0]);
bfa4a6ee 10093 continue;
10094 }
10095
11437ea1 10096 if (!in_func || g_skip_func || skip_code) {
30c8c549 10097 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
bfa4a6ee 10098 if (verbose)
10099 anote("skipping from '%s'\n", g_labels[pi]);
10100 skip_warned = 1;
10101 }
d7857c3a 10102 free(g_labels[pi]);
10103 g_labels[pi] = NULL;
bfa4a6ee 10104 continue;
10105 }
10106
ddaf8bd7 10107 if (wordc > 1 && IS(words[1], "="))
10108 {
91977a1c 10109 if (wordc != 5)
10110 aerr("unhandled equ, wc=%d\n", wordc);
10111 if (g_eqcnt >= eq_alloc) {
10112 eq_alloc *= 2;
10113 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
10114 my_assert_not(g_eqs, NULL);
10115 }
10116
10117 len = strlen(words[0]);
10118 if (len > sizeof(g_eqs[0].name) - 1)
10119 aerr("equ name too long: %d\n", len);
10120 strcpy(g_eqs[g_eqcnt].name, words[0]);
10121
10122 if (!IS(words[3], "ptr"))
10123 aerr("unhandled equ\n");
10124 if (IS(words[2], "dword"))
10125 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
10126 else if (IS(words[2], "word"))
10127 g_eqs[g_eqcnt].lmod = OPLM_WORD;
10128 else if (IS(words[2], "byte"))
10129 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
90307a99 10130 else if (IS(words[2], "qword"))
10131 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
91977a1c 10132 else
10133 aerr("bad lmod: '%s'\n", words[2]);
10134
e27467d0 10135 g_eqs[g_eqcnt].offset = parse_number(words[4], 0);
91977a1c 10136 g_eqcnt++;
10137 continue;
10138 }
10139
10140 if (pi >= ARRAY_SIZE(ops))
10141 aerr("too many ops\n");
10142
91977a1c 10143 parse_op(&ops[pi], words, wordc);
ddaf8bd7 10144
865f1aca 10145 ops[pi].datap = sctproto;
10146 sctproto = NULL;
91977a1c 10147 pi++;
91977a1c 10148 }
10149
9af2d373 10150 if (g_header_mode)
92d715b6 10151 output_hdr(fout);
10152
91977a1c 10153 fclose(fout);
10154 fclose(fasm);
06c5d854 10155 fclose(g_fhdr);
91977a1c 10156
10157 return 0;
c36e914d 10158}
91977a1c 10159
10160// vim:ts=2:shiftwidth=2:expandtab