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