summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Maniero <carlos@maniero.me>2023-05-10 14:26:40 -0300
committerCarlos Maniero <carlos@maniero.me>2023-05-10 14:26:40 -0300
commit2cf0bcb409f3a1fd298b664103d57c945c6349f5 (patch)
tree6756f530d3007d529fae11fd0168c235355bc220
parentf1b1c191975581d5ef13bd04f33b6965235d00b4 (diff)
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 <carlos@maniero.me>
-rw-r--r--src/gas_assembly_generator.c83
-rw-r--r--src/gas_assembly_generator.h6
-rw-r--r--src/main.c2
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:
@@ -229,6 +242,36 @@ gas_assembly_generator_compile_return_stmt(gas_assembly_generator_t *gen, ast_re
}
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,
int stack_offset)
@@ -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