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