mirror of https://github.com/rui314/chibicc
Add va_start to support variadic functions
This commit is contained in:
parent
58fc86137c
commit
754a24fafc
|
@ -92,6 +92,7 @@ struct Obj {
|
|||
Obj *params;
|
||||
Node *body;
|
||||
Obj *locals;
|
||||
Obj *va_area;
|
||||
int stack_size;
|
||||
};
|
||||
|
||||
|
|
30
codegen.c
30
codegen.c
|
@ -567,6 +567,36 @@ static void emit_text(Obj *prog) {
|
|||
println(" mov %%rsp, %%rbp");
|
||||
println(" sub $%d, %%rsp", fn->stack_size);
|
||||
|
||||
// Save arg registers if function is variadic
|
||||
if (fn->va_area) {
|
||||
int gp = 0;
|
||||
for (Obj *var = fn->params; var; var = var->next)
|
||||
gp++;
|
||||
int off = fn->va_area->offset;
|
||||
|
||||
// va_elem
|
||||
println(" movl $%d, %d(%%rbp)", gp * 8, off);
|
||||
println(" movl $0, %d(%%rbp)", off + 4);
|
||||
println(" movq %%rbp, %d(%%rbp)", off + 16);
|
||||
println(" addq $%d, %d(%%rbp)", off + 24, off + 16);
|
||||
|
||||
// __reg_save_area__
|
||||
println(" movq %%rdi, %d(%%rbp)", off + 24);
|
||||
println(" movq %%rsi, %d(%%rbp)", off + 32);
|
||||
println(" movq %%rdx, %d(%%rbp)", off + 40);
|
||||
println(" movq %%rcx, %d(%%rbp)", off + 48);
|
||||
println(" movq %%r8, %d(%%rbp)", off + 56);
|
||||
println(" movq %%r9, %d(%%rbp)", off + 64);
|
||||
println(" movsd %%xmm0, %d(%%rbp)", off + 72);
|
||||
println(" movsd %%xmm1, %d(%%rbp)", off + 80);
|
||||
println(" movsd %%xmm2, %d(%%rbp)", off + 88);
|
||||
println(" movsd %%xmm3, %d(%%rbp)", off + 96);
|
||||
println(" movsd %%xmm4, %d(%%rbp)", off + 104);
|
||||
println(" movsd %%xmm5, %d(%%rbp)", off + 112);
|
||||
println(" movsd %%xmm6, %d(%%rbp)", off + 120);
|
||||
println(" movsd %%xmm7, %d(%%rbp)", off + 128);
|
||||
}
|
||||
|
||||
// Save passed-by-register arguments to the stack
|
||||
int i = 0;
|
||||
for (Obj *var = fn->params; var; var = var->next)
|
||||
|
|
2
parse.c
2
parse.c
|
@ -2212,6 +2212,8 @@ static Token *function(Token *tok, Type *basety, VarAttr *attr) {
|
|||
enter_scope();
|
||||
create_param_lvars(ty->params);
|
||||
fn->params = locals;
|
||||
if (ty->is_variadic)
|
||||
fn->va_area = new_lvar("__va_area__", array_of(ty_char, 136));
|
||||
|
||||
tok = skip(tok, "{");
|
||||
fn->body = compound_stmt(&tok, tok);
|
||||
|
|
|
@ -72,6 +72,25 @@ short short_fn();
|
|||
|
||||
int add_all(int n, ...);
|
||||
|
||||
typedef struct {
|
||||
int gp_offset;
|
||||
int fp_offset;
|
||||
void *overflow_arg_area;
|
||||
void *reg_save_area;
|
||||
} __va_elem;
|
||||
|
||||
typedef __va_elem va_list[1];
|
||||
|
||||
int add_all(int n, ...);
|
||||
int sprintf(char *buf, char *fmt, ...);
|
||||
int vsprintf(char *buf, char *fmt, va_list ap);
|
||||
|
||||
char *fmt(char *buf, char *fmt, ...) {
|
||||
va_list ap;
|
||||
*ap = *(__va_elem *)__va_area__;
|
||||
vsprintf(buf, fmt, ap);
|
||||
}
|
||||
|
||||
int main() {
|
||||
ASSERT(3, ret3());
|
||||
ASSERT(8, add2(3, 5));
|
||||
|
@ -121,8 +140,12 @@ int main() {
|
|||
ASSERT(6, add_all(3,1,2,3));
|
||||
ASSERT(5, add_all(4,1,2,3,-1));
|
||||
|
||||
{ char buf[100]; fmt(buf, "%d %d %s", 1, 2, "foo"); printf("%s\n", buf); }
|
||||
|
||||
ASSERT(0, ({ char buf[100]; sprintf(buf, "%d %d %s", 1, 2, "foo"); strcmp("1 2 foo", buf); }));
|
||||
|
||||
ASSERT(0, ({ char buf[100]; fmt(buf, "%d %d %s", 1, 2, "foo"); strcmp("1 2 foo", buf); }));
|
||||
|
||||
printf("OK\n");
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue