summaryrefslogtreecommitdiff
path: root/masm/asm_mips32.c
diff options
context:
space:
mode:
Diffstat (limited to 'masm/asm_mips32.c')
-rw-r--r--masm/asm_mips32.c841
1 files changed, 577 insertions, 264 deletions
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;
}