Added a.out format for NED binaries to track symbols through to the disassembler.
[ned1] / nedasm / nedasm_codegen.c
index 9484a1d..ddfd792 100644 (file)
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 
 #include "nedasm_structures.h"
 
 #include "nedasm_structures.h"
+#include "nedasm_misc.h"
+#include "../common/a.out.h"
 
 void
 
 void
-write_word_to_file(uint32_t * word, FILE * file)
+write_aout_exec_header(FILE * output, struct exec * aout_exec)
 {
 {
-    fwrite(word, 4, 1, file);
+    uint32_t write_count = 0;
+    for (uint32_t i=0; i<8; i++) {
+        switch (i) {
+            case 0: write_count = fwrite(&(aout_exec->a_midmag),  4, 1, output); break;
+            case 1: write_count = fwrite(&(aout_exec->a_text),    4, 1, output); break;
+            case 2: write_count = fwrite(&(aout_exec->a_data),    4, 1, output); break;
+            case 3: write_count = fwrite(&(aout_exec->a_bss),     4, 1, output); break;
+            case 4: write_count = fwrite(&(aout_exec->a_syms),    4, 1, output); break;
+            case 5: write_count = fwrite(&(aout_exec->a_entry),   4, 1, output); break;
+            case 6: write_count = fwrite(&(aout_exec->a_trsize),  4, 1, output); break;
+            case 7: write_count = fwrite(&(aout_exec->a_drsize),  4, 1, output); break;
+        }
+        if (write_count != 1) {
+            fprintf(stderr, "ERROR: Failed to write aout header.\n");
+            exit(EXIT_FAILURE);
+        }
+    }
+}
+
+void
+write_aout_text_segment(FILE * output, uint32_t * text_segment)
+{
+    for (uint32_t i=1; i <= text_segment[0]; i++) {
+        uint32_t write_count = fwrite(&(text_segment[i]), 4, 1, output);
+        if (write_count != 1) {
+            fprintf(stderr, "ERROR: Failed to write text segment.\n");
+            exit(EXIT_FAILURE);
+        }
+    }
+}
+
+void
+write_aout_symbol_table(FILE * output, struct nlist * symbol_table, uint32_t symbol_count)
+{
+    uint32_t write_count = 0;
+    for (uint32_t i=0; i < symbol_count; i++) {
+        for (uint32_t j=0; j<5; j++) {
+            switch (j) {
+                case 0: write_count = fwrite(&(symbol_table[i].n_un.n_strx), 4, 1, output); break;
+                case 1: write_count = fwrite(&(symbol_table[i].n_type),      4, 1, output); break;
+                case 2: write_count = fwrite(&(symbol_table[i].n_other),     4, 1, output); break;
+                case 3: write_count = fwrite(&(symbol_table[i].n_desc),      4, 1, output); break;
+                case 4: write_count = fwrite(&(symbol_table[i].n_value),     4, 1, output); break;
+            }
+            if (write_count != 1) {
+                fprintf(stderr, "ERROR: Failed to write symbol table.\n");
+                exit(EXIT_FAILURE);
+            }
+        }
+    }
+}
+
+void
+write_aout_string_table(FILE * output, char * string_table, uint32_t string_table_size)
+{
+    uint32_t write_count = fwrite(&string_table_size, 4, 1, output);
+    if (write_count != 1) {
+        fprintf(stderr, "ERROR: Failed to write string table size.\n");
+        exit(EXIT_FAILURE);
+    }
+    for (uint32_t i=0; i < string_table_size; i++) {
+        write_count = fwrite(&(string_table[i]), 1, 1, output);
+        if (write_count != 1) {
+            fprintf(stderr, "ERROR: Failed to write string table.\n");
+            exit(EXIT_FAILURE);
+        }
+    }
 }
 
 void
 }
 
 void
-pad_word_boundary(uint8_t * syllable_count, uint32_t * word, FILE * output)
+generate_aout(FILE * output, uint32_t * text_segment,
+              struct nlist * symbol_table, uint32_t symbol_count)
+{
+    struct exec aout_exec;
+    N_SETMAGIC(aout_exec, NED_MAGIC1, MID_NED, 0);
+    aout_exec.a_text = (4 * text_segment[0]); /* 4 bytes per word. */
+    aout_exec.a_data = 0;
+    aout_exec.a_bss = 0;
+    aout_exec.a_syms = (20 * symbol_count); /* 20 = 5x 32-bit values from nlist struct. */
+    aout_exec.a_entry = MEM_BEGIN;
+    aout_exec.a_trsize = 0;
+    aout_exec.a_drsize = 0;
+    write_aout_exec_header(output, &aout_exec);
+
+    write_aout_text_segment(output,text_segment);
+
+    uint32_t string_table_size = 0;
+    for (uint32_t i = 0; i < symbol_count; i++) {
+        string_table_size += (strnlen(symbol_table[i].n_un.n_name, MAX_LABEL_LEN) + 1);
+    }
+    char * string_table = malloc(string_table_size);
+    uint32_t string_table_offset = 0;
+    for (uint32_t i = 0; i < symbol_count; i++) {
+        uint32_t len = (strnlen(symbol_table[i].n_un.n_name, MAX_LABEL_LEN) + 1);
+        strncpy(string_table+string_table_offset, symbol_table[i].n_un.n_name, len);
+        symbol_table[i].n_un.n_strx = string_table_offset;
+        string_table_offset += len;
+    }
+
+    write_aout_symbol_table(output, symbol_table, symbol_count);
+
+    write_aout_string_table(output, string_table, string_table_size);
+}
+
+void
+write_word_to_text_segment(uint32_t * word, uint32_t * text_seg)
+{
+    text_seg[(++text_seg[0])] = *word;
+}
+
+void
+pad_word_boundary(uint8_t * syllable_count, uint32_t * word, uint32_t * text_seg)
 {
     if (*syllable_count > 0) {
         while (*syllable_count <= 4) {
             *word |= 0b000001 << 6 * (4 - (*syllable_count)++);
         }
 {
     if (*syllable_count > 0) {
         while (*syllable_count <= 4) {
             *word |= 0b000001 << 6 * (4 - (*syllable_count)++);
         }
-        write_word_to_file(word, output);
+        write_word_to_text_segment(word, text_seg);
         *syllable_count = 0;
         *word = 0;
     }
 }
 
 void
         *syllable_count = 0;
         *word = 0;
     }
 }
 
 void
-generate_code_WORD(struct instruction * instructions, FILE * output)
+generate_code_WORD(struct instruction * instructions, uint32_t * text_seg)
 {
     /* Set the instruction format to Type A. */
     uint32_t temp_word = 0b10000000000000000000000000000000;
 {
     /* Set the instruction format to Type A. */
     uint32_t temp_word = 0b10000000000000000000000000000000;
@@ -49,12 +159,11 @@ generate_code_WORD(struct instruction * instructions, FILE * output)
     /* Set the data portion of the instruction. */
     temp_word |= instructions->data >> 1;
 
     /* Set the data portion of the instruction. */
     temp_word |= instructions->data >> 1;
 
-    /* Write to disk. */
-    write_word_to_file(&temp_word, output);
+    write_word_to_text_segment(&temp_word, text_seg);
 }
 
 void
 }
 
 void
-generate_code_IM(struct instruction * instructions, FILE * output,
+generate_code_IM(struct instruction * instructions,
                  uint8_t * syllable_count, uint32_t * temp_word)
 {
     uint8_t temp_syllable = 0b00100000;
                  uint8_t * syllable_count, uint32_t * temp_word)
 {
     uint8_t temp_syllable = 0b00100000;
@@ -68,7 +177,7 @@ generate_code_IM(struct instruction * instructions, FILE * output,
 }
 
 void
 }
 
 void
-generate_code_LDSP(struct instruction * instructions, FILE * output,
+generate_code_LDSP(struct instruction * instructions,
                    uint8_t * syllable_count, uint32_t * temp_word)
 {
     uint8_t temp_syllable = 0b00011000;
                    uint8_t * syllable_count, uint32_t * temp_word)
 {
     uint8_t temp_syllable = 0b00011000;
@@ -82,7 +191,7 @@ generate_code_LDSP(struct instruction * instructions, FILE * output,
 }
 
 void
 }
 
 void
-generate_code_STSP(struct instruction * instructions, FILE * output,
+generate_code_STSP(struct instruction * instructions,
                    uint8_t * syllable_count, uint32_t * temp_word)
 {
     uint8_t temp_syllable = 0b00010000;
                    uint8_t * syllable_count, uint32_t * temp_word)
 {
     uint8_t temp_syllable = 0b00010000;
@@ -95,12 +204,35 @@ generate_code_STSP(struct instruction * instructions, FILE * output,
     *temp_word |= temp_syllable << 6 * (4 - *syllable_count);
 }
 
     *temp_word |= temp_syllable << 6 * (4 - *syllable_count);
 }
 
+void
+generate_label(struct instruction * instructions, struct nlist * symbol_table, uint32_t index)
+{
+    symbol_table[index].n_un.n_name = instructions->label;
+    symbol_table[index].n_type = N_ABS;
+    symbol_table[index].n_other = AUX_FUNC;
+    symbol_table[index].n_desc = 0;
+    while (instructions->syllable == LABEL) instructions = instructions->next;
+    symbol_table[index].n_value = instructions->address;
+}
+
 void
 generate_code(struct instruction * instructions, FILE * output)
 {
 void
 generate_code(struct instruction * instructions, FILE * output)
 {
+    uint32_t label_count = 0;
+    uint32_t max_word_count = 0;
+    struct instruction * temp = seek_instruction_list_start(instructions);
+    while (temp != NULL) {
+        (temp->syllable == LABEL) ? (label_count++) : (max_word_count++);
+        temp = temp->next;
+    }
+    /* +1 to store the number of entries as the first element of the array. */
+    uint32_t * text_segment = malloc((max_word_count * sizeof(uint32_t)) + 1);
+    struct nlist * symbol_table = malloc(label_count * sizeof(struct nlist));
+
     uint8_t syllable_count = 0;
     uint32_t temp_word = 0;
 
     uint8_t syllable_count = 0;
     uint32_t temp_word = 0;
 
+    label_count = 0;
     instructions = seek_instruction_list_start(instructions);
     while (instructions != NULL) {
         /* If starting a new word, zero the word, setting it to Type C by default. */
     instructions = seek_instruction_list_start(instructions);
     while (instructions != NULL) {
         /* If starting a new word, zero the word, setting it to Type C by default. */
@@ -109,17 +241,17 @@ generate_code(struct instruction * instructions, FILE * output)
         switch (instructions->syllable) {
             case WORD:
                 /* Must pad partial word w/NOPs & write to disk before starting new WORD. */
         switch (instructions->syllable) {
             case WORD:
                 /* Must pad partial word w/NOPs & write to disk before starting new WORD. */
-                pad_word_boundary(&syllable_count, &temp_word, output);
-                generate_code_WORD(instructions, output);
+                pad_word_boundary(&syllable_count, &temp_word, text_segment);
+                generate_code_WORD(instructions, text_segment);
                 break;
             case IM:
                 break;
             case IM:
-                generate_code_IM(instructions, output, &syllable_count, &temp_word);
+                generate_code_IM(instructions, &syllable_count, &temp_word);
                 break;
             case LDSP:
                 break;
             case LDSP:
-                generate_code_LDSP(instructions, output, &syllable_count, &temp_word);
+                generate_code_LDSP(instructions, &syllable_count, &temp_word);
                 break;
             case STSP:
                 break;
             case STSP:
-                generate_code_STSP(instructions, output, &syllable_count, &temp_word);
+                generate_code_STSP(instructions, &syllable_count, &temp_word);
                 break;
             case MVSTCK:    temp_word |= 0b001111 << 6 * (4 - syllable_count);  break;
             case ADD:       temp_word |= 0b001100 << 6 * (4 - syllable_count);  break;
                 break;
             case MVSTCK:    temp_word |= 0b001111 << 6 * (4 - syllable_count);  break;
             case ADD:       temp_word |= 0b001100 << 6 * (4 - syllable_count);  break;
@@ -137,18 +269,27 @@ generate_code(struct instruction * instructions, FILE * output)
             case HALT:      temp_word |= 0b000000 << 6 * (4 - syllable_count);  break;
             case SWAP:      temp_word |= 0b001101 << 6 * (4 - syllable_count);  break;
             case JMP:       temp_word |= 0b001110 << 6 * (4 - syllable_count);  break;
             case HALT:      temp_word |= 0b000000 << 6 * (4 - syllable_count);  break;
             case SWAP:      temp_word |= 0b001101 << 6 * (4 - syllable_count);  break;
             case JMP:       temp_word |= 0b001110 << 6 * (4 - syllable_count);  break;
+            case LABEL:
+                generate_label(instructions, symbol_table, label_count);
+                label_count++;
+                break;
             default:
                 fprintf(stderr, "ERROR: Unassigned syllable on line %u.\n", instructions->linenum);
                 break;
         }
 
             default:
                 fprintf(stderr, "ERROR: Unassigned syllable on line %u.\n", instructions->linenum);
                 break;
         }
 
-        if (syllable_count == 4) write_word_to_file(&temp_word, output);
+        if (syllable_count == 4) write_word_to_text_segment(&temp_word, text_segment);
 
 
-        if (instructions->syllable != WORD) syllable_count = (syllable_count + 1) % 5;
+        if (instructions->syllable != WORD && instructions->syllable != LABEL) {
+            syllable_count = (syllable_count + 1) % 5;
+        }
 
         instructions = instructions->next;
     }
 
     /* If necessary, pad incomplete word with NOPs. */
 
         instructions = instructions->next;
     }
 
     /* If necessary, pad incomplete word with NOPs. */
-    pad_word_boundary(&syllable_count, &temp_word, output);
+    pad_word_boundary(&syllable_count, &temp_word, text_segment);
+
+    /* Write to disk */
+    generate_aout(output, text_segment, symbol_table, label_count);
 }
 }