diff options
author | Mitya Selivanov <automainint@guattari.tech> | 2024-07-25 11:52:25 +0200 |
---|---|---|
committer | Mitya Selivanov <automainint@guattari.tech> | 2024-07-25 11:52:25 +0200 |
commit | 46189dd08f21ee1c26b656bfc212d442cb8ad469 (patch) | |
tree | 6f6dd7354655e5a3edd8cd0cdf414bc2784907a2 | |
parent | 8a78b1b3dba5e0c589f91a42bece8f797ab5856a (diff) | |
download | bxgen-46189dd08f21ee1c26b656bfc212d442cb8ad469.zip |
Example: call printf
-rwxr-xr-x | bxgen.c | 102 |
1 files changed, 73 insertions, 29 deletions
@@ -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"); |