summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFreya Murphy <freya@freyacat.org>2024-09-09 20:48:08 -0400
committerFreya Murphy <freya@freyacat.org>2024-09-09 20:48:08 -0400
commit0ff948af3d65150f44c9fe801ada806ce0637fe1 (patch)
treeba766d33d12bf1063660c2144af2d5f5c36b4c87
parenti forgor syscall (diff)
downloadmips-0ff948af3d65150f44c9fe801ada806ce0637fe1.tar.gz
mips-0ff948af3d65150f44c9fe801ada806ce0637fe1.tar.bz2
mips-0ff948af3d65150f44c9fe801ada806ce0637fe1.zip
relocation table hell
-rw-r--r--config.mk2
-rw-r--r--include/mips32.h8
-rw-r--r--masm/asm.c41
-rw-r--r--masm/asm.h31
-rw-r--r--masm/asm_mips32.c841
-rw-r--r--masm/parse.c16
-rw-r--r--masm/parse.h38
-rw-r--r--masm/parse_mips32.c955
-rw-r--r--masm/parse_mips32.h4
-rw-r--r--masm/reftbl.c10
-rw-r--r--masm/sectbl.c112
-rw-r--r--masm/strtbl.c55
-rw-r--r--masm/test.asm5
13 files changed, 1306 insertions, 812 deletions
diff --git a/config.mk b/config.mk
index 682002b..3f23d71 100644
--- a/config.mk
+++ b/config.mk
@@ -5,7 +5,7 @@ LD=cc
CFLAGS += -pipe
CFLAGS += -Wall -Wextra -pedantic
-CFLAGS += -O3 -g
+CFLAGS += -O0 -g
# ======================== CONFIG OPTIONS ==
#
diff --git a/include/mips32.h b/include/mips32.h
index ce0e997..228e213 100644
--- a/include/mips32.h
+++ b/include/mips32.h
@@ -117,6 +117,7 @@ enum mips32_instruction_type {
MIPS32_INS_SRLV,
MIPS32_INS_SUB,
MIPS32_INS_SUBU,
+ MIPS32_INS_SYSCALL,
MIPS32_INS_OR,
MIPS32_INS_ORI,
MIPS32_INS_NOR,
@@ -447,6 +448,10 @@ MIPS32_INS(SUB, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_SUB)
#define MIPS32_FUNCT_SUBU 0b100011
MIPS32_INS(SUBU, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_SUBU)
+/* SYSCALL - syscall */
+#define MIPS32_FUNCT_SYSCALL 0b001100
+MIPS32_INS(SYSCALL, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_SYSCALL)
+
/* OR - or */
#define MIPS32_FUNCT_OR 0b100101
MIPS32_INS(OR, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_OR)
@@ -478,11 +483,14 @@ enum mips32_directive_type {
MIPS32_DIRECTIVE_HALF,
MIPS32_DIRECTIVE_BYTE,
MIPS32_DIRECTIVE_SECTION,
+ MIPS32_DIRECTIVE_EXTERN,
+ MIPS32_DIRECTIVE_GLOBL,
};
/* mip32 directive */
struct mips32_directive {
enum mips32_directive_type type;
+ uint32_t len; // used for words, halfs, bytes
union {
uint16_t align;
uint16_t space;
diff --git a/masm/asm.c b/masm/asm.c
new file mode 100644
index 0000000..6e2a56c
--- /dev/null
+++ b/masm/asm.c
@@ -0,0 +1,41 @@
+#include <merror.h>
+#include <stdlib.h>
+
+#include "asm.h"
+
+int assembler_init(struct assembler *asm, const char *path)
+{
+ if (lexer_init(path, &asm->lexer))
+ return M_ERROR;
+
+ if (parser_init(&asm->lexer, &asm->parser)) {
+ lexer_free(&asm->lexer);
+ return M_ERROR;
+ }
+
+ if (strtbl_init(&asm->shstr_tbl)) {
+ parser_free(&asm->parser);
+ lexer_free(&asm->lexer);
+ return M_ERROR;
+ }
+
+ if (strtbl_init(&asm->str_tbl)) {
+ strtbl_free(&asm->shstr_tbl);
+ parser_free(&asm->parser);
+ lexer_free(&asm->lexer);
+ return M_ERROR;
+ }
+
+ asm->meta = NULL;
+
+ return M_SUCCESS;
+}
+
+void assembler_free(struct assembler *asm)
+{
+ strtbl_free(&asm->str_tbl);
+ strtbl_free(&asm->shstr_tbl);
+ parser_free(&asm->parser);
+ lexer_free(&asm->lexer);
+ free(asm->meta);
+}
diff --git a/masm/asm.h b/masm/asm.h
index 1bc7cf5..b8e6214 100644
--- a/masm/asm.h
+++ b/masm/asm.h
@@ -5,13 +5,16 @@
#include <stddef.h>
+#include "lex.h"
+#include "parse.h"
+
struct str_table {
- char *ptr;
- size_t size;
+ char *ptr;
+ size_t size;
};
/* initalize a string table */
-void strtbl_init(struct str_table *str_tbl);
+int strtbl_init(struct str_table *str_tbl);
/* free a string table */
void strtbl_free(struct str_table *str_tbl);
@@ -22,11 +25,29 @@ int strtbl_get_str(struct str_table *str_tbl, const char *str, size_t *res);
/* get or append a string into the string table */
int strtbl_write_str(struct str_table *str_tbl, const char *str, size_t *res);
+struct section_meta {
+ void *reltbl;
+ uint32_t reltbl_len;
+ uint32_t reltbl_idx; // reltbl idx in shdr
+ uint32_t shdr_idx; // sec idx in shdr
+ uint32_t v_addr;
+};
+
struct assembler {
- struct parser *parser;
- struct str_table str_tbl;
+ struct lexer lexer;
+ struct parser parser;
+ struct str_table shstr_tbl;
+ struct str_table str_tbl;
+
+ struct section_meta *meta;
+ size_t shstrtbl_idx;
+ size_t strtbl_idx;
+ size_t symtbl_idx;
};
+int assembler_init(struct assembler *asm, const char *path);
+void assembler_free(struct assembler *asm);
+
/* assemble a mips32 file*/
int assemble_file_mips32(char *path);
diff --git a/masm/asm_mips32.c b/masm/asm_mips32.c
index dcb81e5..deda214 100644
--- a/masm/asm_mips32.c
+++ b/masm/asm_mips32.c
@@ -14,352 +14,665 @@
extern char *current_file;
-#define SHDR_SYMTBL 0
-#define SHDR_STRTBL 1
-#define SHDR_SECTIONS 2
+static int handle_directive(struct assembler *asm,
+ struct mips32_directive *directive)
+{
+ switch (directive->type) {
+ case MIPS32_DIRECTIVE_SECTION: {
+ struct section_table *sec_tbl = &asm->parser.sec_tbl;
+ struct section *sec;
+ if (sectbl_get(sec_tbl, &sec, directive->name)
+ == M_SUCCESS) {
+ sec_tbl->current = sec;
+ break;
+ }
+
+ if (sectbl_alloc(sec_tbl, &sec, directive->name))
+ return M_ERROR;
+
+ sec_tbl->current = sec;
+ break;
+ }
+
+ case MIPS32_DIRECTIVE_ALIGN: {
+ asm->parser.sec_tbl.current->alignment =
+ 1 << directive->align;
+ break;
+ }
+
+ case MIPS32_DIRECTIVE_SPACE: {
+ struct section_entry entry;
+ entry.type = ENT_NO_DATA;
+ entry.size = directive->space;
+ if (sec_push(asm->parser.sec_tbl.current, entry))
+ return M_ERROR;
+ break;
+ }
+
+ case MIPS32_DIRECTIVE_WORD: {
+ for (uint32_t i = 0; i < directive->len; i++) {
+ struct section_entry entry;
+ entry.type = ENT_WORD;
+ entry.word = directive->words[i];
+ if (sec_push(asm->parser.sec_tbl.current, entry))
+ return M_ERROR;
+ }
+ break;
+ }
+
+ case MIPS32_DIRECTIVE_HALF: {
+ for (uint32_t i = 0; i < directive->len; i++) {
+ struct section_entry entry;
+ entry.type = ENT_HALF;
+ entry.half = directive->halfs[i];
+ if (sec_push(asm->parser.sec_tbl.current, entry))
+ return M_ERROR;
+ }
+ break;
+ }
+
+ case MIPS32_DIRECTIVE_BYTE: {
+ for (uint32_t i = 0; i < directive->len; i++) {
+ struct section_entry entry;
+ entry.type = ENT_BYTE;
+ entry.byte = directive->bytes[i];
+ if (sec_push(asm->parser.sec_tbl.current, entry))
+ return M_ERROR;
+ }
+ break;
+ }
+
+ case MIPS32_DIRECTIVE_EXTERN: {
+ struct symbol symbol;
+ if (symtbl_find(&asm->parser.sym_tbl, NULL, directive->name)
+ == M_SUCCESS) {
+ ERROR("cannot extern local symbol '%s'",
+ directive->name);
+ return M_ERROR;
+ }
+
+ symbol = (struct symbol) {
+ .name = "",
+ .sec = asm->parser.sec_tbl.current,
+ .index = asm->parser.sec_tbl.current->count,
+ .flag = SYM_EXTERNAL,
+ };
+ strcpy(symbol.name, directive->name);
+
+ if (symtbl_push(&asm->parser.sym_tbl, symbol))
+ return M_ERROR;
+
+ break;
+ }
+
+ case MIPS32_DIRECTIVE_GLOBL: {
+ struct symbol symbol;
+ if (symtbl_find(&asm->parser.sym_tbl, NULL, directive->name)
+ == M_SUCCESS) {
+ symbol.flag = SYM_GLOBAL;
+ break;
+ }
+
+ symbol = (struct symbol) {
+ .name = "",
+ .sec = NULL,
+ .index = 0,
+ .flag = SYM_GLOBAL,
+ };
+ strcpy(symbol.name, directive->name);
+
+ if (symtbl_push(&asm->parser.sym_tbl, symbol))
+ return M_ERROR;
+
+ break;
+ }
+ }
+
+ return M_SUCCESS;
+}
-static int parse_file(struct parser *parser)
+static int parse_file(struct assembler *asm)
{
+ struct parser *parser = &asm->parser;
+
while (1) {
struct expr expr;
if (parser_next(parser, &expr)) {
break;
}
- if (expr.type == EXPR_INS)
- if (sectbl_push(&parser->sec_tbl,
- parser->sec_tbl.current, expr.ins))
- return M_ERROR;
- }
+ switch (expr.type) {
+ case EXPR_INS:
+ struct section_entry entry;
+ entry.type = ENT_INS;
+ entry.size = sizeof(struct mips32_instruction);
+ entry.ins = expr.ins;
+ if (sec_push(parser->sec_tbl.current, entry))
+ return M_ERROR;
+ break;
- for (uint32_t i = 0; i < parser->ref_tbl.count; i++) {
- struct reference *ref = &parser->ref_tbl.references[i];
- struct symbol *sym;
- struct mips32_instruction *ins;
+ case EXPR_DIRECTIVE:
+ if (handle_directive(asm, &expr.directive.mips32))
+ return M_ERROR;
+ break;
- if (symtbl_find(&parser->sym_tbl, &sym, ref->name)) {
- ERROR("undefined symbol '%s'", ref->name);
- return M_ERROR;
+ case EXPR_CONSTANT:
+ case EXPR_LABEL:
+ // nothing needed to be done
+ break;
}
+ }
- ins = &ref->section->ins[ref->index].mips32;
+ struct section_meta *meta = malloc(sizeof(struct section_meta) *
+ parser->sec_tbl.count);
+ if (meta == NULL) {
+ ERROR("cannot alloc");
+ return M_ERROR;
+ }
- switch (ref->type) {
- case REF_OFFESET:
- ins->B_data.offset += sym->position -
- (ref->section->start + ref->index);
- break;
- case REF_TARGET:
- ins->J_data.target += sym->position;
- break;
- }
- };
+ asm->meta = meta;
- return M_SUCCESS;
+ size_t ptr = 0;
+ for (uint32_t i = 0; i < parser->sec_tbl.count; i++) {
+ struct section *sec = &parser->sec_tbl.sections[i];
+ meta[i].v_addr = ptr;
+ ptr += sec_size(sec);
+ }
+
+ return M_SUCCESS;
}
static int assemble_phdr(struct assembler *asm, Elf32_Phdr **res,
- uint32_t *res2)
+ uint32_t *res2)
{
- struct parser *parser = asm->parser;
- Elf32_Phdr *phdr = malloc(sizeof(Elf32_Phdr) *
- parser->sec_tbl.count);
- size_t ins_sz = sizeof(struct mips32_instruction);
+ struct parser *parser = &asm->parser;
+ Elf32_Phdr *phdr = malloc(sizeof(Elf32_Phdr) *
+ parser->sec_tbl.count);
+ if (phdr == NULL) {
+ ERROR("cannot alloc");
+ return M_ERROR;;
+ }
- if (phdr == NULL) {
- ERROR("cannot alloc");
- return M_ERROR;;
- }
+ for (uint32_t i = 0; i < parser->sec_tbl.count; i++) {
+ Elf32_Phdr *hdr = &phdr[i];
+ struct section *sec = &parser->sec_tbl.sections[i];
+ size_t size = sec_size(sec);
+ hdr->p_type = PT_LOAD;
+ hdr->p_flags = (sec->execute << 0) |
+ (sec->write << 1) |
+ (sec->read << 2);
+ hdr->p_offset = 0;
+ hdr->p_vaddr = 0;
+ hdr->p_paddr = 0;
+ hdr->p_filesz = size;
+ hdr->p_memsz = size;
+ hdr->p_align = sec->alignment;
+ }
- for (uint32_t i = 0; i < parser->sec_tbl.count; i++) {
- Elf32_Phdr *hdr = &phdr[i];
- struct section *sec = &parser->sec_tbl.sections[i];
+ *res = phdr;
+ *res2 = parser->sec_tbl.count;
+ return M_SUCCESS;
+}
- hdr->p_type = PT_LOAD;
- hdr->p_flags = PF_X | PF_W | PF_R; // FIXME: this is bad
- hdr->p_offset = sec->start * ins_sz;
- hdr->p_vaddr = sec->start * ins_sz;
- hdr->p_paddr = 0x00;
- hdr->p_filesz = sec->count * ins_sz;
- hdr->p_memsz = sec->count * ins_sz;
- hdr->p_align = sec->alignment;
- }
+static int assemble_symtbl(struct assembler *asm, Elf32_Sym **res,
+ uint32_t *res2)
+{
+ Elf32_Sym *stbl = malloc(sizeof(Elf32_Sym) * asm->parser.sym_tbl
+ .count);
+ size_t size = 0;
- *res = phdr;
- *res2 = parser->sec_tbl.count;
- return M_SUCCESS;
+ if (stbl == NULL)
+ return M_ERROR;
+
+ for (uint32_t i = 0; i < asm->parser.sym_tbl.count; i++) {
+ struct symbol *sym = &asm->parser.sym_tbl.symbols[i];
+ size_t str_off;
+ unsigned char bind;
+ unsigned char type = STT_NOTYPE;
+
+ if (strtbl_write_str(&asm->str_tbl, sym->name, &str_off)) {
+ free(stbl);
+ return M_ERROR;
+ }
+
+ if (sym->flag != SYM_LOCAL)
+ bind = STB_LOCAL;
+ else
+ bind = STB_GLOBAL;
+
+ stbl[i] = (Elf32_Sym) {
+ .st_name = str_off,
+ .st_value = sym->index,
+ .st_size = 0,
+ .st_info = ELF32_ST_INFO(bind, type),
+ .st_other = ELF32_ST_VISIBILITY(STV_DEFAULT),
+ .st_shndx = asm->meta[sym->sec->index].shdr_idx,
+ };
+ size = i + 1;
+ };
+
+ *res = stbl;
+ *res2 = size;
+
+ return M_SUCCESS;
}
-static int assemble_symtbl(struct assembler *asm, Elf32_Sym **res,
- uint32_t *res2)
+static int assemble_reltbl_sec(struct assembler *asm, Elf32_Sym *symtbl,
+ uint32_t symtbl_len, struct section *sec)
{
- Elf32_Sym *stbl = malloc(sizeof(Elf32_Sym) * asm->parser->sym_tbl
- .count);
+ uint32_t len = 0;
+
+ for (uint32_t i = 0; i < asm->parser.ref_tbl.count; i++) {
+ struct reference *ref = &asm->parser.ref_tbl.references[i];
+ if (ref->section->index == sec->index) {
+ len++;
+ }
+ }
- if (stbl == NULL)
- return M_ERROR;
+ if (len == 0) {
+ asm->meta[sec->index].reltbl = NULL;
+ return M_SUCCESS;
+ }
- for (uint32_t i = 0; i < asm->parser->sym_tbl.count; i++) {
- struct symbol *sym = &asm->parser->sym_tbl.symbols[i];
- size_t str_off;
+ Elf32_Rela *reltbl = malloc(sizeof(Elf32_Rela) * len);
- if (strtbl_write_str(&asm->str_tbl, sym->name, &str_off)) {
- free(stbl);
- return M_ERROR;
- }
+ if (reltbl == NULL) {
+ ERROR("cannot alloc");
+ return M_ERROR;
+ }
- int viz = STB_LOCAL;
- switch (sym->flag) {
- case SYM_LOCAL:
- viz = STB_LOCAL;
- break;
- case SYM_GLOBAL:
- case SYM_EXTERNAL:
- viz = STB_GLOBAL;
- break;
- }
+ for (uint32_t i = 0; i < asm->parser.ref_tbl.count; i++) {
+ struct reference *ref = &asm->parser.ref_tbl.references[i];
+ struct mips32_instruction *ins = &ref->section->
+ entries[ref->index].ins.mips32;
+ struct section_meta *meta = &asm->meta[ref->section->index];
- stbl[i] = (Elf32_Sym) {
- .st_name = str_off,
- .st_value = sym->position,
- .st_size = 0,
- .st_info = (unsigned char)
- ELF32_ST_INFO(SYMINFO_BT_SELF,
- SYMINFO_FLG_DIRECT),
- .st_other = (unsigned char)
- ELF32_ST_VISIBILITY(viz),
- .st_shndx = 0, // FIXME: specify section
- };
- };
+ if (ref->section->index != sec->index) {
+ continue;
+ }
- *res = stbl;
- *res2 = asm->parser->sym_tbl.count;
+ int32_t addend = 0;
+ unsigned char type = 0;
+ switch (ref->type) {
+ case REF_OFFESET:
+ addend = ins->B_data.offset;
+ type = R_MIPS_PC16;
+ break;
+ case REF_TARGET:
+ addend = ins->J_data.target;
+ type = R_MIPS_26;
+ break;
+ }
- return M_SUCCESS;
+ int32_t symidx = -1;
+
+ for (uint32_t i = 0; i < symtbl_len; i++) {
+ Elf32_Sym *sym = &symtbl[i];
+ const char *str = &asm->str_tbl.ptr[sym->st_name];
+ if (strcmp(ref->name, str) == 0) {
+ symidx = i;
+ break;
+ }
+ }
+
+ if (symidx == -1) {
+ ERROR("undefined symbol '%s'", ref->name);
+ free(reltbl);
+ return M_ERROR;
+ }
+
+ reltbl[i] = (Elf32_Rela) {
+ .r_info = ELF32_R_INFO(symidx, type),
+ .r_addend = addend,
+ .r_offset = meta->v_addr +
+ sec_index(ref->section, ref->index),
+ };
+ };
+
+ asm->meta[sec->index].reltbl_len = len;
+ asm->meta[sec->index].reltbl = reltbl;
+
+ return M_SUCCESS;
+}
+
+static int assemble_reltbl(struct assembler *asm, Elf32_Sym *symtbl,
+ uint32_t symtbl_len)
+{
+ for (uint32_t i = 0; i < asm->parser.sec_tbl.count; i++) {
+ struct section *sec = &asm->parser.sec_tbl.sections[i];
+ if (assemble_reltbl_sec(asm, symtbl, symtbl_len, sec))
+ return M_ERROR;
+ }
+
+ return M_SUCCESS;
}
static int assemble_shdr(struct assembler *asm, Elf32_Shdr **res,
- uint32_t *res2)
+ uint32_t *res2)
{
- uint32_t entries = 2; // str table and sym tabel
- entries += asm->parser->sec_tbl.count; // sections
+ uint32_t max_entries = 4; // symtab, strtab, shstrtab
+ max_entries += asm->parser.sec_tbl.count; // sections
+ max_entries += asm->parser.sec_tbl.count; // reltabs per section
- Elf32_Shdr *shdr = malloc(sizeof(Elf32_Shdr) * entries);
+ Elf32_Shdr *shdr = malloc(sizeof(Elf32_Shdr) * max_entries);
- size_t str_off;
- if (strtbl_write_str(&asm->str_tbl, ".shsymtab", &str_off)) {
- free(shdr);
- return M_ERROR;
- }
+ size_t str_off;
+ uint32_t count = 0;
- // symbol table
- shdr[SHDR_SYMTBL] = (Elf32_Shdr) {
- .sh_name = str_off,
- .sh_type = SHT_SYMTAB,
- .sh_flags = 0,
- .sh_addr = 0,
- .sh_offset = 0,
- .sh_size = 0,
- .sh_link = 1,
- .sh_info = 0,
- .sh_addralign = 1,
- .sh_entsize = sizeof(Elf32_Sym),
- };
+ // eeltables
+ for (uint32_t i = 0; i < asm->parser.sec_tbl.count; i++) {
- if (strtbl_write_str(&asm->str_tbl, ".shstrtab", &str_off)) {
- free(shdr);
- return M_ERROR;
- }
+ if (asm->meta[i].reltbl == NULL)
+ continue;
- // string table
- shdr[SHDR_STRTBL] = (Elf32_Shdr) {
- .sh_name = str_off,
- .sh_type = SHT_STRTAB,
- .sh_flags = SHF_STRINGS,
- .sh_addr = 0,
- .sh_offset = 0,
- .sh_size = 0,
- .sh_link = 0,
- .sh_info = 0,
- .sh_addralign = 1,
- .sh_entsize = 0,
- };
+ struct section *sec = &asm->parser.sec_tbl.sections[i];
+ const char *prefix = ".reltab.";
+ char reltab_name[MAX_LEX_LENGTH + 8];
- // for each section
- for (uint32_t i = 0; i < asm->parser->sec_tbl.count; i++) {
- struct section *sec = &asm->parser->sec_tbl.sections[i];
- char name[MAX_LEX_LENGTH+1] = ".";
- strcat(name, sec->name);
- if (strtbl_write_str(&asm->str_tbl, name, &str_off)) {
- free(shdr);
- return M_ERROR;
- }
- shdr[i+SHDR_SECTIONS] = (Elf32_Shdr) {
- .sh_name = str_off,
- .sh_type = SHT_PROGBITS,
- .sh_flags = SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR,
- .sh_addr = 0,
- .sh_offset = 0,
- .sh_size = 0,
- .sh_link = 0,
- .sh_info = 0,
- .sh_addralign = sec->alignment,
- .sh_entsize = sizeof(struct mips32_instruction),
+ strcpy(reltab_name, prefix);
+ strcat(reltab_name, sec->name);
+
+ if (strtbl_write_str(&asm->shstr_tbl, reltab_name, &str_off)) {
+ free(shdr);
+ return M_ERROR;
+ }
+
+ asm->meta[i].reltbl_idx = count;
+ shdr[count++] = (Elf32_Shdr) {
+ .sh_name = str_off,
+ .sh_type = SHT_RELA,
+ .sh_flags = 0,
+ .sh_addr = 0,
+ .sh_offset = 0,
+ .sh_size = 0,
+ .sh_link = 0,
+ .sh_info = 0,
+ .sh_addralign = 1,
+ .sh_entsize = sizeof(Elf32_Rela),
+ };
+ }
+
+ // for each section
+ for (uint32_t i = 0; i < asm->parser.sec_tbl.count; i++) {
+ struct section *sec = &asm->parser.sec_tbl.sections[i];
+ char name[MAX_LEX_LENGTH+1] = ".";
+ strcat(name, sec->name);
+ if (strtbl_write_str(&asm->shstr_tbl, name, &str_off)) {
+ free(shdr);
+ return M_ERROR;
+ }
+ asm->meta[i].shdr_idx = count;
+ if (asm->meta[i].reltbl != NULL)
+ shdr[asm->meta[i].reltbl_idx].sh_info = count;
+ shdr[count++] = (Elf32_Shdr){
+ .sh_name = str_off,
+ .sh_type = SHT_PROGBITS,
+ .sh_flags = (sec->write << 0) | (sec->execute << 2) |
+ SHF_ALLOC,
+ .sh_addr = 0,
+ .sh_offset = 0,
+ .sh_size = 0,
+ .sh_link = 0,
+ .sh_info = 0,
+ .sh_addralign = sec->alignment,
+ .sh_entsize = sizeof(struct mips32_instruction),
};
}
- *res = shdr;
- *res2 = entries;
+ // symbol table
+ if (strtbl_write_str(&asm->shstr_tbl, ".symtab", &str_off)) {
+ free(shdr);
+ return M_ERROR;
+ }
+
+ asm->symtbl_idx = count;
+ shdr[count++] = (Elf32_Shdr) {
+ .sh_name = str_off,
+ .sh_type = SHT_SYMTAB,
+ .sh_flags = 0,
+ .sh_addr = 0,
+ .sh_offset = 0,
+ .sh_size = 0,
+ .sh_link = 1,
+ .sh_info = 0,
+ .sh_addralign = 1,
+ .sh_entsize = sizeof(Elf32_Sym),
+ };
- return M_SUCCESS;
+ // string table
+ if (strtbl_write_str(&asm->shstr_tbl, ".strtab", &str_off)) {
+ free(shdr);
+ return M_ERROR;
+ }
+
+ asm->strtbl_idx = count;
+ shdr[count++] = (Elf32_Shdr) {
+ .sh_name = str_off,
+ .sh_type = SHT_STRTAB,
+ .sh_flags = SHF_STRINGS,
+ .sh_addr = 0,
+ .sh_offset = 0,
+ .sh_size = 0,
+ .sh_link = 0,
+ .sh_info = 0,
+ .sh_addralign = 1,
+ .sh_entsize = 0,
+ };
+
+ // sh string table
+ if (strtbl_write_str(&asm->shstr_tbl, ".shstrtab", &str_off)) {
+ free(shdr);
+ return M_ERROR;
+ }
+
+ asm->shstrtbl_idx = count;
+ shdr[count++] = (Elf32_Shdr) {
+ .sh_name = str_off,
+ .sh_type = SHT_STRTAB,
+ .sh_flags = SHF_STRINGS,
+ .sh_addr = 0,
+ .sh_offset = 0,
+ .sh_size = 0,
+ .sh_link = 0,
+ .sh_info = 0,
+ .sh_addralign = 1,
+ .sh_entsize = 0,
+ };
+
+ for (uint32_t i = 0; i < asm->parser.sec_tbl.count; i++) {
+ if (asm->meta[i].reltbl == NULL)
+ continue;
+ shdr[asm->meta[i].reltbl_idx].sh_link = asm->symtbl_idx;
+ }
+
+ *res = shdr;
+ *res2 = count;
+
+ return M_SUCCESS;
}
static int assemble_file(struct assembler *asm)
{
- Elf32_Phdr *phdr;
- Elf32_Shdr *shdr;
- Elf32_Sym *symtbl;
- uint32_t phdr_len;
- uint32_t shdr_len;
- uint32_t symtbl_len;
+ Elf32_Phdr *phdr;
+ Elf32_Shdr *shdr;
+ Elf32_Sym *symtbl;
+ uint32_t phdr_len;
+ uint32_t shdr_len;
+ uint32_t symtbl_len;
- if (assemble_symtbl(asm, &symtbl, &symtbl_len))
- return M_ERROR;
+ if (assemble_symtbl(asm, &symtbl, &symtbl_len))
+ return M_ERROR;
- if (assemble_phdr(asm, &phdr, &phdr_len)) {
- free(symtbl);
- return M_ERROR;
- }
+ if (assemble_reltbl(asm, symtbl, symtbl_len)) {
+ free(symtbl);
+ return M_ERROR;
+ };
+
+ if (assemble_phdr(asm, &phdr, &phdr_len)) {
+ free(symtbl);
+ return M_ERROR;
+ }
- if (assemble_shdr(asm, &shdr, &shdr_len)) {
- free(symtbl);
- free(phdr);
- return M_ERROR;
- };
+ if (assemble_shdr(asm, &shdr, &shdr_len)) {
+ free(symtbl);
+ free(phdr);
+ return M_ERROR;
+ };
- Elf32_Ehdr ehdr = {
- .e_ident = {
- [EI_MAG0] = ELFMAG0,
- [EI_MAG1] = ELFMAG1,
- [EI_MAG2] = ELFMAG2,
- [EI_MAG3] = ELFMAG3,
- [EI_CLASS] = ELFCLASS32,
- [EI_DATA] = ELFDATA2LSB,
- [EI_VERSION] = EV_CURRENT,
- [EI_OSABI] = ELFOSABI_NONE,
- [EI_ABIVERSION] = 0x00,
- [EI_PAD] = 0x00,
- },
- .e_type = ET_REL,
- .e_machine = EM_MIPS,
- .e_version = EV_CURRENT,
- .e_entry = 0x00,
- .e_phoff = 0x00,
- .e_shoff = 0x00,
- .e_flags = EF_MIPS_ARCH_32R6,
- .e_ehsize = sizeof(Elf32_Ehdr),
- .e_phentsize = sizeof(Elf32_Phdr),
- .e_phnum = phdr_len,
- .e_shentsize = sizeof(Elf32_Shdr),
- .e_shnum = shdr_len,
- .e_shstrndx = SHDR_STRTBL,
- };
+ Elf32_Ehdr ehdr = {
+ .e_ident = {
+ [EI_MAG0] = ELFMAG0,
+ [EI_MAG1] = ELFMAG1,
+ [EI_MAG2] = ELFMAG2,
+ [EI_MAG3] = ELFMAG3,
+ [EI_CLASS] = ELFCLASS32,
+ [EI_DATA] = ELFDATA2LSB,
+ [EI_VERSION] = EV_CURRENT,
+ [EI_OSABI] = ELFOSABI_NONE,
+ [EI_ABIVERSION] = 0x00,
+ [EI_PAD] = 0x00,
+ },
+ .e_type = ET_REL,
+ .e_machine = EM_MIPS,
+ .e_version = EV_CURRENT,
+ .e_entry = 0x00,
+ .e_phoff = 0x00,
+ .e_shoff = 0x00,
+ .e_flags = EF_MIPS_ARCH_32R6,
+ .e_ehsize = sizeof(Elf32_Ehdr),
+ .e_phentsize = sizeof(Elf32_Phdr),
+ .e_phnum = phdr_len,
+ .e_shentsize = sizeof(Elf32_Shdr),
+ .e_shnum = shdr_len,
+ .e_shstrndx = asm->shstrtbl_idx,
+ };
- uint32_t ptr = 0;
+ uint32_t ptr = 0;
- // we must now correct offets and sizes inside the ehdr, phdr,
- // and shdr
+ // we must now correct offets and sizes inside the ehdr, phdr,
+ // and shdr
+ ptr += sizeof(Elf32_Ehdr);
- ptr += sizeof(Elf32_Ehdr);
+ // phdr
+ ehdr.e_phoff = ptr;
+ ptr += phdr_len * sizeof(Elf32_Phdr);
- // phdr
- ehdr.e_phoff = ptr;
- ptr += phdr_len * sizeof(Elf32_Phdr);
+ // reltbls
+ for (uint32_t i = 0; i < asm->parser.sec_tbl.count; i++) {
+ if (asm->meta[i].reltbl == NULL)
+ continue;
+ int idx = asm->meta[i].reltbl_idx;
+ int len = asm->meta[i].reltbl_len;
+ shdr[idx].sh_offset = ptr;
+ shdr[idx].sh_size = len * sizeof(Elf32_Rela);
+ ptr += len * sizeof(Elf32_Rela);
+ }
- // sections
- for (uint32_t i = 0; i < asm->parser->sec_tbl.count; i++) {
- phdr[i].p_offset = ptr;
- phdr[i].p_vaddr = ptr;
- shdr[i+SHDR_SECTIONS].sh_offset = ptr;
- shdr[i+SHDR_SECTIONS].sh_size = phdr[i].p_filesz;
- ptr += phdr[i].p_filesz;
- }
+ // sections
+ for (uint32_t i = 0; i < asm->parser.sec_tbl.count; i++) {
+ int idx = asm->meta[i].shdr_idx;
+ phdr[i].p_offset = ptr;
+ phdr[i].p_vaddr = ptr;
+ phdr[i].p_paddr = ptr;
+ shdr[idx].sh_offset = ptr;
+ shdr[idx].sh_size = phdr[i].p_filesz;
+ shdr[idx].sh_addr = phdr[i].p_vaddr;
+ shdr[idx].sh_addralign = phdr[i].p_align;
+ ptr += phdr[i].p_filesz;
+ }
- // symtbl
- shdr[SHDR_SYMTBL].sh_offset = ptr;
- shdr[SHDR_SYMTBL].sh_size = symtbl_len * sizeof(Elf32_Sym);
- ptr += symtbl_len * sizeof(Elf32_Sym);
+ // symtbl
+ shdr[asm->symtbl_idx].sh_offset = ptr;
+ shdr[asm->symtbl_idx].sh_link = asm->strtbl_idx;
+ shdr[asm->symtbl_idx].sh_size = symtbl_len * sizeof(Elf32_Sym);
+ ptr += symtbl_len * sizeof(Elf32_Sym);
- // strtbl
- shdr[SHDR_STRTBL].sh_offset = ptr;
- shdr[SHDR_STRTBL].sh_size = asm->str_tbl.size;
- ptr += asm->str_tbl.size;
+ // strtbl
+ shdr[asm->strtbl_idx].sh_offset = ptr;
+ shdr[asm->strtbl_idx].sh_size = asm->str_tbl.size;
+ ptr += asm->str_tbl.size;
- // shdr
- ehdr.e_shoff = ptr;
+ // shstrtbl
+ shdr[asm->shstrtbl_idx].sh_offset = ptr;
+ shdr[asm->shstrtbl_idx].sh_size = asm->shstr_tbl.size;
+ ptr += asm->shstr_tbl.size;
- FILE *out = fopen("out.o", "w");
+ // shdr
+ ehdr.e_shoff = ptr;
- // ehdr
- fwrite(&ehdr, sizeof(Elf32_Ehdr), 1, out);
+ FILE *out = fopen("out.o", "w");
- // phdr
- fwrite(phdr, sizeof(Elf32_Phdr), phdr_len, out);
+ // ehdr
+ fwrite(&ehdr, sizeof(Elf32_Ehdr), 1, out);
- // sections
- for (uint32_t i = 0; i < asm->parser->sec_tbl.count; i++) {
- struct section *sec = &asm->parser->sec_tbl.sections[i];
- for (uint32_t j = 0; j < sec->count; j++) {
- struct mips32_instruction *ins = &sec->ins[j].mips32;
- fwrite(ins, sizeof(struct mips32_instruction),
- 1, out);
- }
- }
+ // phdr
+ fwrite(phdr, sizeof(Elf32_Phdr), phdr_len, out);
- // sym tbl
- fwrite(symtbl, sizeof(Elf32_Sym), symtbl_len, out);
+ // reltbls
+ for (uint32_t i = 0; i < asm->parser.sec_tbl.count; i++) {
+ if (asm->meta[i].reltbl == NULL)
+ continue;
+ void *ptr = asm->meta[i].reltbl;
+ int len = asm->meta[i].reltbl_len;
+ asm->meta[i].reltbl = NULL;
+ fwrite(ptr, sizeof(Elf32_Rela), len, out);
+ }
- // str tbl
- fwrite(asm->str_tbl.ptr, asm->str_tbl.size, 1, out);
+ // sections
+ for (uint32_t i = 0; i < asm->parser.sec_tbl.count; i++) {
+ struct section *sec = &asm->parser.sec_tbl.sections[i];
+ for (uint32_t j = 0; j < sec->count; j++) {
+ struct section_entry *entry = &sec->entries[j];
+ size_t size = entry->size;
+ fwrite(&entry->data, size, 1, out);
+ while(size % sec->alignment) {
+ uint8_t zero = 0;
+ fwrite(&zero, 1, 1, out);
+ size++;
+ }
+ }
+ }
- // shdr
- fwrite(shdr, sizeof(Elf32_Shdr), shdr_len, out);
+ // sym tbl
+ fwrite(symtbl, sizeof(Elf32_Sym), symtbl_len, out);
- fclose(out);
+ // str tbl
+ fwrite(asm->str_tbl.ptr, asm->str_tbl.size, 1, out);
- free(shdr);
- free(phdr);
- free(symtbl);
+ // shstr tbl
+ fwrite(asm->shstr_tbl.ptr, asm->shstr_tbl.size, 1, out);
- return M_SUCCESS;
+ // shdr
+ fwrite(shdr, sizeof(Elf32_Shdr), shdr_len, out);
+
+ // cleanip
+ fclose(out);
+ free(shdr);
+ free(phdr);
+ free(symtbl);
+
+ return M_SUCCESS;
}
int assemble_file_mips32(char *path)
{
- struct lexer lexer;
- struct parser parser;
- current_file = path;
- int res = M_SUCCESS;
+ struct assembler asm;
+ int res = M_SUCCESS;
- if (lexer_init(current_file, &lexer))
- return M_ERROR;
+ current_file = path;
- if (mips32_parser_init(&lexer, &parser))
+ if (assembler_init(&asm, path))
return M_ERROR;
- if (res == M_SUCCESS)
- res = parse_file(&parser);
+ mips32_parser_init(&asm.parser);
- struct assembler assembler;
- assembler.parser = &parser;
- strtbl_init(&assembler.str_tbl);
+ if (res == M_SUCCESS)
+ res = parse_file(&asm);
- if (res == M_SUCCESS)
- res = assemble_file(&assembler);
+ if (res == M_SUCCESS)
+ res = assemble_file(&asm);
- strtbl_free(&assembler.str_tbl);
- lexer_free(&lexer);
- parser_free(&parser);
+ assembler_free(&asm);
- return res;
+ return res;
}
diff --git a/masm/parse.c b/masm/parse.c
index 9876311..9f8ddb1 100644
--- a/masm/parse.c
+++ b/masm/parse.c
@@ -105,23 +105,27 @@ static int parse_label(struct parser *parser,
struct expr *expr)
{
struct token token;
- struct symbol symbol;
- uint32_t index;
if (assert_token(parser, TOK_LABEL, &token))
return M_ERROR;
strcpy(expr->text, token.text);
- if (symtbl_find(&parser->sym_tbl, NULL, token.text) == M_SUCCESS) {
+ struct symbol *ref;
+ if (symtbl_find(&parser->sym_tbl, &ref, token.text) == M_SUCCESS) {
+ if (ref->flag == SYM_GLOBAL && ref->sec == NULL) {
+ ref->sec = parser->sec_tbl.current;
+ ref->index = parser->sec_tbl.current->count;
+ return M_SUCCESS;
+ }
ERROR_POS(token, "redefined symbol '%s'", token.text);
return M_ERROR;
}
- index = parser->sec_tbl.current->start +
- parser->sec_tbl.current->count;
+ struct symbol symbol;
symbol = (struct symbol) {
.name = "",
- .position = index,
+ .sec = parser->sec_tbl.current,
+ .index = parser->sec_tbl.current->count,
.flag = SYM_LOCAL,
};
strcpy(symbol.name, token.text);
diff --git a/masm/parse.h b/masm/parse.h
index 2aea0be..5f37052 100644
--- a/masm/parse.h
+++ b/masm/parse.h
@@ -18,7 +18,6 @@ enum expr_type {
EXPR_INS,
EXPR_DIRECTIVE,
EXPR_CONSTANT,
- EXPR_SEGMENT,
EXPR_LABEL,
};
@@ -44,7 +43,8 @@ enum symbol_flag {
struct symbol {
char name[MAX_LEX_LENGTH];
- uint32_t position;
+ uint32_t index;
+ struct section *sec;
enum symbol_flag flag;
};
@@ -62,13 +62,37 @@ int symtbl_push(struct symbol_table *sym_tbl, struct symbol sym);
int symtbl_find(struct symbol_table *sym_tbl, struct symbol **sym,
const char name[MAX_LEX_LENGTH]);
+enum section_entry_type {
+ ENT_INS,
+ ENT_WORD,
+ ENT_HALF,
+ ENT_BYTE,
+ ENT_NO_DATA,
+};
+
+struct section_entry {
+ enum section_entry_type type;
+ size_t size;
+
+ union {
+ char data; // to get memory address
+ union mips_instruction ins;
+ int32_t word;
+ int16_t half;
+ int8_t byte;
+ };
+};
+
struct section {
uint32_t count;
uint32_t len;
- uint32_t start;
uint32_t alignment;
- union mips_instruction *ins;
+ uint32_t index; // what index is my section
char name[MAX_LEX_LENGTH];
+ bool read;
+ bool write;
+ bool execute;
+ struct section_entry *entries;
};
struct section_table {
@@ -77,7 +101,6 @@ struct section_table {
struct section *sections;
struct section *current;
char name[MAX_LEX_LENGTH];
- uint32_t total_ins;
};
int sectbl_init(struct section_table *sec_tbl);
@@ -85,10 +108,11 @@ void sectbl_free(struct section_table *sec_tbl);
int sectbl_alloc(struct section_table *sec_tbl, struct section **sec,
const char name[MAX_LEX_LENGTH]);
-int sectbl_push(struct section_table *sec_tbl, struct section *section,
- union mips_instruction ins);
int sectbl_get(struct section_table *sec_tbl, struct section **sec,
const char name[MAX_LEX_LENGTH]);
+int sec_push(struct section *section, struct section_entry entry);
+size_t sec_size(struct section *section);
+size_t sec_index(struct section *section, uint32_t index);
enum reference_type {
REF_OFFESET,
diff --git a/masm/parse_mips32.c b/masm/parse_mips32.c
index 032f115..db7f346 100644
--- a/masm/parse_mips32.c
+++ b/masm/parse_mips32.c
@@ -14,50 +14,50 @@
/* each instruction has a given parse format
* internal to the parser */
enum mips32_parse_format {
- // register type: rs, rt, td
- MIPS32_PARSE_R,
- // register type: rs, rt
- MIPS32_PARSE_R2,
- // register type: rd
- MIPS32_PARSE_RD,
- // register type: rs
- MIPS32_PARSE_RS,
- // imeediate type: rs, rt, immd
- MIPS32_PARSE_I,
- // jump type: offset
- MIPS32_PARSE_J,
- // jump type: register
- MIPS32_PARSE_JR,
- // offset 16b type: offset
- MIPS32_PARSE_O16,
- // offset 26b type: offset
- MIPS32_PARSE_O26,
- // breanch equal type: rs, rt, offset
- MIPS32_PARSE_BE,
- // branch zero type: rs, offset
- MIPS32_PARSE_BZ,
- // store and load: rt, offset(base)
- MIPS32_PARSE_SL,
- // store and load immediate: rt, immediate
- MIPS32_PARSE_SLI,
- // shift: rd, rt, sa
- MIPS32_PARSE_S,
- // shift variable: rd, rt, rs
- MIPS32_PARSE_SV,
- // none:
- MIPS32_PARSE_NONE,
+ // register type: rs, rt, td
+ MIPS32_PARSE_R,
+ // register type: rs, rt
+ MIPS32_PARSE_R2,
+ // register type: rd
+ MIPS32_PARSE_RD,
+ // register type: rs
+ MIPS32_PARSE_RS,
+ // imeediate type: rs, rt, immd
+ MIPS32_PARSE_I,
+ // jump type: offset
+ MIPS32_PARSE_J,
+ // jump type: register
+ MIPS32_PARSE_JR,
+ // offset 16b type: offset
+ MIPS32_PARSE_O16,
+ // offset 26b type: offset
+ MIPS32_PARSE_O26,
+ // breanch equal type: rs, rt, offset
+ MIPS32_PARSE_BE,
+ // branch zero type: rs, offset
+ MIPS32_PARSE_BZ,
+ // store and load: rt, offset(base)
+ MIPS32_PARSE_SL,
+ // store and load immediate: rt, immediate
+ MIPS32_PARSE_SLI,
+ // shift: rd, rt, sa
+ MIPS32_PARSE_S,
+ // shift variable: rd, rt, rs
+ MIPS32_PARSE_SV,
+ // none:
+ MIPS32_PARSE_NONE,
};
#define FORMAT(ins, format) \
- [MIPS32_INS_##ins] = MIPS32_PARSE_##format, \
+ [MIPS32_INS_##ins] = MIPS32_PARSE_##format, \
const enum mips32_parse_format mips32_parse_formats[] = {
- FORMAT(ADD, R)
- FORMAT(ADDI, I)
+ FORMAT(ADD, R)
+ FORMAT(ADDI, I)
FORMAT(ADDIU, I)
FORMAT(ADDU, R)
- FORMAT(AND, R)
- FORMAT(ANDI, I)
+ FORMAT(AND, R)
+ FORMAT(ANDI, I)
FORMAT(BAL, O16)
FORMAT(BALC, O26)
FORMAT(BC, O26)
@@ -94,34 +94,34 @@ const enum mips32_parse_format mips32_parse_formats[] = {
FORMAT(LW, SL)
FORMAT(LWL, SL)
FORMAT(LWR, SL)
- FORMAT(MFHI, RD)
- FORMAT(MFLO, RD)
- FORMAT(MTHI, RS)
- FORMAT(MTLO, RS)
- FORMAT(MULT, R2)
- FORMAT(MULTU, R2)
+ FORMAT(MFHI, RD)
+ FORMAT(MFLO, RD)
+ FORMAT(MTHI, RS)
+ FORMAT(MTLO, RS)
+ FORMAT(MULT, R2)
+ FORMAT(MULTU, R2)
FORMAT(SB, SL)
FORMAT(SH, SL)
FORMAT(SW, SL)
FORMAT(SWL, SL)
FORMAT(SLL, S)
FORMAT(SLLV, SV)
- FORMAT(SLT, R)
- FORMAT(SLTI, I)
- FORMAT(SLTIU, I)
- FORMAT(SLTU, R)
+ FORMAT(SLT, R)
+ FORMAT(SLTI, I)
+ FORMAT(SLTIU, I)
+ FORMAT(SLTU, R)
FORMAT(SRA, S)
FORMAT(SRAV, SV)
FORMAT(SRL, S)
FORMAT(SRLV, SV)
- FORMAT(SYSCALL, NONE)
- FORMAT(OR, R)
- FORMAT(ORI, I)
- FORMAT(NOR, R)
- FORMAT(SUB, R)
- FORMAT(SUBU, R)
- FORMAT(XOR, R)
- FORMAT(XORI, I)
+ FORMAT(SYSCALL, NONE)
+ FORMAT(OR, R)
+ FORMAT(ORI, I)
+ FORMAT(NOR, R)
+ FORMAT(SUB, R)
+ FORMAT(SUBU, R)
+ FORMAT(XOR, R)
+ FORMAT(XORI, I)
};
#undef FORMAT
@@ -131,75 +131,75 @@ const enum mips32_parse_format mips32_parse_formats[] = {
#define MAX26 67108864
static int get_reference(struct parser *parser, uint32_t *offset,
- enum reference_type type)
+ enum reference_type type)
{
- struct token token;
+ struct token token;
- if (next_token(parser, &token))
- return M_ERROR;
+ if (next_token(parser, &token))
+ return M_ERROR;
- if (token.type == TOK_NUMBER) {
- *offset = token.number;
- return M_SUCCESS;
- }
+ if (token.type == TOK_NUMBER) {
+ *offset = token.number;
+ return M_SUCCESS;
+ }
- if (token.type != TOK_IDENT) {
- ERROR_POS(token, "unexpected token of type '%s'",
- token_str(token.type));
- return M_ERROR;
- }
+ if (token.type != TOK_IDENT) {
+ ERROR_POS(token, "unexpected token of type '%s'",
+ token_str(token.type));
+ return M_ERROR;
+ }
- struct reference reference = {
- .section = parser->sec_tbl.current,
- .index = parser->sec_tbl.current->count,
- .type = type,
- };
- strcpy(reference.name, token.text);
+ struct reference reference = {
+ .section = parser->sec_tbl.current,
+ .index = parser->sec_tbl.current->count,
+ .type = type,
+ };
+ strcpy(reference.name, token.text);
- if (reftbl_push(&parser->ref_tbl, reference))
- return M_ERROR;
+ if (reftbl_push(&parser->ref_tbl, reference))
+ return M_ERROR;
- *offset = 0;
+ *offset = 0;
- return M_SUCCESS;
+ return M_SUCCESS;
}
static int get_offset(struct parser *parser, uint32_t *offset)
{
- return get_reference(parser, offset, REF_OFFESET);
+ return get_reference(parser, offset, REF_OFFESET);
}
static int get_target(struct parser *parser, uint32_t *offset)
{
- return get_reference(parser, offset, REF_TARGET);
+ return get_reference(parser, offset, REF_TARGET);
}
static int get_instruction(const char *ident, struct mips32_instruction *res)
{
- for (int i = 0; i < __MIPS32_INS_LEN; i++) {
- struct mips32_instruction ins =
- mips32_instructions[i];
- if (strcasecmp(ident, ins.name) == 0) {
- if (res != NULL)
- *res = ins;
- return M_SUCCESS;
- }
- }
- return M_ERROR;
+ for (int i = 0; i < __MIPS32_INS_LEN; i++) {
+ struct mips32_instruction ins =
+ mips32_instructions[i];
+ if (strcasecmp(ident, ins.name) == 0) {
+ if (res != NULL)
+ *res = ins;
+ return M_SUCCESS;
+ }
+ }
+ return M_ERROR;
}
static int is_instruction(const char *ident)
{
- return get_instruction(ident, NULL);
+ return get_instruction(ident, NULL);
}
static int parse_register(struct parser *parser, enum mips32_register *reg)
{
- struct token token;
- if (assert_token(parser, TOK_REG, &token))
- return M_ERROR;
+ struct token token;
+ if (assert_token(parser, TOK_REG, &token))
+ return M_ERROR;
- int len = strlen(token.text);
+ int len = strlen(token.text);
int c0 = len > 0 ? token.text[0] : '\0',
c1 = len > 1 ? token.text[1] : '\0',
c2 = len > 2 ? token.text[2] : '\0',
@@ -304,550 +304,569 @@ static int parse_register(struct parser *parser, enum mips32_register *reg)
i += c1 - '0';
}
if (i <= 31) {
- *reg = i;
- return M_SUCCESS;
- }
+ *reg = i;
+ return M_SUCCESS;
+ }
}
- ERROR_POS(token, "unknown register $%s", token.text);
+ ERROR_POS(token, "unknown register $%s", token.text);
return M_ERROR;
}
static int parse_instruction_r(struct parser *parser,
- struct mips32_instruction *ins)
+ struct mips32_instruction *ins)
{
- // format: rs, rt, rd
- enum mips32_register reg;
+ // format: rs, rt, rd
+ enum mips32_register reg;
- if (parse_register(parser, &reg))
- return M_ERROR;
- ins->R_data.rd = reg;
+ if (parse_register(parser, &reg))
+ return M_ERROR;
+ ins->R_data.rd = reg;
- if (assert_token(parser, TOK_COMMA, NULL))
- return M_ERROR;
+ if (assert_token(parser, TOK_COMMA, NULL))
+ return M_ERROR;
- if (parse_register(parser, &reg))
- return M_ERROR;
- ins->R_data.rs = reg;
+ if (parse_register(parser, &reg))
+ return M_ERROR;
+ ins->R_data.rs = reg;
- if (assert_token(parser, TOK_COMMA, NULL))
- return M_ERROR;
+ if (assert_token(parser, TOK_COMMA, NULL))
+ return M_ERROR;
- if (parse_register(parser, &reg))
- return M_ERROR;
- ins->R_data.rt = reg;
+ if (parse_register(parser, &reg))
+ return M_ERROR;
+ ins->R_data.rt = reg;
- return M_SUCCESS;
+ return M_SUCCESS;
}
static int parse_instruction_r2(struct parser *parser,
- struct mips32_instruction *ins)
+ struct mips32_instruction *ins)
{
- // format: rs, rt
- enum mips32_register reg;
+ // format: rs, rt
+ enum mips32_register reg;
- if (parse_register(parser, &reg))
- return M_ERROR;
- ins->R_data.rs = reg;
+ if (parse_register(parser, &reg))
+ return M_ERROR;
+ ins->R_data.rs = reg;
- if (assert_token(parser, TOK_COMMA, NULL))
- return M_ERROR;
+ if (assert_token(parser, TOK_COMMA, NULL))
+ return M_ERROR;
- if (parse_register(parser, &reg))
- return M_ERROR;
- ins->R_data.rt = reg;
+ if (parse_register(parser, &reg))
+ return M_ERROR;
+ ins->R_data.rt = reg;
- return M_SUCCESS;
+ return M_SUCCESS;
}
static int parse_instruction_rs(struct parser *parser,
- struct mips32_instruction *ins)
+ struct mips32_instruction *ins)
{
- // format: rs
- enum mips32_register reg;
+ // format: rs
+ enum mips32_register reg;
- if (parse_register(parser, &reg))
- return M_ERROR;
- ins->R_data.rs = reg;
+ if (parse_register(parser, &reg))
+ return M_ERROR;
+ ins->R_data.rs = reg;
- return M_SUCCESS;
+ return M_SUCCESS;
}
static int parse_instruction_rd(struct parser *parser,
- struct mips32_instruction *ins)
+ struct mips32_instruction *ins)
{
- // format: rd
- enum mips32_register reg;
+ // format: rd
+ enum mips32_register reg;
- if (parse_register(parser, &reg))
- return M_ERROR;
- ins->R_data.rd = reg;
+ if (parse_register(parser, &reg))
+ return M_ERROR;
+ ins->R_data.rd = reg;
- return M_SUCCESS;
+ return M_SUCCESS;
}
static int parse_instruction_i(struct parser *parser,
- struct mips32_instruction *ins)
+ struct mips32_instruction *ins)
{
- // format: rs, rt, immd
- enum mips32_register reg;
- struct token token;
+ // format: rs, rt, immd
+ enum mips32_register reg;
+ struct token token;
- if (parse_register(parser, &reg))
- return M_ERROR;
- ins->I_data.rt = reg;
+ if (parse_register(parser, &reg))
+ return M_ERROR;
+ ins->I_data.rt = reg;
- if (assert_token(parser, TOK_COMMA, NULL))
- return M_ERROR;
+ if (assert_token(parser, TOK_COMMA, NULL))
+ return M_ERROR;
- if (parse_register(parser, &reg))
- return M_ERROR;
- ins->I_data.rs = reg;
+ if (parse_register(parser, &reg))
+ return M_ERROR;
+ ins->I_data.rs = reg;
- if (assert_token(parser, TOK_COMMA, NULL))
- return M_ERROR;
+ if (assert_token(parser, TOK_COMMA, NULL))
+ return M_ERROR;
- if (assert_token(parser, TOK_NUMBER, &token))
- return M_ERROR;
+ if (assert_token(parser, TOK_NUMBER, &token))
+ return M_ERROR;
- if (token.number >= MAX16)
- return M_ERROR;
- ins->I_data.immd = token.number;
+ if (token.number >= MAX16)
+ return M_ERROR;
+ ins->I_data.immd = token.number;
- return M_SUCCESS;
+ return M_SUCCESS;
}
static int parse_instruction_offset(struct parser *parser,
- uint32_t max,
- struct mips32_instruction *ins)
+ uint32_t max,
+ struct mips32_instruction *ins)
{
- uint32_t n;
- if (get_offset(parser, &n) || n > max)
- return M_ERROR;
+ uint32_t n;
+ if (get_offset(parser, &n) || n > max)
+ return M_ERROR;
- switch (max) {
- case MAX26:
- ins->J_data.target = n;
- break;
- case MAX16:
- ins->B_data.offset = n;
- break;
- }
+ switch (max) {
+ case MAX26:
+ ins->J_data.target = n;
+ break;
+ case MAX16:
+ ins->B_data.offset = n;
+ break;
+ }
- return M_SUCCESS;
+ return M_SUCCESS;
}
static int parse_instruction_j(struct parser *parser,
- struct mips32_instruction *ins)
+ struct mips32_instruction *ins)
{
- uint32_t n;
- if (get_target(parser, &n) || n > MAX26)
- return M_ERROR;
- ins->J_data.target = n;
+ uint32_t n;
+ if (get_target(parser, &n) || n > MAX26)
+ return M_ERROR;
+ ins->J_data.target = n;
- return M_SUCCESS;
+ return M_SUCCESS;
}
static int parse_instruction_jr(struct parser *parser,
- struct mips32_instruction *ins)
+ struct mips32_instruction *ins)
{
- uint32_t n;
- if (get_target(parser, &n) || n > MAX26)
- return M_ERROR;
- ins->J_data.target = n;
+ uint32_t n;
+ if (get_target(parser, &n) || n > MAX26)
+ return M_ERROR;
+ ins->J_data.target = n;
- return M_SUCCESS;
+ return M_SUCCESS;
}
static int parse_instruction_branch_equal(struct parser *parser,
- struct mips32_instruction *ins)
+ struct mips32_instruction *ins)
{
- enum mips32_register reg;
- if (parse_register(parser, &reg))
- return M_ERROR;
- ins->R_data.rs = reg;
+ enum mips32_register reg;
+ if (parse_register(parser, &reg))
+ return M_ERROR;
+ ins->R_data.rs = reg;
- return M_SUCCESS;
+ return M_SUCCESS;
}
static int parse_instruction_branch(struct parser *parser,
- struct mips32_instruction *ins)
+ struct mips32_instruction *ins)
{
- enum mips32_register reg;
- uint32_t n;
+ enum mips32_register reg;
+ uint32_t n;
- if (parse_register(parser, &reg))
- return M_ERROR;
- ins->B_data.rs = reg;
+ if (parse_register(parser, &reg))
+ return M_ERROR;
+ ins->B_data.rs = reg;
- if (assert_token(parser, TOK_COMMA, NULL))
- return M_ERROR;
+ if (assert_token(parser, TOK_COMMA, NULL))
+ return M_ERROR;
- if (get_offset(parser, &n) || n > MAX16)
- return M_ERROR;
- ins->B_data.offset = n;
+ if (get_offset(parser, &n) || n > MAX16)
+ return M_ERROR;
+ ins->B_data.offset = n;
- return M_SUCCESS;
+ return M_SUCCESS;
}
static int parse_instruction_sl(struct parser *parser,
- struct mips32_instruction *ins)
+ struct mips32_instruction *ins)
{
- enum mips32_register reg;
- uint32_t offset = 0;
- struct token token;
+ enum mips32_register reg;
+ uint32_t offset = 0;
+ struct token token;
- if (parse_register(parser, &reg))
- return M_ERROR;
- ins->I_data.rt = reg;
+ if (parse_register(parser, &reg))
+ return M_ERROR;
+ ins->I_data.rt = reg;
- if (assert_token(parser, TOK_COMMA, NULL))
- return M_ERROR;
+ if (assert_token(parser, TOK_COMMA, NULL))
+ return M_ERROR;
- if (peek_token(parser, &token))
- return M_ERROR;
+ if (peek_token(parser, &token))
+ return M_ERROR;
- if (token.type != TOK_LPAREN)
- if (get_offset(parser, &offset))
- return M_ERROR;
- ins->I_data.immd = offset;
+ if (token.type != TOK_LPAREN)
+ if (get_offset(parser, &offset))
+ return M_ERROR;
+ ins->I_data.immd = offset;
- if (peek_token(parser, &token))
- return M_ERROR;
+ if (peek_token(parser, &token))
+ return M_ERROR;
- if (token.type == TOK_NL) {
- ins->I_data.rs = MIPS32_REG_ZERO;
- return M_SUCCESS;
- }
+ if (token.type == TOK_NL) {
+ ins->I_data.rs = MIPS32_REG_ZERO;
+ return M_SUCCESS;
+ }
- if (assert_token(parser, TOK_LPAREN, NULL))
- return M_ERROR;
+ if (assert_token(parser, TOK_LPAREN, NULL))
+ return M_ERROR;
- if (parse_register(parser, &reg))
- return M_ERROR;
- ins->I_data.rs = reg;
+ if (parse_register(parser, &reg))
+ return M_ERROR;
+ ins->I_data.rs = reg;
- if (assert_token(parser, TOK_RPAREN, NULL))
- return M_ERROR;
+ if (assert_token(parser, TOK_RPAREN, NULL))
+ return M_ERROR;
- return M_SUCCESS;
+ return M_SUCCESS;
}
static int parse_instruction_sli(struct parser *parser,
- struct mips32_instruction *ins)
+ struct mips32_instruction *ins)
{
- enum mips32_register reg;
- struct token token;
+ enum mips32_register reg;
+ struct token token;
- if (parse_register(parser, &reg))
- return M_ERROR;
- ins->I_data.rt = reg;
+ if (parse_register(parser, &reg))
+ return M_ERROR;
+ ins->I_data.rt = reg;
- if (assert_token(parser, TOK_COMMA, NULL))
- return M_ERROR;
+ if (assert_token(parser, TOK_COMMA, NULL))
+ return M_ERROR;
- if (assert_token(parser, TOK_NUMBER, &token) || token.number > MAX16)
- return M_ERROR;
- ins->I_data.immd = token.number;
+ if (assert_token(parser, TOK_NUMBER, &token) || token.number > MAX16)
+ return M_ERROR;
+ ins->I_data.immd = token.number;
- return M_SUCCESS;
+ return M_SUCCESS;
}
static int parse_instruction_s(struct parser *parser,
- struct mips32_instruction *ins)
+ struct mips32_instruction *ins)
{
- enum mips32_register reg;
- struct token token;
+ enum mips32_register reg;
+ struct token token;
- if (parse_register(parser, &reg))
- return M_ERROR;
- ins->R_data.rd = reg;
+ if (parse_register(parser, &reg))
+ return M_ERROR;
+ ins->R_data.rd = reg;
- if (assert_token(parser, TOK_COMMA, NULL))
- return M_ERROR;
+ if (assert_token(parser, TOK_COMMA, NULL))
+ return M_ERROR;
- if (parse_register(parser, &reg))
- return M_ERROR;
- ins->R_data.rt = reg;
+ if (parse_register(parser, &reg))
+ return M_ERROR;
+ ins->R_data.rt = reg;
- if (assert_token(parser, TOK_COMMA, NULL))
- return M_ERROR;
+ if (assert_token(parser, TOK_COMMA, NULL))
+ return M_ERROR;
- if (assert_token(parser, TOK_NUMBER, &token) || token.number > MAX5)
- return M_ERROR;
- ins->R_data.shamt = token.number;
+ if (assert_token(parser, TOK_NUMBER, &token) || token.number > MAX5)
+ return M_ERROR;
+ ins->R_data.shamt = token.number;
- return M_SUCCESS;
+ return M_SUCCESS;
}
static int parse_instruction_sv(struct parser *parser,
- struct mips32_instruction *ins)
+ struct mips32_instruction *ins)
{
- enum mips32_register reg;
+ enum mips32_register reg;
- if (parse_register(parser, &reg))
- return M_ERROR;
- ins->R_data.rd = reg;
+ if (parse_register(parser, &reg))
+ return M_ERROR;
+ ins->R_data.rd = reg;
- if (assert_token(parser, TOK_COMMA, NULL))
- return M_ERROR;
+ if (assert_token(parser, TOK_COMMA, NULL))
+ return M_ERROR;
- if (parse_register(parser, &reg))
- return M_ERROR;
- ins->R_data.rt = reg;
+ if (parse_register(parser, &reg))
+ return M_ERROR;
+ ins->R_data.rt = reg;
- if (assert_token(parser, TOK_COMMA, NULL))
- return M_ERROR;
+ if (assert_token(parser, TOK_COMMA, NULL))
+ return M_ERROR;
- if (parse_register(parser, &reg))
- return M_ERROR;
- ins->R_data.rs = reg;
+ if (parse_register(parser, &reg))
+ return M_ERROR;
+ ins->R_data.rs = reg;
- return M_SUCCESS;
+ return M_SUCCESS;
}
static int parse_instruction(struct parser *parser,
- union mips_instruction *ins,
- struct token ident)
+ union mips_instruction *ins,
+ struct token ident)
{
- struct mips32_instruction instruction;
- enum mips32_parse_format format;
- int res = M_SUCCESS;
+ struct mips32_instruction instruction;
+ enum mips32_parse_format format;
+ int res = M_SUCCESS;
- if (get_instruction(ident.text, &instruction)) {
- ERROR_POS(ident, "unknown instruction '%s'", ident.text);
- return M_ERROR;
- }
+ if (get_instruction(ident.text, &instruction)) {
+ ERROR_POS(ident, "unknown instruction '%s'", ident.text);
+ return M_ERROR;
+ }
- ins->mips32 = instruction;
- format = mips32_parse_formats[instruction.type];
+ ins->mips32 = instruction;
+ format = mips32_parse_formats[instruction.type];
- switch (format) {
- case MIPS32_PARSE_R:
- res = parse_instruction_r(parser, &ins->mips32);
- break;
- case MIPS32_PARSE_R2:
- res = parse_instruction_r2(parser, &ins->mips32);
- break;
- case MIPS32_PARSE_RS:
- res = parse_instruction_rs(parser, &ins->mips32);
- break;
- case MIPS32_PARSE_RD:
- res = parse_instruction_rd(parser, &ins->mips32);
- break;
- case MIPS32_PARSE_I:
- res = parse_instruction_i(parser, &ins->mips32);
- break;
- case MIPS32_PARSE_J:
- res = parse_instruction_j(parser, &ins->mips32);
- break;
- case MIPS32_PARSE_JR:
- res = parse_instruction_jr(parser, &ins->mips32);
- break;
- case MIPS32_PARSE_O16:
- res = parse_instruction_offset(parser, MAX16, &ins->mips32);
- break;
- case MIPS32_PARSE_O26:
- res = parse_instruction_offset(parser, MAX26, &ins->mips32);
- break;
- case MIPS32_PARSE_BE:
- res = parse_instruction_branch_equal(parser, &ins->mips32);
- break;
- case MIPS32_PARSE_BZ:
- res = parse_instruction_branch(parser, &ins->mips32);
- break;
- case MIPS32_PARSE_SL:
- res = parse_instruction_sl(parser, &ins->mips32);
- break;
- case MIPS32_PARSE_SLI:
- res = parse_instruction_sli(parser, &ins->mips32);
- break;
- case MIPS32_PARSE_S:
- res = parse_instruction_s(parser, &ins->mips32);
- break;
- case MIPS32_PARSE_SV:
- res = parse_instruction_sv(parser, &ins->mips32);
- break;
- case MIPS32_PARSE_NONE:
- res = M_SUCCESS;
- break;
- }
+ switch (format) {
+ case MIPS32_PARSE_R:
+ res = parse_instruction_r(parser, &ins->mips32);
+ break;
+ case MIPS32_PARSE_R2:
+ res = parse_instruction_r2(parser, &ins->mips32);
+ break;
+ case MIPS32_PARSE_RS:
+ res = parse_instruction_rs(parser, &ins->mips32);
+ break;
+ case MIPS32_PARSE_RD:
+ res = parse_instruction_rd(parser, &ins->mips32);
+ break;
+ case MIPS32_PARSE_I:
+ res = parse_instruction_i(parser, &ins->mips32);
+ break;
+ case MIPS32_PARSE_J:
+ res = parse_instruction_j(parser, &ins->mips32);
+ break;
+ case MIPS32_PARSE_JR:
+ res = parse_instruction_jr(parser, &ins->mips32);
+ break;
+ case MIPS32_PARSE_O16:
+ res = parse_instruction_offset(parser, MAX16, &ins->mips32);
+ break;
+ case MIPS32_PARSE_O26:
+ res = parse_instruction_offset(parser, MAX26, &ins->mips32);
+ break;
+ case MIPS32_PARSE_BE:
+ res = parse_instruction_branch_equal(parser, &ins->mips32);
+ break;
+ case MIPS32_PARSE_BZ:
+ res = parse_instruction_branch(parser, &ins->mips32);
+ break;
+ case MIPS32_PARSE_SL:
+ res = parse_instruction_sl(parser, &ins->mips32);
+ break;
+ case MIPS32_PARSE_SLI:
+ res = parse_instruction_sli(parser, &ins->mips32);
+ break;
+ case MIPS32_PARSE_S:
+ res = parse_instruction_s(parser, &ins->mips32);
+ break;
+ case MIPS32_PARSE_SV:
+ res = parse_instruction_sv(parser, &ins->mips32);
+ break;
+ case MIPS32_PARSE_NONE:
+ res = M_SUCCESS;
+ break;
+ }
- if (res == M_SUCCESS && assert_eol(parser))
- return M_ERROR;
+ if (res == M_SUCCESS && assert_eol(parser))
+ return M_ERROR;
- return res;
+ return res;
}
static int parse_directive_align(struct parser *parser,
- struct mips32_directive *directive)
+ struct mips32_directive *directive)
{
- struct token token;
- if (assert_token(parser, TOK_NUMBER, &token))
- return M_ERROR;
+ struct token token;
+ if (assert_token(parser, TOK_NUMBER, &token))
+ return M_ERROR;
- if (token.number < 0) {
- ERROR_POS(token, "cannot align negative");
- return M_ERROR;
- }
+ if (token.number < 0) {
+ ERROR_POS(token, "cannot align negative");
+ return M_ERROR;
+ }
- if (token.number > MAX16) {
- ERROR_POS(token, "cannot align more than 65kb");
- return M_ERROR;
- }
+ if (token.number > MAX16) {
+ ERROR_POS(token, "cannot align more than 65kb");
+ return M_ERROR;
+ }
- directive->type = MIPS32_DIRECTIVE_ALIGN;
- directive->align = token.number;
+ directive->type = MIPS32_DIRECTIVE_ALIGN;
+ directive->align = token.number;
- return M_SUCCESS;
+ return M_SUCCESS;
}
static int parse_directive_space(struct parser *parser,
- struct mips32_directive *directive)
+ struct mips32_directive *directive)
{
- struct token token;
- if (assert_token(parser, TOK_NUMBER, &token))
- return M_ERROR;
+ struct token token;
+ if (assert_token(parser, TOK_NUMBER, &token))
+ return M_ERROR;
- if (token.number < 0) {
- ERROR_POS(token, "cannot reserve negative");
- return M_ERROR;
- }
+ if (token.number < 0) {
+ ERROR_POS(token, "cannot reserve negative");
+ return M_ERROR;
+ }
- if (token.number > MAX16) {
- ERROR_POS(token, "cannot reserve more than 65kb");
- return M_ERROR;
- }
+ if (token.number > MAX16) {
+ ERROR_POS(token, "cannot reserve more than 65kb");
+ return M_ERROR;
+ }
- directive->type = MIPS32_DIRECTIVE_SPACE;
- directive->space = token.number;
+ directive->type = MIPS32_DIRECTIVE_SPACE;
+ directive->space = token.number;
- return M_SUCCESS;
+ return M_SUCCESS;
}
static int parse_directive_whb(struct parser *parser,
- struct mips32_directive *directive,
- enum mips32_directive_type type)
+ struct mips32_directive *directive,
+ enum mips32_directive_type type)
{
- struct token token;
- uint32_t size = 0;
- uint32_t len = 0;
+ struct token token;
+ uint32_t size = 0;
+ uint32_t len = 0;
- switch (type) {
- case MIPS32_DIRECTIVE_WORD:
- size = UINT32_MAX;
- break;
- case MIPS32_DIRECTIVE_HALF:
- size = UINT16_MAX;
- break;
- case MIPS32_DIRECTIVE_BYTE:
- size = UINT8_MAX;
- break;
- default:
- }
+ switch (type) {
+ case MIPS32_DIRECTIVE_WORD:
+ size = UINT32_MAX;
+ break;
+ case MIPS32_DIRECTIVE_HALF:
+ size = UINT16_MAX;
+ break;
+ case MIPS32_DIRECTIVE_BYTE:
+ size = UINT8_MAX;
+ break;
+ default:
+ }
+
+ directive->type = type;
+
+ while (1) {
+ if (assert_token(parser, TOK_NUMBER, &token))
+ return M_ERROR;
+
+ if (len >= MAX_ARG_LENGTH) {
+ ERROR_POS(token, "directives cannot be longer than "
+ "%d arguments", MAX_ARG_LENGTH);
+ return M_ERROR;
+ }
+
+ if (token.number > size) {
+ ERROR_POS(token, "number cannot execede max size of: "
+ "%d", size);
+ return M_ERROR;
+ }
+
+ switch (type) {
+ case MIPS32_DIRECTIVE_WORD:
+ directive->words[len++] = token.number;
- directive->type = type;
+ break;
+ case MIPS32_DIRECTIVE_HALF:
+ directive->halfs[len++] = token.number;
+ break;
+ case MIPS32_DIRECTIVE_BYTE:
+ directive->bytes[len++] = token.number;
+ break;
+ default:
+ }
- while (1) {
- if (assert_token(parser, TOK_NUMBER, &token))
- return M_ERROR;
+ if (peek_token(parser, &token))
+ return M_ERROR;
- if (len >= MAX_ARG_LENGTH) {
- ERROR_POS(token, "directives cannot be longer than "
- "%d arguments", MAX_ARG_LENGTH);
- return M_ERROR;
- }
+ if (token.type == TOK_COMMA) {
+ next_token(parser, NULL);
+ continue;
+ }
- if (token.number > size) {
- ERROR_POS(token, "number cannot execede max size of: "
- "%d", size);
- return M_ERROR;
- }
+ break;
+ }
- switch (type) {
- case MIPS32_DIRECTIVE_WORD:
- directive->words[len++] = token.number;
- break;
- case MIPS32_DIRECTIVE_HALF:
- directive->halfs[len++] = token.number;
- break;
- case MIPS32_DIRECTIVE_BYTE:
- directive->bytes[len++] = token.number;
- break;
- default:
- }
+ directive->len = len;
- if (peek_token(parser, &token))
- return M_ERROR;
+ return M_SUCCESS;
+}
- if (token.type == TOK_COMMA) {
- next_token(parser, NULL);
- continue;
- }
+static int parse_directive_extern(struct parser *parser,
+ struct mips32_directive *directive)
+{
+ struct token token;
+ if (assert_token(parser, TOK_IDENT, &token))
+ return M_ERROR;
- break;
- }
+ directive->type = MIPS32_DIRECTIVE_EXTERN;
+ strcpy(directive->name, token.text);
- return M_SUCCESS;
+ return M_SUCCESS;
}
-static int parse_section(struct parser *parser,
- struct mips32_directive *directive,
- char name[MAX_LEX_LENGTH])
+static int parse_directive_globl(struct parser *parser,
+ struct mips32_directive *directive)
{
- directive->type = MIPS32_DIRECTIVE_SECTION;
- strcpy(directive->name, name);
+ struct token token;
+ if (assert_token(parser, TOK_IDENT, &token))
+ return M_ERROR;
+
+ directive->type = MIPS32_DIRECTIVE_GLOBL;
+ strcpy(directive->name, token.text);
- struct section *sec;
- if (sectbl_get(&parser->sec_tbl, &sec, name) == M_SUCCESS) {
- parser->sec_tbl.current = sec;
- return M_SUCCESS;
- }
+ return M_SUCCESS;
+}
- if (sectbl_alloc(&parser->sec_tbl, &sec, name))
- return M_ERROR;
+static int parse_section(struct mips32_directive *directive,
+ char name[MAX_LEX_LENGTH])
+{
+ directive->type = MIPS32_DIRECTIVE_SECTION;
+ strcpy(directive->name, name);
- parser->sec_tbl.current = sec;
- return M_SUCCESS;
+ return M_SUCCESS;
}
static int parse_directive(struct parser *parser,
- union mips_directive *directive)
+ union mips_directive *directive)
{
- struct token token;
- if (assert_token(parser, TOK_DIRECTIVE, &token))
- return M_ERROR;
+ struct token token;
+ if (assert_token(parser, TOK_DIRECTIVE, &token))
+ return M_ERROR;
- // .align n
- if (strcmp(token.text, "align") == 0)
- return parse_directive_align(parser, &directive->mips32);
- else if (strcmp(token.text, "space") == 0)
- return parse_directive_space(parser, &directive->mips32);
- else if (strcmp(token.text, "word") == 0)
- return parse_directive_whb(parser, &directive->mips32,
- MIPS32_DIRECTIVE_WORD);
- else if (strcmp(token.text, "half") == 0)
- return parse_directive_whb(parser, &directive->mips32,
- MIPS32_DIRECTIVE_HALF);
- else if (strcmp(token.text, "byte") == 0)
- return parse_directive_whb(parser, &directive->mips32,
- MIPS32_DIRECTIVE_BYTE);
- else
- return parse_section(parser, &directive->mips32, token.text);
+ // .align n
+ if (strcmp(token.text, "align") == 0)
+ return parse_directive_align(parser, &directive->mips32);
+ else if (strcmp(token.text, "space") == 0)
+ return parse_directive_space(parser, &directive->mips32);
+ else if (strcmp(token.text, "word") == 0)
+ return parse_directive_whb(parser, &directive->mips32,
+ MIPS32_DIRECTIVE_WORD);
+ else if (strcmp(token.text, "half") == 0)
+ return parse_directive_whb(parser, &directive->mips32,
+ MIPS32_DIRECTIVE_HALF);
+ else if (strcmp(token.text, "byte") == 0)
+ return parse_directive_whb(parser, &directive->mips32,
+ MIPS32_DIRECTIVE_BYTE);
+ else if (strcmp(token.text, "extern") == 0)
+ return parse_directive_extern(parser, &directive->mips32);
+ else if (strcmp(token.text, "globl") == 0)
+ return parse_directive_globl(parser, &directive->mips32);
+ else
+ return parse_section(&directive->mips32, token.text);
}
-int mips32_parser_init(struct lexer *lexer, struct parser *parser)
+void mips32_parser_init(struct parser *parser)
{
- if (parser_init(lexer, parser))
- return M_ERROR;
- parser->parse_instruction = parse_instruction;
- parser->is_instruction = is_instruction;
- parser->parse_directive = parse_directive;
- return M_SUCCESS;
+ parser->parse_instruction = parse_instruction;
+ parser->is_instruction = is_instruction;
+ parser->parse_directive = parse_directive;
}
void mips32_parser_free(struct parser *parser)
{
- parser_free(parser);
+ parser_free(parser);
}
diff --git a/masm/parse_mips32.h b/masm/parse_mips32.h
index 6de154f..5262d68 100644
--- a/masm/parse_mips32.h
+++ b/masm/parse_mips32.h
@@ -5,8 +5,8 @@
#include "parse.h"
-/* initzlize a mips32 parser*/
-int mips32_parser_init(struct lexer *lexer, struct parser *parser);
+/* initzlize a mips32 parser vtable */
+void mips32_parser_init(struct parser *parser);
/* free the mips32 parser */
void mips32_parser_free(struct parser *parser);
diff --git a/masm/reftbl.c b/masm/reftbl.c
index bdd1f07..198af83 100644
--- a/masm/reftbl.c
+++ b/masm/reftbl.c
@@ -12,13 +12,13 @@ int reftbl_init(struct reference_table *ref_tbl)
{
ref_tbl->len = RELTBL_INIT_LEN;
ref_tbl->count = 0;
- ref_tbl->references = malloc(sizeof(struct reference) *
+ ref_tbl->references = malloc(sizeof(struct reference) *
RELTBL_INIT_LEN);
- if (ref_tbl->references == NULL) {
- ERROR("cannot alloc");
- return M_ERROR;
- }
+ if (ref_tbl->references == NULL) {
+ ERROR("cannot alloc");
+ return M_ERROR;
+ }
return M_SUCCESS;
}
diff --git a/masm/sectbl.c b/masm/sectbl.c
index f568a6f..6eafc60 100644
--- a/masm/sectbl.c
+++ b/masm/sectbl.c
@@ -13,13 +13,12 @@ int sectbl_init(struct section_table *sec_tbl)
{
sec_tbl->len = SECTBL_INIT_LEN;
sec_tbl->count = 0;
- sec_tbl->total_ins = 0;
- sec_tbl->sections = malloc(sizeof(struct section) * SECTBL_INIT_LEN);
+ sec_tbl->sections = malloc(sizeof(struct section) * SECTBL_INIT_LEN);
- if (sec_tbl->sections == NULL) {
- ERROR("cannot alloc");
- return M_ERROR;
- }
+ if (sec_tbl->sections == NULL) {
+ ERROR("cannot alloc");
+ return M_ERROR;
+ }
if (sectbl_alloc(sec_tbl, &sec_tbl->current, inital_section))
return M_ERROR;
@@ -30,11 +29,26 @@ int sectbl_init(struct section_table *sec_tbl)
void sectbl_free(struct section_table *sec_tbl)
{
for (uint32_t i = 0; i < sec_tbl->count; i++) {
- free(sec_tbl->sections[i].ins);
+ free(sec_tbl->sections[i].entries);
}
free(sec_tbl->sections);
}
+struct section_settings {
+ const char *name;
+ bool read;
+ bool write;
+ bool execute;
+ uint32_t align;
+};
+
+static struct section_settings default_section_settings[] = {
+ {"data", true, true, false, 1},
+ {"bss", true, true, false, 1},
+ {"rodata", true, false, false, 1},
+ {"text", true, false, true, 4},
+};
+
int sectbl_alloc(struct section_table *sec_tbl, struct section **sec,
const char name[MAX_LEX_LENGTH])
{
@@ -50,54 +64,96 @@ int sectbl_alloc(struct section_table *sec_tbl, struct section **sec,
}
struct section *temp;
- temp = &sec_tbl->sections[sec_tbl->count++];
+ temp = &sec_tbl->sections[sec_tbl->count];
strcpy(temp->name,name);
temp->count = 0;
temp->len = SECTBL_INIT_LEN;
- temp->start = sec_tbl->total_ins;
temp->alignment = 1;
- temp->ins = malloc(sizeof(union mips_instruction) * SECTBL_INIT_LEN);
+ temp->read = true;
+ temp->write = true;
+ temp->execute = false;
+ temp->index = sec_tbl->count;
+ temp->entries = malloc(sizeof(struct section_entry) * SECTBL_INIT_LEN);
- if (temp->ins == NULL) {
+ for (int i = 0; i < 4; i++) {
+ struct section_settings *set = &default_section_settings[i];
+ if (strcmp(set->name, name) == 0) {
+ temp->read = set->read;
+ temp->write = set->write;
+ temp->execute = set->execute;
+ temp->alignment = set->align;
+ break;
+ }
+ }
+
+ if (temp->entries == NULL) {
ERROR("cannot alloc");
return M_ERROR;
}
+ sec_tbl->count++;
+
*sec = temp;
return M_SUCCESS;
}
-int sectbl_push(struct section_table *sec_tbl, struct section *section,
- union mips_instruction ins)
+int sectbl_get(struct section_table *sec_tbl, struct section **sec,
+ const char name[MAX_LEX_LENGTH])
+{
+ for (uint32_t i = 0; i < sec_tbl->count; i++) {
+ struct section *temp = &sec_tbl->sections[i];
+ if (strcmp(name, temp->name) == 0) {
+ if (sec != NULL)
+ *sec = temp;
+ return M_SUCCESS;
+ }
+ }
+
+ return M_ERROR;
+}
+
+int sec_push(struct section *section, struct section_entry entry)
{
if (section->count >= section->len) {
section->len *= 2;
- section->ins = realloc(section->ins,
- sizeof(union mips_instruction) * section->len);
+ void *new = realloc(section->entries,
+ sizeof(struct section_entry) * section->len);
- if (section->ins == NULL) {
+ if (new == NULL) {
ERROR("cannot realloc");
return M_ERROR;
}
+
+ section->entries = new;
}
- section->ins[section->count++] = ins;
- sec_tbl->total_ins++;
+ section->entries[section->count++] = entry;
return M_SUCCESS;
}
-int sectbl_get(struct section_table *sec_tbl, struct section **sec,
- const char name[MAX_LEX_LENGTH])
+size_t sec_size(struct section *sec)
{
- for (uint32_t i = 0; i < sec_tbl->count; i++) {
- struct section *temp = &sec_tbl->sections[i];
- if (strcmp(name, temp->name) == 0) {
- if (sec != NULL)
- *sec = temp;
- return M_SUCCESS;
- }
+ size_t n = 0;
+ for (uint32_t i = 0; i < sec->count; i++) {
+ size_t t = sec->entries[i].size;
+ size_t m = t % sec->alignment;
+ if (m)
+ t += sec->alignment - m;
+ n += t;
}
+ return n;
+}
- return M_ERROR;
+size_t sec_index(struct section *sec, uint32_t idx)
+{
+ size_t n = 0;
+ for (uint32_t i = 0; i < idx; i++) {
+ size_t t = sec->entries[i].size;
+ size_t m = t % sec->alignment;
+ if (m)
+ t += sec->alignment - m;
+ n += t;
+ }
+ return n;
}
diff --git a/masm/strtbl.c b/masm/strtbl.c
index b01bb92..7bdbbea 100644
--- a/masm/strtbl.c
+++ b/masm/strtbl.c
@@ -6,44 +6,49 @@
int strtbl_get_str(struct str_table *str_tbl, const char *str, size_t *res)
{
- for (size_t i = 0; i < str_tbl->size; i ++) {
- if (strcmp(str_tbl->ptr + i, str) == 0) {
- if (res != NULL)
- *res = i;
- return M_SUCCESS;
- }
- }
+ for (size_t i = 0; i < str_tbl->size; i ++) {
+ if (strcmp(str_tbl->ptr + i, str) == 0) {
+ if (res != NULL)
+ *res = i;
+ return M_SUCCESS;
+ }
+ }
- return M_ERROR;
+ return M_ERROR;
}
int strtbl_write_str(struct str_table *str_tbl, const char *str, size_t *res)
{
- if (strtbl_get_str(str_tbl, str, res) == M_SUCCESS)
- return M_SUCCESS;
+ if (strtbl_get_str(str_tbl, str, res) == M_SUCCESS)
+ return M_SUCCESS;
- size_t len = strlen(str);
- char *new = realloc(str_tbl->ptr, str_tbl->size + len + 1);
- if (new == NULL)
- return M_ERROR;
- str_tbl->ptr = new;
- memcpy(str_tbl->ptr + str_tbl->size, str, len + 1);
+ size_t len = strlen(str);
+ char *new = realloc(str_tbl->ptr, str_tbl->size + len + 1);
+ if (new == NULL)
+ return M_ERROR;
+ str_tbl->ptr = new;
+ memcpy(str_tbl->ptr + str_tbl->size, str, len + 1);
- if (res != NULL)
- *res = str_tbl->size;
+ if (res != NULL)
+ *res = str_tbl->size;
- str_tbl->size += len + 1;
- return M_SUCCESS;
+ str_tbl->size += len + 1;
+ return M_SUCCESS;
}
-void strtbl_init(struct str_table *str_tbl)
+int strtbl_init(struct str_table *str_tbl)
{
- str_tbl->size = 1;
- str_tbl->ptr = malloc(1);
- *str_tbl->ptr = '\0';
+ str_tbl->size = 1;
+ str_tbl->ptr = malloc(1);
+ if (str_tbl->ptr == NULL) {
+ ERROR("cannot alloc");
+ return M_ERROR;
+ }
+ *str_tbl->ptr = '\0';
+ return M_SUCCESS;
}
void strtbl_free(struct str_table *str_tbl)
{
- free(str_tbl->ptr);
+ free(str_tbl->ptr);
}
diff --git a/masm/test.asm b/masm/test.asm
index c3b61fb..1820b62 100644
--- a/masm/test.asm
+++ b/masm/test.asm
@@ -1,6 +1,9 @@
.text
.align 2
+.globl main
+.extern test2
+
main:
add $zero,$t7,$t7
xori $a0, $v1, 69
@@ -19,4 +22,4 @@ test:
mfhi $s0
mtlo $s7
- j test
+ j test2