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