From 2cf0bcb409f3a1fd298b664103d57c945c6349f5 Mon Sep 17 00:00:00 2001 From: Carlos Maniero Date: Wed, 10 May 2023 14:26:40 -0300 Subject: gas: Removes Linux entrypoint logic from function declaration Before this commit, function declarations were making syscalls to interrupt the flow. This is a fair approach considering all our examples just have a main function. But won't work if the namespace has more then a single function. The return now always sets the return value on RAX and jumps to the function return label. The function return label, will restore RBP and jump back to callee's next instruction using RET instruction. Function labels are kept, which means that a function called my_fn will have the assembly label my_fn, so then, they can have INTEROP with other languages. Signed-off-by: Carlos Maniero --- src/gas_assembly_generator.c | 83 +++++++++++++++++++++++++++++++++----------- src/gas_assembly_generator.h | 6 +++- src/main.c | 2 +- 3 files changed, 69 insertions(+), 22 deletions(-) diff --git a/src/gas_assembly_generator.c b/src/gas_assembly_generator.c index 97ba9ce..413fbb0 100644 --- a/src/gas_assembly_generator.c +++ b/src/gas_assembly_generator.c @@ -137,7 +137,8 @@ gas_assembly_generator_init(gas_assembly_generator_t *gen, FILE *stream) gen->stream = stream; gen->refs = vector_new(); gen->stack_offset = 0; - gen->cur_label_index = 0; + gen->counter_label_index = 1; + gen->return_label_index = 0; } void @@ -183,28 +184,40 @@ gas_assembly_generator_compile_function(gas_assembly_generator_t *gen, ast_funct { assert(func); - if (!string_view_eq(func->identifier.name, string_view_from_str("main"))) { - fprintf(stderr, "[ERROR]: no main function has been defined!\n"); - exit(EXIT_FAILURE); - } + uint64_t previous_index = gen->return_label_index; + uint64_t return_label_index = gen->return_label_index = gen->counter_label_index++; - fprintf(gen->stream, ".global _start\n"); - fprintf(gen->stream, ".text\n"); - fprintf(gen->stream, "_start:\n"); + fprintf(gen->stream, SVFMT ":\n", SVARG(&func->identifier.name)); fprintf(gen->stream, " push %%rbp\n"); fprintf(gen->stream, " mov %%rsp, %%rbp\n"); gas_assembly_generator_compile(gen, func->body); + fprintf(gen->stream, ".L%ld:\n", return_label_index); fprintf(gen->stream, " pop %%rbp\n"); + fprintf(gen->stream, " ret\n"); + + gen->return_label_index = previous_index; } -static void -gas_assembly_generator_compile_return_stmt(gas_assembly_generator_t *gen, ast_return_stmt_t *return_stmt) +void +gas_assembly_generator_compile_linux_main(gas_assembly_generator_t *gen, ast_node_t *func) { - assert(gen && return_stmt); + assert(func); + assert(func->kind == AST_FUNCTION_DECLARATION); - gas_assembly_generator_compile(gen, return_stmt->argument); + if (!string_view_eq(func->data.function.identifier.name, string_view_from_str("main"))) { + fprintf(stderr, "[ERROR]: no main function has been defined!\n"); + exit(EXIT_FAILURE); + } + + fprintf(gen->stream, ".global _start\n"); + fprintf(gen->stream, ".text\n"); + + gas_assembly_generator_compile(gen, func); + + fprintf(gen->stream, "_start:\n"); + fprintf(gen->stream, " call main\n"); switch (gen->latest_evaluation.kind) { case EVALUATION_RESULT_AS_LITERAL_INTEGER: @@ -228,6 +241,36 @@ gas_assembly_generator_compile_return_stmt(gas_assembly_generator_t *gen, ast_re fprintf(gen->stream, " syscall\n"); } +static void +gas_assembly_generator_compile_return_stmt(gas_assembly_generator_t *gen, ast_return_stmt_t *return_stmt) +{ + assert(gen && return_stmt); + assert(gen->return_label_index != 0 && "There are no return label index set"); + + gas_assembly_generator_compile(gen, return_stmt->argument); + + switch (gen->latest_evaluation.kind) { + case EVALUATION_RESULT_AS_LITERAL_INTEGER: + fprintf(gen->stream, " mov $%ld, %%rax\n", gen->latest_evaluation.data.literal_int); + gas_assembly_generator_set_latest_evaluation_to_rax(gen); + break; + case EVALUATION_RESULT_ON_RAX: + gas_assembly_generator_set_latest_evaluation_to_rax(gen); + break; + case EVALUATION_RESULT_ON_STACK: + fprintf(gen->stream, " mov %d(%%rbp), %%rax\n", gen->latest_evaluation.data.stack_offset); + gas_assembly_generator_set_latest_evaluation_to_rax(gen); + break; + case EVALUATION_RESULT_VOID: + break; + case EVALUATION_RESULT_AS_LITERAL_BOOL: + assert(false && "Unexpected"); + break; + } + + fprintf(gen->stream, " jmp .L%ld\n", gen->return_label_index); +} + static void gas_assembly_generator_compile_variable_assign_value(gas_assembly_generator_t *gen, ast_node_t *expression, @@ -241,9 +284,9 @@ gas_assembly_generator_compile_variable_assign_value(gas_assembly_generator_t *g return; } - uint64_t true_label_index = gen->cur_label_index++; - uint64_t false_label_index = gen->cur_label_index++; - uint64_t after_assign_label_index = gen->cur_label_index++; + uint64_t true_label_index = gen->counter_label_index++; + uint64_t false_label_index = gen->counter_label_index++; + uint64_t after_assign_label_index = gen->counter_label_index++; gas_assembly_generator_compile_condition(gen, expression, true_label_index, false, false_label_index, true); @@ -446,7 +489,7 @@ gas_assembly_generator_compile_condition(gas_assembly_generator_t *gen, } if (condition->data.binary_operation.kind == AST_BINOP_OR) { - uint64_t or_false_branch_label_index = gen->cur_label_index++; + uint64_t or_false_branch_label_index = gen->counter_label_index++; gas_assembly_generator_compile_condition( gen, condition->data.binary_operation.left, true_label_index, true, or_false_branch_label_index, false); @@ -459,7 +502,7 @@ gas_assembly_generator_compile_condition(gas_assembly_generator_t *gen, } if (condition->data.binary_operation.kind == AST_BINOP_AND) { - uint64_t and_true_branch_label_index = gen->cur_label_index++; + uint64_t and_true_branch_label_index = gen->counter_label_index++; gas_assembly_generator_compile_condition( gen, condition->data.binary_operation.left, and_true_branch_label_index, false, false_label_index, true); @@ -497,8 +540,8 @@ gas_assembly_generator_compile_if_stmt(gas_assembly_generator_t *gen, ast_if_stm switch (if_stmt->condition->kind) { case AST_BINARY_OPERATION: case AST_LITERAL: { - uint64_t true_label_index = gen->cur_label_index++; - uint64_t false_label_index = gen->cur_label_index++; + uint64_t true_label_index = gen->counter_label_index++; + uint64_t false_label_index = gen->counter_label_index++; gas_assembly_generator_compile_condition( gen, if_stmt->condition, true_label_index, false, false_label_index, true); @@ -510,7 +553,7 @@ gas_assembly_generator_compile_if_stmt(gas_assembly_generator_t *gen, ast_if_stm break; } case AST_VARIABLE: { - uint64_t false_label_index = gen->cur_label_index++; + uint64_t false_label_index = gen->counter_label_index++; int stack_offset = ref_find_variable_reference_stack_offset(gen->refs, if_stmt->condition->data.variable.identifier); diff --git a/src/gas_assembly_generator.h b/src/gas_assembly_generator.h index e400d2c..18ffb7f 100644 --- a/src/gas_assembly_generator.h +++ b/src/gas_assembly_generator.h @@ -48,7 +48,8 @@ typedef struct gas_assembly_generator_t FILE *stream; vector_t *refs; int stack_offset; - uint64_t cur_label_index; + uint64_t counter_label_index; + uint64_t return_label_index; evaluation_result_t latest_evaluation; } gas_assembly_generator_t; @@ -58,4 +59,7 @@ gas_assembly_generator_init(gas_assembly_generator_t *gen, FILE *stream); void gas_assembly_generator_compile(gas_assembly_generator_t *gen, ast_node_t *ast); +void +gas_assembly_generator_compile_linux_main(gas_assembly_generator_t *gen, ast_node_t *func); + #endif /* GAS_ASSEMBLY_GENERATOR_H */ diff --git a/src/main.c b/src/main.c index 4f68256..780499c 100644 --- a/src/main.c +++ b/src/main.c @@ -31,7 +31,7 @@ generate_gas_x86_64_linux(ast_node_t *func) { gas_assembly_generator_t gen; gas_assembly_generator_init(&gen, stdout); - gas_assembly_generator_compile(&gen, func); + gas_assembly_generator_compile_linux_main(&gen, func); } static void -- cgit v1.2.3