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);
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",
}
// 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);
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++) {
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);
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);
{
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;
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");
}
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
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)
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:
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");
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;
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;
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:
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) {
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++)
{
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;");