summaryrefslogtreecommitdiff
path: root/masm/asm_mips32.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--masm/asm_mips32.c746
1 files changed, 0 insertions, 746 deletions
diff --git a/masm/asm_mips32.c b/masm/asm_mips32.c
deleted file mode 100644
index 7716f4d..0000000
--- a/masm/asm_mips32.c
+++ /dev/null
@@ -1,746 +0,0 @@
-#include <merror.h>
-#include <mips.h>
-#include <mips32.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <elf.h>
-#include <string.h>
-#include <stddef.h>
-
-#include "asm.h"
-#include "mlimits.h"
-#include "parse.h"
-#include "parse_mips32.h"
-
-extern char *current_file;
-
-static int handle_directive(struct assembler *assembler,
- struct mips32_directive *directive)
-{
- switch (directive->type) {
- case MIPS32_DIRECTIVE_SECTION: {
- struct section_table *sec_tbl = &assembler->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: {
- assembler->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(assembler->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(assembler->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(assembler->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(assembler->parser.sec_tbl.current,
- entry))
- return M_ERROR;
- }
- break;
- }
-
- case MIPS32_DIRECTIVE_EXTERN: {
- struct symbol symbol;
- if (symtbl_find(&assembler->sym_tbl, NULL, directive->name)
- == M_SUCCESS) {
- ERROR("cannot extern local symbol '%s'",
- directive->name);
- return M_ERROR;
- }
-
- symbol = (struct symbol) {
- .name = "",
- .sec = NULL,
- .index = 0,
- .flag = SYM_EXTERNAL,
- };
- strcpy(symbol.name, directive->name);
-
- if (symtbl_push(&assembler->sym_tbl, symbol))
- return M_ERROR;
-
- break;
- }
-
- case MIPS32_DIRECTIVE_GLOBL: {
- struct symbol symbol;
- if (symtbl_find(&assembler->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(&assembler->sym_tbl, symbol))
- return M_ERROR;
-
- break;
- }
- }
-
- return M_SUCCESS;
-}
-
-static int handle_label(struct assembler *assembler,
- const char name[MAX_LEX_LENGTH])
-{
- struct symbol *ref;
- if (symtbl_find(&assembler->sym_tbl, &ref, name) == M_SUCCESS) {
- if (ref->flag == SYM_GLOBAL && ref->sec == NULL) {
- ref->sec = assembler->parser.sec_tbl.current;
- ref->index = assembler->parser.sec_tbl.current->count;
- return M_SUCCESS;
- }
- ERROR("redefined symbol '%s'", name);
- return M_ERROR;
- }
-
- struct symbol symbol;
- symbol = (struct symbol) {
- .name = "",
- .sec = assembler->parser.sec_tbl.current,
- .index = assembler->parser.sec_tbl.current->count,
- .flag = SYM_LOCAL,
- };
- strcpy(symbol.name, name);
-
- if (symtbl_push(&assembler->sym_tbl, symbol))
- return M_ERROR;
-
- return M_SUCCESS;
-}
-
-static int parse_file(struct assembler *assembler)
-{
- struct parser *parser = &assembler->parser;
-
- while (1) {
- struct expr expr;
- if (parser_next(parser, &expr))
- 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;
-
- case EXPR_DIRECTIVE:
- if (handle_directive(assembler,
- &expr.directive.mips32))
- return M_ERROR;
- break;
-
- case EXPR_LABEL:
- if (handle_label(assembler, expr.text))
- return M_ERROR;
- break;
-
- case EXPR_CONSTANT:
- break;
- }
- }
-
- struct section_meta *meta = malloc(sizeof(struct section_meta) *
- parser->sec_tbl.count);
- if (meta == NULL) {
- ERROR("cannot alloc");
- return M_ERROR;
- }
-
- assembler->meta = meta;
-
- 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 *assembler, Elf32_Phdr **res,
- uint32_t *res2)
-{
- struct parser *parser = &assembler->parser;
- Elf32_Phdr *phdr = malloc(sizeof(Elf32_Phdr) *
- parser->sec_tbl.count);
- 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;
- }
-
- *res = phdr;
- *res2 = parser->sec_tbl.count;
- return M_SUCCESS;
-}
-
-static int assemble_symtab(struct assembler *assembler, Elf32_Sym **res,
- uint32_t *res2)
-{
- Elf32_Sym *stbl = malloc(sizeof(Elf32_Sym) * assembler->sym_tbl
- .count);
- size_t size = 0;
-
- if (stbl == NULL)
- return M_ERROR;
-
- for (uint32_t i = 0; i < assembler->sym_tbl.count; i++) {
- struct symbol *sym = &assembler->sym_tbl.symbols[i];
- size_t str_off;
- unsigned char bind;
- unsigned char type = STT_NOTYPE;
-
- if (strtbl_write_str(&assembler->str_tbl,
- sym->name, &str_off)) {
- free(stbl);
- return M_ERROR;
- }
-
- if (sym->flag == SYM_GLOBAL && sym->sec == NULL) {
- ERROR("never defined global symbol '%s'", sym->name);
- 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 = 0,
- };
- size = i + 1;
- };
-
- *res = stbl;
- *res2 = size;
-
- return M_SUCCESS;
-}
-
-static void assemble_symtab_shndx(struct assembler *assembler, Elf32_Sym *tbl)
-{
- for (uint32_t i = 0; i < assembler->sym_tbl.count; i++) {
- struct symbol *sym = &assembler->sym_tbl.symbols[i];
- if (sym->sec != NULL)
- tbl[i].st_shndx =
- assembler->meta[sym->sec->index].shdr_idx;
- }
-}
-
-static int assemble_reltbl_sec(struct assembler *assembler, Elf32_Sym *symtab,
- uint32_t symtab_len, struct section *sec)
-{
- uint32_t len = 0;
-
- for (uint32_t i = 0; i < assembler->parser.ref_tbl.count; i++) {
- struct reference *ref =
- &assembler->parser.ref_tbl.references[i];
- if (ref->section->index == sec->index) {
- len++;
- }
- }
-
- if (len == 0) {
- assembler->meta[sec->index].reltbl = NULL;
- return M_SUCCESS;
- }
-
- Elf32_Rela *reltbl = malloc(sizeof(Elf32_Rela) * len);
-
- if (reltbl == NULL) {
- ERROR("cannot alloc");
- return M_ERROR;
- }
-
- for (uint32_t i = 0; i < assembler->parser.ref_tbl.count; i++) {
- struct reference *ref =
- &assembler->parser.ref_tbl.references[i];
- struct mips32_instruction *ins = &ref->section->
- entries[ref->index].ins.mips32;
-
- if (ref->section->index != sec->index) {
- continue;
- }
-
- 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;
- }
-
- int32_t symidx = -1;
-
- for (uint32_t i = 0; i < symtab_len; i++) {
- Elf32_Sym *sym = &symtab[i];
- const char *str =
- &assembler->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 = sec_index(ref->section, ref->index),
- };
- };
-
- assembler->meta[sec->index].reltbl_len = len;
- assembler->meta[sec->index].reltbl = reltbl;
-
- return M_SUCCESS;
-}
-
-static int assemble_reltbl(struct assembler *assembler, Elf32_Sym *symtab,
- uint32_t symtab_len)
-{
- for (uint32_t i = 0; i < assembler->parser.sec_tbl.count; i++) {
- struct section *sec = &assembler->parser.sec_tbl.sections[i];
- if (assemble_reltbl_sec(assembler, symtab, symtab_len, sec))
- return M_ERROR;
- }
-
- return M_SUCCESS;
-}
-
-static int assemble_shdr(struct assembler *assembler, Elf32_Shdr **res,
- uint32_t *res2)
-{
- uint32_t max_entries = 4; // symtab, strtab, shstrtab
- max_entries += assembler->parser.sec_tbl.count; // sections
- max_entries += assembler->parser.sec_tbl.count; // reltabs per section
-
- Elf32_Shdr *shdr = malloc(sizeof(Elf32_Shdr) * max_entries);
-
- size_t str_off;
- uint32_t count = 0;
-
- // eeltables
- for (uint32_t i = 0; i < assembler->parser.sec_tbl.count; i++) {
-
- if (assembler->meta[i].reltbl == NULL)
- continue;
-
- struct section *sec = &assembler->parser.sec_tbl.sections[i];
- const char *prefix = ".reltab.";
- char reltab_name[MAX_LEX_LENGTH + 8];
-
- strcpy(reltab_name, prefix);
- strcat(reltab_name, sec->name);
-
- if (strtbl_write_str(&assembler->shstr_tbl,
- reltab_name, &str_off)) {
- free(shdr);
- return M_ERROR;
- }
-
- assembler->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 < assembler->parser.sec_tbl.count; i++) {
- struct section *sec = &assembler->parser.sec_tbl.sections[i];
- char name[MAX_LEX_LENGTH+1] = ".";
- strcat(name, sec->name);
- if (strtbl_write_str(&assembler->shstr_tbl, name, &str_off)) {
- free(shdr);
- return M_ERROR;
- }
- assembler->meta[i].shdr_idx = count;
- if (assembler->meta[i].reltbl != NULL)
- shdr[assembler->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),
- };
- }
-
- // symbol table
- if (strtbl_write_str(&assembler->shstr_tbl, ".symtab", &str_off)) {
- free(shdr);
- return M_ERROR;
- }
-
- assembler->symtab_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),
- };
-
- // string table
- if (strtbl_write_str(&assembler->shstr_tbl, ".strtab", &str_off)) {
- free(shdr);
- return M_ERROR;
- }
-
- assembler->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(&assembler->shstr_tbl, ".shstrtab", &str_off)) {
- free(shdr);
- return M_ERROR;
- }
-
- assembler->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 < assembler->parser.sec_tbl.count; i++) {
- if (assembler->meta[i].reltbl == NULL)
- continue;
- shdr[assembler->meta[i].reltbl_idx].sh_link =
- assembler->symtab_idx;
- }
-
- *res = shdr;
- *res2 = count;
-
- return M_SUCCESS;
-}
-
-static void update_offsets(struct assembler *assembler, Elf32_Ehdr *ehdr)
-{
- Elf32_Shdr *shdr = (Elf32_Shdr *) assembler->shdr;
- Elf32_Phdr *phdr = (Elf32_Phdr *) assembler->phdr;
- uint32_t ptr = 0;
-
- // we must now correct offets and sizes inside the ehdr, phdr,
- // and shdr
- ptr += sizeof(Elf32_Ehdr);
-
- // phdr
- ehdr->e_phoff = ptr;
- ptr += assembler->phdr_len * sizeof(Elf32_Phdr);
-
- // reltbls
- for (uint32_t i = 0; i < assembler->parser.sec_tbl.count; i++) {
- if (assembler->meta[i].reltbl == NULL)
- continue;
- int idx = assembler->meta[i].reltbl_idx;
- int len = assembler->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 < assembler->parser.sec_tbl.count; i++) {
- int idx = assembler->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;
- }
-
- // symtab
- shdr[assembler->symtab_idx].sh_offset = ptr;
- shdr[assembler->symtab_idx].sh_link = assembler->strtbl_idx;
- shdr[assembler->symtab_idx].sh_size =
- assembler->symtab_len * sizeof(Elf32_Sym);
- ptr += assembler->symtab_len * sizeof(Elf32_Sym);
-
- // strtbl
- shdr[assembler->strtbl_idx].sh_offset = ptr;
- shdr[assembler->strtbl_idx].sh_size = assembler->str_tbl.size;
- ptr += assembler->str_tbl.size;
-
- // shstrtbl
- shdr[assembler->shstrtbl_idx].sh_offset = ptr;
- shdr[assembler->shstrtbl_idx].sh_size = assembler->shstr_tbl.size;
- ptr += assembler->shstr_tbl.size;
-
- // shdr
- ehdr->e_shoff = ptr;
-}
-
-static int write_file(struct assembler *assembler, Elf32_Ehdr *ehdr,
- const char *path)
-{
- FILE *out = fopen(path, "w");
-
- if (out == NULL) {
- ERROR("cannot write '%s'", path);
- return M_ERROR;
- }
-
- // ehdr
- fwrite(ehdr, sizeof(Elf32_Ehdr), 1, out);
-
- // phdr
- fwrite(assembler->phdr, sizeof(Elf32_Phdr), assembler->phdr_len, out);
-
- // reltbls
- for (uint32_t i = 0; i < assembler->parser.sec_tbl.count; i++) {
- if (assembler->meta[i].reltbl == NULL)
- continue;
- void *ptr = assembler->meta[i].reltbl;
- int len = assembler->meta[i].reltbl_len;
- fwrite(ptr, sizeof(Elf32_Rela), len, out);
- }
-
- // sections
- for (uint32_t i = 0; i < assembler->parser.sec_tbl.count; i++) {
- struct section *sec = &assembler->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++;
- }
- }
- }
-
- // sym tbl
- fwrite(assembler->symtab, sizeof(Elf32_Sym),
- assembler->symtab_len, out);
-
- // str tbl
- fwrite(assembler->str_tbl.ptr, assembler->str_tbl.size, 1, out);
-
- // shstr tbl
- fwrite(assembler->shstr_tbl.ptr, assembler->shstr_tbl.size, 1, out);
-
- // shdr
- fwrite(assembler->shdr, sizeof(Elf32_Shdr), assembler->shdr_len, out);
-
- fclose(out);
-
- return M_SUCCESS;
-}
-
-static int assemble_elf(struct assembler *assembler, const char *out)
-{
- if (assemble_symtab(assembler, (Elf32_Sym **) &assembler->symtab,
- &assembler->symtab_len))
- return M_ERROR;
-
- if (assemble_reltbl(assembler, assembler->symtab,
- assembler->symtab_len)) {
- return M_ERROR;
- };
-
- if (assemble_phdr(assembler, (Elf32_Phdr **) &assembler->phdr,
- &assembler->phdr_len)) {
- return M_ERROR;
- }
-
- if (assemble_shdr(assembler, (Elf32_Shdr **) &assembler->shdr,
- &assembler->shdr_len)) {
- return M_ERROR;
- };
-
- // update the symbol tables with their given section
- assemble_symtab_shndx(assembler, assembler->symtab);
-
- 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 = assembler->phdr_len,
- .e_shentsize = sizeof(Elf32_Shdr),
- .e_shnum = assembler->shdr_len,
- .e_shstrndx = assembler->shstrtbl_idx,
- };
-
- update_offsets(assembler, &ehdr);
-
- if (write_file(assembler, &ehdr, out))
- return M_ERROR;
-
- return M_SUCCESS;
-}
-
-int assemble_file_mips32(struct assembler_arguments args)
-{
- struct assembler assembler;
- int res = M_SUCCESS;
-
- current_file = args.in_file;
-
- if (assembler_init(&assembler, args.in_file))
- return M_ERROR;
-
- mips32_parser_init(&assembler.parser);
-
- if (res == M_SUCCESS)
- res = parse_file(&assembler);
-
- if (res == M_SUCCESS)
- res = assemble_elf(&assembler, args.out_file);
-
- assembler_free(&assembler);
-
- return res;
-}