From 4f12f6710a7063a10190be9fc45158c6ee46800c Mon Sep 17 00:00:00 2001 From: notaz Date: Thu, 26 Dec 2013 04:18:17 +0200 Subject: [PATCH] vararg funcs/calls, ebp- in ebp_frame, fixes --- stdc.hlist | 2 ++ tools/mkbridge.c | 24 +++++++++++--- tools/protoparse.h | 4 +++ tools/translate.c | 81 +++++++++++++++++++++++++++++++++++----------- 4 files changed, 88 insertions(+), 23 deletions(-) diff --git a/stdc.hlist b/stdc.hlist index ea66b4b..b294913 100644 --- a/stdc.hlist +++ b/stdc.hlist @@ -86,6 +86,8 @@ size_t __cdecl fwrite (const void*, size_t, size_t, FILE*); int __cdecl fseek (FILE*, long, int); long __cdecl ftell (FILE*); void __cdecl rewind (FILE*); +int __cdecl _snprintf (char*, size_t, const char*, ...); +int __cdecl _vsnprintf (char*, size_t, const char*, __VALIST); unsigned char* __cdecl _mbscpy (unsigned char*, const unsigned char*); unsigned char* __cdecl _mbsncpy (unsigned char*, const unsigned char*, size_t); diff --git a/tools/mkbridge.c b/tools/mkbridge.c index f0727d4..1e2f458 100644 --- a/tools/mkbridge.c +++ b/tools/mkbridge.c @@ -28,8 +28,13 @@ static void out_toasm_x86(FILE *f, char *sym, struct parsed_proto *pp) int must_save = 0; int sarg_ofs = 1; // stack offset to args, in DWORDs int args_repushed = 0; + int argc_repush; int i; + argc_repush = pp->argc; + if (pp->is_vararg) + argc_repush = ARRAY_SIZE(pp->arg); // hopefully enough? + for (i = 0; i < pp->argc; i++) { if (pp->arg[i].reg != NULL) must_save |= is_x86_reg_saved(pp->arg[i].reg); @@ -43,7 +48,9 @@ static void out_toasm_x86(FILE *f, char *sym, struct parsed_proto *pp) return; } - if (pp->argc_stack == 0 && !must_save && !pp->is_stdcall) { + if (pp->argc_stack == 0 && !must_save && !pp->is_stdcall + && !pp->is_vararg) + { // load arg regs for (i = 0; i < pp->argc; i++) { fprintf(f, "\tmovl %d(%%esp), %%%s\n", @@ -62,7 +69,7 @@ static void out_toasm_x86(FILE *f, char *sym, struct parsed_proto *pp) } // reconstruct arg stack - for (i = pp->argc - 1; i >= 0; i--) { + for (i = argc_repush - 1; i >= 0; i--) { if (pp->arg[i].reg == NULL) { fprintf(f, "\tmovl %d(%%esp), %%eax\n", (i + sarg_ofs) * 4); @@ -71,7 +78,7 @@ static void out_toasm_x86(FILE *f, char *sym, struct parsed_proto *pp) args_repushed++; } } - my_assert(args_repushed, pp->argc_stack); + // my_assert(args_repushed, pp->argc_stack); // load arg regs for (i = 0; i < pp->argc; i++) { @@ -99,9 +106,17 @@ static void out_toasm_x86(FILE *f, char *sym, struct parsed_proto *pp) static void out_fromasm_x86(FILE *f, char *sym, struct parsed_proto *pp) { int sarg_ofs = 1; // stack offset to args, in DWORDs + int argc_repush; int stack_args; int i; + argc_repush = pp->argc; + stack_args = pp->argc_stack; + if (pp->is_vararg) { + argc_repush = ARRAY_SIZE(pp->arg); // hopefully enough? + stack_args = argc_repush - pp->argc_reg; + } + fprintf(f, "# %s\n", pp->is_stdcall ? "__stdcall" : "__cdecl"); fprintf(f, ".global %s\n", sym); fprintf(f, "%s:\n", sym); @@ -115,8 +130,7 @@ static void out_fromasm_x86(FILE *f, char *sym, struct parsed_proto *pp) sarg_ofs++; // construct arg stack - stack_args = pp->argc_stack; - for (i = pp->argc - 1; i >= 0; i--) { + for (i = argc_repush - 1; i >= 0; i--) { if (pp->arg[i].reg == NULL) { fprintf(f, "\tmovl %d(%%esp), %%edx\n", (sarg_ofs + stack_args - 1) * 4); diff --git a/tools/protoparse.h b/tools/protoparse.h index c7d41dc..bce24ae 100644 --- a/tools/protoparse.h +++ b/tools/protoparse.h @@ -131,12 +131,16 @@ static const char *known_ptr_types[] = { "PDWORD", "PVOID", "PCVOID", + "va_list", + "__VALIST", }; static const char *ignored_keywords[] = { "extern", "WINBASEAPI", "WINUSERAPI", + "WINGDIAPI", + "WINADVAPI", }; // returns ptr to char after type ends diff --git a/tools/translate.c b/tools/translate.c index 7da8be5..4f01599 100644 --- a/tools/translate.c +++ b/tools/translate.c @@ -1149,21 +1149,32 @@ static void stack_frame_access(struct parsed_op *po, { enum opr_lenmod tmp_lmod = OPLM_UNSPEC; const char *prefix = ""; + const char *bp_arg = NULL; char ofs_reg[16] = { 0, }; struct parsed_equ *eq; + const char *p; + char *endp = NULL; int i, arg_i, arg_s; - const char *bp_arg; int stack_ra = 0; int offset = 0; int sf_ofs; - bp_arg = parse_stack_el(name, ofs_reg); - snprintf(g_comment, sizeof(g_comment), "%s", bp_arg); - eq = equ_find(po, bp_arg, &offset); - if (eq == NULL) - ferr(po, "detected but missing eq\n"); - - offset += eq->offset; + if (!IS_START(name, "ebp-")) { + bp_arg = parse_stack_el(name, ofs_reg); + snprintf(g_comment, sizeof(g_comment), "%s", bp_arg); + eq = equ_find(po, bp_arg, &offset); + if (eq == NULL) + ferr(po, "detected but missing eq\n"); + offset += eq->offset; + } + else { + p = name + 4; + if (IS_START(p, "0x")) + p += 2; + offset = -strtoul(p, &endp, 16); + if (*endp != 0) + ferr(po, "ebp- parse of '%s' failed\n", name); + } if (!strncmp(name, "ebp", 3)) stack_ra = 4; @@ -1171,11 +1182,21 @@ static void stack_frame_access(struct parsed_op *po, if (stack_ra <= offset && offset < stack_ra + 4) ferr(po, "reference to ra? %d %d\n", offset, stack_ra); - if (offset > stack_ra) { + if (offset > stack_ra) + { arg_i = (offset - stack_ra - 4) / 4; if (arg_i < 0 || arg_i >= g_func_pp.argc_stack) - ferr(po, "offset %d (%s) doesn't map to any arg\n", - offset, bp_arg); + { + if (g_func_pp.is_vararg && arg_i == g_func_pp.argc_stack && is_lea) { + // should be va_list + if (cast[0] == 0) + cast = "(u32)"; + snprintf(buf, buf_size, "%sap", cast); + return; + } + ferr(po, "offset %d (%s,%d) doesn't map to any arg\n", + offset, bp_arg, arg_i); + } if (ofs_reg[0] != 0) ferr(po, "offset reg on arg access?\n"); @@ -1188,12 +1209,12 @@ static void stack_frame_access(struct parsed_op *po, } if (i == g_func_pp.argc) ferr(po, "arg %d not in prototype?\n", arg_i); - if (is_lea) - ferr(po, "lea to arg?\n"); switch (lmod) { case OPLM_BYTE: + if (is_lea) + ferr(po, "lea/byte to arg?\n"); if (is_src && (offset & 3) == 0) snprintf(buf, buf_size, "(u8)a%d", i + 1); else @@ -1201,6 +1222,8 @@ static void stack_frame_access(struct parsed_op *po, break; case OPLM_WORD: + if (is_lea) + ferr(po, "lea/word to arg?\n"); if (offset & 1) ferr(po, "unaligned arg access\n"); if (is_src && (offset & 2) == 0) @@ -1217,7 +1240,7 @@ static void stack_frame_access(struct parsed_op *po, prefix = cast; else if (is_src) prefix = "(u32)"; - snprintf(buf, buf_size, "%sa%d", prefix, i + 1); + snprintf(buf, buf_size, "%s%sa%d", prefix, is_lea ? "&" : "", i + 1); break; default: @@ -1230,7 +1253,8 @@ static void stack_frame_access(struct parsed_op *po, ferr(po, "bp_arg arg/w offset %d and type '%s'\n", offset, g_func_pp.arg[i].type.name); } - else { + else + { if (g_stack_fsz == 0) ferr(po, "stack var access without stackframe\n"); @@ -1323,7 +1347,9 @@ static char *out_src_opr(char *buf, size_t buf_size, break; case OPT_REGMEM: - if (parse_stack_el(popr->name, NULL)) { + if (parse_stack_el(popr->name, NULL) + || (g_bp_frame && IS_START(popr->name, "ebp-"))) + { stack_frame_access(po, popr->lmod, buf, buf_size, popr->name, cast, 1, is_lea); break; @@ -1411,7 +1437,9 @@ static char *out_dst_opr(char *buf, size_t buf_size, break; case OPT_REGMEM: - if (parse_stack_el(popr->name, NULL)) { + if (parse_stack_el(popr->name, NULL) + || (g_bp_frame && IS_START(popr->name, "ebp-"))) + { stack_frame_access(po, popr->lmod, buf, buf_size, popr->name, "", 0, 0); break; @@ -1960,6 +1988,11 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) fprintf(fout, ", "); fprintf(fout, "%s a%d", g_func_pp.arg[i].type.name, i + 1); } + if (g_func_pp.is_vararg) { + if (i > 0) + fprintf(fout, ", "); + fprintf(fout, "..."); + } fprintf(fout, ")\n{\n"); // pass1: @@ -2398,11 +2431,14 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) fprintf(fout, " };\n"); } - // declare stack frame + // declare stack frame, va_arg if (g_stack_fsz) fprintf(fout, " union { u32 d[%d]; u16 w[%d]; u8 b[%d]; } sf;\n", (g_stack_fsz + 3) / 4, (g_stack_fsz + 1) / 2, g_stack_fsz); + if (g_func_pp.is_vararg) + fprintf(fout, " va_list ap;\n"); + // declare arg-registers for (i = 0; i < g_func_pp.argc; i++) { if (g_func_pp.arg[i].reg != NULL) { @@ -2474,6 +2510,12 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) if (had_decl) fprintf(fout, "\n"); + if (g_func_pp.is_vararg) { + if (g_func_pp.argc_stack == 0) + ferr(ops, "vararg func without stack args?\n"); + fprintf(fout, " va_start(ap, a%d);\n", g_func_pp.argc); + } + // output ops for (i = 0; i < opcnt; i++) { @@ -2928,6 +2970,9 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) break; case OP_RET: + if (g_func_pp.is_vararg) + fprintf(fout, " va_end(ap);\n"); + if (IS(g_func_pp.ret_type.name, "void")) { if (i != opcnt - 1 || label_pending) fprintf(fout, " return;"); -- 2.39.5