summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitya Selivanov <automainint@guattari.tech>2024-06-11 06:54:43 +0200
committerMitya Selivanov <automainint@guattari.tech>2024-06-11 06:54:43 +0200
commitb8ab04e26e8d1352e5a6cbd51e640c7d799e2eb3 (patch)
treeea40adc514cfc027cfbb343a08fa3cd06d9a49b2
parentb76549bb7bb94832ed0c7a3985cd304ab38d6cd2 (diff)
downloadbxgen-b8ab04e26e8d1352e5a6cbd51e640c7d799e2eb3.zip
Implement IO dispatch
-rwxr-xr-xbxgen.c188
1 files changed, 146 insertions, 42 deletions
diff --git a/bxgen.c b/bxgen.c
index 26cb4d9..1482992 100755
--- a/bxgen.c
+++ b/bxgen.c
@@ -59,6 +59,7 @@ exit $?
// Done features
//
// - ELF header
+// - IO static dispatch
//
// ================================================================
//
@@ -76,8 +77,6 @@ exit $?
//
// ================================================================
-#include <stdio.h>
-
typedef signed char i8;
typedef signed short i16;
typedef signed int i32;
@@ -176,6 +175,15 @@ enum {
MAX_LINK_COUNT = 20,
MAX_ARG_COUNT = 20,
MAX_ENTITY_COUNT = 16384,
+
+ // IO dispatch operations
+ //
+
+ IO_OPEN = 0,
+ IO_CLOSE,
+ IO_READ,
+ IO_WRITE,
+ IO_CHMOD_EXE,
};
// A semantic node is an operation with optional data
@@ -302,13 +310,13 @@ i64 node_init(pool_t *pool, node_t data);
void node_destroy(pool_t *pool, i64 node);
i64 node_data_i64(pool_t *pool, i64 value);
i64 node_ctrl_call(pool_t *pool, i16 convention, i64 target_proc, i64 arg_count, var_t *args);
-i64 node_ctrl_call_by_name(pool_t *pool, i16 convention, i64 name_size, c8 const *name, i64 arg_count, var_t *args);
+i64 node_ctrl_call_by_name(pool_t *pool, i16 convention, i64 name_size, c8 *name, i64 arg_count, var_t *args);
i64 node_ctrl_ret(pool_t *pool, i64 value_count, var_t *values);
i64 proc_init(pool_t *pool);
void proc_destroy(pool_t *pool, i64 proc);
void proc_set_convention(pool_t *pool, i64 proc, i16 convention);
-void proc_set_name(pool_t *pool, i64 proc, i64 name_size, c8 const *name);
+void proc_set_name(pool_t *pool, i64 proc, i64 name_size, c8 *name);
void proc_node_add(pool_t *pool, i64 proc, i64 node);
void proc_node_remove(pool_t *pool, i64 proc, i64 node);
@@ -318,24 +326,32 @@ void unit_proc_add(pool_t *pool, i64 unit, i64 proc);
void unit_proc_remove(pool_t *pool, i64 unit, i64 proc);
void unit_link_add(pool_t *pool, i64 unit, i64 link_unit);
void unit_link_remove(pool_t *pool, i64 unit, i64 link_unit);
-void unit_set_name(pool_t *pool, i64 unit, i64 name_size, c8 const *name);
+void unit_set_name(pool_t *pool, i64 unit, i64 name_size, c8 *name);
void unit_set_entry_point(pool_t *pool, i64 unit, i64 entry_point_proc);
-void unit_write(pool_t *pool, i64 unit, u16 target, FILE *out);
+void unit_write(pool_t *pool, i64 unit, u16 target, i64 io_id, void *io_user_data);
+
+i64 io_open(i64 name_size, c8 *name, void *user_data);
+void io_close(i64 f, void *user_data);
+i64 io_read(i64 f, i64 size, void *data, void *user_data);
+i64 io_write(i64 f, i64 size, void *data, void *user_data);
+void io_chmod_exe(i64 f, void *user_data);
+
+void io_dispatch(i16 op, i64 *id, i64 *size, void *data, void *user_data);
#ifndef DISABLE_HELPERS
i64 n_i64(i64 value);
i64 n_call(i16 convention, i64 target_proc, i64 arg_count, var_t *args);
-i64 n_call_by_name(i16 convention, c8 const *name, i64 arg_count, var_t *args);
+i64 n_call_by_name(i16 convention, c8 *name, i64 arg_count, var_t *args);
i64 n_ret(i64 val_count, var_t *vals);
-i64 p_new(c8 const *name);
+i64 p_new(c8 *name);
void p_add(i64 proc, i64 node);
i64 u_new();
void u_add(i64 unit, i64 proc);
void u_entry_point(i64 unit, i64 proc);
-void u_elf_x86_64(i64 unit, c8 const *output_file_name);
+void u_elf_x86_64(i64 unit, c8 *output_file_name);
void l_code(i64 unit, i64 link_unit);
-void l_object(i64 unit, c8 const *object_library);
-void l_static(i64 unit, c8 const *static_library);
+void l_object(i64 unit, c8 *object_library);
+void l_static(i64 unit, c8 *static_library);
#endif
#ifdef __cplusplus
@@ -418,7 +434,7 @@ i64 node_ctrl_call(pool_t *pool, i16 convention, i64 target_proc, i64 arg_count,
});
}
-i64 node_ctrl_call_by_name(pool_t *pool, i16 convention, i64 name_size, c8 const *name, i64 arg_count, var_t *args) {
+i64 node_ctrl_call_by_name(pool_t *pool, i16 convention, i64 name_size, c8 *name, i64 arg_count, var_t *args) {
assert(arg_count <= MAX_ARG_COUNT);
call_t call = {
@@ -475,7 +491,7 @@ void proc_set_convention(pool_t *pool, i64 proc, i16 convention) {
pool->entities[proc].proc.convention = convention;
}
-void proc_set_name(pool_t *pool, i64 proc, i64 name_size, c8 const *name) {
+void proc_set_name(pool_t *pool, i64 proc, i64 name_size, c8 *name) {
assert(pool != NULL && pool->entities != NULL);
assert(pool->entities[proc].is_enabled);
assert(pool->entities[proc].type == ENTITY_PROC);
@@ -645,7 +661,7 @@ void unit_link_remove(pool_t *pool, i64 unit, i64 link_unit) {
assert(0);
}
-void unit_set_name(pool_t *pool, i64 unit, i64 name_size, c8 const *name) {
+void unit_set_name(pool_t *pool, i64 unit, i64 name_size, c8 *name) {
assert(pool != NULL && pool->entities != NULL);
assert(pool->entities[unit].is_enabled);
assert(pool->entities[unit].type == ENTITY_UNIT);
@@ -689,17 +705,13 @@ void unit_set_entry_point(pool_t *pool, i64 unit, i64 entry_point_proc) {
// Code generation proc
//
-void unit_write(pool_t *pool, i64 unit, u16 target, FILE *out) {
- // TODO
- // Use callback instead of `FILE` to not depend on `stdio.h` here.
-
+void unit_write(pool_t *pool, i64 unit, u16 target, i64 io_out, void *io_user_data) {
assert(pool != NULL && pool->entities != NULL);
assert(pool->entities[unit].is_enabled);
assert(pool->entities[unit].unit.entry_point_index != UNDEFINED);
- assert(out != NULL);
assert(target == (FORMAT_ELF | ARCH_X86_64));
- printf("Writing ELF x86_64 executable...\n");
+// unit_t *u =
u16 ehs = 64;
u16 shs = 0;
@@ -724,11 +736,12 @@ void unit_write(pool_t *pool, i64 unit, u16 target, FILE *out) {
// ELF header
//
- #define WRITE_V(...) fwrite(&(u8[]) {__VA_ARGS__}, 1, sizeof((u8[]) {__VA_ARGS__}), out)
- #define WRITE_DUP(x, n) fwrite( (u8[n]) { 0 }, 1, n, out)
- #define WRITE_2(x) fwrite(&(u16) { x }, 2, 1, out)
- #define WRITE_4(x) fwrite(&(u32) { x }, 4, 1, out)
- #define WRITE_8(x) fwrite(&(u64) { x }, 8, 1, out)
+ #define WRITE(x, n) io_write( io_out, n, x, io_user_data )
+ #define WRITE_V(...) io_write( io_out, sizeof((u8[]) {__VA_ARGS__}), (u8[]) {__VA_ARGS__}, io_user_data )
+ #define WRITE_DUP(x, n) io_write( io_out, n, (u8[n]) { 0 }, io_user_data )
+ #define WRITE_2(x) io_write( io_out, 2, &(u16) { x }, io_user_data )
+ #define WRITE_4(x) io_write( io_out, 4, &(u32) { x }, io_user_data )
+ #define WRITE_8(x) io_write( io_out, 8, &(u64) { x }, io_user_data )
WRITE_V( 0x7f, 'E', 'L', 'F' ); // magic
@@ -766,18 +779,44 @@ void unit_write(pool_t *pool, i64 unit, u16 target, FILE *out) {
WRITE_8( code_size ); // memsz
WRITE_8( 8 ); // align
+ // Code
+ //
+
+ for (i64 i = code_offset - ehs - phs; i > 0; --i)
+ WRITE_V( 0 );
+
+ WRITE( code, code_size );
+
#undef WRITE_V
#undef WRITE_DUP
#undef WRITE_32
#undef WRITE_64
- // Code
- //
+ #undef WRITE
+}
- for (i64 i = code_offset - ehs - phs; i > 0; --i)
- fwrite(&(u8) { 0 }, 1, 1, out);
+i64 io_open(i64 name_size, c8 *name, void *user_data) {
+ i64 f;
+ io_dispatch(IO_OPEN, &f, &name_size, name, user_data);
+ return f;
+}
- fwrite(code, 1, code_size, out);
+void io_close(i64 f, void *user_data) {
+ io_dispatch(IO_CLOSE, &f, NULL, NULL, user_data);
+}
+
+i64 io_read(i64 f, i64 size, void *data, void *user_data) {
+ io_dispatch(IO_READ, &f, &size, data, user_data);
+ return size;
+}
+
+i64 io_write(i64 f, i64 size, void *data, void *user_data) {
+ io_dispatch(IO_WRITE, &f, &size, data, user_data);
+ return size;
+}
+
+void io_chmod_exe(i64 f, void *user_data) {
+ io_dispatch(IO_CHMOD_EXE, &f, NULL, NULL, user_data);
}
// ================================================================
@@ -788,11 +827,75 @@ void unit_write(pool_t *pool, i64 unit, u16 target, FILE *out) {
#ifndef DISABLE_HELPERS
+#include <stdio.h>
+
#ifdef __unix__
#include <sys/types.h>
#include <sys/stat.h>
#endif
+// IO dispatch procedure
+//
+
+void io_dispatch(i16 op, i64 *id, i64 *size, void *data, void *user_data) {
+ assert(id != NULL);
+
+ (void) user_data;
+
+ FILE **f = (FILE **) id;
+ c8 buf[MAX_NAME_SIZE] = { 0 };
+
+ switch (op) {
+ case IO_OPEN:
+ assert(size != NULL);
+ assert(*size > 0 && *size < MAX_NAME_SIZE);
+ assert(data != NULL);
+
+ memcpy(buf, data, *size);
+ *f = fopen(buf, "rb");
+ assert(*f != NULL);
+ break;
+
+ case IO_CLOSE:
+ assert(*f != NULL);
+ assert(size == NULL);
+ assert(data == NULL);
+
+ fclose(*f);
+ break;
+
+ case IO_READ:
+ assert(*f != NULL);
+ assert(size != NULL);
+ assert(data != NULL);
+ assert(*size > 0);
+
+ *size = fread(data, 1, *size, *f);
+ break;
+
+ case IO_WRITE:
+ assert(*f != NULL);
+ assert(size != NULL);
+ assert(data != NULL);
+ assert(*size > 0);
+
+ *size = fwrite(data, 1, *size, *f);
+ break;
+
+ case IO_CHMOD_EXE:
+ assert(*f != NULL);
+ assert(size == NULL);
+
+#ifdef __unix__
+ fchmod(fileno(*f), 0775);
+#endif
+ break;
+
+ default:
+ assert(0);
+ }
+}
+
// Global state
//
@@ -817,7 +920,7 @@ i64 n_call(i16 convention, i64 target_proc, i64 arg_count, var_t *args) {
return node_ctrl_call(&g_pool, convention, target_proc, arg_count, args);
}
-i64 n_call_by_name(i16 convention, c8 const *name, i64 arg_count, var_t *args) {
+i64 n_call_by_name(i16 convention, c8 *name, i64 arg_count, var_t *args) {
return node_ctrl_call_by_name(&g_pool, convention, strlen(name), name, arg_count, args);
}
@@ -825,7 +928,7 @@ i64 n_ret(i64 val_count, var_t *vals) {
return node_ctrl_ret(&g_pool, val_count, vals);
}
-i64 p_new(c8 const *name) {
+i64 p_new(c8 *name) {
i64 p = proc_init(&g_pool);
proc_set_name(&g_pool, p, strlen(name), name);
return p;
@@ -847,27 +950,28 @@ void u_entry_point(i64 unit, i64 proc) {
unit_set_entry_point(&g_pool, unit, proc);
}
-void u_elf_x86_64(i64 unit, c8 const *output_file_name) {
- FILE *f = fopen(output_file_name, "wb");
- assert(f != NULL);
- unit_write(&g_pool, unit, FORMAT_ELF | ARCH_X86_64, f);
-#ifdef __unix__
- fchmod(fileno(f), 0775);
-#endif
- fclose(f);
+void u_elf_x86_64(i64 unit, c8 *output_file_name) {
+ printf("Writing ELF x86_64 executable...\n");
+
+ i64 out = io_open(strlen(output_file_name), output_file_name, NULL);
+
+ unit_write(&g_pool, unit, FORMAT_ELF | ARCH_X86_64, out, NULL);
+
+ io_chmod_exe(out, NULL);
+ io_close(out, NULL);
}
void l_code(i64 unit, i64 link_unit) {
unit_link_add(&g_pool, unit, link_unit);
}
-void l_object(i64 unit, c8 const *object_library) {
+void l_object(i64 unit, c8 *object_library) {
i64 l = unit_init(&g_pool, UNIT_LIBRARY_OBJECT);
unit_set_name(&g_pool, l, strlen(object_library), object_library);
unit_link_add(&g_pool, unit, l);
}
-void l_static(i64 unit, c8 const *static_library) {
+void l_static(i64 unit, c8 *static_library) {
i64 l = unit_init(&g_pool, UNIT_LIBRARY_STATIC);
unit_set_name(&g_pool, l, strlen(static_library), static_library);
unit_link_add(&g_pool, unit, l);