diff options
Diffstat (limited to '')
-rw-r--r-- | masm/asm_mips32.c | 746 |
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; -} |