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