relocation table hell
This commit is contained in:
parent
d079aac905
commit
0ff948af3d
13 changed files with 1315 additions and 821 deletions
|
@ -5,7 +5,7 @@ LD=cc
|
||||||
|
|
||||||
CFLAGS += -pipe
|
CFLAGS += -pipe
|
||||||
CFLAGS += -Wall -Wextra -pedantic
|
CFLAGS += -Wall -Wextra -pedantic
|
||||||
CFLAGS += -O3 -g
|
CFLAGS += -O0 -g
|
||||||
|
|
||||||
# ======================== CONFIG OPTIONS ==
|
# ======================== CONFIG OPTIONS ==
|
||||||
#
|
#
|
||||||
|
|
|
@ -117,6 +117,7 @@ enum mips32_instruction_type {
|
||||||
MIPS32_INS_SRLV,
|
MIPS32_INS_SRLV,
|
||||||
MIPS32_INS_SUB,
|
MIPS32_INS_SUB,
|
||||||
MIPS32_INS_SUBU,
|
MIPS32_INS_SUBU,
|
||||||
|
MIPS32_INS_SYSCALL,
|
||||||
MIPS32_INS_OR,
|
MIPS32_INS_OR,
|
||||||
MIPS32_INS_ORI,
|
MIPS32_INS_ORI,
|
||||||
MIPS32_INS_NOR,
|
MIPS32_INS_NOR,
|
||||||
|
@ -447,6 +448,10 @@ MIPS32_INS(SUB, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_SUB)
|
||||||
#define MIPS32_FUNCT_SUBU 0b100011
|
#define MIPS32_FUNCT_SUBU 0b100011
|
||||||
MIPS32_INS(SUBU, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_SUBU)
|
MIPS32_INS(SUBU, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_SUBU)
|
||||||
|
|
||||||
|
/* SYSCALL - syscall */
|
||||||
|
#define MIPS32_FUNCT_SYSCALL 0b001100
|
||||||
|
MIPS32_INS(SYSCALL, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_SYSCALL)
|
||||||
|
|
||||||
/* OR - or */
|
/* OR - or */
|
||||||
#define MIPS32_FUNCT_OR 0b100101
|
#define MIPS32_FUNCT_OR 0b100101
|
||||||
MIPS32_INS(OR, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_OR)
|
MIPS32_INS(OR, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_OR)
|
||||||
|
@ -478,11 +483,14 @@ enum mips32_directive_type {
|
||||||
MIPS32_DIRECTIVE_HALF,
|
MIPS32_DIRECTIVE_HALF,
|
||||||
MIPS32_DIRECTIVE_BYTE,
|
MIPS32_DIRECTIVE_BYTE,
|
||||||
MIPS32_DIRECTIVE_SECTION,
|
MIPS32_DIRECTIVE_SECTION,
|
||||||
|
MIPS32_DIRECTIVE_EXTERN,
|
||||||
|
MIPS32_DIRECTIVE_GLOBL,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* mip32 directive */
|
/* mip32 directive */
|
||||||
struct mips32_directive {
|
struct mips32_directive {
|
||||||
enum mips32_directive_type type;
|
enum mips32_directive_type type;
|
||||||
|
uint32_t len; // used for words, halfs, bytes
|
||||||
union {
|
union {
|
||||||
uint16_t align;
|
uint16_t align;
|
||||||
uint16_t space;
|
uint16_t space;
|
||||||
|
|
41
masm/asm.c
Normal file
41
masm/asm.c
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#include <merror.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "asm.h"
|
||||||
|
|
||||||
|
int assembler_init(struct assembler *asm, const char *path)
|
||||||
|
{
|
||||||
|
if (lexer_init(path, &asm->lexer))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
if (parser_init(&asm->lexer, &asm->parser)) {
|
||||||
|
lexer_free(&asm->lexer);
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strtbl_init(&asm->shstr_tbl)) {
|
||||||
|
parser_free(&asm->parser);
|
||||||
|
lexer_free(&asm->lexer);
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strtbl_init(&asm->str_tbl)) {
|
||||||
|
strtbl_free(&asm->shstr_tbl);
|
||||||
|
parser_free(&asm->parser);
|
||||||
|
lexer_free(&asm->lexer);
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
asm->meta = NULL;
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void assembler_free(struct assembler *asm)
|
||||||
|
{
|
||||||
|
strtbl_free(&asm->str_tbl);
|
||||||
|
strtbl_free(&asm->shstr_tbl);
|
||||||
|
parser_free(&asm->parser);
|
||||||
|
lexer_free(&asm->lexer);
|
||||||
|
free(asm->meta);
|
||||||
|
}
|
29
masm/asm.h
29
masm/asm.h
|
@ -5,13 +5,16 @@
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "lex.h"
|
||||||
|
#include "parse.h"
|
||||||
|
|
||||||
struct str_table {
|
struct str_table {
|
||||||
char *ptr;
|
char *ptr;
|
||||||
size_t size;
|
size_t size;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* initalize a string table */
|
/* initalize a string table */
|
||||||
void strtbl_init(struct str_table *str_tbl);
|
int strtbl_init(struct str_table *str_tbl);
|
||||||
|
|
||||||
/* free a string table */
|
/* free a string table */
|
||||||
void strtbl_free(struct str_table *str_tbl);
|
void strtbl_free(struct str_table *str_tbl);
|
||||||
|
@ -22,11 +25,29 @@ int strtbl_get_str(struct str_table *str_tbl, const char *str, size_t *res);
|
||||||
/* get or append a string into the string table */
|
/* get or append a string into the string table */
|
||||||
int strtbl_write_str(struct str_table *str_tbl, const char *str, size_t *res);
|
int strtbl_write_str(struct str_table *str_tbl, const char *str, size_t *res);
|
||||||
|
|
||||||
struct assembler {
|
struct section_meta {
|
||||||
struct parser *parser;
|
void *reltbl;
|
||||||
struct str_table str_tbl;
|
uint32_t reltbl_len;
|
||||||
|
uint32_t reltbl_idx; // reltbl idx in shdr
|
||||||
|
uint32_t shdr_idx; // sec idx in shdr
|
||||||
|
uint32_t v_addr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct assembler {
|
||||||
|
struct lexer lexer;
|
||||||
|
struct parser parser;
|
||||||
|
struct str_table shstr_tbl;
|
||||||
|
struct str_table str_tbl;
|
||||||
|
|
||||||
|
struct section_meta *meta;
|
||||||
|
size_t shstrtbl_idx;
|
||||||
|
size_t strtbl_idx;
|
||||||
|
size_t symtbl_idx;
|
||||||
|
};
|
||||||
|
|
||||||
|
int assembler_init(struct assembler *asm, const char *path);
|
||||||
|
void assembler_free(struct assembler *asm);
|
||||||
|
|
||||||
/* assemble a mips32 file*/
|
/* assemble a mips32 file*/
|
||||||
int assemble_file_mips32(char *path);
|
int assemble_file_mips32(char *path);
|
||||||
|
|
||||||
|
|
|
@ -14,58 +14,180 @@
|
||||||
|
|
||||||
extern char *current_file;
|
extern char *current_file;
|
||||||
|
|
||||||
#define SHDR_SYMTBL 0
|
static int handle_directive(struct assembler *asm,
|
||||||
#define SHDR_STRTBL 1
|
struct mips32_directive *directive)
|
||||||
#define SHDR_SECTIONS 2
|
|
||||||
|
|
||||||
static int parse_file(struct parser *parser)
|
|
||||||
{
|
{
|
||||||
|
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 assembler *asm)
|
||||||
|
{
|
||||||
|
struct parser *parser = &asm->parser;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
struct expr expr;
|
struct expr expr;
|
||||||
if (parser_next(parser, &expr)) {
|
if (parser_next(parser, &expr)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expr.type == EXPR_INS)
|
switch (expr.type) {
|
||||||
if (sectbl_push(&parser->sec_tbl,
|
case EXPR_INS:
|
||||||
parser->sec_tbl.current, 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(asm, &expr.directive.mips32))
|
||||||
|
return M_ERROR;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EXPR_CONSTANT:
|
||||||
|
case EXPR_LABEL:
|
||||||
|
// nothing needed to be done
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct section_meta *meta = malloc(sizeof(struct section_meta) *
|
||||||
|
parser->sec_tbl.count);
|
||||||
|
if (meta == NULL) {
|
||||||
|
ERROR("cannot alloc");
|
||||||
return M_ERROR;
|
return M_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint32_t i = 0; i < parser->ref_tbl.count; i++) {
|
asm->meta = meta;
|
||||||
struct reference *ref = &parser->ref_tbl.references[i];
|
|
||||||
struct symbol *sym;
|
|
||||||
struct mips32_instruction *ins;
|
|
||||||
|
|
||||||
if (symtbl_find(&parser->sym_tbl, &sym, ref->name)) {
|
size_t ptr = 0;
|
||||||
ERROR("undefined symbol '%s'", ref->name);
|
for (uint32_t i = 0; i < parser->sec_tbl.count; i++) {
|
||||||
return M_ERROR;
|
struct section *sec = &parser->sec_tbl.sections[i];
|
||||||
|
meta[i].v_addr = ptr;
|
||||||
|
ptr += sec_size(sec);
|
||||||
}
|
}
|
||||||
|
|
||||||
ins = &ref->section->ins[ref->index].mips32;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
return M_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int assemble_phdr(struct assembler *asm, Elf32_Phdr **res,
|
static int assemble_phdr(struct assembler *asm, Elf32_Phdr **res,
|
||||||
uint32_t *res2)
|
uint32_t *res2)
|
||||||
{
|
{
|
||||||
struct parser *parser = asm->parser;
|
struct parser *parser = &asm->parser;
|
||||||
Elf32_Phdr *phdr = malloc(sizeof(Elf32_Phdr) *
|
Elf32_Phdr *phdr = malloc(sizeof(Elf32_Phdr) *
|
||||||
parser->sec_tbl.count);
|
parser->sec_tbl.count);
|
||||||
size_t ins_sz = sizeof(struct mips32_instruction);
|
|
||||||
|
|
||||||
if (phdr == NULL) {
|
if (phdr == NULL) {
|
||||||
ERROR("cannot alloc");
|
ERROR("cannot alloc");
|
||||||
return M_ERROR;;
|
return M_ERROR;;
|
||||||
|
@ -74,14 +196,16 @@ static int assemble_phdr(struct assembler *asm, Elf32_Phdr **res,
|
||||||
for (uint32_t i = 0; i < parser->sec_tbl.count; i++) {
|
for (uint32_t i = 0; i < parser->sec_tbl.count; i++) {
|
||||||
Elf32_Phdr *hdr = &phdr[i];
|
Elf32_Phdr *hdr = &phdr[i];
|
||||||
struct section *sec = &parser->sec_tbl.sections[i];
|
struct section *sec = &parser->sec_tbl.sections[i];
|
||||||
|
size_t size = sec_size(sec);
|
||||||
hdr->p_type = PT_LOAD;
|
hdr->p_type = PT_LOAD;
|
||||||
hdr->p_flags = PF_X | PF_W | PF_R; // FIXME: this is bad
|
hdr->p_flags = (sec->execute << 0) |
|
||||||
hdr->p_offset = sec->start * ins_sz;
|
(sec->write << 1) |
|
||||||
hdr->p_vaddr = sec->start * ins_sz;
|
(sec->read << 2);
|
||||||
hdr->p_paddr = 0x00;
|
hdr->p_offset = 0;
|
||||||
hdr->p_filesz = sec->count * ins_sz;
|
hdr->p_vaddr = 0;
|
||||||
hdr->p_memsz = sec->count * ins_sz;
|
hdr->p_paddr = 0;
|
||||||
|
hdr->p_filesz = size;
|
||||||
|
hdr->p_memsz = size;
|
||||||
hdr->p_align = sec->alignment;
|
hdr->p_align = sec->alignment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,47 +217,132 @@ static int assemble_phdr(struct assembler *asm, Elf32_Phdr **res,
|
||||||
static int assemble_symtbl(struct assembler *asm, Elf32_Sym **res,
|
static int assemble_symtbl(struct assembler *asm, Elf32_Sym **res,
|
||||||
uint32_t *res2)
|
uint32_t *res2)
|
||||||
{
|
{
|
||||||
Elf32_Sym *stbl = malloc(sizeof(Elf32_Sym) * asm->parser->sym_tbl
|
Elf32_Sym *stbl = malloc(sizeof(Elf32_Sym) * asm->parser.sym_tbl
|
||||||
.count);
|
.count);
|
||||||
|
size_t size = 0;
|
||||||
|
|
||||||
if (stbl == NULL)
|
if (stbl == NULL)
|
||||||
return M_ERROR;
|
return M_ERROR;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < asm->parser->sym_tbl.count; i++) {
|
for (uint32_t i = 0; i < asm->parser.sym_tbl.count; i++) {
|
||||||
struct symbol *sym = &asm->parser->sym_tbl.symbols[i];
|
struct symbol *sym = &asm->parser.sym_tbl.symbols[i];
|
||||||
size_t str_off;
|
size_t str_off;
|
||||||
|
unsigned char bind;
|
||||||
|
unsigned char type = STT_NOTYPE;
|
||||||
|
|
||||||
if (strtbl_write_str(&asm->str_tbl, sym->name, &str_off)) {
|
if (strtbl_write_str(&asm->str_tbl, sym->name, &str_off)) {
|
||||||
free(stbl);
|
free(stbl);
|
||||||
return M_ERROR;
|
return M_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
int viz = STB_LOCAL;
|
if (sym->flag != SYM_LOCAL)
|
||||||
switch (sym->flag) {
|
bind = STB_LOCAL;
|
||||||
case SYM_LOCAL:
|
else
|
||||||
viz = STB_LOCAL;
|
bind = STB_GLOBAL;
|
||||||
break;
|
|
||||||
case SYM_GLOBAL:
|
|
||||||
case SYM_EXTERNAL:
|
|
||||||
viz = STB_GLOBAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
stbl[i] = (Elf32_Sym) {
|
stbl[i] = (Elf32_Sym) {
|
||||||
.st_name = str_off,
|
.st_name = str_off,
|
||||||
.st_value = sym->position,
|
.st_value = sym->index,
|
||||||
.st_size = 0,
|
.st_size = 0,
|
||||||
.st_info = (unsigned char)
|
.st_info = ELF32_ST_INFO(bind, type),
|
||||||
ELF32_ST_INFO(SYMINFO_BT_SELF,
|
.st_other = ELF32_ST_VISIBILITY(STV_DEFAULT),
|
||||||
SYMINFO_FLG_DIRECT),
|
.st_shndx = asm->meta[sym->sec->index].shdr_idx,
|
||||||
.st_other = (unsigned char)
|
|
||||||
ELF32_ST_VISIBILITY(viz),
|
|
||||||
.st_shndx = 0, // FIXME: specify section
|
|
||||||
};
|
};
|
||||||
|
size = i + 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
*res = stbl;
|
*res = stbl;
|
||||||
*res2 = asm->parser->sym_tbl.count;
|
*res2 = size;
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int assemble_reltbl_sec(struct assembler *asm, Elf32_Sym *symtbl,
|
||||||
|
uint32_t symtbl_len, struct section *sec)
|
||||||
|
{
|
||||||
|
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 (len == 0) {
|
||||||
|
asm->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 < 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];
|
||||||
|
|
||||||
|
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 < 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;
|
return M_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -141,19 +350,83 @@ static int assemble_symtbl(struct assembler *asm, Elf32_Sym **res,
|
||||||
static int assemble_shdr(struct assembler *asm, Elf32_Shdr **res,
|
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
|
uint32_t max_entries = 4; // symtab, strtab, shstrtab
|
||||||
entries += asm->parser->sec_tbl.count; // sections
|
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;
|
size_t str_off;
|
||||||
if (strtbl_write_str(&asm->str_tbl, ".shsymtab", &str_off)) {
|
uint32_t count = 0;
|
||||||
|
|
||||||
|
// eeltables
|
||||||
|
for (uint32_t i = 0; i < asm->parser.sec_tbl.count; i++) {
|
||||||
|
|
||||||
|
if (asm->meta[i].reltbl == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
struct section *sec = &asm->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(&asm->shstr_tbl, reltab_name, &str_off)) {
|
||||||
free(shdr);
|
free(shdr);
|
||||||
return M_ERROR;
|
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),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// symbol table
|
// symbol table
|
||||||
shdr[SHDR_SYMTBL] = (Elf32_Shdr) {
|
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_name = str_off,
|
||||||
.sh_type = SHT_SYMTAB,
|
.sh_type = SHT_SYMTAB,
|
||||||
.sh_flags = 0,
|
.sh_flags = 0,
|
||||||
|
@ -166,13 +439,14 @@ static int assemble_shdr(struct assembler *asm, Elf32_Shdr **res,
|
||||||
.sh_entsize = sizeof(Elf32_Sym),
|
.sh_entsize = sizeof(Elf32_Sym),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (strtbl_write_str(&asm->str_tbl, ".shstrtab", &str_off)) {
|
// string table
|
||||||
|
if (strtbl_write_str(&asm->shstr_tbl, ".strtab", &str_off)) {
|
||||||
free(shdr);
|
free(shdr);
|
||||||
return M_ERROR;
|
return M_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// string table
|
asm->strtbl_idx = count;
|
||||||
shdr[SHDR_STRTBL] = (Elf32_Shdr) {
|
shdr[count++] = (Elf32_Shdr) {
|
||||||
.sh_name = str_off,
|
.sh_name = str_off,
|
||||||
.sh_type = SHT_STRTAB,
|
.sh_type = SHT_STRTAB,
|
||||||
.sh_flags = SHF_STRINGS,
|
.sh_flags = SHF_STRINGS,
|
||||||
|
@ -185,31 +459,34 @@ static int assemble_shdr(struct assembler *asm, Elf32_Shdr **res,
|
||||||
.sh_entsize = 0,
|
.sh_entsize = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
// for each section
|
// sh string table
|
||||||
for (uint32_t i = 0; i < asm->parser->sec_tbl.count; i++) {
|
if (strtbl_write_str(&asm->shstr_tbl, ".shstrtab", &str_off)) {
|
||||||
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);
|
free(shdr);
|
||||||
return M_ERROR;
|
return M_ERROR;
|
||||||
}
|
}
|
||||||
shdr[i+SHDR_SECTIONS] = (Elf32_Shdr) {
|
|
||||||
|
asm->shstrtbl_idx = count;
|
||||||
|
shdr[count++] = (Elf32_Shdr) {
|
||||||
.sh_name = str_off,
|
.sh_name = str_off,
|
||||||
.sh_type = SHT_PROGBITS,
|
.sh_type = SHT_STRTAB,
|
||||||
.sh_flags = SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR,
|
.sh_flags = SHF_STRINGS,
|
||||||
.sh_addr = 0,
|
.sh_addr = 0,
|
||||||
.sh_offset = 0,
|
.sh_offset = 0,
|
||||||
.sh_size = 0,
|
.sh_size = 0,
|
||||||
.sh_link = 0,
|
.sh_link = 0,
|
||||||
.sh_info = 0,
|
.sh_info = 0,
|
||||||
.sh_addralign = sec->alignment,
|
.sh_addralign = 1,
|
||||||
.sh_entsize = sizeof(struct mips32_instruction),
|
.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;
|
*res = shdr;
|
||||||
*res2 = entries;
|
*res2 = count;
|
||||||
|
|
||||||
return M_SUCCESS;
|
return M_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -226,6 +503,11 @@ static int assemble_file(struct assembler *asm)
|
||||||
if (assemble_symtbl(asm, &symtbl, &symtbl_len))
|
if (assemble_symtbl(asm, &symtbl, &symtbl_len))
|
||||||
return M_ERROR;
|
return M_ERROR;
|
||||||
|
|
||||||
|
if (assemble_reltbl(asm, symtbl, symtbl_len)) {
|
||||||
|
free(symtbl);
|
||||||
|
return M_ERROR;
|
||||||
|
};
|
||||||
|
|
||||||
if (assemble_phdr(asm, &phdr, &phdr_len)) {
|
if (assemble_phdr(asm, &phdr, &phdr_len)) {
|
||||||
free(symtbl);
|
free(symtbl);
|
||||||
return M_ERROR;
|
return M_ERROR;
|
||||||
|
@ -262,39 +544,59 @@ static int assemble_file(struct assembler *asm)
|
||||||
.e_phnum = phdr_len,
|
.e_phnum = phdr_len,
|
||||||
.e_shentsize = sizeof(Elf32_Shdr),
|
.e_shentsize = sizeof(Elf32_Shdr),
|
||||||
.e_shnum = shdr_len,
|
.e_shnum = shdr_len,
|
||||||
.e_shstrndx = SHDR_STRTBL,
|
.e_shstrndx = asm->shstrtbl_idx,
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t ptr = 0;
|
uint32_t ptr = 0;
|
||||||
|
|
||||||
// we must now correct offets and sizes inside the ehdr, phdr,
|
// we must now correct offets and sizes inside the ehdr, phdr,
|
||||||
// and shdr
|
// and shdr
|
||||||
|
|
||||||
ptr += sizeof(Elf32_Ehdr);
|
ptr += sizeof(Elf32_Ehdr);
|
||||||
|
|
||||||
// phdr
|
// phdr
|
||||||
ehdr.e_phoff = ptr;
|
ehdr.e_phoff = ptr;
|
||||||
ptr += phdr_len * sizeof(Elf32_Phdr);
|
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
|
// sections
|
||||||
for (uint32_t i = 0; i < asm->parser->sec_tbl.count; i++) {
|
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_offset = ptr;
|
||||||
phdr[i].p_vaddr = ptr;
|
phdr[i].p_vaddr = ptr;
|
||||||
shdr[i+SHDR_SECTIONS].sh_offset = ptr;
|
phdr[i].p_paddr = ptr;
|
||||||
shdr[i+SHDR_SECTIONS].sh_size = phdr[i].p_filesz;
|
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;
|
ptr += phdr[i].p_filesz;
|
||||||
}
|
}
|
||||||
|
|
||||||
// symtbl
|
// symtbl
|
||||||
shdr[SHDR_SYMTBL].sh_offset = ptr;
|
shdr[asm->symtbl_idx].sh_offset = ptr;
|
||||||
shdr[SHDR_SYMTBL].sh_size = symtbl_len * sizeof(Elf32_Sym);
|
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);
|
ptr += symtbl_len * sizeof(Elf32_Sym);
|
||||||
|
|
||||||
// strtbl
|
// strtbl
|
||||||
shdr[SHDR_STRTBL].sh_offset = ptr;
|
shdr[asm->strtbl_idx].sh_offset = ptr;
|
||||||
shdr[SHDR_STRTBL].sh_size = asm->str_tbl.size;
|
shdr[asm->strtbl_idx].sh_size = asm->str_tbl.size;
|
||||||
ptr += asm->str_tbl.size;
|
ptr += asm->str_tbl.size;
|
||||||
|
|
||||||
|
// shstrtbl
|
||||||
|
shdr[asm->shstrtbl_idx].sh_offset = ptr;
|
||||||
|
shdr[asm->shstrtbl_idx].sh_size = asm->shstr_tbl.size;
|
||||||
|
ptr += asm->shstr_tbl.size;
|
||||||
|
|
||||||
// shdr
|
// shdr
|
||||||
ehdr.e_shoff = ptr;
|
ehdr.e_shoff = ptr;
|
||||||
|
|
||||||
|
@ -306,13 +608,28 @@ static int assemble_file(struct assembler *asm)
|
||||||
// phdr
|
// phdr
|
||||||
fwrite(phdr, sizeof(Elf32_Phdr), phdr_len, out);
|
fwrite(phdr, sizeof(Elf32_Phdr), phdr_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);
|
||||||
|
}
|
||||||
|
|
||||||
// sections
|
// sections
|
||||||
for (uint32_t i = 0; i < asm->parser->sec_tbl.count; i++) {
|
for (uint32_t i = 0; i < asm->parser.sec_tbl.count; i++) {
|
||||||
struct section *sec = &asm->parser->sec_tbl.sections[i];
|
struct section *sec = &asm->parser.sec_tbl.sections[i];
|
||||||
for (uint32_t j = 0; j < sec->count; j++) {
|
for (uint32_t j = 0; j < sec->count; j++) {
|
||||||
struct mips32_instruction *ins = &sec->ins[j].mips32;
|
struct section_entry *entry = &sec->entries[j];
|
||||||
fwrite(ins, sizeof(struct mips32_instruction),
|
size_t size = entry->size;
|
||||||
1, out);
|
fwrite(&entry->data, size, 1, out);
|
||||||
|
while(size % sec->alignment) {
|
||||||
|
uint8_t zero = 0;
|
||||||
|
fwrite(&zero, 1, 1, out);
|
||||||
|
size++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,11 +639,14 @@ static int assemble_file(struct assembler *asm)
|
||||||
// str tbl
|
// str tbl
|
||||||
fwrite(asm->str_tbl.ptr, asm->str_tbl.size, 1, out);
|
fwrite(asm->str_tbl.ptr, asm->str_tbl.size, 1, out);
|
||||||
|
|
||||||
|
// shstr tbl
|
||||||
|
fwrite(asm->shstr_tbl.ptr, asm->shstr_tbl.size, 1, out);
|
||||||
|
|
||||||
// shdr
|
// shdr
|
||||||
fwrite(shdr, sizeof(Elf32_Shdr), shdr_len, out);
|
fwrite(shdr, sizeof(Elf32_Shdr), shdr_len, out);
|
||||||
|
|
||||||
|
// cleanip
|
||||||
fclose(out);
|
fclose(out);
|
||||||
|
|
||||||
free(shdr);
|
free(shdr);
|
||||||
free(phdr);
|
free(phdr);
|
||||||
free(symtbl);
|
free(symtbl);
|
||||||
|
@ -336,30 +656,23 @@ static int assemble_file(struct assembler *asm)
|
||||||
|
|
||||||
int assemble_file_mips32(char *path)
|
int assemble_file_mips32(char *path)
|
||||||
{
|
{
|
||||||
struct lexer lexer;
|
struct assembler asm;
|
||||||
struct parser parser;
|
|
||||||
current_file = path;
|
|
||||||
int res = M_SUCCESS;
|
int res = M_SUCCESS;
|
||||||
|
|
||||||
if (lexer_init(current_file, &lexer))
|
current_file = path;
|
||||||
|
|
||||||
|
if (assembler_init(&asm, path))
|
||||||
return M_ERROR;
|
return M_ERROR;
|
||||||
|
|
||||||
if (mips32_parser_init(&lexer, &parser))
|
mips32_parser_init(&asm.parser);
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
if (res == M_SUCCESS)
|
if (res == M_SUCCESS)
|
||||||
res = parse_file(&parser);
|
res = parse_file(&asm);
|
||||||
|
|
||||||
struct assembler assembler;
|
|
||||||
assembler.parser = &parser;
|
|
||||||
strtbl_init(&assembler.str_tbl);
|
|
||||||
|
|
||||||
if (res == M_SUCCESS)
|
if (res == M_SUCCESS)
|
||||||
res = assemble_file(&assembler);
|
res = assemble_file(&asm);
|
||||||
|
|
||||||
strtbl_free(&assembler.str_tbl);
|
assembler_free(&asm);
|
||||||
lexer_free(&lexer);
|
|
||||||
parser_free(&parser);
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
16
masm/parse.c
16
masm/parse.c
|
@ -105,23 +105,27 @@ static int parse_label(struct parser *parser,
|
||||||
struct expr *expr)
|
struct expr *expr)
|
||||||
{
|
{
|
||||||
struct token token;
|
struct token token;
|
||||||
struct symbol symbol;
|
|
||||||
uint32_t index;
|
|
||||||
|
|
||||||
if (assert_token(parser, TOK_LABEL, &token))
|
if (assert_token(parser, TOK_LABEL, &token))
|
||||||
return M_ERROR;
|
return M_ERROR;
|
||||||
strcpy(expr->text, token.text);
|
strcpy(expr->text, token.text);
|
||||||
|
|
||||||
if (symtbl_find(&parser->sym_tbl, NULL, token.text) == M_SUCCESS) {
|
struct symbol *ref;
|
||||||
|
if (symtbl_find(&parser->sym_tbl, &ref, token.text) == M_SUCCESS) {
|
||||||
|
if (ref->flag == SYM_GLOBAL && ref->sec == NULL) {
|
||||||
|
ref->sec = parser->sec_tbl.current;
|
||||||
|
ref->index = parser->sec_tbl.current->count;
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
ERROR_POS(token, "redefined symbol '%s'", token.text);
|
ERROR_POS(token, "redefined symbol '%s'", token.text);
|
||||||
return M_ERROR;
|
return M_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
index = parser->sec_tbl.current->start +
|
struct symbol symbol;
|
||||||
parser->sec_tbl.current->count;
|
|
||||||
symbol = (struct symbol) {
|
symbol = (struct symbol) {
|
||||||
.name = "",
|
.name = "",
|
||||||
.position = index,
|
.sec = parser->sec_tbl.current,
|
||||||
|
.index = parser->sec_tbl.current->count,
|
||||||
.flag = SYM_LOCAL,
|
.flag = SYM_LOCAL,
|
||||||
};
|
};
|
||||||
strcpy(symbol.name, token.text);
|
strcpy(symbol.name, token.text);
|
||||||
|
|
38
masm/parse.h
38
masm/parse.h
|
@ -18,7 +18,6 @@ enum expr_type {
|
||||||
EXPR_INS,
|
EXPR_INS,
|
||||||
EXPR_DIRECTIVE,
|
EXPR_DIRECTIVE,
|
||||||
EXPR_CONSTANT,
|
EXPR_CONSTANT,
|
||||||
EXPR_SEGMENT,
|
|
||||||
EXPR_LABEL,
|
EXPR_LABEL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -44,7 +43,8 @@ enum symbol_flag {
|
||||||
|
|
||||||
struct symbol {
|
struct symbol {
|
||||||
char name[MAX_LEX_LENGTH];
|
char name[MAX_LEX_LENGTH];
|
||||||
uint32_t position;
|
uint32_t index;
|
||||||
|
struct section *sec;
|
||||||
enum symbol_flag flag;
|
enum symbol_flag flag;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -62,13 +62,37 @@ int symtbl_push(struct symbol_table *sym_tbl, struct symbol sym);
|
||||||
int symtbl_find(struct symbol_table *sym_tbl, struct symbol **sym,
|
int symtbl_find(struct symbol_table *sym_tbl, struct symbol **sym,
|
||||||
const char name[MAX_LEX_LENGTH]);
|
const char name[MAX_LEX_LENGTH]);
|
||||||
|
|
||||||
|
enum section_entry_type {
|
||||||
|
ENT_INS,
|
||||||
|
ENT_WORD,
|
||||||
|
ENT_HALF,
|
||||||
|
ENT_BYTE,
|
||||||
|
ENT_NO_DATA,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct section_entry {
|
||||||
|
enum section_entry_type type;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
union {
|
||||||
|
char data; // to get memory address
|
||||||
|
union mips_instruction ins;
|
||||||
|
int32_t word;
|
||||||
|
int16_t half;
|
||||||
|
int8_t byte;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
struct section {
|
struct section {
|
||||||
uint32_t count;
|
uint32_t count;
|
||||||
uint32_t len;
|
uint32_t len;
|
||||||
uint32_t start;
|
|
||||||
uint32_t alignment;
|
uint32_t alignment;
|
||||||
union mips_instruction *ins;
|
uint32_t index; // what index is my section
|
||||||
char name[MAX_LEX_LENGTH];
|
char name[MAX_LEX_LENGTH];
|
||||||
|
bool read;
|
||||||
|
bool write;
|
||||||
|
bool execute;
|
||||||
|
struct section_entry *entries;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct section_table {
|
struct section_table {
|
||||||
|
@ -77,7 +101,6 @@ struct section_table {
|
||||||
struct section *sections;
|
struct section *sections;
|
||||||
struct section *current;
|
struct section *current;
|
||||||
char name[MAX_LEX_LENGTH];
|
char name[MAX_LEX_LENGTH];
|
||||||
uint32_t total_ins;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int sectbl_init(struct section_table *sec_tbl);
|
int sectbl_init(struct section_table *sec_tbl);
|
||||||
|
@ -85,10 +108,11 @@ void sectbl_free(struct section_table *sec_tbl);
|
||||||
|
|
||||||
int sectbl_alloc(struct section_table *sec_tbl, struct section **sec,
|
int sectbl_alloc(struct section_table *sec_tbl, struct section **sec,
|
||||||
const char name[MAX_LEX_LENGTH]);
|
const char name[MAX_LEX_LENGTH]);
|
||||||
int sectbl_push(struct section_table *sec_tbl, struct section *section,
|
|
||||||
union mips_instruction ins);
|
|
||||||
int sectbl_get(struct section_table *sec_tbl, struct section **sec,
|
int sectbl_get(struct section_table *sec_tbl, struct section **sec,
|
||||||
const char name[MAX_LEX_LENGTH]);
|
const char name[MAX_LEX_LENGTH]);
|
||||||
|
int sec_push(struct section *section, struct section_entry entry);
|
||||||
|
size_t sec_size(struct section *section);
|
||||||
|
size_t sec_index(struct section *section, uint32_t index);
|
||||||
|
|
||||||
enum reference_type {
|
enum reference_type {
|
||||||
REF_OFFESET,
|
REF_OFFESET,
|
||||||
|
|
|
@ -768,6 +768,7 @@ static int parse_directive_whb(struct parser *parser,
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case MIPS32_DIRECTIVE_WORD:
|
case MIPS32_DIRECTIVE_WORD:
|
||||||
directive->words[len++] = token.number;
|
directive->words[len++] = token.number;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case MIPS32_DIRECTIVE_HALF:
|
case MIPS32_DIRECTIVE_HALF:
|
||||||
directive->halfs[len++] = token.number;
|
directive->halfs[len++] = token.number;
|
||||||
|
@ -789,26 +790,43 @@ static int parse_directive_whb(struct parser *parser,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
directive->len = len;
|
||||||
|
|
||||||
return M_SUCCESS;
|
return M_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_section(struct parser *parser,
|
static int parse_directive_extern(struct parser *parser,
|
||||||
struct mips32_directive *directive,
|
struct mips32_directive *directive)
|
||||||
|
{
|
||||||
|
struct token token;
|
||||||
|
if (assert_token(parser, TOK_IDENT, &token))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
directive->type = MIPS32_DIRECTIVE_EXTERN;
|
||||||
|
strcpy(directive->name, token.text);
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_directive_globl(struct parser *parser,
|
||||||
|
struct mips32_directive *directive)
|
||||||
|
{
|
||||||
|
struct token token;
|
||||||
|
if (assert_token(parser, TOK_IDENT, &token))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
directive->type = MIPS32_DIRECTIVE_GLOBL;
|
||||||
|
strcpy(directive->name, token.text);
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_section(struct mips32_directive *directive,
|
||||||
char name[MAX_LEX_LENGTH])
|
char name[MAX_LEX_LENGTH])
|
||||||
{
|
{
|
||||||
directive->type = MIPS32_DIRECTIVE_SECTION;
|
directive->type = MIPS32_DIRECTIVE_SECTION;
|
||||||
strcpy(directive->name, name);
|
strcpy(directive->name, name);
|
||||||
|
|
||||||
struct section *sec;
|
|
||||||
if (sectbl_get(&parser->sec_tbl, &sec, name) == M_SUCCESS) {
|
|
||||||
parser->sec_tbl.current = sec;
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sectbl_alloc(&parser->sec_tbl, &sec, name))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
parser->sec_tbl.current = sec;
|
|
||||||
return M_SUCCESS;
|
return M_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -833,18 +851,19 @@ static int parse_directive(struct parser *parser,
|
||||||
else if (strcmp(token.text, "byte") == 0)
|
else if (strcmp(token.text, "byte") == 0)
|
||||||
return parse_directive_whb(parser, &directive->mips32,
|
return parse_directive_whb(parser, &directive->mips32,
|
||||||
MIPS32_DIRECTIVE_BYTE);
|
MIPS32_DIRECTIVE_BYTE);
|
||||||
|
else if (strcmp(token.text, "extern") == 0)
|
||||||
|
return parse_directive_extern(parser, &directive->mips32);
|
||||||
|
else if (strcmp(token.text, "globl") == 0)
|
||||||
|
return parse_directive_globl(parser, &directive->mips32);
|
||||||
else
|
else
|
||||||
return parse_section(parser, &directive->mips32, token.text);
|
return parse_section(&directive->mips32, token.text);
|
||||||
}
|
}
|
||||||
|
|
||||||
int mips32_parser_init(struct lexer *lexer, struct parser *parser)
|
void mips32_parser_init(struct parser *parser)
|
||||||
{
|
{
|
||||||
if (parser_init(lexer, parser))
|
|
||||||
return M_ERROR;
|
|
||||||
parser->parse_instruction = parse_instruction;
|
parser->parse_instruction = parse_instruction;
|
||||||
parser->is_instruction = is_instruction;
|
parser->is_instruction = is_instruction;
|
||||||
parser->parse_directive = parse_directive;
|
parser->parse_directive = parse_directive;
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void mips32_parser_free(struct parser *parser)
|
void mips32_parser_free(struct parser *parser)
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
|
|
||||||
#include "parse.h"
|
#include "parse.h"
|
||||||
|
|
||||||
/* initzlize a mips32 parser*/
|
/* initzlize a mips32 parser vtable */
|
||||||
int mips32_parser_init(struct lexer *lexer, struct parser *parser);
|
void mips32_parser_init(struct parser *parser);
|
||||||
|
|
||||||
/* free the mips32 parser */
|
/* free the mips32 parser */
|
||||||
void mips32_parser_free(struct parser *parser);
|
void mips32_parser_free(struct parser *parser);
|
||||||
|
|
108
masm/sectbl.c
108
masm/sectbl.c
|
@ -13,7 +13,6 @@ int sectbl_init(struct section_table *sec_tbl)
|
||||||
{
|
{
|
||||||
sec_tbl->len = SECTBL_INIT_LEN;
|
sec_tbl->len = SECTBL_INIT_LEN;
|
||||||
sec_tbl->count = 0;
|
sec_tbl->count = 0;
|
||||||
sec_tbl->total_ins = 0;
|
|
||||||
sec_tbl->sections = malloc(sizeof(struct section) * SECTBL_INIT_LEN);
|
sec_tbl->sections = malloc(sizeof(struct section) * SECTBL_INIT_LEN);
|
||||||
|
|
||||||
if (sec_tbl->sections == NULL) {
|
if (sec_tbl->sections == NULL) {
|
||||||
|
@ -30,11 +29,26 @@ int sectbl_init(struct section_table *sec_tbl)
|
||||||
void sectbl_free(struct section_table *sec_tbl)
|
void sectbl_free(struct section_table *sec_tbl)
|
||||||
{
|
{
|
||||||
for (uint32_t i = 0; i < sec_tbl->count; i++) {
|
for (uint32_t i = 0; i < sec_tbl->count; i++) {
|
||||||
free(sec_tbl->sections[i].ins);
|
free(sec_tbl->sections[i].entries);
|
||||||
}
|
}
|
||||||
free(sec_tbl->sections);
|
free(sec_tbl->sections);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct section_settings {
|
||||||
|
const char *name;
|
||||||
|
bool read;
|
||||||
|
bool write;
|
||||||
|
bool execute;
|
||||||
|
uint32_t align;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct section_settings default_section_settings[] = {
|
||||||
|
{"data", true, true, false, 1},
|
||||||
|
{"bss", true, true, false, 1},
|
||||||
|
{"rodata", true, false, false, 1},
|
||||||
|
{"text", true, false, true, 4},
|
||||||
|
};
|
||||||
|
|
||||||
int sectbl_alloc(struct section_table *sec_tbl, struct section **sec,
|
int sectbl_alloc(struct section_table *sec_tbl, struct section **sec,
|
||||||
const char name[MAX_LEX_LENGTH])
|
const char name[MAX_LEX_LENGTH])
|
||||||
{
|
{
|
||||||
|
@ -50,43 +64,39 @@ int sectbl_alloc(struct section_table *sec_tbl, struct section **sec,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct section *temp;
|
struct section *temp;
|
||||||
temp = &sec_tbl->sections[sec_tbl->count++];
|
temp = &sec_tbl->sections[sec_tbl->count];
|
||||||
strcpy(temp->name,name);
|
strcpy(temp->name,name);
|
||||||
temp->count = 0;
|
temp->count = 0;
|
||||||
temp->len = SECTBL_INIT_LEN;
|
temp->len = SECTBL_INIT_LEN;
|
||||||
temp->start = sec_tbl->total_ins;
|
|
||||||
temp->alignment = 1;
|
temp->alignment = 1;
|
||||||
temp->ins = malloc(sizeof(union mips_instruction) * SECTBL_INIT_LEN);
|
temp->read = true;
|
||||||
|
temp->write = true;
|
||||||
|
temp->execute = false;
|
||||||
|
temp->index = sec_tbl->count;
|
||||||
|
temp->entries = malloc(sizeof(struct section_entry) * SECTBL_INIT_LEN);
|
||||||
|
|
||||||
if (temp->ins == NULL) {
|
for (int i = 0; i < 4; i++) {
|
||||||
|
struct section_settings *set = &default_section_settings[i];
|
||||||
|
if (strcmp(set->name, name) == 0) {
|
||||||
|
temp->read = set->read;
|
||||||
|
temp->write = set->write;
|
||||||
|
temp->execute = set->execute;
|
||||||
|
temp->alignment = set->align;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (temp->entries == NULL) {
|
||||||
ERROR("cannot alloc");
|
ERROR("cannot alloc");
|
||||||
return M_ERROR;
|
return M_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sec_tbl->count++;
|
||||||
|
|
||||||
*sec = temp;
|
*sec = temp;
|
||||||
return M_SUCCESS;
|
return M_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sectbl_push(struct section_table *sec_tbl, struct section *section,
|
|
||||||
union mips_instruction ins)
|
|
||||||
{
|
|
||||||
if (section->count >= section->len) {
|
|
||||||
section->len *= 2;
|
|
||||||
section->ins = realloc(section->ins,
|
|
||||||
sizeof(union mips_instruction) * section->len);
|
|
||||||
|
|
||||||
if (section->ins == NULL) {
|
|
||||||
ERROR("cannot realloc");
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
section->ins[section->count++] = ins;
|
|
||||||
sec_tbl->total_ins++;
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sectbl_get(struct section_table *sec_tbl, struct section **sec,
|
int sectbl_get(struct section_table *sec_tbl, struct section **sec,
|
||||||
const char name[MAX_LEX_LENGTH])
|
const char name[MAX_LEX_LENGTH])
|
||||||
{
|
{
|
||||||
|
@ -101,3 +111,49 @@ int sectbl_get(struct section_table *sec_tbl, struct section **sec,
|
||||||
|
|
||||||
return M_ERROR;
|
return M_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int sec_push(struct section *section, struct section_entry entry)
|
||||||
|
{
|
||||||
|
if (section->count >= section->len) {
|
||||||
|
section->len *= 2;
|
||||||
|
void *new = realloc(section->entries,
|
||||||
|
sizeof(struct section_entry) * section->len);
|
||||||
|
|
||||||
|
if (new == NULL) {
|
||||||
|
ERROR("cannot realloc");
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
section->entries = new;
|
||||||
|
}
|
||||||
|
|
||||||
|
section->entries[section->count++] = entry;
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t sec_size(struct section *sec)
|
||||||
|
{
|
||||||
|
size_t n = 0;
|
||||||
|
for (uint32_t i = 0; i < sec->count; i++) {
|
||||||
|
size_t t = sec->entries[i].size;
|
||||||
|
size_t m = t % sec->alignment;
|
||||||
|
if (m)
|
||||||
|
t += sec->alignment - m;
|
||||||
|
n += t;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t sec_index(struct section *sec, uint32_t idx)
|
||||||
|
{
|
||||||
|
size_t n = 0;
|
||||||
|
for (uint32_t i = 0; i < idx; i++) {
|
||||||
|
size_t t = sec->entries[i].size;
|
||||||
|
size_t m = t % sec->alignment;
|
||||||
|
if (m)
|
||||||
|
t += sec->alignment - m;
|
||||||
|
n += t;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
|
@ -36,11 +36,16 @@ int strtbl_write_str(struct str_table *str_tbl, const char *str, size_t *res)
|
||||||
return M_SUCCESS;
|
return M_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void strtbl_init(struct str_table *str_tbl)
|
int strtbl_init(struct str_table *str_tbl)
|
||||||
{
|
{
|
||||||
str_tbl->size = 1;
|
str_tbl->size = 1;
|
||||||
str_tbl->ptr = malloc(1);
|
str_tbl->ptr = malloc(1);
|
||||||
|
if (str_tbl->ptr == NULL) {
|
||||||
|
ERROR("cannot alloc");
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
*str_tbl->ptr = '\0';
|
*str_tbl->ptr = '\0';
|
||||||
|
return M_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void strtbl_free(struct str_table *str_tbl)
|
void strtbl_free(struct str_table *str_tbl)
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
.text
|
.text
|
||||||
.align 2
|
.align 2
|
||||||
|
|
||||||
|
.globl main
|
||||||
|
.extern test2
|
||||||
|
|
||||||
main:
|
main:
|
||||||
add $zero,$t7,$t7
|
add $zero,$t7,$t7
|
||||||
xori $a0, $v1, 69
|
xori $a0, $v1, 69
|
||||||
|
@ -19,4 +22,4 @@ test:
|
||||||
mfhi $s0
|
mfhi $s0
|
||||||
mtlo $s7
|
mtlo $s7
|
||||||
|
|
||||||
j test
|
j test2
|
||||||
|
|
Loading…
Reference in a new issue