From a35ae51b2fba4fb27afce7080d106df52aecd943 Mon Sep 17 00:00:00 2001 From: Max Wash Date: Wed, 14 May 2025 16:27:22 +0100 Subject: [PATCH] asm: assembler: implement label creation and resolution --- asm/assembler/assembler.c | 69 +++++++++++++-- asm/assembler/assembler.h | 54 +++++++----- asm/assembler/block.c | 150 +++++++++++++++++++++++++++++++- asm/include/ivy/asm/assembler.h | 9 ++ 4 files changed, 252 insertions(+), 30 deletions(-) diff --git a/asm/assembler/assembler.c b/asm/assembler/assembler.c index 53df3f7..719edd8 100644 --- a/asm/assembler/assembler.c +++ b/asm/assembler/assembler.c @@ -63,6 +63,7 @@ enum ivy_status ivy_assembler_create(FILE *fp, struct ivy_assembler **as) static void pad(struct ivy_assembler *as, unsigned int boundary) { + fseek(as->as_data, as->as_data_offset, SEEK_SET); while ((as->as_data_offset % boundary) != 0) { fputc(0, as->as_data); as->as_data_offset++; @@ -75,6 +76,7 @@ enum ivy_status ivy_assembler_finish(struct ivy_assembler *as) size_t xdat_len = as->as_next_xdata_key; fseek(as->as_xdat, 0, SEEK_SET); + fseek(as->as_data, as->as_data_offset, SEEK_SET); unsigned char *buf = malloc(buf_len); if (!buf) { @@ -143,16 +145,40 @@ enum ivy_status ivy_assembler_finish(struct ivy_assembler *as) return IVY_OK; } +size_t ivy_assembler_get_ptr(const struct ivy_assembler *as) +{ + return as->as_data_offset; +} + size_t assembler_write_data(struct ivy_assembler *as, const void *p, size_t len) { size_t offset = as->as_data_offset; - fwrite(p, 1, len, as->as_data); + fseek(as->as_data, offset, SEEK_SET); + size_t w = fwrite(p, 1, len, as->as_data); as->as_data_offset += len; return offset; } +enum ivy_status assembler_read_data_at( + struct ivy_assembler *as, void *p, size_t offset, size_t len, size_t *nr_read) +{ + fseek(as->as_data, offset, SEEK_SET); + *nr_read = fread(p, 1, len, as->as_data); + + return ferror(as->as_data) ? IVY_ERR_IO_FAILURE : IVY_OK; +} + +size_t assembler_write_data_at( + struct ivy_assembler *as, const void *p, size_t offset, size_t len) +{ + fseek(as->as_data, offset, SEEK_SET); + fwrite(p, 1, len, as->as_data); + + return ferror(as->as_data) ? IVY_ERR_IO_FAILURE : IVY_OK; +} + ivy_extended_data_key assembler_write_extended_data( struct ivy_assembler *as, const void *p, size_t len) { @@ -193,10 +219,7 @@ enum ivy_status ivy_assembler_begin_scope( memset(scope, 0x0, type_info->s_scope_size); - while ((as->as_data_offset % 16) != 0) { - fputc(0, as->as_data); - as->as_data_offset++; - } + pad(as, 16); scope->s_ops = type_info; scope->s_type = type; @@ -314,3 +337,39 @@ enum ivy_status ivy_assembler_put_instr( return type_info->s_put_instr(as, scope, i); } + +enum ivy_status ivy_assembler_put_label( + struct ivy_assembler *as, const struct ivy_asm_token *label_name, + size_t label_offset) +{ + struct assembler_scope *scope = as->as_scope; + + if (!scope) { + return IVY_ERR_NOT_SUPPORTED; + } + + const struct assembler_scope_type *type_info = scope->s_ops; + if (!type_info || !type_info->s_put_label) { + return IVY_ERR_NOT_SUPPORTED; + } + + return type_info->s_put_label(as, scope, label_name, label_offset); +} + +enum ivy_status ivy_assembler_put_label_ref( + struct ivy_assembler *as, const struct ivy_asm_token *label_name, + size_t ref_offset) +{ + struct assembler_scope *scope = as->as_scope; + + if (!scope) { + return IVY_ERR_NOT_SUPPORTED; + } + + const struct assembler_scope_type *type_info = scope->s_ops; + if (!type_info || !type_info->s_put_label_ref) { + return IVY_ERR_NOT_SUPPORTED; + } + + return type_info->s_put_label_ref(as, scope, label_name, ref_offset); +} diff --git a/asm/assembler/assembler.h b/asm/assembler/assembler.h index 5e82ad6..40f2a9d 100644 --- a/asm/assembler/assembler.h +++ b/asm/assembler/assembler.h @@ -2,10 +2,11 @@ #define _ASSEMBLER_ASSEMBLER_H_ #include -#include #include +#include struct assembler_scope_type; +struct ivy_asm_token; struct assembler_scope { enum ivy_assembler_scope_type s_type; @@ -17,36 +18,45 @@ struct assembler_scope { struct assembler_scope_type { size_t s_scope_size; - enum ivy_status(*s_init_scope)( - struct ivy_assembler *, - struct assembler_scope *, + enum ivy_status (*s_init_scope)( + struct ivy_assembler *, struct assembler_scope *, const ivy_assembler_attrib_table); - enum ivy_status(*s_finish_scope)( - struct ivy_assembler *, - struct assembler_scope *); + enum ivy_status (*s_finish_scope)( + struct ivy_assembler *, struct assembler_scope *); - enum ivy_status(*s_put_pval)(struct ivy_assembler *, - struct assembler_scope *, - enum ivy_assembler_pval_type, - const void *, + enum ivy_status (*s_put_pval)( + struct ivy_assembler *, struct assembler_scope *, + enum ivy_assembler_pval_type, const void *, ivy_extended_data_key *key); - enum ivy_status(*s_put_xval)( - struct ivy_assembler *, - struct assembler_scope *, - enum ivy_assembler_xval_type, - const ivy_assembler_attrib_table); + enum ivy_status (*s_put_xval)( + struct ivy_assembler *, struct assembler_scope *, + enum ivy_assembler_xval_type, const ivy_assembler_attrib_table); - enum ivy_status(*s_put_instr)( - struct ivy_assembler *, - struct assembler_scope *, + enum ivy_status (*s_put_instr)( + struct ivy_assembler *, struct assembler_scope *, const struct ivy_instr *); + + enum ivy_status (*s_put_label)( + struct ivy_assembler *, struct assembler_scope *, + const struct ivy_asm_token *, size_t); + enum ivy_status (*s_put_label_ref)( + struct ivy_assembler *, struct assembler_scope *, + const struct ivy_asm_token *, size_t); }; -extern size_t assembler_write_data(struct ivy_assembler *as, const void *p, size_t len); -extern ivy_extended_data_key assembler_write_extended_data(struct ivy_assembler *as, const void *p, size_t len); +extern size_t assembler_write_data( + struct ivy_assembler *as, const void *p, size_t len); +extern ivy_extended_data_key assembler_write_extended_data( + struct ivy_assembler *as, const void *p, size_t len); + +extern enum ivy_status assembler_read_data_at( + struct ivy_assembler *as, void *p, size_t offset, size_t len, + size_t *nr_read); +extern size_t assembler_write_data_at( + struct ivy_assembler *as, const void *p, size_t offset, size_t len); extern struct assembler_scope *assembler_get_scope(struct ivy_assembler *as); -#endif \ No newline at end of file +#endif diff --git a/asm/assembler/block.c b/asm/assembler/block.c index 58a600f..a1237e2 100644 --- a/asm/assembler/block.c +++ b/asm/assembler/block.c @@ -1,32 +1,130 @@ #include "assembler.h" #include -#include +#include #include #include #include #include +#include #include #include +#include +#include + +enum label_state { + LABEL_UNRESOLVED = 0, + LABEL_RESOLVED, +}; + +struct label { + enum label_state l_state; + b_queue_entry l_entry; + const struct ivy_asm_token *l_name; + size_t l_offset; +}; struct block_assembler_scope { struct assembler_scope s_base; + b_hashmap *s_labels; + b_queue s_label_refs; + size_t s_text_start; }; +static struct label *label_create(enum label_state state) +{ + struct label *out = malloc(sizeof *out); + if (!out) { + return NULL; + } + + memset(out, 0x0, sizeof *out); + + out->l_state = state; + + return out; +} + +static void label_destroy(struct label *label) +{ + free(label); +} + static enum ivy_status init_scope( struct ivy_assembler *as, struct assembler_scope *scope, const ivy_assembler_attrib_table attrib) { struct ivy_bin_block header = {0}; + struct block_assembler_scope *c = (struct block_assembler_scope *)scope; + c->s_labels = b_hashmap_create(NULL, NULL); + c->s_text_start = ivy_assembler_get_ptr(as); + header.b_index = b_i32_htob((uint32_t)attrib[IVY_ASM_ATTRIB_INDEX]); assembler_write_data(as, &header, sizeof header); - struct block_assembler_scope *c = (struct block_assembler_scope *)scope; - return IVY_OK; } +static struct label *get_label(struct block_assembler_scope *scope, const char *name) +{ + b_hashmap_key key = { + .key_data = name, + .key_size = strlen(name), + }; + + const b_hashmap_value *v = b_hashmap_get(scope->s_labels, &key); + if (!v) { + return NULL; + } + + return v->value_data; +} + +static enum ivy_status resolve_label_refs( + struct ivy_assembler *as, struct assembler_scope *scope) +{ + struct block_assembler_scope *c = (struct block_assembler_scope *)scope; + enum ivy_status status = IVY_OK; + size_t nr_read = 0; + + b_queue_iterator it; + b_queue_foreach (&it, &c->s_label_refs) { + struct label *label_ref = b_unbox(struct label, it.entry, l_entry); + struct label *label_dest = get_label(c, label_ref->l_name->t_str); + + if (!label_dest) { + printf("cannot resolve label '%s'\n", + label_ref->l_name->t_str); + return IVY_ERR_NO_ENTRY; + } + + b_i32 x; + status = assembler_read_data_at( + as, &x, label_ref->l_offset, sizeof x, &nr_read); + + if (status != IVY_OK || nr_read != sizeof x) { + printf("cannot fix label reference at 0x%zx\n", + label_ref->l_offset); + return IVY_ERR_IO_FAILURE; + } + + uint32_t instr = b_i32_btoh(x); + instr = R_SET_D3(instr, label_dest->l_offset); + x = b_i32_htob(instr); + + assembler_write_data_at(as, &x, label_ref->l_offset, sizeof x); + } + + return status; +} + +static enum ivy_status finish_scope( + struct ivy_assembler *as, struct assembler_scope *scope) +{ + return resolve_label_refs(as, scope); +} + static enum ivy_status put_instr( struct ivy_assembler *as, struct assembler_scope *scope, const struct ivy_instr *instr) @@ -70,8 +168,54 @@ static enum ivy_status put_instr( return IVY_OK; } +static enum ivy_status put_label( + struct ivy_assembler *as, struct assembler_scope *scope, + const struct ivy_asm_token *label_name, size_t label_offset) +{ + struct block_assembler_scope *c = (struct block_assembler_scope *)scope; + struct label *label = label_create(LABEL_RESOLVED); + + label->l_name = label_name; + label->l_offset = label_offset - c->s_text_start; + + b_hashmap_key key = { + .key_data = label_name->t_str, + .key_size = strlen(label_name->t_str), + }; + + b_hashmap_value value = { + .value_data = label, + .value_size = sizeof *label, + }; + + if (b_hashmap_get(c->s_labels, &key)) { + return IVY_ERR_NAME_EXISTS; + } + + b_status status = b_hashmap_put(c->s_labels, &key, &value); + + return ivy_status_from_b_status(status); +} + +static enum ivy_status put_label_ref( + struct ivy_assembler *as, struct assembler_scope *scope, + const struct ivy_asm_token *label_name, size_t ref_offset) +{ + struct block_assembler_scope *c = (struct block_assembler_scope *)scope; + struct label *label = label_create(LABEL_UNRESOLVED); + + label->l_name = label_name; + label->l_offset = ref_offset; + + b_queue_push_back(&c->s_label_refs, &label->l_entry); + return IVY_OK; +} + const struct assembler_scope_type block_scope_type = { .s_scope_size = sizeof(struct block_assembler_scope), .s_init_scope = init_scope, + .s_finish_scope = finish_scope, .s_put_instr = put_instr, + .s_put_label = put_label, + .s_put_label_ref = put_label_ref, }; diff --git a/asm/include/ivy/asm/assembler.h b/asm/include/ivy/asm/assembler.h index 28a2125..7dae232 100644 --- a/asm/include/ivy/asm/assembler.h +++ b/asm/include/ivy/asm/assembler.h @@ -13,6 +13,7 @@ typedef uint32_t ivy_extended_data_key; struct ivy_selector; struct ivy_instr; +struct ivy_asm_token; struct ivy_assembler; @@ -62,6 +63,7 @@ typedef unsigned long long ivy_assembler_attrib_table[__IVY_ASM_ATTRIB_COUNT]; IVY_API enum ivy_status ivy_assembler_create(FILE *out, struct ivy_assembler **as); IVY_API enum ivy_status ivy_assembler_finish(struct ivy_assembler *as); +IVY_API size_t ivy_assembler_get_ptr(const struct ivy_assembler *as); IVY_API enum ivy_status ivy_assembler_begin_scope( struct ivy_assembler *as, enum ivy_assembler_scope_type type, @@ -77,4 +79,11 @@ IVY_API enum ivy_status ivy_assembler_put_xval( IVY_API enum ivy_status ivy_assembler_put_instr( struct ivy_assembler *as, const struct ivy_instr *i); +IVY_API enum ivy_status ivy_assembler_put_label( + struct ivy_assembler *as, const struct ivy_asm_token *label_name, + size_t label_offset); +IVY_API enum ivy_status ivy_assembler_put_label_ref( + struct ivy_assembler *as, const struct ivy_asm_token *label_name, + size_t ref_offset); + #endif