2024-09-10 00:48:08 +00:00
|
|
|
#include <merror.h>
|
2024-09-11 16:06:09 +00:00
|
|
|
#include <mips.h>
|
2024-09-12 12:37:46 +00:00
|
|
|
#include <netinet/in.h>
|
2024-09-11 16:06:09 +00:00
|
|
|
#include <stdio.h>
|
2024-09-10 00:48:08 +00:00
|
|
|
#include <stdlib.h>
|
2024-09-11 16:06:09 +00:00
|
|
|
#include <elf.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stddef.h>
|
2024-09-21 00:46:37 +00:00
|
|
|
#include <melf.h>
|
2024-09-10 00:48:08 +00:00
|
|
|
|
|
|
|
#include "asm.h"
|
2024-09-11 16:06:09 +00:00
|
|
|
#include "mlimits.h"
|
|
|
|
#include "parse.h"
|
2024-09-10 00:48:08 +00:00
|
|
|
|
2024-09-11 16:06:09 +00:00
|
|
|
extern char *current_file;
|
|
|
|
|
|
|
|
#define SYMSEC_STUB -1
|
|
|
|
#define SYMSEC_EXTERN -1
|
|
|
|
|
2024-09-12 13:42:04 +00:00
|
|
|
#define SEC_ALIGN 0x1000
|
|
|
|
|
2024-09-11 16:06:09 +00:00
|
|
|
static int create_symbol(struct assembler *assembler,
|
|
|
|
const char name[MAX_LEX_LENGTH],
|
|
|
|
ssize_t section_idx,
|
|
|
|
size_t section_offset,
|
|
|
|
unsigned char bind)
|
2024-09-10 00:48:08 +00:00
|
|
|
{
|
2024-09-11 16:06:09 +00:00
|
|
|
size_t str_off;
|
|
|
|
if (strtab_write_str(&assembler->strtab, name, &str_off))
|
|
|
|
return M_ERROR;
|
|
|
|
|
|
|
|
Elf32_Sym symbol = {
|
2024-09-21 00:46:37 +00:00
|
|
|
.st_name = B32(str_off),
|
|
|
|
.st_value = B32(section_offset),
|
2024-09-11 16:06:09 +00:00
|
|
|
.st_size = 0,
|
|
|
|
.st_info = ELF32_ST_INFO(bind, STT_NOTYPE),
|
|
|
|
.st_other = ELF32_ST_VISIBILITY(STV_DEFAULT),
|
2024-09-21 00:46:37 +00:00
|
|
|
.st_shndx = B16(section_idx),
|
2024-09-11 16:06:09 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// dont put magic flag values inside symbol, only real indexes
|
|
|
|
if (section_idx < 0)
|
|
|
|
symbol.st_shndx = 0;
|
|
|
|
|
|
|
|
if (symtab_push(&assembler->symtab, symbol, section_idx))
|
|
|
|
return M_ERROR;
|
|
|
|
|
|
|
|
return M_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int find_symbol_or_stub(struct assembler *assembler,
|
|
|
|
const char name[MAX_LEX_LENGTH],
|
|
|
|
Elf32_Sym **res,
|
|
|
|
size_t *res2)
|
|
|
|
{
|
|
|
|
if (symtab_find(&assembler->symtab, res, res2, name) == M_SUCCESS)
|
|
|
|
return M_SUCCESS;
|
|
|
|
|
|
|
|
if (create_symbol(assembler, name, SYMSEC_STUB, 0, STB_LOCAL))
|
|
|
|
return M_ERROR;
|
|
|
|
|
|
|
|
size_t idx = assembler->symtab.len - 1;
|
|
|
|
|
|
|
|
if (res != NULL)
|
|
|
|
*res = &assembler->symtab.symbols[idx];
|
|
|
|
if (res2 != NULL)
|
|
|
|
*res2 = idx;
|
|
|
|
|
|
|
|
return M_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int handle_directive(struct assembler *assembler,
|
|
|
|
struct mips_directive *directive)
|
|
|
|
{
|
|
|
|
switch (directive->type) {
|
|
|
|
case MIPS_DIRECTIVE_SECTION: {
|
|
|
|
struct section_table *sec_tbl = &assembler->sectab;
|
|
|
|
struct section *sec;
|
|
|
|
if (sectab_get(sec_tbl, &sec, directive->name)
|
|
|
|
== M_SUCCESS) {
|
|
|
|
sec_tbl->current = sec;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sectab_alloc(sec_tbl, &sec, directive->name))
|
|
|
|
return M_ERROR;
|
|
|
|
|
|
|
|
sec_tbl->current = sec;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case MIPS_DIRECTIVE_ALIGN: {
|
|
|
|
assembler->sectab.current->alignment =
|
|
|
|
1 << directive->align;
|
2024-09-21 00:46:37 +00:00
|
|
|
if (assembler->sectab.current->alignment == 0) {
|
|
|
|
ERROR("cannot align to zero");
|
|
|
|
return M_ERROR;
|
|
|
|
}
|
2024-09-11 16:06:09 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case MIPS_DIRECTIVE_SPACE: {
|
|
|
|
struct section_entry entry;
|
|
|
|
entry.type = ENT_NO_DATA;
|
|
|
|
entry.size = directive->space;
|
|
|
|
if (sec_push(assembler->sectab.current, entry))
|
|
|
|
return M_ERROR;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case MIPS_DIRECTIVE_WORD: {
|
|
|
|
for (uint32_t i = 0; i < directive->len; i++) {
|
|
|
|
struct section_entry entry;
|
|
|
|
entry.type = ENT_WORD;
|
|
|
|
entry.word = directive->words[i];
|
2024-09-12 12:37:46 +00:00
|
|
|
entry.size = sizeof(uint32_t);
|
2024-09-11 16:06:09 +00:00
|
|
|
if (sec_push(assembler->sectab.current,
|
|
|
|
entry))
|
|
|
|
return M_ERROR;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case MIPS_DIRECTIVE_HALF: {
|
|
|
|
for (uint32_t i = 0; i < directive->len; i++) {
|
|
|
|
struct section_entry entry;
|
|
|
|
entry.type = ENT_HALF;
|
|
|
|
entry.half = directive->halfs[i];
|
2024-09-12 12:37:46 +00:00
|
|
|
entry.size = sizeof(uint16_t);
|
2024-09-11 16:06:09 +00:00
|
|
|
if (sec_push(assembler->sectab.current,
|
|
|
|
entry))
|
|
|
|
return M_ERROR;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case MIPS_DIRECTIVE_BYTE: {
|
|
|
|
for (uint32_t i = 0; i < directive->len; i++) {
|
|
|
|
struct section_entry entry;
|
|
|
|
entry.type = ENT_BYTE;
|
|
|
|
entry.byte = directive->bytes[i];
|
2024-09-12 12:37:46 +00:00
|
|
|
entry.size = sizeof(uint8_t);
|
2024-09-11 16:06:09 +00:00
|
|
|
if (sec_push(assembler->sectab.current,
|
|
|
|
entry))
|
|
|
|
return M_ERROR;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case MIPS_DIRECTIVE_EXTERN: {
|
|
|
|
if (symtab_find(&assembler->symtab, NULL, NULL,
|
|
|
|
directive->name) == M_SUCCESS) {
|
|
|
|
ERROR("cannot extern local symbol '%s'",
|
|
|
|
directive->name);
|
|
|
|
return M_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (create_symbol(assembler, directive->name, SYMSEC_EXTERN, 0,
|
|
|
|
STB_GLOBAL))
|
|
|
|
return M_ERROR;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case MIPS_DIRECTIVE_GLOBL: {
|
|
|
|
Elf32_Sym *sym;
|
|
|
|
if (symtab_find(&assembler->symtab, &sym, NULL,
|
|
|
|
directive->name) == M_SUCCESS) {
|
|
|
|
sym->st_info = ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (create_symbol(assembler, directive->name, SYMSEC_STUB, 0,
|
|
|
|
STB_GLOBAL))
|
|
|
|
return M_ERROR;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2024-09-11 16:47:27 +00:00
|
|
|
|
|
|
|
case MIPS_DIRECTIVE_ASCII: {
|
|
|
|
struct section_entry entry;
|
|
|
|
entry.type = ENT_STR;
|
|
|
|
entry.size = strlen(directive->name);
|
|
|
|
memcpy(entry.str, directive->name, entry.size);
|
|
|
|
if (sec_push(assembler->sectab.current, entry))
|
|
|
|
return M_ERROR;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case MIPS_DIRECTIVE_ASCIIZ: {
|
|
|
|
struct section_entry entry;
|
|
|
|
entry.type = ENT_STR;
|
|
|
|
entry.size = strlen(directive->name) + 1;
|
|
|
|
memcpy(entry.str, directive->name, entry.size);
|
|
|
|
if (sec_push(assembler->sectab.current, entry))
|
|
|
|
return M_ERROR;
|
|
|
|
break;
|
|
|
|
}
|
2024-09-11 16:06:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return M_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int handle_label(struct assembler *assembler,
|
|
|
|
const char name[MAX_LEX_LENGTH])
|
|
|
|
{
|
|
|
|
struct section *cur = assembler->sectab.current;
|
|
|
|
|
|
|
|
Elf32_Sym *ref;
|
|
|
|
size_t symidx;
|
|
|
|
|
|
|
|
if (symtab_find(&assembler->symtab, &ref, &symidx, name) == M_SUCCESS) {
|
|
|
|
ssize_t *sec = &assembler->symtab.sections[symidx];
|
|
|
|
|
|
|
|
// check if the symbol is acutally jus a stub, if so
|
|
|
|
// we need to update it
|
|
|
|
if (*sec == SYMSEC_STUB) {
|
|
|
|
*sec = cur->index;
|
2024-09-21 00:46:37 +00:00
|
|
|
ref->st_value = B32(sec_size(cur));
|
2024-09-11 16:06:09 +00:00
|
|
|
return M_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
ERROR("redefined symbol '%s'", name);
|
2024-09-10 00:48:08 +00:00
|
|
|
return M_ERROR;
|
2024-09-11 16:06:09 +00:00
|
|
|
}
|
2024-09-10 00:48:08 +00:00
|
|
|
|
2024-09-11 16:06:09 +00:00
|
|
|
if (create_symbol(assembler, name, cur->index, sec_size(cur),
|
|
|
|
STB_LOCAL))
|
2024-09-10 00:48:08 +00:00
|
|
|
return M_ERROR;
|
2024-09-11 16:06:09 +00:00
|
|
|
|
|
|
|
return M_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int handle_ins(struct assembler *assembler,
|
|
|
|
struct ins_expr *expr)
|
|
|
|
{
|
|
|
|
struct section *sec = assembler->sectab.current;
|
|
|
|
size_t secidx = sec->len;
|
|
|
|
|
|
|
|
for (size_t i = 0; i < expr->ins_len; i++) {
|
2024-09-12 12:37:46 +00:00
|
|
|
union mips_instruction_data *ins =
|
|
|
|
&expr->ins[i].data;
|
2024-09-11 16:06:09 +00:00
|
|
|
struct reference *ref =
|
|
|
|
&expr->ref[i];
|
|
|
|
struct section_entry entry;
|
|
|
|
|
|
|
|
entry.type = ENT_INS;
|
2024-09-12 12:37:46 +00:00
|
|
|
entry.size = sizeof(union mips_instruction_data);
|
2024-09-21 00:46:37 +00:00
|
|
|
entry.ins = B32(ins->raw);
|
2024-09-11 16:06:09 +00:00
|
|
|
|
|
|
|
if (sec_push(sec, entry))
|
|
|
|
return M_ERROR;
|
|
|
|
|
2024-09-13 15:11:18 +00:00
|
|
|
if (ref->type == R_MIPS_NONE)
|
2024-09-11 16:06:09 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
size_t symidx;
|
|
|
|
if (find_symbol_or_stub(assembler, ref->name, NULL, &symidx))
|
|
|
|
return M_ERROR;
|
|
|
|
|
|
|
|
Elf32_Rela rel = {
|
2024-09-21 00:46:37 +00:00
|
|
|
.r_info = B32(ELF32_R_INFO(symidx, ref->type)),
|
|
|
|
.r_addend = B32(ref->addend),
|
|
|
|
.r_offset = B32(sec_index(sec, secidx + i)),
|
2024-09-11 16:06:09 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
if (reltab_push(&sec->reltab, rel))
|
|
|
|
return M_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return M_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int parse_file(struct assembler *assembler)
|
|
|
|
{
|
|
|
|
struct parser *parser = &assembler->parser;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
struct expr expr;
|
|
|
|
int res = parser_next(parser, &expr);
|
|
|
|
|
|
|
|
if (res == M_ERROR)
|
|
|
|
return M_ERROR;
|
|
|
|
|
|
|
|
if (res == M_EOF)
|
|
|
|
return M_SUCCESS;
|
|
|
|
|
|
|
|
switch (expr.type) {
|
|
|
|
case EXPR_INS:
|
|
|
|
if (handle_ins(assembler, &expr.ins))
|
|
|
|
return M_ERROR;
|
|
|
|
break;
|
|
|
|
case EXPR_DIRECTIVE:
|
|
|
|
if (handle_directive(assembler,
|
|
|
|
&expr.directive))
|
|
|
|
return M_ERROR;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case EXPR_LABEL:
|
|
|
|
if (handle_label(assembler, expr.label))
|
|
|
|
return M_ERROR;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case EXPR_CONSTANT:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return M_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int assemble_phdr(struct assembler *assembler, Elf32_Phdr **res,
|
|
|
|
uint32_t *res2)
|
|
|
|
{
|
|
|
|
Elf32_Phdr *phdr = malloc(sizeof(Elf32_Phdr) *
|
|
|
|
assembler->sectab.len);
|
|
|
|
if (phdr == NULL) {
|
2024-09-22 20:02:42 +00:00
|
|
|
PERROR("cannot alloc");
|
2024-09-11 16:06:09 +00:00
|
|
|
return M_ERROR;;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < assembler->sectab.len; i++) {
|
|
|
|
Elf32_Phdr *hdr = &phdr[i];
|
|
|
|
struct section *sec = &assembler->sectab.sections[i];
|
|
|
|
size_t size = sec_size(sec);
|
2024-09-21 00:46:37 +00:00
|
|
|
hdr->p_type = B32(PT_LOAD);
|
|
|
|
hdr->p_flags = B32(
|
2024-09-12 12:37:46 +00:00
|
|
|
(sec->execute << 0) |
|
2024-09-11 16:06:09 +00:00
|
|
|
(sec->write << 1) |
|
2024-09-12 12:37:46 +00:00
|
|
|
(sec->read << 2));
|
2024-09-11 16:06:09 +00:00
|
|
|
hdr->p_offset = 0;
|
|
|
|
hdr->p_vaddr = 0;
|
|
|
|
hdr->p_paddr = 0;
|
2024-09-21 00:46:37 +00:00
|
|
|
hdr->p_filesz = B32(size);
|
|
|
|
hdr->p_memsz = B32(size);
|
|
|
|
hdr->p_align = B32(SEC_ALIGN);
|
2024-09-11 16:06:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
*res = phdr;
|
|
|
|
*res2 = assembler->sectab.len;
|
|
|
|
return M_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int assemble_shdr(struct assembler *assembler, Elf32_Shdr **res,
|
|
|
|
uint32_t *res2)
|
|
|
|
{
|
2024-09-12 12:37:46 +00:00
|
|
|
uint32_t max_entries = 0;
|
|
|
|
max_entries += 1; // null
|
|
|
|
max_entries += 1; // symtab
|
|
|
|
max_entries += 1; // strtab
|
|
|
|
max_entries += 1; // shtrtab
|
2024-09-11 16:06:09 +00:00
|
|
|
max_entries += assembler->sectab.len; // sections
|
|
|
|
max_entries += assembler->sectab.len; // reltabs per section
|
|
|
|
|
|
|
|
Elf32_Shdr *shdr = malloc(sizeof(Elf32_Shdr) * max_entries);
|
|
|
|
|
2024-09-22 20:02:42 +00:00
|
|
|
if (shdr == NULL) {
|
|
|
|
PERROR("cannot alloc");
|
|
|
|
return M_ERROR;
|
|
|
|
}
|
|
|
|
|
2024-09-11 16:06:09 +00:00
|
|
|
size_t str_off;
|
|
|
|
uint32_t count = 0;
|
|
|
|
|
2024-09-12 12:37:46 +00:00
|
|
|
// null
|
|
|
|
shdr[count++] = (Elf32_Shdr) {0};
|
|
|
|
|
|
|
|
// reltables
|
2024-09-11 16:06:09 +00:00
|
|
|
for (uint32_t i = 0; i < assembler->sectab.len; i++) {
|
|
|
|
struct section *sec = &assembler->sectab.sections[i];
|
|
|
|
const char *prefix = ".reltab.";
|
|
|
|
char reltab_name[MAX_LEX_LENGTH + 8];
|
|
|
|
|
|
|
|
if (sec->reltab.len == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
strcpy(reltab_name, prefix);
|
|
|
|
strcat(reltab_name, sec->name);
|
|
|
|
|
|
|
|
if (strtab_write_str(&assembler->shstrtab,
|
|
|
|
reltab_name, &str_off)) {
|
|
|
|
free(shdr);
|
|
|
|
return M_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
sec->reltab_shidx = count;
|
|
|
|
shdr[count++] = (Elf32_Shdr) {
|
2024-09-21 00:46:37 +00:00
|
|
|
.sh_name = B32(str_off),
|
|
|
|
.sh_type = B32(SHT_RELA),
|
2024-09-11 16:06:09 +00:00
|
|
|
.sh_flags = 0,
|
|
|
|
.sh_addr = 0,
|
|
|
|
.sh_offset = 0,
|
|
|
|
.sh_size = 0,
|
|
|
|
.sh_link = 0,
|
|
|
|
.sh_info = 0,
|
2024-09-21 00:46:37 +00:00
|
|
|
.sh_addralign = B32(1),
|
|
|
|
.sh_entsize = B32(sizeof(Elf32_Rela)),
|
2024-09-11 16:06:09 +00:00
|
|
|
};
|
2024-09-10 00:48:08 +00:00
|
|
|
}
|
|
|
|
|
2024-09-11 16:06:09 +00:00
|
|
|
// for each section
|
|
|
|
for (uint32_t i = 0; i < assembler->sectab.len; i++) {
|
|
|
|
struct section *sec = &assembler->sectab.sections[i];
|
|
|
|
char name[MAX_LEX_LENGTH+1] = ".";
|
|
|
|
|
|
|
|
strcat(name, sec->name);
|
|
|
|
if (strtab_write_str(&assembler->shstrtab, name, &str_off)) {
|
|
|
|
free(shdr);
|
|
|
|
return M_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
sec->shdr_idx = count;
|
|
|
|
if (sec->reltab.len != 0)
|
2024-09-21 00:46:37 +00:00
|
|
|
shdr[sec->reltab_shidx].sh_info = B32(count);
|
2024-09-11 16:06:09 +00:00
|
|
|
|
|
|
|
shdr[count++] = (Elf32_Shdr){
|
2024-09-21 00:46:37 +00:00
|
|
|
.sh_name = B32(str_off),
|
|
|
|
.sh_type = B32(SHT_PROGBITS),
|
|
|
|
.sh_flags = B32(
|
2024-09-12 12:37:46 +00:00
|
|
|
(sec->write << 0) |
|
|
|
|
(sec->execute << 2) |
|
|
|
|
SHF_ALLOC),
|
2024-09-11 16:06:09 +00:00
|
|
|
.sh_addr = 0,
|
|
|
|
.sh_offset = 0,
|
|
|
|
.sh_size = 0,
|
|
|
|
.sh_link = 0,
|
|
|
|
.sh_info = 0,
|
2024-09-21 00:46:37 +00:00
|
|
|
.sh_addralign = B32(sec->alignment),
|
2024-09-12 12:37:46 +00:00
|
|
|
.sh_entsize = 0,
|
2024-09-11 16:06:09 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
// symbol table
|
|
|
|
if (strtab_write_str(&assembler->shstrtab, ".symtab", &str_off)) {
|
|
|
|
free(shdr);
|
2024-09-10 00:48:08 +00:00
|
|
|
return M_ERROR;
|
|
|
|
}
|
|
|
|
|
2024-09-11 16:06:09 +00:00
|
|
|
assembler->symtab_shidx = count;
|
|
|
|
shdr[count++] = (Elf32_Shdr) {
|
2024-09-21 00:46:37 +00:00
|
|
|
.sh_name = B32(str_off),
|
|
|
|
.sh_type = B32(SHT_SYMTAB),
|
2024-09-11 16:06:09 +00:00
|
|
|
.sh_flags = 0,
|
|
|
|
.sh_addr = 0,
|
|
|
|
.sh_offset = 0,
|
|
|
|
.sh_size = 0,
|
|
|
|
.sh_link = 1,
|
|
|
|
.sh_info = 0,
|
2024-09-21 00:46:37 +00:00
|
|
|
.sh_addralign = B32(1),
|
|
|
|
.sh_entsize = B32(sizeof(Elf32_Sym)),
|
2024-09-11 16:06:09 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// string table
|
|
|
|
if (strtab_write_str(&assembler->shstrtab, ".strtab", &str_off)) {
|
|
|
|
free(shdr);
|
2024-09-10 00:48:08 +00:00
|
|
|
return M_ERROR;
|
|
|
|
}
|
|
|
|
|
2024-09-11 16:06:09 +00:00
|
|
|
assembler->strtab_shidx = count;
|
|
|
|
shdr[count++] = (Elf32_Shdr) {
|
2024-09-21 00:46:37 +00:00
|
|
|
.sh_name = B32(str_off),
|
|
|
|
.sh_type = B32(SHT_STRTAB),
|
|
|
|
.sh_flags = B32(SHF_STRINGS),
|
2024-09-11 16:06:09 +00:00
|
|
|
.sh_addr = 0,
|
|
|
|
.sh_offset = 0,
|
|
|
|
.sh_size = 0,
|
|
|
|
.sh_link = 0,
|
|
|
|
.sh_info = 0,
|
2024-09-21 00:46:37 +00:00
|
|
|
.sh_addralign = B32(1),
|
2024-09-11 16:06:09 +00:00
|
|
|
.sh_entsize = 0,
|
|
|
|
};
|
|
|
|
|
|
|
|
// sh string table
|
|
|
|
if (strtab_write_str(&assembler->shstrtab, ".shstrtab", &str_off)) {
|
|
|
|
free(shdr);
|
2024-09-10 22:23:46 +00:00
|
|
|
return M_ERROR;
|
|
|
|
}
|
|
|
|
|
2024-09-11 16:06:09 +00:00
|
|
|
assembler->shstrtab_shidx = count;
|
|
|
|
shdr[count++] = (Elf32_Shdr) {
|
2024-09-21 00:46:37 +00:00
|
|
|
.sh_name = B32(str_off),
|
|
|
|
.sh_type = B32(SHT_STRTAB),
|
|
|
|
.sh_flags = B32(SHF_STRINGS),
|
2024-09-11 16:06:09 +00:00
|
|
|
.sh_addr = 0,
|
|
|
|
.sh_offset = 0,
|
|
|
|
.sh_size = 0,
|
|
|
|
.sh_link = 0,
|
|
|
|
.sh_info = 0,
|
2024-09-21 00:46:37 +00:00
|
|
|
.sh_addralign = B32(1),
|
2024-09-11 16:06:09 +00:00
|
|
|
.sh_entsize = 0,
|
|
|
|
};
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < assembler->sectab.len; i++) {
|
|
|
|
struct section *sec = &assembler->sectab.sections[i];
|
|
|
|
if (sec->reltab.len == 0)
|
|
|
|
continue;
|
|
|
|
shdr[sec->reltab_shidx].sh_link =
|
2024-09-21 00:46:37 +00:00
|
|
|
B32(assembler->symtab_shidx);
|
2024-09-11 16:06:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
*res = shdr;
|
|
|
|
*res2 = count;
|
2024-09-10 00:48:08 +00:00
|
|
|
|
|
|
|
return M_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2024-09-11 16:06:09 +00:00
|
|
|
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
|
2024-09-21 00:46:37 +00:00
|
|
|
ehdr->e_phoff = B32(ptr);
|
2024-09-11 16:06:09 +00:00
|
|
|
ptr += assembler->phdr_len * sizeof(Elf32_Phdr);
|
|
|
|
|
|
|
|
// reltbls
|
|
|
|
for (uint32_t i = 0; i < assembler->sectab.len; i++) {
|
|
|
|
struct section *sec = &assembler->sectab.sections[i];
|
|
|
|
if (sec->reltab.len == 0)
|
|
|
|
continue;
|
|
|
|
int idx = sec->reltab_shidx;
|
|
|
|
int len = sec->reltab.len;
|
2024-09-21 00:46:37 +00:00
|
|
|
shdr[idx].sh_offset = B32(ptr);
|
|
|
|
shdr[idx].sh_size = B32(len * sizeof(Elf32_Rela));
|
2024-09-11 16:06:09 +00:00
|
|
|
ptr += len * sizeof(Elf32_Rela);
|
|
|
|
}
|
|
|
|
|
2024-09-12 13:42:04 +00:00
|
|
|
// section padding
|
|
|
|
{
|
|
|
|
uint32_t mod = ptr % SEC_ALIGN;
|
|
|
|
if (mod != 0)
|
|
|
|
assembler->secalign = (SEC_ALIGN - mod);
|
|
|
|
else
|
|
|
|
assembler->secalign = 0;
|
|
|
|
ptr += assembler->secalign;
|
|
|
|
}
|
|
|
|
|
2024-09-11 16:06:09 +00:00
|
|
|
// sections
|
2024-09-13 15:11:18 +00:00
|
|
|
size_t v_addr = 0;
|
2024-09-11 16:06:09 +00:00
|
|
|
for (uint32_t i = 0; i < assembler->sectab.len; i++) {
|
|
|
|
struct section *sec = &assembler->sectab.sections[i];
|
2024-09-12 13:42:04 +00:00
|
|
|
uint32_t idx = sec->shdr_idx;
|
|
|
|
uint32_t size = ntohl(phdr[i].p_filesz);
|
2024-09-21 00:46:37 +00:00
|
|
|
phdr[i].p_offset = B32(ptr);
|
|
|
|
phdr[i].p_vaddr = B32(v_addr);
|
|
|
|
phdr[i].p_paddr = B32(v_addr);
|
|
|
|
shdr[idx].sh_offset = B32(ptr);
|
2024-09-11 16:06:09 +00:00
|
|
|
shdr[idx].sh_size = phdr[i].p_filesz;
|
|
|
|
shdr[idx].sh_addr = phdr[i].p_vaddr;
|
2024-09-12 13:42:04 +00:00
|
|
|
v_addr += size;
|
|
|
|
ptr += size;
|
2024-09-11 16:06:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// symtab
|
2024-09-21 00:46:37 +00:00
|
|
|
shdr[assembler->symtab_shidx].sh_offset = B32(ptr);
|
|
|
|
shdr[assembler->symtab_shidx].sh_link = B32(assembler->strtab_shidx);
|
2024-09-11 16:06:09 +00:00
|
|
|
shdr[assembler->symtab_shidx].sh_size =
|
2024-09-21 00:46:37 +00:00
|
|
|
B32(assembler->symtab.len * sizeof(Elf32_Sym));
|
2024-09-11 16:06:09 +00:00
|
|
|
ptr += assembler->symtab.len * sizeof(Elf32_Sym);
|
|
|
|
|
|
|
|
// strtab
|
2024-09-21 00:46:37 +00:00
|
|
|
shdr[assembler->strtab_shidx].sh_offset = B32(ptr);
|
|
|
|
shdr[assembler->strtab_shidx].sh_size = B32(assembler->strtab.size);
|
2024-09-11 16:06:09 +00:00
|
|
|
ptr += assembler->strtab.size;
|
|
|
|
|
|
|
|
// shstrtab
|
2024-09-21 00:46:37 +00:00
|
|
|
shdr[assembler->shstrtab_shidx].sh_offset = B32(ptr);
|
2024-09-12 12:37:46 +00:00
|
|
|
shdr[assembler->shstrtab_shidx].sh_size =
|
2024-09-21 00:46:37 +00:00
|
|
|
B32(assembler->shstrtab.size);
|
2024-09-11 16:06:09 +00:00
|
|
|
ptr += assembler->shstrtab.size;
|
|
|
|
|
|
|
|
// shdr
|
2024-09-21 00:46:37 +00:00
|
|
|
ehdr->e_shoff = B32(ptr);
|
2024-09-11 16:06:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void update_sym_shindx(struct assembler *assembler)
|
|
|
|
{
|
2024-09-12 13:42:04 +00:00
|
|
|
for (size_t i = 0; i < assembler->symtab.len; i++) {
|
2024-09-11 16:06:09 +00:00
|
|
|
Elf32_Sym *sym = &assembler->symtab.symbols[i];
|
|
|
|
ssize_t sec = assembler->symtab.sections[i];
|
|
|
|
|
|
|
|
if (sec >= 0) {
|
2024-09-21 00:46:37 +00:00
|
|
|
sym->st_shndx = B16(assembler->
|
2024-09-12 12:37:46 +00:00
|
|
|
sectab.sections[sec].shdr_idx);
|
2024-09-11 16:06:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int write_file(struct assembler *assembler, Elf32_Ehdr *ehdr,
|
|
|
|
const char *path)
|
2024-09-10 00:48:08 +00:00
|
|
|
{
|
2024-09-11 16:06:09 +00:00
|
|
|
FILE *out = fopen(path, "w");
|
|
|
|
|
2024-09-21 00:46:37 +00:00
|
|
|
if (out == NULL)
|
|
|
|
{
|
2024-09-22 20:02:42 +00:00
|
|
|
PERROR("cannot write '%s'", path);
|
2024-09-11 16:06:09 +00:00
|
|
|
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->sectab.len; i++) {
|
|
|
|
struct section *sec = &assembler->sectab.sections[i];
|
|
|
|
if (sec->reltab.len == 0)
|
|
|
|
continue;
|
|
|
|
void *ptr = sec->reltab.data;
|
|
|
|
int len = sec->reltab.len;
|
|
|
|
fwrite(ptr, sizeof(Elf32_Rela), len, out);
|
|
|
|
}
|
|
|
|
|
2024-09-12 13:42:04 +00:00
|
|
|
// section padding
|
|
|
|
for (uint32_t i = 0; i < assembler->secalign; i++) {
|
|
|
|
uint8_t zero = 0;
|
|
|
|
fwrite(&zero, 1, 1, out);
|
|
|
|
}
|
|
|
|
|
2024-09-11 16:06:09 +00:00
|
|
|
// sections
|
|
|
|
for (uint32_t i = 0; i < assembler->sectab.len; i++) {
|
|
|
|
struct section *sec = &assembler->sectab.sections[i];
|
|
|
|
for (uint32_t j = 0; j < sec->len; j++) {
|
|
|
|
struct section_entry *entry = &sec->entries[j];
|
|
|
|
size_t size = entry->size;
|
2024-09-13 15:11:18 +00:00
|
|
|
size_t zeros = size % sec->alignment;;
|
|
|
|
if (entry->type != ENT_NO_DATA)
|
|
|
|
fwrite(&entry->data, size, 1, out);
|
|
|
|
else
|
|
|
|
zeros += size;
|
|
|
|
while(zeros) {
|
|
|
|
fputc(0, out);
|
|
|
|
zeros--;
|
2024-09-10 22:23:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-11 16:06:09 +00:00
|
|
|
// sym tbl
|
|
|
|
fwrite(assembler->symtab.symbols, sizeof(Elf32_Sym),
|
|
|
|
assembler->symtab.len, out);
|
|
|
|
|
|
|
|
// str tbl
|
|
|
|
fwrite(assembler->strtab.ptr, assembler->strtab.size, 1, out);
|
|
|
|
|
|
|
|
// shstr tbl
|
|
|
|
fwrite(assembler->shstrtab.ptr, assembler->shstrtab.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_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;
|
|
|
|
};
|
|
|
|
|
2024-09-21 00:46:37 +00:00
|
|
|
Elf32_Ehdr ehdr = MIPS_ELF_EHDR;
|
|
|
|
ehdr.e_phnum = B16(assembler->phdr_len);
|
|
|
|
ehdr.e_shnum = B16(assembler->shdr_len);
|
|
|
|
ehdr.e_shstrndx = B16(assembler->shstrtab_shidx);
|
2024-09-11 16:06:09 +00:00
|
|
|
|
|
|
|
update_offsets(assembler, &ehdr);
|
|
|
|
update_sym_shindx(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)
|
|
|
|
{
|
|
|
|
if (lexer_init(path, &assembler->lexer))
|
|
|
|
return M_ERROR;
|
|
|
|
|
|
|
|
if (parser_init(&assembler->lexer, &assembler->parser))
|
|
|
|
return M_ERROR;
|
|
|
|
|
|
|
|
if (strtab_init(&assembler->shstrtab))
|
|
|
|
return M_ERROR;
|
|
|
|
|
|
|
|
if (strtab_init(&assembler->strtab))
|
|
|
|
return M_ERROR;
|
|
|
|
|
|
|
|
if (symtab_init(&assembler->symtab))
|
|
|
|
return M_ERROR;
|
|
|
|
|
|
|
|
if (sectab_init(&assembler->sectab))
|
|
|
|
return M_ERROR;
|
|
|
|
|
|
|
|
assembler->symtab.strtab = &assembler->strtab;
|
|
|
|
assembler->phdr = NULL;
|
|
|
|
assembler->shdr = NULL;
|
|
|
|
|
|
|
|
return M_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
void assembler_free(struct assembler *assembler)
|
|
|
|
{
|
2024-09-10 22:23:46 +00:00
|
|
|
if (assembler->phdr)
|
|
|
|
free(assembler->phdr);
|
|
|
|
if (assembler->shdr)
|
|
|
|
free(assembler->shdr);
|
|
|
|
|
2024-09-11 16:06:09 +00:00
|
|
|
sectab_free(&assembler->sectab);
|
|
|
|
symtab_free(&assembler->symtab);
|
|
|
|
strtab_free(&assembler->strtab);
|
|
|
|
strtab_free(&assembler->shstrtab);
|
2024-09-10 22:23:46 +00:00
|
|
|
|
|
|
|
parser_free(&assembler->parser);
|
|
|
|
lexer_free(&assembler->lexer);
|
|
|
|
}
|