summaryrefslogtreecommitdiff
path: root/masm/asm.c
diff options
context:
space:
mode:
authorFreya Murphy <freya@freyacat.org>2024-10-09 12:07:59 -0400
committerFreya Murphy <freya@freyacat.org>2024-10-09 12:07:59 -0400
commitb663f827057fc9fb199293bc1920cf27315d1846 (patch)
tree477b481694ad50f28bac538bb9b301861b3af4d6 /masm/asm.c
parentupdate generator to support multipe isas, expand grammer syntax (diff)
downloadmips-b663f827057fc9fb199293bc1920cf27315d1846.tar.gz
mips-b663f827057fc9fb199293bc1920cf27315d1846.tar.bz2
mips-b663f827057fc9fb199293bc1920cf27315d1846.zip
refactor elf32 assembler, add support for multiple isa's in cmdline
Diffstat (limited to 'masm/asm.c')
-rw-r--r--masm/asm.c549
1 files changed, 0 insertions, 549 deletions
diff --git a/masm/asm.c b/masm/asm.c
deleted file mode 100644
index 8cbc439..0000000
--- a/masm/asm.c
+++ /dev/null
@@ -1,549 +0,0 @@
-#include <merror.h>
-#include <netinet/in.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <elf.h>
-#include <string.h>
-#include <stddef.h>
-#include <melf.h>
-
-#include "asm.h"
-#include "gen.h"
-#include "tab.h"
-
-extern char *current_file;
-
-#define SYMSEC_STUB -1
-#define SYMSEC_EXTERN -1
-
-#define SEC_ALIGN 0x1000
-
-static int elf_rel_type(enum reference_type ty) {
- switch (ty) {
- case REF_NONE:
- return R_MIPS_NONE;
- case REF_MIPS_16:
- return R_MIPS_16;
- case REF_MIPS_26:
- return R_MIPS_26;
- case REF_MIPS_PC16:
- return R_MIPS_PC16;
- case REF_MIPS_LO16:
- return R_MIPS_LO16;
- case REF_MIPS_HI16:
- return R_MIPS_HI16;
- }
-
- return R_MIPS_NONE;
-}
-
-static int elf_section_init_reltab(struct section *sec,
- struct elf_section *elf_sec)
-{
- Elf32_Rel *reltab = malloc(sizeof(Elf32_Rel) *
- sec->reftab.len);
-
- if (reltab == NULL) {
- PERROR("cannot alloc");
- return M_ERROR;
- }
- for (uint32_t i = 0; i < sec->reftab.len; i++) {
- Elf32_Rel *rel = &reltab[i];
- struct reference *ref = &sec->reftab.references[i];
- rel->r_offset = B32(ref->offset);
- int sym = ref->symbol->tabidx + 1;
- int type = elf_rel_type(ref->type);
- rel->r_info = B32(ELF32_R_INFO(sym, type));
- }
-
- elf_sec->reltab_len = sec->reftab.len;
- elf_sec->reltab = reltab;
-
- return M_SUCCESS;
-}
-
-static int elf_section_init(struct section *sec, struct elf_section *elf_sec)
-{
- elf_sec->data = sec;
- elf_sec->shdr_idx = 0; // dont know yet
- elf_sec->reltab_shidx = 0; // dont know yet
- elf_sec->reltab_len = sec->reftab.len;
- elf_sec->reltab = NULL;
-
- if (sec->reftab.len && elf_section_init_reltab(sec, elf_sec))
- return M_ERROR;
-
- return M_SUCCESS;
-}
-
-/* free an elf section */
-static void elf_section_free(struct elf_section *sec)
-{
- if (sec->reltab != NULL)
- free(sec->reltab);
-}
-
-static int asm_init_sections(struct assembler *assembler)
-{
- struct section *sections = assembler->gen.sections;
- uint32_t len = assembler->gen.sections_len;
-
- struct elf_section *elftab = malloc(sizeof(struct elf_section) * len);
- if (elftab == NULL) {
- PERROR("cannot alloc");
- return M_ERROR;
- }
-
- for (uint32_t i = 0; i < len; i++) {
- struct elf_section *elfsec = &elftab[i];
- elfsec->data = &sections[i];
- if (elf_section_init(&sections[i], elfsec)) {
- free(elftab);
- return M_ERROR;
- }
- }
-
- assembler->sections = elftab;
- assembler->section_len = len;
- return M_SUCCESS;
-}
-
-static int elf_sym_bind(enum symbol_type ty) {
- switch (ty) {
- case SYM_LOCAL:
- return STB_LOCAL;
- case SYM_GLOBAL:
- return STB_GLOBAL;
- case SYM_EXTERN:
- return STB_GLOBAL;
- }
-
- return STB_GLOBAL;
-}
-
-static int asm_init_symtab(struct assembler *assembler) {
- struct symbol_table *symtab = &assembler->gen.symtab;
- size_t len = symtab->len + 1;
- Elf32_Sym *elftab = malloc(sizeof(Elf32_Sym) * len);
- if (elftab == NULL) {
- PERROR("cannot alloc");
- }
-
- // add null entry
- elftab[0] = (Elf32_Sym) {0};
-
- // add rest of the entries
- for (uint32_t i = 0; i < symtab->len; i++) {
- struct symbol *sym = &symtab->symbols[i];
- int bind = elf_sym_bind(sym->type);
- int type = STT_NOTYPE;
-
- // get name
- size_t str_off;
- if (strtab_write_str(&assembler->strtab, sym->name.str,
- &str_off)) {
- free(elftab);
- return M_ERROR;
- }
-
- elftab[i+1] = (Elf32_Sym) {
- .st_name = B32(str_off),
- .st_info = ELF32_ST_INFO(bind, type),
- .st_size = 0,
- .st_other = 0,
- .st_value = B32(sym->offset),
- .st_shndx = 0,
- };
- }
-
- assembler->symbols = elftab;
- assembler->symtab_len = len;
-
- return M_SUCCESS;
-}
-
-static int parse_file(struct assembler *assembler)
-{
- if (generate_mips32r6(&assembler->gen))
- return M_ERROR;
- if (asm_init_sections(assembler))
- return M_ERROR;
- if (asm_init_symtab(assembler))
- return M_ERROR;
- return M_SUCCESS;
-}
-
-static int assemble_shdr(struct assembler *assembler, Elf32_Shdr **res,
- uint32_t *res2)
-{
- uint32_t max_entries = 0;
- max_entries += 1; // null
- max_entries += 1; // symtab
- max_entries += 1; // strtab
- max_entries += 1; // shtrtab
- max_entries += assembler->section_len; // sections
- max_entries += assembler->section_len; // reltabs per section
-
- Elf32_Shdr *shdr = malloc(sizeof(Elf32_Shdr) * max_entries);
-
- if (shdr == NULL) {
- PERROR("cannot alloc");
- return M_ERROR;
- }
-
- size_t str_off;
- uint32_t count = 0;
-
- // null
- shdr[count++] = (Elf32_Shdr) {0};
-
- // reltables
- for (uint32_t i = 0; i < assembler->section_len; i++) {
- struct elf_section *sec = &assembler->sections[i];
- const char *prefix = ".reltab";
- char reltab_name[MAX_EXT_LENGTH + strlen(prefix)];
-
- if (sec->reltab_len == 0)
- continue;
-
- strcpy(reltab_name, prefix);
- strncat(reltab_name, sec->data->name.str,
- MAX_EXT_LENGTH - strlen(prefix));
-
- if (strtab_write_str(&assembler->shstrtab,
- reltab_name, &str_off)) {
- free(shdr);
- return M_ERROR;
- }
-
- sec->reltab_shidx = count;
- shdr[count++] = (Elf32_Shdr) {
- .sh_name = B32(str_off),
- .sh_type = B32(SHT_REL),
- .sh_flags = 0,
- .sh_addr = 0,
- .sh_offset = 0,
- .sh_size = 0,
- .sh_link = 0,
- .sh_info = 0,
- .sh_addralign = B32(1),
- .sh_entsize = B32(sizeof(Elf32_Rel)),
- };
- }
-
- // for each section
- for (uint32_t i = 0; i < assembler->section_len; i++) {
- struct elf_section *sec = &assembler->sections[i];
- const char *name = sec->data->name.str;
-
- if (strtab_write_str(&assembler->shstrtab, name, &str_off)) {
- free(shdr);
- return M_ERROR;
- }
-
- sec->shdr_idx = count;
- if (sec->reltab_len != 0)
- shdr[sec->reltab_shidx].sh_info = B32(count);
-
- shdr[count++] = (Elf32_Shdr){
- .sh_name = B32(str_off),
- .sh_type = B32(sec->data->execute ?
- SHT_PROGBITS : SHT_NOBITS),
- .sh_flags = B32(
- (sec->data->write << 0) |
- (sec->data->execute << 2) |
- SHF_ALLOC),
- .sh_addr = 0,
- .sh_offset = 0,
- .sh_size = 0,
- .sh_link = 0,
- .sh_info = 0,
- .sh_addralign = B32(SEC_ALIGN),
- .sh_entsize = 0,
- };
- }
-
- // symbol table
- if (strtab_write_str(&assembler->shstrtab, ".symtab", &str_off)) {
- free(shdr);
- return M_ERROR;
- }
-
- assembler->symtab_shidx = count;
- shdr[count++] = (Elf32_Shdr) {
- .sh_name = B32(str_off),
- .sh_type = B32(SHT_SYMTAB),
- .sh_flags = 0,
- .sh_addr = 0,
- .sh_offset = 0,
- .sh_size = 0,
- .sh_link = 1,
- .sh_info = 0,
- .sh_addralign = B32(1),
- .sh_entsize = B32(sizeof(Elf32_Sym)),
- };
-
- // string table
- if (strtab_write_str(&assembler->shstrtab, ".strtab", &str_off)) {
- free(shdr);
- return M_ERROR;
- }
-
- assembler->strtab_shidx = count;
- shdr[count++] = (Elf32_Shdr) {
- .sh_name = B32(str_off),
- .sh_type = B32(SHT_STRTAB),
- .sh_flags = B32(SHF_STRINGS),
- .sh_addr = 0,
- .sh_offset = 0,
- .sh_size = 0,
- .sh_link = 0,
- .sh_info = 0,
- .sh_addralign = B32(1),
- .sh_entsize = 0,
- };
-
- // sh string table
- if (strtab_write_str(&assembler->shstrtab, ".shstrtab", &str_off)) {
- free(shdr);
- return M_ERROR;
- }
-
- assembler->shstrtab_shidx = count;
- shdr[count++] = (Elf32_Shdr) {
- .sh_name = B32(str_off),
- .sh_type = B32(SHT_STRTAB),
- .sh_flags = B32(SHF_STRINGS),
- .sh_addr = 0,
- .sh_offset = 0,
- .sh_size = 0,
- .sh_link = 0,
- .sh_info = 0,
- .sh_addralign = B32(1),
- .sh_entsize = 0,
- };
-
- for (uint32_t i = 0; i < assembler->section_len; i++) {
- struct elf_section *sec = &assembler->sections[i];
- if (sec->reltab_len == 0)
- continue;
- shdr[sec->reltab_shidx].sh_link =
- B32(assembler->symtab_shidx);
- }
-
- *res = shdr;
- *res2 = count;
-
- return M_SUCCESS;
-}
-
-static void update_offsets(struct assembler *assembler, Elf32_Ehdr *ehdr)
-{
- Elf32_Shdr *shdr = (Elf32_Shdr *) assembler->shdr;
- uint32_t ptr = 0;
-
- // we must now correct offets and sizes inside the ehdr, phdr,
- // and shdr
- ptr += sizeof(Elf32_Ehdr);
-
- // reltbls
- for (uint32_t i = 0; i < assembler->section_len; i++) {
- struct elf_section *sec = &assembler->sections[i];
- if (sec->reltab_len == 0)
- continue;
- int idx = sec->reltab_shidx;
- int len = sec->reltab_len;
- shdr[idx].sh_offset = B32(ptr);
- shdr[idx].sh_size = B32(len * sizeof(Elf32_Rel));
- ptr += len * sizeof(Elf32_Rel);
- }
-
- // sections
- size_t v_addr = 0;
- for (uint32_t i = 0; i < assembler->section_len; i++) {
-
- size_t pad = v_addr % SEC_ALIGN;
- if (pad)
- pad = SEC_ALIGN - pad;
- v_addr += pad;
-
- struct elf_section *sec = &assembler->sections[i];
- uint32_t idx = sec->shdr_idx;
- uint32_t size = sec->data->len;
- shdr[idx].sh_offset = B32(ptr);
- shdr[idx].sh_size = B32(size);
- shdr[idx].sh_addr = B32(v_addr);
- v_addr += size;
- ptr += size;
- }
-
- // symtab
- {
- uint32_t len = assembler->symtab_len;
- uint32_t size = len * sizeof(Elf32_Sym);
- shdr[assembler->symtab_shidx].sh_offset = B32(ptr);
- shdr[assembler->symtab_shidx].sh_link =
- B32(assembler->strtab_shidx);
- shdr[assembler->symtab_shidx].sh_size = B32(size);
- ptr += size;
- }
-
- // strtab
- shdr[assembler->strtab_shidx].sh_offset = B32(ptr);
- shdr[assembler->strtab_shidx].sh_size = B32(assembler->strtab.size);
- ptr += assembler->strtab.size;
-
- // shstrtab
- shdr[assembler->shstrtab_shidx].sh_offset = B32(ptr);
- shdr[assembler->shstrtab_shidx].sh_size =
- B32(assembler->shstrtab.size);
- ptr += assembler->shstrtab.size;
- // shdr
- ehdr->e_shoff = B32(ptr);
-}
-
-static int write_file(struct assembler *assembler, Elf32_Ehdr *ehdr,
- const char *path)
-{
- FILE *out = fopen(path, "w");
-
- if (out == NULL)
- {
- PERROR("cannot write '%s'", path);
- return M_ERROR;
- }
-
- // ehdr
- fwrite(ehdr, sizeof(Elf32_Ehdr), 1, out);
-
- // reltbls
- for (uint32_t i = 0; i < assembler->section_len; i++) {
- struct elf_section *sec = &assembler->sections[i];
- void *ptr = sec->reltab;
- int len = sec->reltab_len;
- if (len < 1)
- continue;
- fwrite(ptr, sizeof(Elf32_Rel), len, out);
- }
-
- // sections
- for (uint32_t i = 0; i < assembler->section_len; i++) {
- struct elf_section *sec = &assembler->sections[i];
- void *ptr = sec->data->data;
- size_t size = sec->data->len;
- fwrite(ptr, 1, size, out);
- }
-
- // sym tbl
- fwrite(assembler->symbols, sizeof(Elf32_Sym), assembler->symtab_len,
- out);
-
- // str tbl
- fwrite(assembler->strtab.ptr, 1, assembler->strtab.size, out);
-
- // shstr tbl
- fwrite(assembler->shstrtab.ptr, 1, assembler->shstrtab.size, out);
-
- // shdr
- fwrite(assembler->shdr, sizeof(Elf32_Shdr), assembler->shdr_len, out);
-
- // close
- fclose(out);
-
- return M_SUCCESS;
-}
-
-static void update_sym_shndx(struct assembler *assembler)
-{
- for (uint32_t i = 1; i < assembler->symtab_len; i++) {
- Elf32_Sym *esym = &assembler->symbols[i];
- struct symbol *sym = &assembler->gen.symtab.symbols[i - 1];
-
- // get shindx
- int shindx = 0;
- if (sym->secidx != SYM_SEC_STUB)
- shindx = assembler->sections[sym->secidx].shdr_idx;
- else if (sym->type == SYM_EXTERN)
- shindx = 0;
-
- esym->st_shndx = B16(shindx);
- }
-}
-
-static int assemble_elf(struct assembler *assembler, const char *out)
-{
- if (assemble_shdr(assembler, &assembler->shdr, &assembler->shdr_len))
- return M_ERROR;
-
- Elf32_Ehdr ehdr = MIPS_ELF_EHDR;
- ehdr.e_shnum = B16(assembler->shdr_len);
- ehdr.e_shstrndx = B16(assembler->shstrtab_shidx);
- update_offsets(assembler, &ehdr);
- update_sym_shndx(assembler);
-
- if (write_file(assembler, &ehdr, out))
- return M_ERROR;
-
- return M_SUCCESS;
-}
-
-int assemble_file(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;
-
- if (res == M_SUCCESS)
- res = parse_file(&assembler);
-
- if (res == M_SUCCESS)
- res = assemble_elf(&assembler, args.out_file);
-
- assembler_free(&assembler);
-
- return res;
-}
-
-int assembler_init(struct assembler *assembler, const char *path)
-{
- assembler->shdr = NULL;
- assembler->symbols = NULL;
- assembler->sections = NULL;
- assembler->strtab.ptr = NULL;
- assembler->shstrtab.ptr = NULL;
- assembler->gen.sections = NULL;
- assembler->gen.symtab.symbols = NULL;
- assembler->section_len = 0;
-
- if (generator_init(path, &assembler->gen))
- return M_ERROR;
-
- if (strtab_init(&assembler->shstrtab))
- return M_ERROR;
-
- if (strtab_init(&assembler->strtab))
- return M_ERROR;
-
- return M_SUCCESS;
-}
-
-void assembler_free(struct assembler *assembler)
-{
- if (assembler->shdr)
- free(assembler->shdr);
- if (assembler->symbols)
- free(assembler->symbols);
- if (assembler->sections) {
- for (uint32_t i = 0; i < assembler->section_len; i++)
- elf_section_free(&assembler->sections[i]);
- free(assembler->sections);
- }
-
- strtab_free(&assembler->strtab);
- strtab_free(&assembler->shstrtab);
- generator_free(&assembler->gen);
-}