asm: assembler: implement label creation and resolution
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
#define _ASSEMBLER_ASSEMBLER_H_
|
||||
|
||||
#include <ivy/asm/assembler.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct assembler_scope_type;
|
||||
struct ivy_asm_token;
|
||||
|
||||
struct assembler_scope {
|
||||
enum ivy_assembler_scope_type s_type;
|
||||
@@ -17,35 +18,44 @@ 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);
|
||||
|
||||
|
||||
@@ -1,32 +1,130 @@
|
||||
#include "assembler.h"
|
||||
|
||||
#include <blue/core/hash.h>
|
||||
#include <blue/object/dict.h>
|
||||
#include <blue/object/hashmap.h>
|
||||
#include <blue/object/number.h>
|
||||
#include <blue/object/string.h>
|
||||
#include <ivy/asm/bin.h>
|
||||
#include <ivy/asm/instr.h>
|
||||
#include <ivy/asm/lex.h>
|
||||
#include <ivy/ident.h>
|
||||
#include <ivy/selector.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user