summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitya Selivanov <automainint@guattari.tech>2024-07-25 11:52:25 +0200
committerMitya Selivanov <automainint@guattari.tech>2024-07-25 11:52:25 +0200
commit46189dd08f21ee1c26b656bfc212d442cb8ad469 (patch)
tree6f6dd7354655e5a3edd8cd0cdf414bc2784907a2
parent8a78b1b3dba5e0c589f91a42bece8f797ab5856a (diff)
downloadbxgen-46189dd08f21ee1c26b656bfc212d442cb8ad469.zip
Example: call printf
-rwxr-xr-xbxgen.c102
1 files changed, 73 insertions, 29 deletions
diff --git a/bxgen.c b/bxgen.c
index bc1d09b..523a294 100755
--- a/bxgen.c
+++ b/bxgen.c
@@ -190,7 +190,8 @@ enum {
// Semantic node operations
//
- DATA_I64 = 0,
+ DATA_C8 = 0,
+ DATA_I64,
CTRL_CALL,
CTRL_RET,
@@ -204,7 +205,8 @@ enum {
// Primitive data types
//
- TYPE_I32 = 0,
+ TYPE_PTR = 0,
+ TYPE_I32,
// Unit types
//
@@ -445,6 +447,7 @@ void pool_remove(Pool *pool, i64 entity, i16 type);
i64 node_init(Pool *pool, Node data);
void node_destroy(Pool *pool, i64 node);
+i64 node_data_array_c8(Pool *pool, i64 size, c8 *data);
i64 node_data_i64(Pool *pool, i64 value);
i64 node_ctrl_call(Pool *pool, i16 convention, i64 target_proc, i64 num_args, Var *args);
i64 node_ctrl_call_by_name(Pool *pool, i16 convention, i64 name_size, c8 *name, i64 num_args, Var *args);
@@ -481,6 +484,7 @@ void io_chmod_exe(i64 f, void *user_data);
// Helpers API
//
#ifndef DISABLE_HELPERS
+i64 n_str(c8 *value);
i64 n_i64(i64 value);
i64 n_call(i16 convention, i64 target_proc, i64 num_args, Var *args);
i64 n_call_by_name(i16 convention, c8 *name, i64 num_args, Var *args);
@@ -720,6 +724,13 @@ void node_destroy(Pool *pool, i64 node) {
pool_remove(pool, node, ENTITY_NODE);
}
+i64 node_data_array_c8(Pool *pool, i64 size, c8 *data) {
+ BX_CHECK(size < MAX_LITERAL_SIZE, "Too big", UNDEFINED);
+ Node node_entry = { .op = DATA_C8, };
+ bx_mem_cpy(node_entry.lit_bytes, data, size);
+ return node_init(pool, node_entry);
+}
+
i64 node_data_i64(Pool *pool, i64 value) {
return node_init(pool, (Node) {
.op = DATA_I64,
@@ -1648,39 +1659,50 @@ i64 x86_64_emit_node(
u8 *end = codegen->code_buffer + codegen->max_code_size;
switch (n->op) {
- case DATA_I64: {
+ case DATA_C8:
+ case DATA_I64:
// Do nothing
- } break;
+ break;
case CTRL_CALL: {
- BX_FAIL("Not implemented", 0);
+ BX_LOG(ERROR, "CTRL_CALL: not implemented", 0);
} break;
case CTRL_RET: {
- // TEMP We just emit an exit syscall.
+ if ((context & EMIT_ENTRY_PROC) != 0) {
+ BX_CHECK(n->ret.num_vals == 1, "Not implemented", 0);
+ BX_CHECK(n->ret.vals[0].num == 1, "Not implemented", 0);
+
+ write_u8 (LE, 0xb8, begin, end); // mov eax
+ write_u32(LE, 60, begin + 1, end); // 60
- BX_CHECK((context & EMIT_ENTRY_PROC) != 0, "Not implemented", 0);
- BX_CHECK(n->ret.num_vals == 1, "Not implemented", 0);
- BX_CHECK(n->ret.vals[0].num == 1, "Not implemented", 0);
+ if (n->ret.num_vals == 0) {
+ write_u8 (LE, 0xbf, begin + 5, end); // mov edi
+ write_u32(LE, 0, begin + 6, end); // 0
- i64 n_val = n->ret.vals[0].node;
- BX_CHECK(n_val != UNDEFINED, "Internal", 0);
- BX_CHECK(pool->entities[n_val].is_enabled, "Internal", 0);
- BX_CHECK(pool->entities[n_val].type == ENTITY_NODE, "Internal", 0);
+ } else {
+ if (n->ret.num_vals > 1)
+ BX_LOG(WARNING, "Some return values are ignored for node %lld", node);
- Node *val = &pool->entities[n_val].node;
- BX_CHECK(val->op == DATA_I64, "Not implemented", 0);
+ i64 n_val = n->ret.vals[0].node;
+ BX_CHECK(n_val != UNDEFINED, "Internal", 0);
+ BX_CHECK(pool->entities[n_val].is_enabled, "Internal", 0);
+ BX_CHECK(pool->entities[n_val].type == ENTITY_NODE, "Internal", 0);
- write_u8 (LE, 0xb8, begin, end); // mov eax
- write_u32(LE, 60, begin + 1, end); // 60
+ Node *val = &pool->entities[n_val].node;
+ BX_CHECK(val->op == DATA_I64, "Not implemented", 0);
- write_u8 (LE, 0xbf, begin + 5, end); // mov edi
- write_u32(LE, val->lit_u32, begin + 6, end); // <- literal
+ write_u8 (LE, 0xbf, begin + 5, end); // mov edi
+ write_u32(LE, val->lit_u32, begin + 6, end); // <- literal
+ }
- write_u8 (LE, 0x0f, begin + 10, end); // syscall
- write_u8 (LE, 0x05, begin + 11, end);
+ write_u8 (LE, 0x0f, begin + 10, end); // syscall
+ write_u8 (LE, 0x05, begin + 11, end);
- offset += 12;
+ offset += 12;
+ } else {
+ BX_FAIL("Not implemented", 0);
+ }
} break;
default:
@@ -3090,6 +3112,11 @@ Linker_Context g_linker = {
// Handy procedures
//
+i64 n_str(c8 *value) {
+ i64 len = bx_str_len(value, value + MAX_LITERAL_SIZE);
+ return node_data_array_c8(&g_pool, len, value);
+}
+
i64 n_i64(i64 value) {
return node_data_i64(&g_pool, value);
}
@@ -3171,23 +3198,40 @@ int main(int argc, char **argv) {
BX_LOG(INFO, "bxgen " BX_VERSION);
// Add the `main` procedure.
- i64 main = p_new("main");
+ i64 mainproc = p_new("main");
+
+ // Create string literal
+ i64 n0 = n_str("hello sailor");
+ p_add(mainproc, n0);
+
+ // Call printf
+ p_add(mainproc,
+ n_call_by_name(
+ CONV_CDECL,
+ "printf",
+ 1,
+ (Var[]) {{
+ .num = 1,
+ .type = TYPE_PTR,
+ .node = n0,
+ }}
+ ));
// Create `42` i64 data node and add it into the `main`.
- i64 n0 = n_i64(42);
- p_add(main, n0);
+ i64 n1 = n_i64(42);
+ p_add(mainproc, n1);
// Add a return statement into the `main`.
// The return statement will point at the previously
// created node `42`.
- p_add(main,
+ p_add(mainproc,
// Create a ret node.
n_ret( 1, // number of returned values
(Var[]) {{
// the return value
.num = 1, // number of elements
.type = TYPE_I32, // type
- .node = n0, // source to get the value from
+ .node = n1, // source to get the value from
}}
));
@@ -3195,10 +3239,10 @@ int main(int argc, char **argv) {
i64 u = u_new();
// Add the `main` procedure to the compilation unit.
- u_add(u, main);
+ u_add(u, mainproc);
// Set the `main` as the entry point of the compilation unit.
- u_entry_point(u, main);
+ u_entry_point(u, mainproc);
// Link a static library.
l_static(u, "/lib/x86_64-linux-gnu/libc.a");