Files
ivy/asm/assembler/assembler.c
Max Wash 2845c29c5f asm: assembler: constpool value indices are now used and enforced
constpool values must be defined in ascending sequence, each index must be greater than the last.
any gaps in the sequence will automatically be filled with null values.
2025-05-15 12:08:34 +01:00

376 lines
8.4 KiB
C

#include "assembler.h"
#include <blue/core/queue.h>
#include <ivy/asm/assembler.h>
#include <ivy/asm/bin.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern struct assembler_scope_type class_scope_type;
extern struct assembler_scope_type constpool_scope_type;
extern struct assembler_scope_type block_scope_type;
static const struct assembler_scope_type *scope_types[] = {
[IVY_ASM_SCOPE_CLASS] = &class_scope_type,
[IVY_ASM_SCOPE_CONSTPOOL] = &constpool_scope_type,
[IVY_ASM_SCOPE_BLOCK] = &block_scope_type,
};
static const size_t nr_scope_types = sizeof scope_types / sizeof scope_types[0];
struct asm_table_entry {
b_queue_entry e_entry;
struct ivy_bin_table_entry e_data;
};
struct ivy_assembler {
struct assembler_scope *as_scope;
b_queue as_table;
FILE *as_data;
size_t as_data_offset;
FILE *as_xdat;
ivy_extended_data_key as_next_xdata_key;
};
enum ivy_status ivy_assembler_create(FILE *fp, struct ivy_assembler **as)
{
struct ivy_assembler *out = malloc(sizeof *out);
if (!out) {
return IVY_ERR_NO_MEMORY;
}
memset(out, 0x0, sizeof *out);
out->as_data = fp;
out->as_xdat = tmpfile();
struct ivy_bin_header header = {0};
header.h_magic = b_i32_htob(0xAABBCCDD);
fseek(fp, 0, SEEK_SET);
fwrite(&header, sizeof header, 1, fp);
out->as_data_offset = sizeof header;
char blank[16] = {0};
assembler_write_extended_data(out, blank, sizeof blank);
*as = out;
return IVY_OK;
}
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++;
}
}
enum ivy_status ivy_assembler_finish(struct ivy_assembler *as)
{
const size_t buf_len = 4096;
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) {
return IVY_ERR_NO_MEMORY;
}
pad(as, 16);
struct ivy_bin_table_entry xdat = {0};
xdat.e_offset = b_i64_htob(as->as_data_offset);
xdat.e_size = b_i32_htob((uint32_t)xdat_len);
xdat.e_type = b_i32_htob(IVY_TABLE_XDAT);
while (1) {
size_t r = fread(buf, 1, buf_len, as->as_xdat);
fwrite(buf, 1, r, as->as_data);
as->as_data_offset += r;
if (r == buf_len) {
continue;
}
if (ferror(as->as_xdat)) {
free(buf);
return IVY_ERR_IO_FAILURE;
}
break;
}
free(buf);
unsigned short nr_table_entries = 0;
pad(as, 16);
struct ivy_bin_header header = {0};
header.h_table_offset = b_i64_htob(as->as_data_offset);
header.h_table_len = b_i16_htob(0);
header.h_magic = b_i32_htob(IVY_BIN_MAGIC);
b_queue_iterator it = {0};
b_queue_foreach (&it, &as->as_table) {
struct asm_table_entry *e
= b_unbox(struct asm_table_entry, it.entry, e_entry);
size_t w = fwrite(&e->e_data, 1, sizeof e->e_data, as->as_data);
if (w < sizeof e->e_data) {
return IVY_ERR_IO_FAILURE;
}
nr_table_entries++;
}
fwrite(&xdat, 1, sizeof xdat, as->as_data);
nr_table_entries++;
header.h_table_len = b_i16_htob(nr_table_entries);
fseek(as->as_data, 0, SEEK_SET);
fwrite(&header, 1, sizeof header, as->as_data);
fclose(as->as_xdat);
free(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;
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)
{
ivy_extended_data_key key = as->as_next_xdata_key;
fwrite(p, 1, len, as->as_xdat);
as->as_next_xdata_key += (ivy_extended_data_key)len;
return key;
}
struct assembler_scope *assembler_get_scope(struct ivy_assembler *as)
{
return as->as_scope;
}
enum ivy_status ivy_assembler_begin_scope(
struct ivy_assembler *as, enum ivy_assembler_scope_type type,
const ivy_assembler_attrib_table attrib)
{
if (type < 0 || type >= nr_scope_types) {
return IVY_ERR_NOT_SUPPORTED;
}
const struct assembler_scope_type *type_info = scope_types[type];
if (!type_info) {
return IVY_ERR_NOT_SUPPORTED;
}
if (as->as_scope) {
return IVY_ERR_NOT_SUPPORTED;
}
struct assembler_scope *scope = malloc(type_info->s_scope_size);
if (!scope) {
return IVY_ERR_NO_MEMORY;
}
memset(scope, 0x0, type_info->s_scope_size);
pad(as, 16);
scope->s_ops = type_info;
scope->s_type = type;
scope->s_start_offset = as->as_data_offset;
as->as_scope = scope;
if (type_info->s_init_scope) {
type_info->s_init_scope(as, scope, attrib);
}
return IVY_OK;
}
enum ivy_status ivy_assembler_end_scope(struct ivy_assembler *as)
{
if (!as->as_scope) {
return IVY_ERR_NOT_SUPPORTED;
}
const struct assembler_scope_type *type_info = as->as_scope->s_ops;
if (!type_info) {
return IVY_ERR_NOT_SUPPORTED;
}
if (type_info->s_finish_scope) {
type_info->s_finish_scope(as, as->as_scope);
}
struct asm_table_entry *entry = malloc(sizeof *entry);
if (!entry) {
return IVY_ERR_NO_MEMORY;
}
memset(entry, 0x0, sizeof *entry);
entry->e_data.e_offset
= b_i64_htob((uint64_t)as->as_scope->s_start_offset);
entry->e_data.e_size = b_i32_htob(
(uint32_t)(as->as_data_offset - as->as_scope->s_start_offset));
switch (as->as_scope->s_type) {
case IVY_ASM_SCOPE_CLASS:
entry->e_data.e_type = b_i32_htob(IVY_TABLE_CLASS);
break;
case IVY_ASM_SCOPE_BLOCK:
entry->e_data.e_type = b_i32_htob(IVY_TABLE_BLOCK);
break;
case IVY_ASM_SCOPE_CONSTPOOL:
entry->e_data.e_type = b_i32_htob(IVY_TABLE_POOL);
break;
case IVY_ASM_SCOPE_IMPORT:
entry->e_data.e_type = b_i32_htob(IVY_TABLE_IMPORT);
break;
default:
break;
}
b_queue_push_back(&as->as_table, &entry->e_entry);
free(as->as_scope);
as->as_scope = NULL;
return IVY_OK;
}
enum ivy_status ivy_assembler_put_pval(
struct ivy_assembler *as, enum ivy_assembler_pval_type type,
size_t slot, const void *val, ivy_extended_data_key *key)
{
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_pval) {
return IVY_ERR_NOT_SUPPORTED;
}
return type_info->s_put_pval(as, scope, type, slot, val, key);
}
enum ivy_status ivy_assembler_put_xval(
struct ivy_assembler *as, enum ivy_assembler_xval_type type,
const ivy_assembler_attrib_table attrib)
{
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_xval) {
return IVY_ERR_NOT_SUPPORTED;
}
return type_info->s_put_xval(as, scope, type, attrib);
}
enum ivy_status ivy_assembler_put_instr(
struct ivy_assembler *as, const struct ivy_instr *i)
{
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_instr) {
return IVY_ERR_NOT_SUPPORTED;
}
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);
}