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