aboutsummaryrefslogtreecommitdiff
path: root/tools/assemble.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/assemble.c')
-rw-r--r--tools/assemble.c217
1 files changed, 217 insertions, 0 deletions
diff --git a/tools/assemble.c b/tools/assemble.c
new file mode 100644
index 0000000..07416fd
--- /dev/null
+++ b/tools/assemble.c
@@ -0,0 +1,217 @@
+#include "wasm_compile.h"
+#include "wasm.h"
+#include "stack_machine_instruction.h"
+
+/* instruction structs are connected in a circular list */
+void free_expr(struct instruction *expr)
+{
+ struct instruction *tmp;
+
+ if (expr) {
+ tmp = expr->next;
+ while (tmp != expr) {
+ tmp = tmp->next;
+ free(tmp->prev);
+ }
+
+ free(expr);
+ }
+}
+
+/* instructions are stored in a circular list */
+int add_instruction(struct instruction **expr, uint16_t encoding,
+ struct instruction_data data)
+{
+ struct instruction *new;
+
+ new = malloc(sizeof(struct instruction));
+
+ if (!new) {
+ PRERR(MSG_ALLOC_FAIL(sizeof(struct instruction)));
+ return -1;
+ }
+
+ new->address_assigned = false;
+ new->encoding = encoding;
+ new->data = data;
+
+ if (!*expr) {
+ new->next = new;
+ new->prev = new;
+ *expr = new;
+ } else {
+ new->next = *expr;
+ new->prev = (*expr)->prev;
+ (*expr)->prev->next = new;
+ (*expr)->prev = new;
+ }
+
+ return 0;
+}
+
+static uint8_t estimate_instruction_size(struct instruction *instruction)
+{
+ switch (instruction->data.info) {
+ case DATA_NONE :
+ return 2;
+ case DATA_KNOWN :
+ case DATA_UNKNOWN :
+ return 6;
+ case DATA_KNOWN_21_BITS :
+ return 4;
+ default /* case DATA_KNOWN_6_BITS */ :
+ return 2;
+ }
+}
+
+static uint64_t estimate_expr_size(struct instruction *expr)
+{
+ struct instruction *tmp = expr;
+ uint64_t max_expr_size = 0;
+
+ do {
+ max_expr_size += estimate_instruction_size(tmp);
+ tmp = tmp->next;
+ } while (tmp != expr);
+
+ return max_expr_size;
+}
+
+static void assign_addresses_and_sizes(struct instruction *expr,
+ uint32_t address)
+{
+ struct instruction *tmp = expr;
+
+ do {
+ tmp->address = address;
+ tmp->address_assigned = true;
+
+ if (tmp->data.info == DATA_UNKNOWN &&
+ *tmp->data.data.ptr &&
+ (*tmp->data.data.ptr)->address_assigned)
+ tmp->data = im((*tmp->data.data.ptr)->address);
+
+ address += estimate_instruction_size(tmp);
+ tmp = tmp->next;
+ } while (tmp != expr);
+}
+
+static uint16_t im_instruction(uint16_t payload)
+{
+ return payload | (((uint16_t) 1) << 15);
+}
+
+static void encode_instruction(struct instruction *instruction,
+ uint16_t *memory)
+{
+ uint32_t im = 0;
+ uint16_t encoding = instruction->encoding;
+ uint16_t *dest = memory + instruction->address / 2;
+
+ if (instruction->data.info != DATA_NONE) {
+ if (instruction->data.info == DATA_UNKNOWN)
+ im = (*instruction->data.data.ptr)->address;
+ else
+ im = instruction->data.data.im;
+ }
+
+ switch (instruction->data.info) {
+ case DATA_UNKNOWN :
+ case DATA_KNOWN :
+ *(dest++) = im_instruction(im >> 22);
+ case DATA_KNOWN_21_BITS :
+ *(dest++) = im_instruction(im >> 7);
+ case DATA_KNOWN_6_BITS :
+ encoding |= (im & 0x7F);
+ }
+
+ *dest = encoding;
+}
+
+static void encode_expr(struct instruction *expr, uint16_t *memory)
+{
+ struct instruction *tmp = expr;
+
+ do {
+ encode_instruction(tmp, memory);
+ tmp = tmp->next;
+ } while (tmp != expr);
+}
+
+int assemble(uint32_t memory_size, uint16_t memory[memory_size],
+ struct module *module)
+{
+ uint32_t i;
+ struct function *main_function = NULL;
+ uint32_t current_address;
+ uint64_t function_size;
+ struct instruction *startup = NULL;
+ unsigned short startup_size;
+ int retval = -1;
+
+ for (i = 0; i < module->exports_count; i++) {
+ if (module->exports[i].desc == EXPORT_FUNCIDX &&
+ !strcmp(module->exports[i].name, "main")) {
+ main_function = module->functions +
+ module->exports[i].idx;
+ break;
+ }
+ }
+
+ if (!main_function) {
+ PRERR("No 'main' function\n");
+ goto fail;
+ }
+
+ // For now we're passing 2 numbers to main(): 0x32 and 0x14.
+ // This is just a temporary way to check if our Wasm function
+ // actually does anything. In the end - main() will be
+ // a function, that doesn't require any arguments.
+ if (i_const(im(0x23), &startup) ||
+ i_store(im(STACK_FRAME_BACKUP_ADDR), &startup) ||
+ i_const(im(0x32), &startup) ||
+ i_const(im(0x14), &startup) ||
+ i_call (ptr(&main_function->translated_body), &startup) ||
+ i_halt ( &startup))
+ goto fail;
+
+ startup_size = estimate_expr_size(startup);
+
+ i = module->functions_count;
+ current_address = CODE_TOP_ADDR;
+
+ while (i--) {
+ function_size = estimate_expr_size(module->functions[i]
+ .translated_body);
+ if (function_size > current_address - startup_size) {
+ PRERR("Not enough space for code\n");
+ goto fail;
+ }
+
+ current_address -= function_size;
+ module->functions[i].start_addr = current_address;
+ }
+
+ i = module->functions_count;
+ while (i--)
+ assign_addresses_and_sizes(module->functions[i].translated_body,
+ module->functions[i].start_addr);
+
+ assign_addresses_and_sizes(startup, 0x0);
+
+ i = module->functions_count;
+ while (i--)
+ encode_expr(module->functions[i].translated_body, memory);
+
+ encode_expr(startup, memory);
+
+ retval = 0;
+
+fail:
+ if (retval)
+ PRERR("Couldn't assemble code for stack machine\n");
+
+ free_expr(startup);
+
+ return retval;
+}