Compare commits

..

No commits in common. "091c684bf1d2cca09da001b9170b205dbe5c333f" and "4af200b00188e02b2c6207dfe494a3dd12556c5f" have entirely different histories.

24 changed files with 134 additions and 350 deletions

View file

@ -304,8 +304,7 @@ MIPS_INS(JAL, .op = MIPS_OP_JAL)
/* JALR - jump and link register */ /* JALR - jump and link register */
#define MIPS_FUNCT_JALR 0b001001 #define MIPS_FUNCT_JALR 0b001001
MIPS_INS(JALR, .rd = MIPS_REG_RA, .op = MIPS_OP_SPECIAL, MIPS_INS(JALR, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_JALR)
.funct = MIPS_FUNCT_JALR)
/* JALX - jump and link exchange */ /* JALX - jump and link exchange */
#define MIPS_OP_JALX 0b011101 #define MIPS_OP_JALX 0b011101

View file

@ -23,7 +23,6 @@ _start:
# call main # call main
jal main jal main
nop
# exit # exit
move $a0, $v0 move $a0, $v0

View file

@ -889,17 +889,6 @@ static int parse_pseudo_move(struct parser *parser, struct ins_expr *expr)
return M_SUCCESS; return M_SUCCESS;
} }
static int parse_pseudo_nop(struct parser *parser, struct ins_expr *expr)
{
(void) parser;
expr->ins_len = 1;
expr->ins[0] = mips_instructions[MIPS_INS_SLL];
expr->ref[0].type = R_MIPS_NONE;
return M_SUCCESS;
}
static int parse_pseudo_instruction(struct parser *parser, static int parse_pseudo_instruction(struct parser *parser,
struct ins_expr *expr, struct ins_expr *expr,
struct token ident) struct token ident)
@ -922,10 +911,6 @@ static int parse_pseudo_instruction(struct parser *parser,
res = parse_pseudo_la(parser, expr); res = parse_pseudo_la(parser, expr);
else CHK(move) else CHK(move)
res = parse_pseudo_move(parser, expr); res = parse_pseudo_move(parser, expr);
else CHK(nop)
res = parse_pseudo_nop(parser, expr);
#undef CHK
if (res) { if (res) {
// reset on fail // reset on fail

View file

@ -12,6 +12,8 @@
#include "link.h" #include "link.h"
#include "mips.h" #include "mips.h"
#define SEC_ALIGN 0x1000
static int load_objects(struct linker *linker) static int load_objects(struct linker *linker)
{ {
int max_entries = linker->args->in_count + 1; int max_entries = linker->args->in_count + 1;
@ -166,7 +168,7 @@ static int relocate_symbol(struct linker *linker, struct object *obj,
struct symbol_table *symtab, const Elf32_Sym *sym) struct symbol_table *symtab, const Elf32_Sym *sym)
{ {
size_t shndx = B16(sym->st_shndx); size_t shndx = B16(sym->st_shndx);
if (shndx == 0 || shndx == SHN_ABS) if (shndx == 0)
return M_SUCCESS; // ignore this symbol return M_SUCCESS; // ignore this symbol
// find the given section // find the given section
@ -182,9 +184,11 @@ static int relocate_symbol(struct linker *linker, struct object *obj,
return M_ERROR; return M_ERROR;
} }
Elf32_Shdr const *shdr = &obj->shdr[shndx];
struct segment *sec = NULL; struct segment *sec = NULL;
for (size_t i = 0; i < obj->phdr_len; i++) { for (size_t i = 0; i < obj->phdr_len; i++) {
if (obj->phdr_to_shdr_mapping[i] == shndx) { Elf32_Phdr *temp = &obj->phdr[i];
if (PHDR_SHDR_MATCH(temp, shdr)) {
sec = &obj->segments[i]; sec = &obj->segments[i];
break; break;
} }
@ -215,20 +219,6 @@ static int relocate_symbol(struct linker *linker, struct object *obj,
new.st_shndx = B16(new_shndx); new.st_shndx = B16(new_shndx);
new.st_size = 0; new.st_size = 0;
// rename symbol if its name is empty to perm placeholder
//if (B32(sym->st_name) == 0) {
// #define __MAX 512
// char name[__MAX];
// memset(name, 0, __MAX);
// strcat(name, "__sym");
// snprintf(name + strlen(name), __MAX - strlen(name), "%d",
// B32(sym->st_value));
// if (strtab_push(linker->symtab.strtab, name, &str_off))
// return M_ERROR;
// new.st_name = B32(str_off);
// #undef __MAX
//}
if (symtab_get(&linker->symtab, NULL, name, obj->index) == M_SUCCESS) { if (symtab_get(&linker->symtab, NULL, name, obj->index) == M_SUCCESS) {
ERROR("cannot link doubly defiend symbol '%s'", name); ERROR("cannot link doubly defiend symbol '%s'", name);
return M_ERROR; return M_ERROR;
@ -457,38 +447,33 @@ static int relocate_instruction_rela(struct linker *linker,
// 16bit absolute // 16bit absolute
if (vaddr_abs > UINT16_MAX) if (vaddr_abs > UINT16_MAX)
warn = true; warn = true;
ins.immd += (uint16_t)vaddr_abs; ins.immd = (uint16_t)vaddr_abs;
break; break;
case R_MIPS_PC16: case R_MIPS_PC16:
// 16bit relative shifted // 16bit relative shifted
if (vaddr_rel > INT16_MAX || vaddr_rel < INT16_MIN) if (vaddr_rel > INT16_MAX || vaddr_rel < INT16_MIN)
warn = true; warn = true;
ins.offset += vaddr_rel; ins.offset = vaddr_rel;
break; break;
case R_MIPS_26: case R_MIPS_26:
case R_MIPS_JALR:
// 26bit absolute shifted // 26bit absolute shifted
if (vaddr_abs >= (1 << 25)) if (vaddr_abs >= (1 << 25))
warn = true; warn = true;
ins.target += (vaddr_abs & 0x0FFFFFFF) >> 2; ins.target = (vaddr_abs & 0x0FFFFFFF) >> 2;
break; break;
case R_MIPS_PC26_S2: case R_MIPS_PC26_S2:
// 26bit relative shifted // 26bit relative shifted
if (vaddr_rel >= (1 << 24) || -vaddr_rel > (1 << 24)) if (vaddr_rel >= (1 << 24) || -vaddr_rel > (1 << 24))
warn = true; warn = true;
ins.offs26 += vaddr_rel; ins.offs26 = vaddr_rel;
break; break;
case R_MIPS_LO16: case R_MIPS_LO16:
// lo 16bit absolute // lo 16bit absolute
ins.immd += (uint16_t)(vaddr_abs & 0xFFFF); ins.immd = (uint16_t)(vaddr_abs & 0xFFFF);
break; break;
case R_MIPS_HI16: case R_MIPS_HI16:
// hi 16bit absolute // hi 16bit absolute
ins.immd += (uint16_t)(vaddr_abs >> 16); ins.immd = (uint16_t)(vaddr_abs >> 16);
break;
case R_MIPS_32:
// 32bit absolute
ins.raw = vaddr_abs;
break; break;
default: default:
ERROR("do not know how do handle relocation type [%d]", typ); ERROR("do not know how do handle relocation type [%d]", typ);
@ -611,6 +596,9 @@ static void update_offsets(struct linker *linker)
static int write_file(struct linker *linker) static int write_file(struct linker *linker)
{ {
extern char *current_file;
current_file = linker->args->out_file;
int fd = open(linker->args->out_file, O_RDWR | O_CREAT, 0711); int fd = open(linker->args->out_file, O_RDWR | O_CREAT, 0711);
if (fd < 0) { if (fd < 0) {
PERROR("cannot write"); PERROR("cannot write");
@ -751,16 +739,12 @@ static void linker_free(struct linker *linker)
int link_files(struct linker_arguments args) { int link_files(struct linker_arguments args) {
struct linker linker; struct linker linker;
extern char *current_file;
int res = M_SUCCESS; int res = M_SUCCESS;
if (res == M_SUCCESS) if (res == M_SUCCESS)
res = linker_init(&linker, &args); res = linker_init(&linker, &args);
if (res == M_SUCCESS) if (res == M_SUCCESS)
res = load_objects(&linker); res = load_objects(&linker);
current_file = args.out_file;
if (res == M_SUCCESS) if (res == M_SUCCESS)
res = relocate_segments(&linker); res = relocate_segments(&linker);
if (res == M_SUCCESS) if (res == M_SUCCESS)

View file

@ -35,9 +35,6 @@
#define TEXT_VADDR_MIN 0x00400000 #define TEXT_VADDR_MIN 0x00400000
#define DATA_VADDR_MIN 0x10000000 #define DATA_VADDR_MIN 0x10000000
// alignment of a section
#define SEC_ALIGN 0x1000
// pre define // pre define
struct linker; struct linker;
struct object; struct object;
@ -45,7 +42,6 @@ struct segment;
struct string_table; struct string_table;
struct symbol_table; struct symbol_table;
struct symbol_table_mapping; struct symbol_table_mapping;
struct glboff_table;
/// ///
/// relocation table /// relocation table
@ -224,10 +220,6 @@ struct object {
// program table // program table
Elf32_Phdr *phdr; Elf32_Phdr *phdr;
size_t phdr_len; size_t phdr_len;
bool phdr_local; // if phdr was created though malloc
// phdr <=> shdr mappings
uint32_t *phdr_to_shdr_mapping;
// object meta // object meta
const char *name; const char *name;

105
mld/obj.c
View file

@ -49,10 +49,10 @@ static int load_ehdr(struct object *object)
EHDR_ASSERT(type, sizeof(Elf32_Half)); EHDR_ASSERT(type, sizeof(Elf32_Half));
EHDR_ASSERT(machine, sizeof(Elf32_Half)); EHDR_ASSERT(machine, sizeof(Elf32_Half));
EHDR_ASSERT(version, sizeof(Elf32_Word)); EHDR_ASSERT(version, sizeof(Elf32_Word));
// EHDR_ASSERT(flags, sizeof(Elf32_Word)); EHDR_ASSERT(flags, sizeof(Elf32_Word));
EHDR_ASSERT(ehsize, sizeof(Elf32_Half)); EHDR_ASSERT(ehsize, sizeof(Elf32_Half));
// EHDR_ASSERT(phentsize, sizeof(Elf32_Half)); EHDR_ASSERT(phentsize, sizeof(Elf32_Half));
// EHDR_ASSERT(shentsize, sizeof(Elf32_Half)); EHDR_ASSERT(shentsize, sizeof(Elf32_Half));
#undef EHDR_ASSERT #undef EHDR_ASSERT
@ -81,94 +81,23 @@ static int load_shdr(struct object *object)
return M_SUCCESS; return M_SUCCESS;
} }
/**
* Create the phdr
*/
static int create_phdr(struct object *object)
{
uint32_t entries = 0;
for (uint32_t i = 0; i < object->shdr_len; i++) {
Elf32_Shdr *hdr = &object->shdr[i];
uint32_t type = B32(hdr->sh_type);
if (type != SHT_PROGBITS && type != SHT_NOBITS)
continue;
entries += 1;
}
Elf32_Phdr *phdr = malloc(entries * sizeof(Elf32_Phdr));
if (phdr == NULL) {
PERROR("cannot alloc");
return M_ERROR;
}
object->phdr = phdr;
object->phdr_len = entries;
object->phdr_local = true;
uint32_t *mapping = malloc(entries * sizeof(uint32_t));
if (mapping == NULL) {
PERROR("cannot alloc");
return M_ERROR;
}
object->phdr_to_shdr_mapping = mapping;
uint32_t index = 0;
for (uint32_t i = 0; i < object->shdr_len; i++) {
Elf32_Shdr *hdr = &object->shdr[i];
uint32_t type = B32(hdr->sh_type);
if (type != SHT_PROGBITS && type != SHT_NOBITS)
continue;
mapping[index] = i;
phdr[index++] = (Elf32_Phdr) {
.p_type = B32(PT_LOAD),
.p_flags = B32(
// execute
((B32(hdr->sh_flags) & SHF_EXECINSTR)
? PF_X : 0) |
// write
((B32(hdr->sh_flags) & SHF_WRITE)
? PF_W : 0) |
// read
((B32(hdr->sh_flags) & SHF_ALLOC)
? PF_R : 0)
),
.p_offset = hdr->sh_offset,
.p_vaddr = hdr->sh_addr,
.p_paddr = hdr->sh_addr,
.p_filesz = hdr->sh_size,
.p_memsz = hdr->sh_size,
.p_align = B32(SEC_ALIGN),
};
}
return M_SUCCESS;
}
/** /**
* Map the phdr * Map the phdr
*/ */
static int load_phdr(struct object *object) static int load_phdr(struct object *object)
{ {
//size_t phdr_len = B16(object->ehdr->e_phentsize) * size_t phdr_len = B16(object->ehdr->e_phentsize) *
// B16(object->ehdr->e_phnum); B16(object->ehdr->e_phnum);
size_t phdr_off = B32(object->ehdr->e_phoff);
object->phdr = (Elf32_Phdr *) (object->mapped + phdr_off);
object->phdr_len = B16(object->ehdr->e_phnum);
//if (phdr_len < 1) if (BOUND_CHK(object, phdr_len, phdr_off)) {
return create_phdr(object); ERROR("cannot read phdr");
return M_ERROR;
}
//size_t phdr_off = B32(object->ehdr->e_phoff); return M_SUCCESS;
//object->phdr = (Elf32_Phdr *) (object->mapped + phdr_off);
//object->phdr_len = B16(object->ehdr->e_phnum);
//if (BOUND_CHK(object, phdr_len, phdr_off)) {
// ERROR("cannot read phdr");
// return M_ERROR;
//}
//return M_SUCCESS;
} }
/** /**
@ -302,7 +231,7 @@ static int load_shstrtab(struct object *object)
*/ */
static int load_segments(struct object *object) static int load_segments(struct object *object)
{ {
object->segment_len = object->phdr_len; object->segment_len = B16(object->ehdr->e_phnum);
object->segments = malloc(sizeof(struct segment) * object->segments = malloc(sizeof(struct segment) *
object->segment_len); object->segment_len);
@ -358,8 +287,6 @@ int object_load(struct object *object, char *path, uint32_t index)
object->mapped = NULL; object->mapped = NULL;
object->name = path; object->name = path;
object->index = index; object->index = index;
object->phdr_local = false;
object->phdr_to_shdr_mapping = NULL;
/** load the file */ /** load the file */
if (map_file(object, path)) if (map_file(object, path))
@ -404,10 +331,6 @@ void object_free(struct object *obj)
free(obj->strtabs); free(obj->strtabs);
if (obj->segments != NULL) if (obj->segments != NULL)
free(obj->segments); free(obj->segments);
if (obj->phdr_local)
free(obj->phdr);
if (obj->phdr_to_shdr_mapping)
free(obj->phdr_to_shdr_mapping);
if (obj->fd > 0) if (obj->fd > 0)
close(obj->fd); close(obj->fd);
if (obj->mapped != NULL && obj->mapped != MAP_FAILED) if (obj->mapped != NULL && obj->mapped != MAP_FAILED)

View file

@ -25,8 +25,14 @@ static int load_phdr(struct object *obj, struct segment *seg, size_t index)
*/ */
static int load_shdr(struct object *obj, struct segment *seg, size_t index) static int load_shdr(struct object *obj, struct segment *seg, size_t index)
{ {
uint32_t shndx = obj->phdr_to_shdr_mapping[index]; bool found = false;
Elf32_Shdr *hdr = &obj->shdr[shndx];
for (size_t i = 0; i < obj->shdr_len; i++) {
Elf32_Shdr *hdr = &obj->shdr[i];
// find shdr that matches the offset in phdr
if (!PHDR_SHDR_MATCH(seg->phdr, hdr))
continue;
// get name // get name
uint32_t name = B32(hdr->sh_name); uint32_t name = B32(hdr->sh_name);
@ -46,8 +52,16 @@ static int load_shdr(struct object *obj, struct segment *seg, size_t index)
return M_ERROR; return M_ERROR;
} }
found = true;
seg->shdr = hdr; seg->shdr = hdr;
seg->shdr_idx = shndx; seg->shdr_idx = i;
break;
}
if (!found) {
ERROR("cannot find shdr for segment [%d]", index);
return M_ERROR;
}
return M_SUCCESS; return M_SUCCESS;
} }

View file

@ -56,10 +56,6 @@ int symtab_get(struct symbol_table *symtab, Elf32_Sym **res, const char *name,
if (strcmp(name, symname) != 0) if (strcmp(name, symname) != 0)
continue; continue;
// ignore absolute symbols
if (B16(sym->st_shndx) == SHN_ABS)
continue;
// only allow retrevial of local variables from the // only allow retrevial of local variables from the
// same object // same object
if (sym->st_info >> 4 != STB_GLOBAL && symtab->map != NULL && if (sym->st_info >> 4 != STB_GLOBAL && symtab->map != NULL &&

View file

@ -1,74 +1,25 @@
#include <mips.h> #include <mips.h>
#include <melf.h> #include <melf.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include <merror.h>
#include "sim.h" #include "sim.h"
/* sign extension */ #define I16(n) ((int32_t)(uint16_t)(n))
#define SE(n) ((uint32_t)(int16_t)(n))
/* sign extension 64bit */
#define SE64(n) ((uint64_t)(int32_t)(n))
/* signed sign extension 64bit */
#define SSE64(n) ((int64_t)(int32_t)(n))
/* shifted sign extention */
#define SSE(n, s) (SE(n) << (s))
/* zero extension */
#define ZE(n) ((uint32_t)(uint16_t)(n))
/* get vaddr from offset and base */
#define VADDR(sim, ins) \
((sim->reg[ins.rs] /* base */) + \
(SE(ins.offset) /* offset */))
/* gets the low 32 bits of a 64 bit value */
#define LO(n) (((1ULL << 32) - 1) & (n))
/* gets the hi 32 bits of a 64 bit value */
#define HI(n) ((n) >> 32)
/* convert to a pointer */
#define PTR(ptr, type) ((type *)(uintptr_t)(ptr))
static void sim_delay_slot(struct simulator *sim)
{
if (sim->args->jdelay == false)
return;
uint32_t ins = * (uint32_t *) (uintptr_t) sim->pc;
union mips_instruction_data data = { .raw = B32(ins) };
sim->pc += 4;
switch (data.op) {
case MIPS_OP_REGIMM:
case MIPS_OP_J:
case MIPS_OP_JAL:
case MIPS_OP_JALX:
case MIPS_OP_BEQ:
case MIPS_OP_BEQL:
case MIPS_OP_BNE:
case MIPS_OP_BNEL:
case MIPS_OP_BGTZ:
case MIPS_OP_BGTZL:
case MIPS_OP_BLEZ:
case MIPS_OP_BLEZL:
sim_dump(sim, "attempted to execute jump instruction in delay"
"slot (0b%05b)", data.op);
default:
}
sim_ins(sim, ins);
}
static void sim_ins_special_sop30(struct simulator *sim, static void sim_ins_special_sop30(struct simulator *sim,
union mips_instruction_data ins) union mips_instruction_data ins)
{ {
switch (ins.shamt) { switch (ins.shamt) {
case MIPS_SOP30_MUL: case MIPS_SOP30_MUL:
sim->reg[ins.rd] = (SSE64(sim->reg[ins.rs]) * sim->reg[ins.rd] = ((int64_t)sim->reg[ins.rs] /
SSE64(sim->reg[ins.rt])) >> 0; (int64_t)sim->reg[ins.rt]) >> 0;
break; break;
case MIPS_SOP30_MUH: case MIPS_SOP30_MUH:
sim->reg[ins.rd] = (SSE64(sim->reg[ins.rs]) * sim->reg[ins.rd] = ((int64_t)sim->reg[ins.rs] /
SSE64(sim->reg[ins.rt])) >> 32; (int64_t)sim->reg[ins.rt]) >> 32;
break; break;
default: default:
@ -81,13 +32,13 @@ static void sim_ins_special_sop31(struct simulator *sim,
{ {
switch (ins.shamt) { switch (ins.shamt) {
case MIPS_SOP31_MULU: case MIPS_SOP31_MULU:
sim->reg[ins.rd] = (SE64(sim->reg[ins.rs]) * sim->reg[ins.rd] = ((uint64_t)sim->reg[ins.rs] /
SE64(sim->reg[ins.rt])) >> 0; (uint64_t)sim->reg[ins.rt]) >> 0;
break; break;
case MIPS_SOP31_MUHU: case MIPS_SOP31_MUHU:
sim->reg[ins.rd] = (SE64(sim->reg[ins.rs]) * sim->reg[ins.rd] = ((uint64_t)sim->reg[ins.rs] /
SE64(sim->reg[ins.rt])) >> 32; (uint64_t)sim->reg[ins.rt]) >> 32;
break; break;
default: default:
@ -100,13 +51,13 @@ static void sim_ins_special_sop32(struct simulator *sim,
{ {
switch (ins.shamt) { switch (ins.shamt) {
case MIPS_SOP32_DIV: case MIPS_SOP32_DIV:
sim->reg[ins.rd] = (signed) sim->reg[ins.rs] / sim->reg[ins.rd] = (int32_t)sim->reg[ins.rs] /
(signed) sim->reg[ins.rt]; (int32_t)sim->reg[ins.rt];
break; break;
case MIPS_SOP32_MOD: case MIPS_SOP32_MOD:
sim->reg[ins.rd] = (signed) sim->reg[ins.rs] % sim->reg[ins.rd] = (int32_t)sim->reg[ins.rs] %
(signed) sim->reg[ins.rt]; (int32_t)sim->reg[ins.rt];
break; break;
default: default:
@ -136,8 +87,8 @@ static void sim_ins_special(struct simulator *sim,
{ {
switch (ins.funct) { switch (ins.funct) {
case MIPS_FUNCT_ADD: case MIPS_FUNCT_ADD:
// TODO: trap on overflow sim->reg[ins.rd] = (int32_t)sim->reg[ins.rs] +
sim->reg[ins.rd] = sim->reg[ins.rs] + sim->reg[ins.rt]; (int32_t)sim->reg[ins.rt];
break; break;
case MIPS_FUNCT_ADDU: case MIPS_FUNCT_ADDU:
@ -165,10 +116,9 @@ static void sim_ins_special(struct simulator *sim,
break; break;
case MIPS_FUNCT_JALR: case MIPS_FUNCT_JALR:
sim->reg[ins.rd] = sim->pc + 4; sim->reg[MIPS_REG_RA] = sim->pc;
/* fall through */ /* fall through */
case MIPS_FUNCT_JR: case MIPS_FUNCT_JR:
sim_delay_slot(sim);
sim->pc = sim->reg[ins.rs]; sim->pc = sim->reg[ins.rs];
break; break;
@ -197,8 +147,7 @@ static void sim_ins_special(struct simulator *sim,
break; break;
case MIPS_FUNCT_SLT: case MIPS_FUNCT_SLT:
sim->reg[ins.rd] = (signed) sim->reg[ins.rs] < sim->reg[ins.rd] = (int32_t)sim->reg[ins.rs] < (int32_t)sim->reg[ins.rt] ? 1 : 0;
(signed) sim->reg[ins.rt] ? 1 : 0;
break; break;
case MIPS_FUNCT_SLTU: case MIPS_FUNCT_SLTU:
@ -206,12 +155,11 @@ static void sim_ins_special(struct simulator *sim,
break; break;
case MIPS_FUNCT_SRA: case MIPS_FUNCT_SRA:
sim->reg[ins.rd] = (signed) sim->reg[ins.rt] >> ins.shamt; sim->reg[ins.rd] = (int32_t)sim->reg[ins.rt] >> ins.shamt;
break; break;
case MIPS_FUNCT_SRAV: case MIPS_FUNCT_SRAV:
sim->reg[ins.rd] = (signed) sim->reg[ins.rt] >> sim->reg[ins.rd] = (int32_t)sim->reg[ins.rt] >> sim->reg[ins.rs];
sim->reg[ins.rs];
break; break;
case MIPS_FUNCT_SRL: case MIPS_FUNCT_SRL:
@ -223,8 +171,8 @@ static void sim_ins_special(struct simulator *sim,
break; break;
case MIPS_FUNCT_SUB: case MIPS_FUNCT_SUB:
// TODO: trap on overflow sim->reg[ins.rd] = (int32_t)sim->reg[ins.rs] -
sim->reg[ins.rd] = sim->reg[ins.rs] - sim->reg[ins.rt]; (int32_t)sim->reg[ins.rt];
break; break;
case MIPS_FUNCT_SUBU: case MIPS_FUNCT_SUBU:
@ -261,33 +209,29 @@ static void sim_ins_special(struct simulator *sim,
static void sim_ins_regimm(struct simulator *sim, static void sim_ins_regimm(struct simulator *sim,
union mips_instruction_data ins) union mips_instruction_data ins)
{ {
uint32_t pc = sim->pc;
switch (ins.bfunct) { switch (ins.bfunct) {
case MIPS_FUNCT_BGEZAL: case MIPS_FUNCT_BGEZAL:
case MIPS_FUNCT_BGEZALL: case MIPS_FUNCT_BGEZALL:
sim->reg[MIPS_REG_RA] = sim->pc + 4; sim->reg[MIPS_REG_RA] = sim->pc;
/* fall through */ /* fall through */
case MIPS_FUNCT_BGEZ: case MIPS_FUNCT_BGEZ:
case MIPS_FUNCT_BGEZL: case MIPS_FUNCT_BGEZL:
sim_delay_slot(sim); if ((int32_t)sim->reg[ins.rs] >= 0)
if ((signed) sim->reg[ins.rs] >= 0) sim->pc += ins.offset << 2;
sim->pc = pc + SSE(ins.offset, 2);
break; break;
case MIPS_FUNCT_BLTZAL: case MIPS_FUNCT_BLTZAL:
case MIPS_FUNCT_BLTZALL: case MIPS_FUNCT_BLTZALL:
sim->reg[MIPS_REG_RA] = sim->pc + 4; sim->reg[MIPS_REG_RA] = sim->pc;
/* fall through */ /* fall through */
case MIPS_FUNCT_BLTZ: case MIPS_FUNCT_BLTZ:
case MIPS_FUNCT_BLTZL: case MIPS_FUNCT_BLTZL:
sim_delay_slot(sim); if ((int32_t)sim->reg[ins.rs] < 0)
if ((signed) sim->reg[ins.rs] < 0) sim->pc += ins.offset << 2;
sim->pc = pc + SSE(ins.offset, 2);
break; break;
default: default:
sim_dump(sim, "unknown branch funct (0b%06b)", ins.bfunct); sim_dump(sim, "unknown bfunct (0b%06b)", ins.bfunct);
} }
} }
@ -297,7 +241,6 @@ void sim_ins(struct simulator *sim, uint32_t raw)
union mips_instruction_data ins = { union mips_instruction_data ins = {
.raw = B32(raw) .raw = B32(raw)
}; };
uint32_t pc = sim->pc;
// reset zero reg // reset zero reg
sim->reg[MIPS_REG_ZERO] = 0; sim->reg[MIPS_REG_ZERO] = 0;
@ -313,75 +256,73 @@ void sim_ins(struct simulator *sim, uint32_t raw)
case MIPS_OP_ADDI: case MIPS_OP_ADDI:
sim->reg[ins.rt] = (int32_t)sim->reg[ins.rs] + sim->reg[ins.rt] = (int32_t)sim->reg[ins.rs] +
SE(ins.immd); (int16_t) ins.immd;
break; break;
case MIPS_OP_ADDIU: case MIPS_OP_ADDIU:
sim->reg[ins.rt] = sim->reg[ins.rs] + SE(ins.immd); sim->reg[ins.rt] = sim->reg[ins.rs] + ins.immd;
break; break;
case MIPS_OP_ANDI: case MIPS_OP_ANDI:
sim->reg[ins.rt] = sim->reg[ins.rs] & ZE(ins.immd); sim->reg[ins.rt] = sim->reg[ins.rs] & ins.immd;
break; break;
case MIPS_OP_BALC: case MIPS_OP_BALC:
sim->reg[MIPS_REG_RA] = sim->pc; sim->reg[MIPS_REG_RA] = sim->pc;
/* fall through */ /* fall through */
case MIPS_OP_BC: case MIPS_OP_BC:
sim->pc += SSE(ins.offs26, 2); sim->pc += ins.offs26 << 2;
break; break;
case MIPS_OP_BEQ: case MIPS_OP_BEQ:
case MIPS_OP_BEQL: case MIPS_OP_BEQL:
sim_delay_slot(sim);
if (sim->reg[ins.rs] == sim->reg[ins.rt]) if (sim->reg[ins.rs] == sim->reg[ins.rt])
sim->pc = pc + SSE(ins.offset, 2); sim->pc += ins.offset << 2;
break; break;
case MIPS_OP_BGTZ: case MIPS_OP_BGTZ:
case MIPS_OP_BGTZL: case MIPS_OP_BGTZL:
sim_delay_slot(sim); if ((int32_t)sim->reg[ins.rs] <= 0)
if ((signed) sim->reg[ins.rs] <= 0) sim->pc += ins.offset << 2;
sim->pc = pc + SSE(ins.offset, 2);
break; break;
case MIPS_OP_BLEZ: case MIPS_OP_BLEZ:
case MIPS_OP_BLEZL: case MIPS_OP_BLEZL:
sim_delay_slot(sim); if ((int32_t)sim->reg[ins.rs] <= 0)
if ((signed) sim->reg[ins.rs] <= 0) sim->pc += ins.offset << 2;
sim->pc = pc + SSE(ins.offset, 2);
break; break;
case MIPS_OP_BNE: case MIPS_OP_BNE:
case MIPS_OP_BNEL: case MIPS_OP_BNEL:
sim_delay_slot(sim);
if (sim->reg[ins.rs] != sim->reg[ins.rt]) if (sim->reg[ins.rs] != sim->reg[ins.rt])
sim->pc = pc + SSE(ins.offset, 2); sim->pc += ins.offset << 2;
break; break;
case MIPS_OP_JAL: case MIPS_OP_JAL:
sim->reg[MIPS_REG_RA] = sim->pc + 4; sim->reg[MIPS_REG_RA] = sim->pc;
/* fall through */ /* fall through */
case MIPS_OP_J: case MIPS_OP_J:
sim_delay_slot(sim); sim->pc = ins.target << 2;
sim->pc &= 0xF0000000;
sim->pc |= ins.target << 2;
break; break;
case MIPS_OP_LB: case MIPS_OP_LB:
sim->reg[ins.rt] = *PTR(VADDR(sim, ins), int8_t); sim->reg[ins.rt] = * (int8_t *) (uintptr_t) (sim->reg[ins.rs]
+ ins.offset);
break; break;
case MIPS_OP_LBU: case MIPS_OP_LBU:
sim->reg[ins.rt] = *PTR(VADDR(sim, ins), uint8_t); sim->reg[ins.rt] = * (uint8_t *) (uintptr_t) (sim->reg[ins.rs]
+ ins.offset);
break; break;
case MIPS_OP_LH: case MIPS_OP_LH:
sim->reg[ins.rt] = *PTR(VADDR(sim, ins), int16_t); sim->reg[ins.rt] = * (int16_t *) (uintptr_t) (sim->reg[ins.rs]
+ ins.offset);
break; break;
case MIPS_OP_LHU: case MIPS_OP_LHU:
sim->reg[ins.rt] = *PTR(VADDR(sim, ins), uint16_t); sim->reg[ins.rt] = * (uint16_t *) (uintptr_t) (sim->reg[ins.rs]
+ ins.offset);
break; break;
case MIPS_OP_LUI: case MIPS_OP_LUI:
@ -389,28 +330,32 @@ void sim_ins(struct simulator *sim, uint32_t raw)
break; break;
case MIPS_OP_LW: case MIPS_OP_LW:
sim->reg[ins.rt] = *PTR(VADDR(sim, ins), uint32_t); sim->reg[ins.rt] = * (uint32_t *) (uintptr_t) (sim->reg[ins.rs]
+ ins.offset);
break; break;
case MIPS_OP_SB: case MIPS_OP_SB:
*PTR(VADDR(sim, ins), uint8_t) = sim->reg[ins.rt]; * (uint8_t *) (uintptr_t) (sim->reg[ins.rs] +
+ ins.offset) = sim->reg[ins.rt];
break; break;
case MIPS_OP_SH: case MIPS_OP_SH:
*PTR(VADDR(sim, ins), uint16_t) = sim->reg[ins.rt]; * (uint16_t *) (uintptr_t) (sim->reg[ins.rs] +
ins.offset) = sim->reg[ins.rt];
break; break;
case MIPS_OP_SW: case MIPS_OP_SW:
*PTR(VADDR(sim, ins), uint32_t) = sim->reg[ins.rt]; * (uint32_t *) (uintptr_t) (sim->reg[ins.rs] +
ins.offset) = sim->reg[ins.rt];
break; break;
case MIPS_OP_SLTI: case MIPS_OP_SLTI:
sim->reg[ins.rt] = (signed) sim->reg[ins.rs] < sim->reg[ins.rt] = (int32_t)sim->reg[ins.rs] <
(signed) SE(ins.immd) ? 1 : 0; (int16_t)ins.immd ? 1 : 0;
break; break;
case MIPS_OP_SLTIU: case MIPS_OP_SLTIU:
sim->reg[ins.rt] = sim->reg[ins.rs] < SE(ins.immd) ? 1 : 0; sim->reg[ins.rt] = sim->reg[ins.rs] < ins.immd ? 1 : 0;
break; break;
case MIPS_OP_ORI: case MIPS_OP_ORI:

View file

@ -52,15 +52,12 @@ static int load_ehdr(struct simulator *sim, struct load_state *state)
res |= assert_ehdr(&baseline.e_##name, \ res |= assert_ehdr(&baseline.e_##name, \
&ehdr.e_##name, size) \ &ehdr.e_##name, size) \
// ignore abi ver
ehdr.e_ident[EI_ABIVERSION] = 0x00;
int res = 0; int res = 0;
EHDR_ASSERT(ident, EI_NIDENT); EHDR_ASSERT(ident, EI_NIDENT);
EHDR_ASSERT(type, sizeof(Elf32_Half)); EHDR_ASSERT(type, sizeof(Elf32_Half));
EHDR_ASSERT(machine, sizeof(Elf32_Half)); EHDR_ASSERT(machine, sizeof(Elf32_Half));
EHDR_ASSERT(version, sizeof(Elf32_Word)); EHDR_ASSERT(version, sizeof(Elf32_Word));
// EHDR_ASSERT(flags, sizeof(Elf32_Word)); EHDR_ASSERT(flags, sizeof(Elf32_Word));
EHDR_ASSERT(ehsize, sizeof(Elf32_Half)); EHDR_ASSERT(ehsize, sizeof(Elf32_Half));
EHDR_ASSERT(phentsize, sizeof(Elf32_Half)); EHDR_ASSERT(phentsize, sizeof(Elf32_Half));
EHDR_ASSERT(shentsize, sizeof(Elf32_Half)); EHDR_ASSERT(shentsize, sizeof(Elf32_Half));

View file

@ -2,6 +2,7 @@
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include <merror.h> #include <merror.h>
#include <signal.h>
#include "fault.h" #include "fault.h"
#include "sim.h" #include "sim.h"
@ -10,7 +11,7 @@ static void help(void) {
printf("usage: msim [options] executable\n\n"); printf("usage: msim [options] executable\n\n");
printf("options:\n"); printf("options:\n");
printf("\t-h\t\tprints this help messaage\n"); printf("\t-h\t\tprints this help messaage\n");
printf("\t-j\t\tdisable jump delay slot\n"); printf("\t-c\t\tdisable runtime memory checks (allows segfault)\n");
printf("\t-d\t\truns the debugger\n"); printf("\t-d\t\truns the debugger\n");
} }
@ -20,18 +21,18 @@ int main(int argc, char **argv) {
struct simulator_args args = { struct simulator_args args = {
.executable = NULL, .executable = NULL,
.debug = false, .debug = false,
.jdelay = true, .memchk = true,
}; };
int c; int c;
while ((c = getopt(argc, argv, "hjd")) != 1) { while ((c = getopt(argc, argv, "hcd")) != 1) {
switch (c) { switch (c) {
case 'h': case 'h':
help(); help();
return M_SUCCESS; return M_SUCCESS;
case 'j': case 'c':
args.jdelay = false; args.memchk = false;
break; break;
case 'd': case 'd':
args.debug = true; args.debug = true;

View file

@ -9,7 +9,7 @@
/// arguments /// arguments
struct simulator_args { struct simulator_args {
char *executable; char *executable;
bool jdelay; bool memchk;
bool debug; bool debug;
}; };

View file

@ -15,4 +15,3 @@ main:
# return # return
li $v0, 0 li $v0, 0
jr $ra jr $ra
nop

View file

@ -13,4 +13,3 @@ main:
# return # return
li $v0, 0 li $v0, 0
jr $ra jr $ra
nop

View file

@ -11,7 +11,6 @@ result:
move $t0, $a0 move $t0, $a0
move $v0, $t0 move $v0, $t0
jr $ra jr $ra
nop
main: main:
# save ra on stack # save ra on stack
@ -21,7 +20,6 @@ main:
# set return to 17 # set return to 17
li $a0, 17 li $a0, 17
jal result jal result
nop
# pop ra from stack # pop ra from stack
lw $ra, 0($sp) lw $ra, 0($sp)
@ -29,4 +27,3 @@ main:
# return result # return result
jr $ra jr $ra
nop

View file

@ -24,4 +24,3 @@ main:
# return 1 # return 1
li $v0, 0 li $v0, 0
jr $ra jr $ra
nop

View file

@ -1,41 +0,0 @@
# Copyright (c) 2024 Freya Murphy
# file: recursion.asm
# test: should recurse sum n..0 numbers
.text
.align 2
.globl main
main:
# init $a0
li $a0, 5
sum:
# save stack
addiu $sp, $sp, -8
sw $ra, 0($sp)
sw $s0, 4($sp)
# load n from a0
move $s0, $a0
# skip if n is zero
li $v0, 0
beq $s0, $zero, add
nop
jal sum
addi $a0, $s0, -1
add:
# n = n + returned
add $v0, $s0, $v0
# restore stack
lw $ra, 0($sp)
lw $s0, 4($sp)
addiu $sp, $sp, 8
# return
jr $ra
nop

View file

@ -12,4 +12,4 @@ $v1: 0x00000000 $t3: 0x00000000 $s3: 0x00000000 $k1: 0x00000000
$a0: 0x00000000 $t4: 0x00000000 $s4: 0x00000000 $gp: 0x00000000 $a0: 0x00000000 $t4: 0x00000000 $s4: 0x00000000 $gp: 0x00000000
$a1: 0x00000000 $t5: 0x00000000 $s5: 0x00000000 $sp: 0x10001000 $a1: 0x00000000 $t5: 0x00000000 $s5: 0x00000000 $sp: 0x10001000
$a2: 0x00000000 $t6: 0x00000000 $s6: 0x00000000 $fp: 0x00000000 $a2: 0x00000000 $t6: 0x00000000 $s6: 0x00000000 $fp: 0x00000000
$a3: 0x00000000 $t7: 0x00000000 $s7: 0x00000000 $ra: 0x00400024 $a3: 0x00000000 $t7: 0x00000000 $s7: 0x00000000 $ra: 0x0040001c

View file

@ -12,4 +12,4 @@ $v1: 0x00000000 $t3: 0x00000000 $s3: 0x00000000 $k1: 0x00000000
$a0: 0x00000000 $t4: 0x00000000 $s4: 0x00000000 $gp: 0x00000000 $a0: 0x00000000 $t4: 0x00000000 $s4: 0x00000000 $gp: 0x00000000
$a1: 0x00000000 $t5: 0x00000000 $s5: 0x00000000 $sp: 0x10001000 $a1: 0x00000000 $t5: 0x00000000 $s5: 0x00000000 $sp: 0x10001000
$a2: 0x00000000 $t6: 0x00000000 $s6: 0x00000000 $fp: 0x00000000 $a2: 0x00000000 $t6: 0x00000000 $s6: 0x00000000 $fp: 0x00000000
$a3: 0x00000000 $t7: 0x00000000 $s7: 0x00000000 $ra: 0x00400020 $a3: 0x00000000 $t7: 0x00000000 $s7: 0x00000000 $ra: 0x00400018

View file

View file

@ -1 +0,0 @@
15

View file

@ -35,10 +35,7 @@ if [ $res = 0 ]; then
printf "\033[32mPASSED\033[0m\n" printf "\033[32mPASSED\033[0m\n"
else else
printf "\033[31mFAILED\033[0m\n" printf "\033[31mFAILED\033[0m\n"
if [ "$status" != "$rstatus" ]; then diff <(echo $out) <(echo $rout)
printf "exit: $rstatus (should be $status)\n"
fi
diff -Nau <(printf "%s\n" "$out") <(printf "%s\n" "$rout")
fi fi
exit $res exit $res