Compare commits
No commits in common. "4af200b00188e02b2c6207dfe494a3dd12556c5f" and "b6526332c680d8208c81d300bcfbcad10bc0f33b" have entirely different histories.
4af200b001
...
b6526332c6
32 changed files with 323 additions and 1233 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,4 +1,2 @@
|
||||||
/bin
|
/bin
|
||||||
/fuzz
|
/fuzz
|
||||||
/test/mld
|
|
||||||
/test/msim
|
|
||||||
|
|
|
@ -84,6 +84,8 @@ enum mips_instruction_type {
|
||||||
MIPS_INS_LHU,
|
MIPS_INS_LHU,
|
||||||
MIPS_INS_LUI,
|
MIPS_INS_LUI,
|
||||||
MIPS_INS_LW,
|
MIPS_INS_LW,
|
||||||
|
MIPS_INS_LWL,
|
||||||
|
MIPS_INS_LWR,
|
||||||
MIPS_INS_MFHI,
|
MIPS_INS_MFHI,
|
||||||
MIPS_INS_MFLO,
|
MIPS_INS_MFLO,
|
||||||
MIPS_INS_MTHI,
|
MIPS_INS_MTHI,
|
||||||
|
@ -92,9 +94,12 @@ enum mips_instruction_type {
|
||||||
MIPS_INS_MUH,
|
MIPS_INS_MUH,
|
||||||
MIPS_INS_MULU,
|
MIPS_INS_MULU,
|
||||||
MIPS_INS_MUHU,
|
MIPS_INS_MUHU,
|
||||||
|
MIPS_INS_MULT,
|
||||||
MIPS_INS_SB,
|
MIPS_INS_SB,
|
||||||
MIPS_INS_SH,
|
MIPS_INS_SH,
|
||||||
MIPS_INS_SW,
|
MIPS_INS_SW,
|
||||||
|
MIPS_INS_SWL,
|
||||||
|
MIPS_INS_SWR,
|
||||||
MIPS_INS_SLL,
|
MIPS_INS_SLL,
|
||||||
MIPS_INS_SLLV,
|
MIPS_INS_SLLV,
|
||||||
MIPS_INS_SLT,
|
MIPS_INS_SLT,
|
||||||
|
@ -198,7 +203,7 @@ MIPS_INS(ANDI, .op = MIPS_OP_ANDI)
|
||||||
/* BAL - branch and link */
|
/* BAL - branch and link */
|
||||||
#define MIPS_OP_REGIMM 0b000001
|
#define MIPS_OP_REGIMM 0b000001
|
||||||
#define MIPS_FUNCT_BAL 0b10001
|
#define MIPS_FUNCT_BAL 0b10001
|
||||||
MIPS_INS(BAL, .op = MIPS_OP_REGIMM, .bfunct = MIPS_FUNCT_BAL)
|
MIPS_INS(BAL, .op = MIPS_OP_REGIMM, .funct = MIPS_FUNCT_BAL)
|
||||||
|
|
||||||
/* BALC - branch and link, compact */
|
/* BALC - branch and link, compact */
|
||||||
#define MIPS_OP_BALC 0b111010
|
#define MIPS_OP_BALC 0b111010
|
||||||
|
@ -338,6 +343,14 @@ MIPS_INS(LUI, .op = MIPS_OP_LUI)
|
||||||
#define MIPS_OP_LW 0b100011
|
#define MIPS_OP_LW 0b100011
|
||||||
MIPS_INS(LW, .op = MIPS_OP_LW)
|
MIPS_INS(LW, .op = MIPS_OP_LW)
|
||||||
|
|
||||||
|
/* LWL - load word left */
|
||||||
|
#define MIPS_OP_LWL 0b100010
|
||||||
|
MIPS_INS(LWL, .op = MIPS_OP_LWL)
|
||||||
|
|
||||||
|
/* LWR - load word right */
|
||||||
|
#define MIPS_OP_LWR 0b100110
|
||||||
|
MIPS_INS(LWR, .op = MIPS_OP_LWR)
|
||||||
|
|
||||||
/* MFHI - move from hi */
|
/* MFHI - move from hi */
|
||||||
#define MIPS_FUNCT_MFHI 0b010000
|
#define MIPS_FUNCT_MFHI 0b010000
|
||||||
MIPS_INS(MFHI, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_MFHI)
|
MIPS_INS(MFHI, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_MFHI)
|
||||||
|
@ -376,6 +389,10 @@ MIPS_INS(MULU, .op = MIPS_OP_SPECIAL, .shamt = MIPS_SOP31_MULU,
|
||||||
MIPS_INS(MUHU, .op = MIPS_OP_SPECIAL, .shamt = MIPS_SOP31_MUHU,
|
MIPS_INS(MUHU, .op = MIPS_OP_SPECIAL, .shamt = MIPS_SOP31_MUHU,
|
||||||
.funct = MIPS_FUNCT_SOP31)
|
.funct = MIPS_FUNCT_SOP31)
|
||||||
|
|
||||||
|
/* MULT - multiply (OLD) */
|
||||||
|
#define MIPS_FUNCT_MULT 0b011000
|
||||||
|
MIPS_INS(MULT, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_MULT)
|
||||||
|
|
||||||
/* SB - store byte */
|
/* SB - store byte */
|
||||||
#define MIPS_OP_SB 0b101000
|
#define MIPS_OP_SB 0b101000
|
||||||
MIPS_INS(SB, .op = MIPS_OP_SB)
|
MIPS_INS(SB, .op = MIPS_OP_SB)
|
||||||
|
@ -388,6 +405,14 @@ MIPS_INS(SH, .op = MIPS_OP_SH)
|
||||||
#define MIPS_OP_SW 0b101011
|
#define MIPS_OP_SW 0b101011
|
||||||
MIPS_INS(SW, .op = MIPS_OP_SW)
|
MIPS_INS(SW, .op = MIPS_OP_SW)
|
||||||
|
|
||||||
|
/* SWL - store word left */
|
||||||
|
#define MIPS_OP_SWL 0b101010
|
||||||
|
MIPS_INS(SWL, .op = MIPS_OP_SWL)
|
||||||
|
|
||||||
|
/* SWR - store word right */
|
||||||
|
#define MIPS_OP_SWR 0b101110
|
||||||
|
MIPS_INS(SWR, .op = MIPS_OP_SWR)
|
||||||
|
|
||||||
/* SLL - shift left logical */
|
/* SLL - shift left logical */
|
||||||
#define MIPS_FUNCT_SLL 0b000000
|
#define MIPS_FUNCT_SLL 0b000000
|
||||||
MIPS_INS(SLL, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_SLL)
|
MIPS_INS(SLL, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_SLL)
|
||||||
|
|
|
@ -26,5 +26,5 @@ _start:
|
||||||
|
|
||||||
# exit
|
# exit
|
||||||
move $a0, $v0
|
move $a0, $v0
|
||||||
li $v0, 60
|
li $v0, 1
|
||||||
syscall
|
syscall
|
||||||
|
|
12
masm/lex.c
12
masm/lex.c
|
@ -101,12 +101,6 @@ static int lex_string(struct lexer *lexer,char text[MAX_LEX_LENGTH])
|
||||||
if (c == '"')
|
if (c == '"')
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// strings cannot span multiple lines
|
|
||||||
if (c == '\n') {
|
|
||||||
ERROR_POS(pos, "reached newline before end of string");
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
// match escape character
|
// match escape character
|
||||||
if (c == '\\') {
|
if (c == '\\') {
|
||||||
switch (lex_peek(lexer)) {
|
switch (lex_peek(lexer)) {
|
||||||
|
@ -129,6 +123,12 @@ static int lex_string(struct lexer *lexer,char text[MAX_LEX_LENGTH])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// strings cannot span multiple lines
|
||||||
|
if (c == '\n') {
|
||||||
|
ERROR_POS(pos, "reached newline before end of string");
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
if (len + 1 == MAX_LEX_LENGTH) {
|
if (len + 1 == MAX_LEX_LENGTH) {
|
||||||
ERROR_POS(pos, "string has max length of %d",
|
ERROR_POS(pos, "string has max length of %d",
|
||||||
MAX_LEX_LENGTH);
|
MAX_LEX_LENGTH);
|
||||||
|
|
13
masm/parse.c
13
masm/parse.c
|
@ -148,6 +148,8 @@ const enum mips_parse_format mips_parse_formats[] = {
|
||||||
FORMAT(LHU, SL)
|
FORMAT(LHU, SL)
|
||||||
FORMAT(LUI, SLI)
|
FORMAT(LUI, SLI)
|
||||||
FORMAT(LW, SL)
|
FORMAT(LW, SL)
|
||||||
|
FORMAT(LWL, SL)
|
||||||
|
FORMAT(LWR, SL)
|
||||||
FORMAT(MFHI, RD)
|
FORMAT(MFHI, RD)
|
||||||
FORMAT(MFLO, RD)
|
FORMAT(MFLO, RD)
|
||||||
FORMAT(MTHI, RS)
|
FORMAT(MTHI, RS)
|
||||||
|
@ -156,9 +158,11 @@ const enum mips_parse_format mips_parse_formats[] = {
|
||||||
FORMAT(MUH, R)
|
FORMAT(MUH, R)
|
||||||
FORMAT(MULU, R)
|
FORMAT(MULU, R)
|
||||||
FORMAT(MUHU, R)
|
FORMAT(MUHU, R)
|
||||||
|
FORMAT(MULT, R2)
|
||||||
FORMAT(SB, SL)
|
FORMAT(SB, SL)
|
||||||
FORMAT(SH, SL)
|
FORMAT(SH, SL)
|
||||||
FORMAT(SW, SL)
|
FORMAT(SW, SL)
|
||||||
|
FORMAT(SWL, SL)
|
||||||
FORMAT(SLL, S)
|
FORMAT(SLL, S)
|
||||||
FORMAT(SLLV, SV)
|
FORMAT(SLLV, SV)
|
||||||
FORMAT(SLT, R)
|
FORMAT(SLT, R)
|
||||||
|
@ -858,9 +862,9 @@ static int parse_pseudo_la(struct parser *parser, struct ins_expr *expr)
|
||||||
expr->ins[0] = mips_instructions[MIPS_INS_LUI];
|
expr->ins[0] = mips_instructions[MIPS_INS_LUI];
|
||||||
expr->ins[0].data.rt = reg;
|
expr->ins[0].data.rt = reg;
|
||||||
expr->ins[0].data.immd = B16(hi);
|
expr->ins[0].data.immd = B16(hi);
|
||||||
expr->ins[1] = mips_instructions[MIPS_INS_ADDI];
|
expr->ins[1] = mips_instructions[MIPS_INS_ORI];
|
||||||
expr->ins[1].data.rt = reg;
|
expr->ins[1].data.rt = reg;
|
||||||
expr->ins[1].data.rs = reg;
|
expr->ins[1].data.rs = MIPS_REG_ZERO;
|
||||||
expr->ins[1].data.immd = B16(lo);
|
expr->ins[1].data.immd = B16(lo);
|
||||||
|
|
||||||
return M_SUCCESS;
|
return M_SUCCESS;
|
||||||
|
@ -912,14 +916,13 @@ static int parse_pseudo_instruction(struct parser *parser,
|
||||||
else CHK(move)
|
else CHK(move)
|
||||||
res = parse_pseudo_move(parser, expr);
|
res = parse_pseudo_move(parser, expr);
|
||||||
|
|
||||||
if (res) {
|
if (res)
|
||||||
// reset on fail
|
|
||||||
lexer_load(parser->lexer, &state);
|
lexer_load(parser->lexer, &state);
|
||||||
|
|
||||||
expr->ins[0].data.raw = 0;
|
expr->ins[0].data.raw = 0;
|
||||||
expr->ins[1].data.raw = 0;
|
expr->ins[1].data.raw = 0;
|
||||||
expr->ref[0] = (struct reference) {0};
|
expr->ref[0] = (struct reference) {0};
|
||||||
expr->ref[1] = (struct reference) {0};
|
expr->ref[1] = (struct reference) {0};
|
||||||
}
|
|
||||||
|
|
||||||
log_disabled = 0;
|
log_disabled = 0;
|
||||||
return res;
|
return res;
|
||||||
|
|
46
mld/link.c
46
mld/link.c
|
@ -125,17 +125,6 @@ static int relocate_segment_name(struct linker *linker, const char *name)
|
||||||
if (segtab_ent_push(ent, seg))
|
if (segtab_ent_push(ent, seg))
|
||||||
return M_ERROR;
|
return M_ERROR;
|
||||||
} else {
|
} else {
|
||||||
// update vaddr to be page aligned
|
|
||||||
uint32_t m = seg->new_vaddr % SEC_ALIGN;
|
|
||||||
if (m) {
|
|
||||||
uint32_t add = SEC_ALIGN - m;
|
|
||||||
seg->new_vaddr += add;
|
|
||||||
if (B32(seg->phdr->p_flags) & PF_X)
|
|
||||||
linker->text_vaddr += add;
|
|
||||||
else
|
|
||||||
linker->data_vaddr += add;
|
|
||||||
}
|
|
||||||
|
|
||||||
// else create a new segment
|
// else create a new segment
|
||||||
if (segtab_push(&linker->segments, NULL, seg))
|
if (segtab_push(&linker->segments, NULL, seg))
|
||||||
return M_ERROR;
|
return M_ERROR;
|
||||||
|
@ -547,23 +536,19 @@ static void update_offsets(struct linker *linker)
|
||||||
linker->ehdr.e_phoff = B32(ptr);
|
linker->ehdr.e_phoff = B32(ptr);
|
||||||
ptr += linker->phdr_len * sizeof(Elf32_Phdr);
|
ptr += linker->phdr_len * sizeof(Elf32_Phdr);
|
||||||
|
|
||||||
|
// section padding
|
||||||
|
{
|
||||||
|
uint32_t mod = ptr % SEC_ALIGN;
|
||||||
|
if (mod != 0)
|
||||||
|
linker->secalign = (SEC_ALIGN - mod);
|
||||||
|
else
|
||||||
|
linker->secalign = 0;
|
||||||
|
ptr += linker->secalign;
|
||||||
|
}
|
||||||
|
|
||||||
// sections
|
// sections
|
||||||
for (uint32_t i = 0; i < linker->segments.len; i++) {
|
for (uint32_t i = 0; i < linker->segments.len; i++) {
|
||||||
struct segment_table_entry *ent = &linker->segments.entries[i];
|
struct segment_table_entry *ent = &linker->segments.entries[i];
|
||||||
|
|
||||||
// section padding
|
|
||||||
{
|
|
||||||
uint32_t m = ptr % SEC_ALIGN;
|
|
||||||
if (m) {
|
|
||||||
uint32_t add = SEC_ALIGN - m;
|
|
||||||
ptr += add;
|
|
||||||
ent->off = ptr;
|
|
||||||
ent->padding = add;
|
|
||||||
} else {
|
|
||||||
ent->padding = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t idx = i + 1;
|
uint32_t idx = i + 1;
|
||||||
uint32_t size = segtab_ent_size(ent);
|
uint32_t size = segtab_ent_size(ent);
|
||||||
linker->phdr[i].p_offset = B32(ptr);
|
linker->phdr[i].p_offset = B32(ptr);
|
||||||
|
@ -619,16 +604,15 @@ static int write_file(struct linker *linker)
|
||||||
// phdr
|
// phdr
|
||||||
res |= fwrite(linker->phdr, sizeof(Elf32_Phdr), linker->phdr_len, out);
|
res |= fwrite(linker->phdr, sizeof(Elf32_Phdr), linker->phdr_len, out);
|
||||||
|
|
||||||
// sections
|
|
||||||
for (uint32_t i = 0; i < linker->segments.len; i++) {
|
|
||||||
struct segment_table_entry *ent = &linker->segments.entries[i];
|
|
||||||
// section padding
|
// section padding
|
||||||
{
|
for (uint32_t i = 0; i < linker->secalign; i++) {
|
||||||
for (uint32_t i = 0; i < ent->padding; i++) {
|
|
||||||
uint8_t zero = 0;
|
uint8_t zero = 0;
|
||||||
res |= fwrite(&zero, 1, 1, out);
|
res |= fwrite(&zero, 1, 1, out);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// sections
|
||||||
|
for (uint32_t i = 0; i < linker->segments.len; i++) {
|
||||||
|
struct segment_table_entry *ent = &linker->segments.entries[i];
|
||||||
for (uint32_t j = 0; j < ent->len; j++) {
|
for (uint32_t j = 0; j < ent->len; j++) {
|
||||||
struct segment *seg = ent->parts[j];
|
struct segment *seg = ent->parts[j];
|
||||||
res |= fwrite(seg->bytes, 1, seg->size, out);
|
res |= fwrite(seg->bytes, 1, seg->size, out);
|
||||||
|
|
|
@ -170,8 +170,6 @@ struct segment_table_entry {
|
||||||
uint32_t vaddr;
|
uint32_t vaddr;
|
||||||
// weak segment pointers. we do not own these!!!
|
// weak segment pointers. we do not own these!!!
|
||||||
struct segment **parts;
|
struct segment **parts;
|
||||||
// section padding
|
|
||||||
uint32_t padding;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int segtab_ent_init(struct segment_table_entry *ent);
|
int segtab_ent_init(struct segment_table_entry *ent);
|
||||||
|
@ -275,6 +273,9 @@ struct linker {
|
||||||
uint32_t strtab_shidx;
|
uint32_t strtab_shidx;
|
||||||
uint32_t shstrtab_shidx;
|
uint32_t shstrtab_shidx;
|
||||||
|
|
||||||
|
// section alignment after phdr bytes
|
||||||
|
uint32_t secalign;
|
||||||
|
|
||||||
// all segments
|
// all segments
|
||||||
struct segment_table segments;
|
struct segment_table segments;
|
||||||
};
|
};
|
||||||
|
|
79
msim/debug.c
79
msim/debug.c
|
@ -1,79 +0,0 @@
|
||||||
#include <merror.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <melf.h>
|
|
||||||
|
|
||||||
#include "sim.h"
|
|
||||||
|
|
||||||
static uint32_t read_num() {
|
|
||||||
int i = 0;
|
|
||||||
while (1) {
|
|
||||||
int c = getc(stdin);
|
|
||||||
if (c < '0' || c > '9') {
|
|
||||||
ungetc(c, stdin);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
i *= 10;
|
|
||||||
i += c - '0';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i)
|
|
||||||
return i;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
_Noreturn void sim_debug(struct simulator *sim) {
|
|
||||||
|
|
||||||
int c;
|
|
||||||
sim->pc = sim->entry;
|
|
||||||
sim->current_pc = sim->pc;
|
|
||||||
|
|
||||||
prompt:
|
|
||||||
printf(">> ");
|
|
||||||
fflush(stdout);
|
|
||||||
next:
|
|
||||||
switch ((c = getchar())) {
|
|
||||||
|
|
||||||
/* skip whitespace */
|
|
||||||
case ' ':
|
|
||||||
case '\t':
|
|
||||||
goto next;
|
|
||||||
|
|
||||||
/* ignore nl */
|
|
||||||
case '\n':
|
|
||||||
goto prompt;
|
|
||||||
|
|
||||||
/* exit on eof */
|
|
||||||
case EOF:
|
|
||||||
exit(0);
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* dump registers */
|
|
||||||
case 'r':
|
|
||||||
sim_dump_reg(sim);
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* step ins */
|
|
||||||
case 's': {
|
|
||||||
for (uint32_t i = read_num(); i > 0; i--)
|
|
||||||
sim_step(sim);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* print curr ins */
|
|
||||||
case 'i':
|
|
||||||
printf("0x%08x\n", B32(* (uint32_t *) (uintptr_t) sim->pc));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'a':
|
|
||||||
printf("0x%08x\n", sim->pc);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
ERROR("unknown command '%c'", c);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
goto next;
|
|
||||||
}
|
|
56
msim/fault.c
56
msim/fault.c
|
@ -1,56 +0,0 @@
|
||||||
#include "fault.h"
|
|
||||||
#include "sim.h"
|
|
||||||
#include <signal.h>
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
static struct simulator *sim;
|
|
||||||
|
|
||||||
static void sigsegv_handler(int sig, siginfo_t *info, void *ucontext)
|
|
||||||
{
|
|
||||||
(void) sig;
|
|
||||||
(void) ucontext;
|
|
||||||
|
|
||||||
const char *inner = "";
|
|
||||||
switch (info->si_code) {
|
|
||||||
case SEGV_MAPERR:
|
|
||||||
inner = ": address not mapped to object";
|
|
||||||
break;
|
|
||||||
case SEGV_ACCERR:
|
|
||||||
inner = ": invalid premissions for mapped object";
|
|
||||||
break;
|
|
||||||
case SEGV_BNDERR:
|
|
||||||
inner = ": failed address bound checks";
|
|
||||||
break;
|
|
||||||
case SEGV_PKUERR:
|
|
||||||
inner = ": access was denied by memory protection";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
sim_dump(sim, "page fault at %p%s", info->si_addr, inner);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sigfpe_handler(int sig, siginfo_t *info, void *ucontext)
|
|
||||||
{
|
|
||||||
(void) sig;
|
|
||||||
(void) info;
|
|
||||||
(void) ucontext;
|
|
||||||
|
|
||||||
sim_dump(sim, "floating point exception");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void init_handlers(struct simulator *s)
|
|
||||||
{
|
|
||||||
struct sigaction act = {0};
|
|
||||||
sim = s;
|
|
||||||
|
|
||||||
/* sigsegv */
|
|
||||||
act.sa_sigaction = sigsegv_handler;
|
|
||||||
act.sa_flags = SA_SIGINFO;
|
|
||||||
sigaction(SIGSEGV, &act, NULL);
|
|
||||||
|
|
||||||
/* sigfpe */
|
|
||||||
act.sa_sigaction = sigfpe_handler;
|
|
||||||
act.sa_flags = SA_SIGINFO;
|
|
||||||
sigaction(SIGFPE, &act, NULL);
|
|
||||||
}
|
|
10
msim/fault.h
10
msim/fault.h
|
@ -1,10 +0,0 @@
|
||||||
/* Copyright (c) 2024 Freya Murphy */
|
|
||||||
|
|
||||||
#ifndef __FAULT_H__
|
|
||||||
#define __FAULT_H__
|
|
||||||
|
|
||||||
#include "sim.h"
|
|
||||||
|
|
||||||
void init_handlers(struct simulator *s);
|
|
||||||
|
|
||||||
#endif /* __FAULT_H__ */
|
|
373
msim/ins.c
373
msim/ins.c
|
@ -1,373 +0,0 @@
|
||||||
#include <mips.h>
|
|
||||||
#include <melf.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include "sim.h"
|
|
||||||
|
|
||||||
#define I16(n) ((int32_t)(uint16_t)(n))
|
|
||||||
|
|
||||||
static void sim_ins_special_sop30(struct simulator *sim,
|
|
||||||
union mips_instruction_data ins)
|
|
||||||
{
|
|
||||||
switch (ins.shamt) {
|
|
||||||
case MIPS_SOP30_MUL:
|
|
||||||
sim->reg[ins.rd] = ((int64_t)sim->reg[ins.rs] /
|
|
||||||
(int64_t)sim->reg[ins.rt]) >> 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_SOP30_MUH:
|
|
||||||
sim->reg[ins.rd] = ((int64_t)sim->reg[ins.rs] /
|
|
||||||
(int64_t)sim->reg[ins.rt]) >> 32;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
sim_dump(sim, "unknown sop30 funct (0b%06b)", ins.shamt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sim_ins_special_sop31(struct simulator *sim,
|
|
||||||
union mips_instruction_data ins)
|
|
||||||
{
|
|
||||||
switch (ins.shamt) {
|
|
||||||
case MIPS_SOP31_MULU:
|
|
||||||
sim->reg[ins.rd] = ((uint64_t)sim->reg[ins.rs] /
|
|
||||||
(uint64_t)sim->reg[ins.rt]) >> 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_SOP31_MUHU:
|
|
||||||
sim->reg[ins.rd] = ((uint64_t)sim->reg[ins.rs] /
|
|
||||||
(uint64_t)sim->reg[ins.rt]) >> 32;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
sim_dump(sim, "unknown sop31 funct (0b%06b)", ins.shamt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sim_ins_special_sop32(struct simulator *sim,
|
|
||||||
union mips_instruction_data ins)
|
|
||||||
{
|
|
||||||
switch (ins.shamt) {
|
|
||||||
case MIPS_SOP32_DIV:
|
|
||||||
sim->reg[ins.rd] = (int32_t)sim->reg[ins.rs] /
|
|
||||||
(int32_t)sim->reg[ins.rt];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_SOP32_MOD:
|
|
||||||
sim->reg[ins.rd] = (int32_t)sim->reg[ins.rs] %
|
|
||||||
(int32_t)sim->reg[ins.rt];
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
sim_dump(sim, "unknown sop32 funct (0b%06b)", ins.shamt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sim_ins_special_sop33(struct simulator *sim,
|
|
||||||
union mips_instruction_data ins)
|
|
||||||
{
|
|
||||||
switch (ins.shamt) {
|
|
||||||
case MIPS_SOP33_DIVU:
|
|
||||||
sim->reg[ins.rd] = sim->reg[ins.rs] / sim->reg[ins.rt];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_SOP33_MODU:
|
|
||||||
sim->reg[ins.rd] = sim->reg[ins.rs] % sim->reg[ins.rt];
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
sim_dump(sim, "unknown sop33 funct (0b%06b)", ins.shamt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sim_ins_special(struct simulator *sim,
|
|
||||||
union mips_instruction_data ins)
|
|
||||||
{
|
|
||||||
switch (ins.funct) {
|
|
||||||
case MIPS_FUNCT_ADD:
|
|
||||||
sim->reg[ins.rd] = (int32_t)sim->reg[ins.rs] +
|
|
||||||
(int32_t)sim->reg[ins.rt];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_FUNCT_ADDU:
|
|
||||||
sim->reg[ins.rd] = sim->reg[ins.rs] + sim->reg[ins.rt];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_FUNCT_AND:
|
|
||||||
sim->reg[ins.rd] = sim->reg[ins.rs] & sim->reg[ins.rt];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_FUNCT_SOP30:
|
|
||||||
sim_ins_special_sop30(sim, ins);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_FUNCT_SOP31:
|
|
||||||
sim_ins_special_sop31(sim, ins);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_FUNCT_SOP32:
|
|
||||||
sim_ins_special_sop32(sim, ins);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_FUNCT_SOP33:
|
|
||||||
sim_ins_special_sop33(sim, ins);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_FUNCT_JALR:
|
|
||||||
sim->reg[MIPS_REG_RA] = sim->pc;
|
|
||||||
/* fall through */
|
|
||||||
case MIPS_FUNCT_JR:
|
|
||||||
sim->pc = sim->reg[ins.rs];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_FUNCT_MFHI:
|
|
||||||
sim->reg[ins.rd] = sim->hi;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_FUNCT_MFLO:
|
|
||||||
sim->reg[ins.rd] = sim->low;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_FUNCT_MTHI:
|
|
||||||
sim->hi = sim->reg[ins.rd];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_FUNCT_MTLO:
|
|
||||||
sim->low = sim->reg[ins.rd];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_FUNCT_SLL:
|
|
||||||
sim->reg[ins.rd] = sim->reg[ins.rt] << ins.shamt;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_FUNCT_SLLV:
|
|
||||||
sim->reg[ins.rd] = sim->reg[ins.rt] << sim->reg[ins.rs];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_FUNCT_SLT:
|
|
||||||
sim->reg[ins.rd] = (int32_t)sim->reg[ins.rs] < (int32_t)sim->reg[ins.rt] ? 1 : 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_FUNCT_SLTU:
|
|
||||||
sim->reg[ins.rd] = sim->reg[ins.rs] < sim->reg[ins.rt] ? 1 : 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_FUNCT_SRA:
|
|
||||||
sim->reg[ins.rd] = (int32_t)sim->reg[ins.rt] >> ins.shamt;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_FUNCT_SRAV:
|
|
||||||
sim->reg[ins.rd] = (int32_t)sim->reg[ins.rt] >> sim->reg[ins.rs];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_FUNCT_SRL:
|
|
||||||
sim->reg[ins.rd] = sim->reg[ins.rt] >> ins.shamt;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_FUNCT_SRLV:
|
|
||||||
sim->reg[ins.rd] = sim->reg[ins.rt] >> sim->reg[ins.rs];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_FUNCT_SUB:
|
|
||||||
sim->reg[ins.rd] = (int32_t)sim->reg[ins.rs] -
|
|
||||||
(int32_t)sim->reg[ins.rt];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_FUNCT_SUBU:
|
|
||||||
sim->reg[ins.rd] = sim->reg[ins.rs] - sim->reg[ins.rt];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_FUNCT_SYSCALL:
|
|
||||||
sim->reg[MIPS_REG_V0] = syscall(
|
|
||||||
sim->reg[MIPS_REG_V0],
|
|
||||||
sim->reg[MIPS_REG_A0],
|
|
||||||
sim->reg[MIPS_REG_A1],
|
|
||||||
sim->reg[MIPS_REG_A2],
|
|
||||||
sim->reg[MIPS_REG_A3]
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_FUNCT_OR:
|
|
||||||
sim->reg[ins.rd] = sim->reg[ins.rs] | sim->reg[ins.rt];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_FUNCT_NOR:
|
|
||||||
sim->reg[ins.rd] = !(sim->reg[ins.rs] | sim->reg[ins.rt]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_FUNCT_XOR:
|
|
||||||
sim->reg[ins.rd] = sim->reg[ins.rs] ^ sim->reg[ins.rt];
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
sim_dump(sim, "unknown funct (0b%05b)", ins.funct);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sim_ins_regimm(struct simulator *sim,
|
|
||||||
union mips_instruction_data ins)
|
|
||||||
{
|
|
||||||
switch (ins.bfunct) {
|
|
||||||
case MIPS_FUNCT_BGEZAL:
|
|
||||||
case MIPS_FUNCT_BGEZALL:
|
|
||||||
sim->reg[MIPS_REG_RA] = sim->pc;
|
|
||||||
/* fall through */
|
|
||||||
case MIPS_FUNCT_BGEZ:
|
|
||||||
case MIPS_FUNCT_BGEZL:
|
|
||||||
if ((int32_t)sim->reg[ins.rs] >= 0)
|
|
||||||
sim->pc += ins.offset << 2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_FUNCT_BLTZAL:
|
|
||||||
case MIPS_FUNCT_BLTZALL:
|
|
||||||
sim->reg[MIPS_REG_RA] = sim->pc;
|
|
||||||
/* fall through */
|
|
||||||
case MIPS_FUNCT_BLTZ:
|
|
||||||
case MIPS_FUNCT_BLTZL:
|
|
||||||
if ((int32_t)sim->reg[ins.rs] < 0)
|
|
||||||
sim->pc += ins.offset << 2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
sim_dump(sim, "unknown bfunct (0b%06b)", ins.bfunct);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void sim_ins(struct simulator *sim, uint32_t raw)
|
|
||||||
{
|
|
||||||
// get ins parts
|
|
||||||
union mips_instruction_data ins = {
|
|
||||||
.raw = B32(raw)
|
|
||||||
};
|
|
||||||
|
|
||||||
// reset zero reg
|
|
||||||
sim->reg[MIPS_REG_ZERO] = 0;
|
|
||||||
|
|
||||||
switch (ins.op) {
|
|
||||||
case MIPS_OP_SPECIAL:
|
|
||||||
sim_ins_special(sim, ins);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_OP_REGIMM:
|
|
||||||
sim_ins_regimm(sim, ins);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_OP_ADDI:
|
|
||||||
sim->reg[ins.rt] = (int32_t)sim->reg[ins.rs] +
|
|
||||||
(int16_t) ins.immd;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_OP_ADDIU:
|
|
||||||
sim->reg[ins.rt] = sim->reg[ins.rs] + ins.immd;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_OP_ANDI:
|
|
||||||
sim->reg[ins.rt] = sim->reg[ins.rs] & ins.immd;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_OP_BALC:
|
|
||||||
sim->reg[MIPS_REG_RA] = sim->pc;
|
|
||||||
/* fall through */
|
|
||||||
case MIPS_OP_BC:
|
|
||||||
sim->pc += ins.offs26 << 2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_OP_BEQ:
|
|
||||||
case MIPS_OP_BEQL:
|
|
||||||
if (sim->reg[ins.rs] == sim->reg[ins.rt])
|
|
||||||
sim->pc += ins.offset << 2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_OP_BGTZ:
|
|
||||||
case MIPS_OP_BGTZL:
|
|
||||||
if ((int32_t)sim->reg[ins.rs] <= 0)
|
|
||||||
sim->pc += ins.offset << 2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_OP_BLEZ:
|
|
||||||
case MIPS_OP_BLEZL:
|
|
||||||
if ((int32_t)sim->reg[ins.rs] <= 0)
|
|
||||||
sim->pc += ins.offset << 2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_OP_BNE:
|
|
||||||
case MIPS_OP_BNEL:
|
|
||||||
if (sim->reg[ins.rs] != sim->reg[ins.rt])
|
|
||||||
sim->pc += ins.offset << 2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_OP_JAL:
|
|
||||||
sim->reg[MIPS_REG_RA] = sim->pc;
|
|
||||||
/* fall through */
|
|
||||||
case MIPS_OP_J:
|
|
||||||
sim->pc = ins.target << 2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_OP_LB:
|
|
||||||
sim->reg[ins.rt] = * (int8_t *) (uintptr_t) (sim->reg[ins.rs]
|
|
||||||
+ ins.offset);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_OP_LBU:
|
|
||||||
sim->reg[ins.rt] = * (uint8_t *) (uintptr_t) (sim->reg[ins.rs]
|
|
||||||
+ ins.offset);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_OP_LH:
|
|
||||||
sim->reg[ins.rt] = * (int16_t *) (uintptr_t) (sim->reg[ins.rs]
|
|
||||||
+ ins.offset);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_OP_LHU:
|
|
||||||
sim->reg[ins.rt] = * (uint16_t *) (uintptr_t) (sim->reg[ins.rs]
|
|
||||||
+ ins.offset);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_OP_LUI:
|
|
||||||
sim->reg[ins.rt] = ins.immd << 16;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_OP_LW:
|
|
||||||
sim->reg[ins.rt] = * (uint32_t *) (uintptr_t) (sim->reg[ins.rs]
|
|
||||||
+ ins.offset);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_OP_SB:
|
|
||||||
* (uint8_t *) (uintptr_t) (sim->reg[ins.rs] +
|
|
||||||
+ ins.offset) = sim->reg[ins.rt];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_OP_SH:
|
|
||||||
* (uint16_t *) (uintptr_t) (sim->reg[ins.rs] +
|
|
||||||
ins.offset) = sim->reg[ins.rt];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_OP_SW:
|
|
||||||
* (uint32_t *) (uintptr_t) (sim->reg[ins.rs] +
|
|
||||||
ins.offset) = sim->reg[ins.rt];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_OP_SLTI:
|
|
||||||
sim->reg[ins.rt] = (int32_t)sim->reg[ins.rs] <
|
|
||||||
(int16_t)ins.immd ? 1 : 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_OP_SLTIU:
|
|
||||||
sim->reg[ins.rt] = sim->reg[ins.rs] < ins.immd ? 1 : 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_OP_ORI:
|
|
||||||
sim->reg[ins.rt] = sim->reg[ins.rs] | ins.immd;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MIPS_OP_XORI:
|
|
||||||
sim->reg[ins.rt] = sim->reg[ins.rs] ^ ins.immd;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
sim_dump(sim, "unknown op code (0b%05b)", ins.op);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
226
msim/load.c
226
msim/load.c
|
@ -1,226 +0,0 @@
|
||||||
#include <merror.h>
|
|
||||||
#include <elf.h>
|
|
||||||
#include <melf.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
|
|
||||||
#include "sim.h"
|
|
||||||
|
|
||||||
#define SEC_ALIGN 0x1000
|
|
||||||
|
|
||||||
struct load_state {
|
|
||||||
FILE *file;
|
|
||||||
int fd;
|
|
||||||
uint32_t file_sz;
|
|
||||||
|
|
||||||
Elf32_Phdr *phdr;
|
|
||||||
uint32_t phdr_len;
|
|
||||||
Elf32_Ehdr ehdr;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int assert_ehdr(const void *const given, const void *const assert,
|
|
||||||
size_t size)
|
|
||||||
{
|
|
||||||
if (memcmp(given, assert, size) == 0)
|
|
||||||
return M_SUCCESS;
|
|
||||||
ERROR("invalid elf ehdr");
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int load_ehdr(struct simulator *sim, struct load_state *state)
|
|
||||||
{
|
|
||||||
Elf32_Ehdr ehdr;
|
|
||||||
fseek(state->file, 0, SEEK_SET);
|
|
||||||
if (fread(&ehdr, sizeof(Elf32_Ehdr), 1, state->file) != 1) {
|
|
||||||
ERROR("cannot load ehdr");
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compare each "static" value in the ehdr and make sure it
|
|
||||||
* is what it should be. If not throw and error and eventually
|
|
||||||
* return.
|
|
||||||
*/
|
|
||||||
|
|
||||||
Elf32_Ehdr baseline = MIPS_ELF_EHDR;
|
|
||||||
baseline.e_type = B16(ET_EXEC);
|
|
||||||
|
|
||||||
#define EHDR_ASSERT(name, size) \
|
|
||||||
if (res == M_SUCCESS) \
|
|
||||||
res |= assert_ehdr(&baseline.e_##name, \
|
|
||||||
&ehdr.e_##name, size) \
|
|
||||||
|
|
||||||
int res = 0;
|
|
||||||
EHDR_ASSERT(ident, EI_NIDENT);
|
|
||||||
EHDR_ASSERT(type, sizeof(Elf32_Half));
|
|
||||||
EHDR_ASSERT(machine, sizeof(Elf32_Half));
|
|
||||||
EHDR_ASSERT(version, sizeof(Elf32_Word));
|
|
||||||
EHDR_ASSERT(flags, sizeof(Elf32_Word));
|
|
||||||
EHDR_ASSERT(ehsize, sizeof(Elf32_Half));
|
|
||||||
EHDR_ASSERT(phentsize, sizeof(Elf32_Half));
|
|
||||||
EHDR_ASSERT(shentsize, sizeof(Elf32_Half));
|
|
||||||
|
|
||||||
#undef EHDR_ASSERT
|
|
||||||
|
|
||||||
if (res)
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
state->ehdr = ehdr;
|
|
||||||
sim->entry = B32(ehdr.e_entry);
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int load_phdr(struct load_state *state)
|
|
||||||
{
|
|
||||||
Elf32_Phdr *phdr = NULL;
|
|
||||||
|
|
||||||
uint32_t off = B32(state->ehdr.e_phoff);
|
|
||||||
uint16_t len = B16(state->ehdr.e_phnum);
|
|
||||||
|
|
||||||
if (BOUND_CHK(state->file_sz, len, off)) {
|
|
||||||
ERROR("elf phdr location invalid");
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
phdr = malloc(sizeof(Elf32_Phdr) * len);
|
|
||||||
if (phdr == NULL) {
|
|
||||||
PERROR("cannot alloc");
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
fseek(state->file, off, SEEK_SET);
|
|
||||||
if (fread(phdr, sizeof(Elf32_Phdr), len, state->file) != len) {
|
|
||||||
free(phdr);
|
|
||||||
PERROR("cannot read phdr");
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
state->phdr = phdr;
|
|
||||||
state->phdr_len = len;
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int load_segment(struct simulator *sim,
|
|
||||||
struct load_state *state, Elf32_Phdr *hdr)
|
|
||||||
{
|
|
||||||
uint32_t off = B32(hdr->p_offset);
|
|
||||||
uint32_t len = B32(hdr->p_filesz);
|
|
||||||
uint32_t is_text = B32(hdr->p_flags) & PF_X;
|
|
||||||
|
|
||||||
if (BOUND_CHK(state->file_sz, len, off)) {
|
|
||||||
ERROR("segment location invalid");
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
uintptr_t addr = 0;
|
|
||||||
uint32_t add = 0;
|
|
||||||
|
|
||||||
if (len % SEC_ALIGN) {
|
|
||||||
add = SEC_ALIGN - (len % SEC_ALIGN);
|
|
||||||
len += add;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_text) {
|
|
||||||
addr = sim->text_max;
|
|
||||||
sim->text_max += len;
|
|
||||||
} else {
|
|
||||||
addr = sim->data_max;
|
|
||||||
sim->data_max += len;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool read = B32(hdr->p_flags) & PF_R;
|
|
||||||
bool write = B32(hdr->p_flags) & PF_W;
|
|
||||||
|
|
||||||
uint32_t prot = 0;
|
|
||||||
if (read)
|
|
||||||
prot |= PROT_READ;
|
|
||||||
if (write)
|
|
||||||
prot |= PROT_WRITE;
|
|
||||||
|
|
||||||
void *res = mmap((void*)addr, len, prot, MAP_PRIVATE | MAP_FIXED,
|
|
||||||
state->fd, off);
|
|
||||||
|
|
||||||
if ((uintptr_t)res != addr) {
|
|
||||||
PERROR("failed to map executable");
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int load_memory(struct simulator *sim, struct load_state *state)
|
|
||||||
{
|
|
||||||
uint32_t base = 0;
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < state->phdr_len; i++) {
|
|
||||||
Elf32_Phdr *hdr = NULL;
|
|
||||||
uint32_t min = UINT32_MAX;
|
|
||||||
|
|
||||||
if (B32(state->phdr[i].p_filesz) < 1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// we need to load segments in order
|
|
||||||
for (uint32_t j = 0; j < state->phdr_len; j++) {
|
|
||||||
Elf32_Phdr *temp = &state->phdr[j];
|
|
||||||
uint32_t off = B32(temp->p_offset);
|
|
||||||
uint32_t len = B32(temp->p_filesz);
|
|
||||||
|
|
||||||
if (len < 1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (off <= base)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (off >= min)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
min = off;
|
|
||||||
hdr = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
base = min;
|
|
||||||
|
|
||||||
if (hdr == NULL) {
|
|
||||||
ERROR("invalid elf phdr");
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (load_segment(sim, state, hdr))
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sim_load_file(struct simulator *sim) {
|
|
||||||
struct load_state state;
|
|
||||||
|
|
||||||
state.file = fopen(sim->args->executable, "r");
|
|
||||||
if (state.file == NULL) {
|
|
||||||
PERROR("cannot read '%s'", state.file);
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
state.fd = fileno(state.file);
|
|
||||||
|
|
||||||
// get filesize
|
|
||||||
fseek(state.file, 0, SEEK_END);
|
|
||||||
state.file_sz = ftell(state.file);
|
|
||||||
state.phdr = NULL;
|
|
||||||
|
|
||||||
int res = M_SUCCESS;
|
|
||||||
if (res == M_SUCCESS)
|
|
||||||
res = load_ehdr(sim, &state);
|
|
||||||
if (res == M_SUCCESS)
|
|
||||||
res = load_phdr(&state);
|
|
||||||
if (res == M_SUCCESS)
|
|
||||||
res = load_memory(sim, &state);
|
|
||||||
|
|
||||||
if (state.phdr)
|
|
||||||
free(state.phdr);
|
|
||||||
fclose(state.file);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
74
msim/main.c
74
msim/main.c
|
@ -1,73 +1,5 @@
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <merror.h>
|
|
||||||
#include <signal.h>
|
|
||||||
|
|
||||||
#include "fault.h"
|
int main(void) {
|
||||||
#include "sim.h"
|
// NOT YET IMPLEMENTED
|
||||||
|
return 1;
|
||||||
static void help(void) {
|
|
||||||
printf("usage: msim [options] executable\n\n");
|
|
||||||
printf("options:\n");
|
|
||||||
printf("\t-h\t\tprints this help messaage\n");
|
|
||||||
printf("\t-c\t\tdisable runtime memory checks (allows segfault)\n");
|
|
||||||
printf("\t-d\t\truns the debugger\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
|
||||||
|
|
||||||
struct simulator sim;
|
|
||||||
struct simulator_args args = {
|
|
||||||
.executable = NULL,
|
|
||||||
.debug = false,
|
|
||||||
.memchk = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
int c;
|
|
||||||
|
|
||||||
while ((c = getopt(argc, argv, "hcd")) != 1) {
|
|
||||||
switch (c) {
|
|
||||||
case 'h':
|
|
||||||
help();
|
|
||||||
return M_SUCCESS;
|
|
||||||
case 'c':
|
|
||||||
args.memchk = false;
|
|
||||||
break;
|
|
||||||
case 'd':
|
|
||||||
args.debug = true;
|
|
||||||
break;
|
|
||||||
case '?':
|
|
||||||
return M_ERROR;
|
|
||||||
default:
|
|
||||||
goto next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
next:
|
|
||||||
if (optind < argc - 1) {
|
|
||||||
ERROR("too many executables passed");
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (optind >= argc) {
|
|
||||||
ERROR("no executable passed");
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// set file name
|
|
||||||
args.executable = argv[optind];
|
|
||||||
|
|
||||||
/// create handlers
|
|
||||||
init_handlers(&sim);
|
|
||||||
|
|
||||||
/// init
|
|
||||||
if (sim_init(&sim, &args))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
/* _Noreturn */
|
|
||||||
if (args.debug)
|
|
||||||
sim_debug(&sim);
|
|
||||||
else
|
|
||||||
sim_run(&sim);
|
|
||||||
}
|
}
|
||||||
|
|
93
msim/sim.c
93
msim/sim.c
|
@ -1,93 +0,0 @@
|
||||||
#include <merror.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
|
|
||||||
#include "sim.h"
|
|
||||||
#include "melf.h"
|
|
||||||
|
|
||||||
void sim_dump_reg(struct simulator *sim)
|
|
||||||
{
|
|
||||||
const char *names[32] = {
|
|
||||||
"zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", "t0", "t1",
|
|
||||||
"t2", "t3", "t4", "t5", "t6", "t7", "s0", "s1", "s2", "s3",
|
|
||||||
"s4", "s5", "s6", "s7", "t8", "t9", "k0", "k1", "gp", "sp",
|
|
||||||
"fp", "ra"
|
|
||||||
};
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < 8; i++) {
|
|
||||||
for (uint32_t j = 0; j < 4; j++) {
|
|
||||||
if (j != 0)
|
|
||||||
fputc(' ', stderr);
|
|
||||||
int idx = i+j*8;
|
|
||||||
fprintf(stderr, "$%s:\t0x%08x", names[idx], sim->reg[idx]);
|
|
||||||
}
|
|
||||||
fputc('\n', stderr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__((format(printf, 2, 3)))
|
|
||||||
_Noreturn void sim_dump(struct simulator *sim, const char *format, ...) {
|
|
||||||
|
|
||||||
va_list list;
|
|
||||||
va_start(list, format);
|
|
||||||
|
|
||||||
// header
|
|
||||||
fprintf(stderr, "\n\t\t!!! An exception has occurred !!!\n\n");
|
|
||||||
fprintf(stderr, "\033[31merror: \033[0m");
|
|
||||||
vfprintf(stderr, format, list);
|
|
||||||
fputc('\n', stderr);
|
|
||||||
|
|
||||||
// pc
|
|
||||||
uint32_t pc = sim->current_pc;
|
|
||||||
fprintf(stderr, "pc: 0x%08x\n", pc);
|
|
||||||
|
|
||||||
if (pc >= sim->text_min && pc < sim->text_max)
|
|
||||||
fprintf(stderr, "ins: 0x%08x\n", B32(* (uint32_t *) (uintptr_t) pc));
|
|
||||||
|
|
||||||
// registers
|
|
||||||
fprintf(stderr, "registers:\n");
|
|
||||||
sim_dump_reg(sim);
|
|
||||||
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sim_step(struct simulator *sim)
|
|
||||||
{
|
|
||||||
if (sim->pc < sim->text_min || sim->pc >= sim->text_max)
|
|
||||||
sim_dump(sim, "program counter reached non executable memory");
|
|
||||||
|
|
||||||
uint32_t ins = * (uint32_t *) (uintptr_t) sim->pc;
|
|
||||||
sim->pc += 4;
|
|
||||||
sim_ins(sim, ins);
|
|
||||||
sim->current_pc = sim->pc;
|
|
||||||
}
|
|
||||||
|
|
||||||
_Noreturn void sim_run(struct simulator *sim)
|
|
||||||
{
|
|
||||||
sim->pc = sim->entry;
|
|
||||||
sim->current_pc = sim->pc;
|
|
||||||
while (1)
|
|
||||||
sim_step(sim);
|
|
||||||
}
|
|
||||||
|
|
||||||
int sim_init(struct simulator *sim, struct simulator_args *args) {
|
|
||||||
memset(sim->reg, 0, sizeof(uint32_t) * 32);
|
|
||||||
sim->data_max = MEM_DATA_ADDR;
|
|
||||||
sim->data_min = MEM_DATA_ADDR;
|
|
||||||
sim->text_max = MEM_TEXT_ADDR;
|
|
||||||
sim->text_min = MEM_TEXT_ADDR;
|
|
||||||
sim->args = args;
|
|
||||||
|
|
||||||
// load executable
|
|
||||||
if (sim_load_file(sim))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
// check entry
|
|
||||||
if (sim->entry < sim->text_min || sim->entry >= sim->text_max) {
|
|
||||||
ERROR("elf entrypoint invalid");
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
87
msim/sim.h
87
msim/sim.h
|
@ -1,87 +0,0 @@
|
||||||
/* Copyright (c) 2024 Freya Murphy */
|
|
||||||
|
|
||||||
#ifndef __SIM_H__
|
|
||||||
#define __SIM_H__
|
|
||||||
|
|
||||||
#include <elf.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
/// arguments
|
|
||||||
struct simulator_args {
|
|
||||||
char *executable;
|
|
||||||
bool memchk;
|
|
||||||
bool debug;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// when loading the executable, we need to bounds check to
|
|
||||||
// make sure its within the file size
|
|
||||||
//
|
|
||||||
// this checks that
|
|
||||||
// 1. the end is in the file
|
|
||||||
// 2. the off and len doesnt integer overflow
|
|
||||||
#define BOUND_CHK(size, len, off) \
|
|
||||||
((off) > UINT32_MAX - (len) || (off) + (len) > (size))
|
|
||||||
|
|
||||||
///
|
|
||||||
/// data must start at these
|
|
||||||
/// addresses or the executable is
|
|
||||||
/// invalid
|
|
||||||
///
|
|
||||||
#define MEM_TEXT_ADDR 0x00400000
|
|
||||||
#define MEM_DATA_ADDR 0x10000000
|
|
||||||
|
|
||||||
struct simulator {
|
|
||||||
struct simulator_args *args;
|
|
||||||
|
|
||||||
|
|
||||||
/// the registers
|
|
||||||
uint32_t reg[32];
|
|
||||||
|
|
||||||
/// the program counter
|
|
||||||
uint32_t pc;
|
|
||||||
|
|
||||||
/// the current executing pc
|
|
||||||
uint32_t current_pc;
|
|
||||||
|
|
||||||
/// low and hi
|
|
||||||
uint32_t low;
|
|
||||||
uint32_t hi;
|
|
||||||
|
|
||||||
/// memory address bounds
|
|
||||||
uint32_t data_min;
|
|
||||||
uint32_t data_max;
|
|
||||||
uint32_t text_min;
|
|
||||||
uint32_t text_max;
|
|
||||||
|
|
||||||
// entrypoint
|
|
||||||
uint32_t entry;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* initalize a simulator */
|
|
||||||
int sim_init(struct simulator *sim, struct simulator_args *args);
|
|
||||||
|
|
||||||
/* load a file into a simulator */
|
|
||||||
int sim_load_file(struct simulator *sim);
|
|
||||||
|
|
||||||
/* execute and instruction */
|
|
||||||
void sim_ins(struct simulator *sim, uint32_t ins);
|
|
||||||
|
|
||||||
/* execute the next instruction in the simulator */
|
|
||||||
void sim_step(struct simulator *sim);
|
|
||||||
|
|
||||||
/* run the simulator with the loaded state */
|
|
||||||
_Noreturn void sim_run(struct simulator *sim);
|
|
||||||
|
|
||||||
/* run the debugger for a simulator */
|
|
||||||
_Noreturn void sim_debug(struct simulator *sim);
|
|
||||||
|
|
||||||
/* panics the simulator */
|
|
||||||
__attribute__((format(printf, 2, 3)))
|
|
||||||
_Noreturn void sim_dump(struct simulator *sim, const char *format, ...);
|
|
||||||
|
|
||||||
/* dumps registers */
|
|
||||||
void sim_dump_reg(struct simulator *sim);
|
|
||||||
|
|
||||||
#endif /* __SIM_H__ */
|
|
||||||
|
|
|
@ -1,25 +1,17 @@
|
||||||
|
CC=afl-cc
|
||||||
|
LD=afl-cc
|
||||||
|
|
||||||
BIN=../bin
|
BIN=../bin
|
||||||
|
|
||||||
ASM = $(shell find ./masm -type f -name "*.asm")
|
.PHONY: masm mld msim
|
||||||
OBJ = $(patsubst ./masm/%.asm,./mld/%.o,$(ASM))
|
|
||||||
ELF = $(patsubst ./mld/%.o,./msim/%,$(OBJ))
|
|
||||||
TEST = $(patsubst ./msim/%,%,$(ELF))
|
|
||||||
|
|
||||||
.PHONY: build clean
|
masm:
|
||||||
|
make -C ../masm clean build CC=$(CC) LD=$(LD)
|
||||||
|
$(BIN)/masm/masm -o ./mld/test.o ./masm/test.asm
|
||||||
|
|
||||||
build: $(TEST)
|
mld:
|
||||||
|
make -C ../mld clean build CC=$(CC) LD=$(LD)
|
||||||
|
$(BIN)/mld/mld -o ./msim/test ./mld/test.o
|
||||||
|
|
||||||
clean:
|
msim:
|
||||||
rm -fr ./mld
|
make -C ../msim clean build CC=$(CC) LD=$(LD)
|
||||||
rm -fr ./msim
|
|
||||||
|
|
||||||
$(OBJ): ./mld/%.o : ./masm/%.asm
|
|
||||||
@mkdir -p $(@D)
|
|
||||||
$(BIN)/masm/masm -o $@ $<
|
|
||||||
|
|
||||||
$(ELF): ./msim/% : ./mld/%.o ../lib/runtime.asm
|
|
||||||
@mkdir -p $(@D)
|
|
||||||
$(BIN)/mld/mld -o $@ $<
|
|
||||||
|
|
||||||
$(TEST): % : ./msim/%
|
|
||||||
../tools/test.sh $@
|
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
# Copyright (c) 2024 Freya Murphy
|
|
||||||
|
|
||||||
# file: div.asm
|
|
||||||
# test: should cause floting point exception
|
|
||||||
|
|
||||||
.text
|
|
||||||
.align 2
|
|
||||||
.globl main
|
|
||||||
|
|
||||||
main:
|
|
||||||
# divide by zero
|
|
||||||
li $t0, 0
|
|
||||||
div $t0, $t0, $t0
|
|
||||||
|
|
||||||
# return
|
|
||||||
li $v0, 0
|
|
||||||
jr $ra
|
|
|
@ -1,15 +0,0 @@
|
||||||
# Copyright (c) 2024 Freya Murphy
|
|
||||||
|
|
||||||
# file: div.asm
|
|
||||||
# test: should cause page fault
|
|
||||||
|
|
||||||
.text
|
|
||||||
.align 2
|
|
||||||
.globl main
|
|
||||||
|
|
||||||
main:
|
|
||||||
lw $t0, 0($zero)
|
|
||||||
|
|
||||||
# return
|
|
||||||
li $v0, 0
|
|
||||||
jr $ra
|
|
|
@ -1,29 +0,0 @@
|
||||||
# Copyright (c) 2024 Freya Murphy
|
|
||||||
|
|
||||||
# file: fncall.asm
|
|
||||||
# test: should return value from function call
|
|
||||||
|
|
||||||
.text
|
|
||||||
.align 2
|
|
||||||
.globl main
|
|
||||||
|
|
||||||
result:
|
|
||||||
move $t0, $a0
|
|
||||||
move $v0, $t0
|
|
||||||
jr $ra
|
|
||||||
|
|
||||||
main:
|
|
||||||
# save ra on stack
|
|
||||||
addi $sp, $sp, -4
|
|
||||||
sw $ra, 0($sp)
|
|
||||||
|
|
||||||
# set return to 17
|
|
||||||
li $a0, 17
|
|
||||||
jal result
|
|
||||||
|
|
||||||
# pop ra from stack
|
|
||||||
lw $ra, 0($sp)
|
|
||||||
addi $sp, $sp, 4
|
|
||||||
|
|
||||||
# return result
|
|
||||||
jr $ra
|
|
|
@ -1,26 +0,0 @@
|
||||||
# Copyright (c) 2024 Freya Murphy
|
|
||||||
|
|
||||||
# file: div.asm
|
|
||||||
# test: should print hello world
|
|
||||||
|
|
||||||
.data
|
|
||||||
.align 1
|
|
||||||
|
|
||||||
hw:
|
|
||||||
.asciiz "Hello, world!\n"
|
|
||||||
|
|
||||||
.text
|
|
||||||
.align 2
|
|
||||||
.globl main
|
|
||||||
|
|
||||||
main:
|
|
||||||
# print hello world
|
|
||||||
li $v0, 1
|
|
||||||
li $a0, 1 # stdout
|
|
||||||
la $a1, hw # load string
|
|
||||||
li $a2, 14 # load length
|
|
||||||
syscall
|
|
||||||
|
|
||||||
# return 1
|
|
||||||
li $v0, 0
|
|
||||||
jr $ra
|
|
242
test/masm/test.asm
Normal file
242
test/masm/test.asm
Normal file
|
@ -0,0 +1,242 @@
|
||||||
|
# Copyright (c) 2024 Freya Murphy
|
||||||
|
|
||||||
|
.data
|
||||||
|
.align 2
|
||||||
|
|
||||||
|
heap_start:
|
||||||
|
.space 4
|
||||||
|
heap_len:
|
||||||
|
.space 4
|
||||||
|
heap_free:
|
||||||
|
.space 4
|
||||||
|
heap_ptr:
|
||||||
|
.space 4
|
||||||
|
|
||||||
|
null:
|
||||||
|
.space 4
|
||||||
|
|
||||||
|
.text
|
||||||
|
.align 2
|
||||||
|
.globl main
|
||||||
|
|
||||||
|
# init the heap
|
||||||
|
heap_init:
|
||||||
|
# sbrk(0)
|
||||||
|
li $v0, 9
|
||||||
|
li $a0, 0
|
||||||
|
syscall
|
||||||
|
sw $v0, heap_start
|
||||||
|
sw $v1, heap_len
|
||||||
|
|
||||||
|
# heap is empty, ptr at start
|
||||||
|
sw $v0, heap_ptr
|
||||||
|
# heap is empty, size = len
|
||||||
|
sw $v1, heap_free
|
||||||
|
|
||||||
|
jr $ra
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# $a0 : amount of bytes to increase
|
||||||
|
heap_increase:
|
||||||
|
# t0 : OLD heap len + 1
|
||||||
|
# t1 : heap ptr
|
||||||
|
# t2 : heap end
|
||||||
|
# t2 : heap free
|
||||||
|
# t3 : a0
|
||||||
|
|
||||||
|
# save current length
|
||||||
|
lw $t0, heap_len
|
||||||
|
|
||||||
|
# save a0
|
||||||
|
move $t3, $a0
|
||||||
|
|
||||||
|
# sbrk(amt)
|
||||||
|
li $v0, 9
|
||||||
|
syscall
|
||||||
|
# sbrk(0)
|
||||||
|
li $v0, 9
|
||||||
|
li $a0, 0
|
||||||
|
syscall
|
||||||
|
sw $v0, heap_start
|
||||||
|
sw $v1, heap_len
|
||||||
|
|
||||||
|
lw $t1, heap_ptr # heap ptr
|
||||||
|
add $t2, $v0, $v1 # heap end
|
||||||
|
sub $t3, $t2, $t1 # heap free
|
||||||
|
sw $t3, heap_free
|
||||||
|
|
||||||
|
# set return code to 1 if fail to allocate
|
||||||
|
# i.e. $v1 = $t0 or ($v1 < $t0 + 1)
|
||||||
|
# i.e. heap size hasen't changed
|
||||||
|
addi $t0, $t0, 1
|
||||||
|
slt $v0, $v1, $t0
|
||||||
|
jr $ra
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# $a0 : amount of bytes to allocate
|
||||||
|
malloc:
|
||||||
|
# t0 : heap free + 1
|
||||||
|
# t1 : if enough mem is free
|
||||||
|
# t2 : alloc size [(a0 align 4) + 4096 + 4]
|
||||||
|
# t3 : temp for heap_ptr
|
||||||
|
# t7 : alloc amt (a0 align 4) + 4
|
||||||
|
# t8 : temp for modulo
|
||||||
|
|
||||||
|
# save $a0
|
||||||
|
move $t7, $a0
|
||||||
|
addi $t7, $t7, 4 # add 4 bytes to save INTERAL ptr size
|
||||||
|
|
||||||
|
# align $t7 by 4
|
||||||
|
# allows us to use lw and sw in realloc
|
||||||
|
li $t8, 4
|
||||||
|
div $t8, $t7, $t8
|
||||||
|
mfhi $t8
|
||||||
|
beq $t8, $zero, malloc_aligned
|
||||||
|
addi $t7, $t7, 4
|
||||||
|
sub $t7, $t7, $t8
|
||||||
|
|
||||||
|
malloc_aligned:
|
||||||
|
# check if we have enough memory free
|
||||||
|
lw $t0, heap_free
|
||||||
|
addi $t0, $t0, 1
|
||||||
|
slt $t1, $t7, $t0
|
||||||
|
bne $t1, $zero, malloc_hasmem
|
||||||
|
|
||||||
|
# set needed mem to alloc
|
||||||
|
# page size + alloc request
|
||||||
|
|
||||||
|
# save $ra and $t7
|
||||||
|
addi $sp, $sp, -8
|
||||||
|
sw $ra, 0($sp)
|
||||||
|
sw $t7, 4($sp)
|
||||||
|
|
||||||
|
li $t2, 4096
|
||||||
|
add $t2, $t2, $t7
|
||||||
|
move $a0, $t2
|
||||||
|
jal heap_increase
|
||||||
|
|
||||||
|
# pop $ra and $t7
|
||||||
|
lw $ra, 0($sp)
|
||||||
|
lw $t7, 4($sp)
|
||||||
|
addi $sp, $sp, 8
|
||||||
|
|
||||||
|
# check heap_increase return code
|
||||||
|
beq $v0, $zero, malloc_hasmem
|
||||||
|
|
||||||
|
malloc_error:
|
||||||
|
# failed to sbrk, return null
|
||||||
|
la $v0, null
|
||||||
|
jr $ra
|
||||||
|
|
||||||
|
malloc_hasmem:
|
||||||
|
# set return value, and save ptr size in it
|
||||||
|
# add 4 to return ptr, since first 4 bytes are INTERNAL
|
||||||
|
addi $t3, $t7, -4
|
||||||
|
lw $v0, heap_ptr
|
||||||
|
sw $t3, ($v0)
|
||||||
|
addi $v0, $v0, 4
|
||||||
|
|
||||||
|
lw $t3, heap_ptr
|
||||||
|
add $t3, $t3, $t7 # increase ptr by alloc size
|
||||||
|
sw $t3, heap_ptr
|
||||||
|
|
||||||
|
jr $ra
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# $a0 : address of ptr
|
||||||
|
free:
|
||||||
|
# haha hehe hoho
|
||||||
|
jr $ra
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# $a0 : new size
|
||||||
|
# $a1 : old ptr
|
||||||
|
realloc:
|
||||||
|
# t0 : old ptr size
|
||||||
|
# t2 : new ptr addr
|
||||||
|
|
||||||
|
# check if $a0 is zero, if so then just free
|
||||||
|
bne $a0, $zero, realloc_inner
|
||||||
|
move $a0, $a1
|
||||||
|
la $v0, null
|
||||||
|
j free
|
||||||
|
|
||||||
|
# save to stack
|
||||||
|
addi $sp, $sp, -12
|
||||||
|
sw $ra, 0($sp)
|
||||||
|
sw $a0, 4($sp)
|
||||||
|
sw $a1, 8($sp)
|
||||||
|
|
||||||
|
jal malloc
|
||||||
|
|
||||||
|
# pop to stack
|
||||||
|
lw $ra, 0($sp)
|
||||||
|
lw $a0, 4($sp)
|
||||||
|
lw $a1, 8($sp)
|
||||||
|
addi $sp, $sp, 12
|
||||||
|
|
||||||
|
realloc_inner:
|
||||||
|
addi $a1, $a1, -4
|
||||||
|
lw $t0, ($a1)
|
||||||
|
addi $a1, $a1, 4
|
||||||
|
|
||||||
|
realloc_loop:
|
||||||
|
# loop until $t0 or $t1 is zero
|
||||||
|
beq $t0, $zero, realloc_end
|
||||||
|
beq $a0, $zero, realloc_end
|
||||||
|
|
||||||
|
addi $a1, $a1, 4
|
||||||
|
addi $t0, $t0, -4
|
||||||
|
addi $a0, $a0, -4
|
||||||
|
#lw $t3,
|
||||||
|
|
||||||
|
j realloc_loop
|
||||||
|
|
||||||
|
realloc_end:
|
||||||
|
|
||||||
|
|
||||||
|
realloc_free:
|
||||||
|
jr $ra
|
||||||
|
|
||||||
|
|
||||||
|
main:
|
||||||
|
# push return address
|
||||||
|
addi $sp, $sp, -4
|
||||||
|
sw $ra, ($sp)
|
||||||
|
|
||||||
|
jal heap_init
|
||||||
|
|
||||||
|
li $a0, 24
|
||||||
|
jal malloc
|
||||||
|
|
||||||
|
move $a0, $v0
|
||||||
|
li $v0, 1
|
||||||
|
syscall
|
||||||
|
|
||||||
|
li $v0, 11
|
||||||
|
li $a0, 10
|
||||||
|
syscall
|
||||||
|
|
||||||
|
li $a0, 24
|
||||||
|
jal malloc
|
||||||
|
|
||||||
|
move $a0, $v0
|
||||||
|
li $v0, 1
|
||||||
|
syscall
|
||||||
|
|
||||||
|
li $v0, 11
|
||||||
|
li $a0, 10
|
||||||
|
syscall
|
||||||
|
|
||||||
|
# pop return address
|
||||||
|
lw $ra, ($sp)
|
||||||
|
addi $sp, $sp, 4
|
||||||
|
|
||||||
|
exit:
|
||||||
|
# exit with code 0
|
||||||
|
li $v0, 0
|
||||||
|
jr $ra
|
BIN
test/mld/test.o
Normal file
BIN
test/mld/test.o
Normal file
Binary file not shown.
BIN
test/msim/test
Normal file
BIN
test/msim/test
Normal file
Binary file not shown.
15
test/out/div
15
test/out/div
|
@ -1,15 +0,0 @@
|
||||||
|
|
||||||
!!! An exception has occurred !!!
|
|
||||||
|
|
||||||
[31merror: [0mfloating point exception
|
|
||||||
pc: 0x00400004
|
|
||||||
ins: 0x0108409a
|
|
||||||
registers:
|
|
||||||
$zero: 0x00000000 $t0: 0x00000000 $s0: 0x00000000 $t8: 0x00000000
|
|
||||||
$at: 0x00000000 $t1: 0x00000000 $s1: 0x00000000 $t9: 0x00000000
|
|
||||||
$v0: 0x00000000 $t2: 0x00000000 $s2: 0x00000000 $k0: 0x00000000
|
|
||||||
$v1: 0x00000000 $t3: 0x00000000 $s3: 0x00000000 $k1: 0x00000000
|
|
||||||
$a0: 0x00000000 $t4: 0x00000000 $s4: 0x00000000 $gp: 0x00000000
|
|
||||||
$a1: 0x00000000 $t5: 0x00000000 $s5: 0x00000000 $sp: 0x10001000
|
|
||||||
$a2: 0x00000000 $t6: 0x00000000 $s6: 0x00000000 $fp: 0x00000000
|
|
||||||
$a3: 0x00000000 $t7: 0x00000000 $s7: 0x00000000 $ra: 0x0040001c
|
|
|
@ -1 +0,0 @@
|
||||||
1
|
|
|
@ -1,15 +0,0 @@
|
||||||
|
|
||||||
!!! An exception has occurred !!!
|
|
||||||
|
|
||||||
[31merror: [0mpage fault at (nil): address not mapped to object
|
|
||||||
pc: 0x00400000
|
|
||||||
ins: 0x8c080000
|
|
||||||
registers:
|
|
||||||
$zero: 0x00000000 $t0: 0x00000000 $s0: 0x00000000 $t8: 0x00000000
|
|
||||||
$at: 0x00000000 $t1: 0x00000000 $s1: 0x00000000 $t9: 0x00000000
|
|
||||||
$v0: 0x00000000 $t2: 0x00000000 $s2: 0x00000000 $k0: 0x00000000
|
|
||||||
$v1: 0x00000000 $t3: 0x00000000 $s3: 0x00000000 $k1: 0x00000000
|
|
||||||
$a0: 0x00000000 $t4: 0x00000000 $s4: 0x00000000 $gp: 0x00000000
|
|
||||||
$a1: 0x00000000 $t5: 0x00000000 $s5: 0x00000000 $sp: 0x10001000
|
|
||||||
$a2: 0x00000000 $t6: 0x00000000 $s6: 0x00000000 $fp: 0x00000000
|
|
||||||
$a3: 0x00000000 $t7: 0x00000000 $s7: 0x00000000 $ra: 0x00400018
|
|
|
@ -1 +0,0 @@
|
||||||
1
|
|
|
@ -1 +0,0 @@
|
||||||
17
|
|
|
@ -1 +0,0 @@
|
||||||
Hello, world!
|
|
|
@ -1 +0,0 @@
|
||||||
0
|
|
|
@ -1,41 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
#
|
|
||||||
# tests a binary
|
|
||||||
# against a output and an exit code
|
|
||||||
#
|
|
||||||
|
|
||||||
dir="$(dirname "$0")"
|
|
||||||
|
|
||||||
msim="$dir/../bin/msim/msim"
|
|
||||||
bin="$dir/../test/msim/$1"
|
|
||||||
|
|
||||||
out=$(cat "$dir/../test/out/$1")
|
|
||||||
status=$(cat "$dir/../test/out/$1.status")
|
|
||||||
|
|
||||||
temp=$(mktemp)
|
|
||||||
|
|
||||||
$msim $bin &> $temp
|
|
||||||
|
|
||||||
rstatus="$?"
|
|
||||||
rout=$(cat $temp)
|
|
||||||
rm $temp
|
|
||||||
|
|
||||||
res=0
|
|
||||||
|
|
||||||
if [ "$out" != "$rout" ]; then
|
|
||||||
res=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$status" != "$rstatus" ]; then
|
|
||||||
res=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $res = 0 ]; then
|
|
||||||
printf "\033[32mPASSED\033[0m\n"
|
|
||||||
else
|
|
||||||
printf "\033[31mFAILED\033[0m\n"
|
|
||||||
diff <(echo $out) <(echo $rout)
|
|
||||||
fi
|
|
||||||
|
|
||||||
exit $res
|
|
Loading…
Reference in a new issue