Compare commits
6 commits
4af200b001
...
091c684bf1
Author | SHA1 | Date | |
---|---|---|---|
091c684bf1 | |||
16ebc059d9 | |||
4c6668f2b6 | |||
12e098b682 | |||
fb07130990 | |||
853a1ba612 |
24 changed files with 352 additions and 136 deletions
|
@ -304,7 +304,8 @@ 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, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_JALR)
|
MIPS_INS(JALR, .rd = MIPS_REG_RA, .op = MIPS_OP_SPECIAL,
|
||||||
|
.funct = MIPS_FUNCT_JALR)
|
||||||
|
|
||||||
/* JALX - jump and link exchange */
|
/* JALX - jump and link exchange */
|
||||||
#define MIPS_OP_JALX 0b011101
|
#define MIPS_OP_JALX 0b011101
|
||||||
|
|
|
@ -23,6 +23,7 @@ _start:
|
||||||
|
|
||||||
# call main
|
# call main
|
||||||
jal main
|
jal main
|
||||||
|
nop
|
||||||
|
|
||||||
# exit
|
# exit
|
||||||
move $a0, $v0
|
move $a0, $v0
|
||||||
|
|
15
masm/parse.c
15
masm/parse.c
|
@ -889,6 +889,17 @@ 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)
|
||||||
|
@ -911,6 +922,10 @@ 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
|
||||||
|
|
46
mld/link.c
46
mld/link.c
|
@ -12,8 +12,6 @@
|
||||||
#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;
|
||||||
|
@ -168,7 +166,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)
|
if (shndx == 0 || shndx == SHN_ABS)
|
||||||
return M_SUCCESS; // ignore this symbol
|
return M_SUCCESS; // ignore this symbol
|
||||||
|
|
||||||
// find the given section
|
// find the given section
|
||||||
|
@ -184,11 +182,9 @@ 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++) {
|
||||||
Elf32_Phdr *temp = &obj->phdr[i];
|
if (obj->phdr_to_shdr_mapping[i] == shndx) {
|
||||||
if (PHDR_SHDR_MATCH(temp, shdr)) {
|
|
||||||
sec = &obj->segments[i];
|
sec = &obj->segments[i];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -219,6 +215,20 @@ 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;
|
||||||
|
@ -447,33 +457,38 @@ 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);
|
||||||
|
@ -596,9 +611,6 @@ 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");
|
||||||
|
@ -739,12 +751,16 @@ 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)
|
||||||
|
|
|
@ -35,6 +35,9 @@
|
||||||
#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;
|
||||||
|
@ -42,6 +45,7 @@ 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
|
||||||
|
@ -220,6 +224,10 @@ 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
105
mld/obj.c
|
@ -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,23 +81,94 @@ 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 (BOUND_CHK(object, phdr_len, phdr_off)) {
|
//if (phdr_len < 1)
|
||||||
ERROR("cannot read phdr");
|
return create_phdr(object);
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
//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 (BOUND_CHK(object, phdr_len, phdr_off)) {
|
||||||
|
// ERROR("cannot read phdr");
|
||||||
|
// return M_ERROR;
|
||||||
|
//}
|
||||||
|
|
||||||
|
//return M_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -231,7 +302,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 = B16(object->ehdr->e_phnum);
|
object->segment_len = object->phdr_len;
|
||||||
object->segments = malloc(sizeof(struct segment) *
|
object->segments = malloc(sizeof(struct segment) *
|
||||||
object->segment_len);
|
object->segment_len);
|
||||||
|
|
||||||
|
@ -287,6 +358,8 @@ 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))
|
||||||
|
@ -331,6 +404,10 @@ 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)
|
||||||
|
|
54
mld/seg.c
54
mld/seg.c
|
@ -25,43 +25,29 @@ 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)
|
||||||
{
|
{
|
||||||
bool found = false;
|
uint32_t shndx = obj->phdr_to_shdr_mapping[index];
|
||||||
|
Elf32_Shdr *hdr = &obj->shdr[shndx];
|
||||||
|
|
||||||
for (size_t i = 0; i < obj->shdr_len; i++) {
|
// get name
|
||||||
Elf32_Shdr *hdr = &obj->shdr[i];
|
uint32_t name = B32(hdr->sh_name);
|
||||||
|
if (name >= obj->shstrtab->len) {
|
||||||
// find shdr that matches the offset in phdr
|
ERROR("section name index [%d] out of bounds", name);
|
||||||
if (!PHDR_SHDR_MATCH(seg->phdr, hdr))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// get name
|
|
||||||
uint32_t name = B32(hdr->sh_name);
|
|
||||||
if (name >= obj->shstrtab->len) {
|
|
||||||
ERROR("section name index [%d] out of bounds", name);
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
seg->name = &obj->shstrtab->data[name];
|
|
||||||
|
|
||||||
// map bytes
|
|
||||||
uint32_t len = B32(hdr->sh_size);
|
|
||||||
uint32_t off = B32(hdr->sh_offset);
|
|
||||||
seg->bytes = (unsigned char *) (obj->mapped + off);
|
|
||||||
|
|
||||||
if (BOUND_CHK(obj, len, off)) {
|
|
||||||
ERROR("cannot map seg %s:%d", seg->name, index);
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
found = true;
|
|
||||||
seg->shdr = hdr;
|
|
||||||
seg->shdr_idx = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found) {
|
|
||||||
ERROR("cannot find shdr for segment [%d]", index);
|
|
||||||
return M_ERROR;
|
return M_ERROR;
|
||||||
}
|
}
|
||||||
|
seg->name = &obj->shstrtab->data[name];
|
||||||
|
|
||||||
|
// map bytes
|
||||||
|
uint32_t len = B32(hdr->sh_size);
|
||||||
|
uint32_t off = B32(hdr->sh_offset);
|
||||||
|
seg->bytes = (unsigned char *) (obj->mapped + off);
|
||||||
|
|
||||||
|
if (BOUND_CHK(obj, len, off)) {
|
||||||
|
ERROR("cannot map seg %s:%d", seg->name, index);
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
seg->shdr = hdr;
|
||||||
|
seg->shdr_idx = shndx;
|
||||||
|
|
||||||
return M_SUCCESS;
|
return M_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,10 @@ 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 &&
|
||||||
|
|
177
msim/ins.c
177
msim/ins.c
|
@ -1,25 +1,74 @@
|
||||||
#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"
|
||||||
|
|
||||||
#define I16(n) ((int32_t)(uint16_t)(n))
|
/* sign extension */
|
||||||
|
#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] = ((int64_t)sim->reg[ins.rs] /
|
sim->reg[ins.rd] = (SSE64(sim->reg[ins.rs]) *
|
||||||
(int64_t)sim->reg[ins.rt]) >> 0;
|
SSE64(sim->reg[ins.rt])) >> 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MIPS_SOP30_MUH:
|
case MIPS_SOP30_MUH:
|
||||||
sim->reg[ins.rd] = ((int64_t)sim->reg[ins.rs] /
|
sim->reg[ins.rd] = (SSE64(sim->reg[ins.rs]) *
|
||||||
(int64_t)sim->reg[ins.rt]) >> 32;
|
SSE64(sim->reg[ins.rt])) >> 32;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -32,13 +81,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] = ((uint64_t)sim->reg[ins.rs] /
|
sim->reg[ins.rd] = (SE64(sim->reg[ins.rs]) *
|
||||||
(uint64_t)sim->reg[ins.rt]) >> 0;
|
SE64(sim->reg[ins.rt])) >> 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MIPS_SOP31_MUHU:
|
case MIPS_SOP31_MUHU:
|
||||||
sim->reg[ins.rd] = ((uint64_t)sim->reg[ins.rs] /
|
sim->reg[ins.rd] = (SE64(sim->reg[ins.rs]) *
|
||||||
(uint64_t)sim->reg[ins.rt]) >> 32;
|
SE64(sim->reg[ins.rt])) >> 32;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -51,13 +100,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] = (int32_t)sim->reg[ins.rs] /
|
sim->reg[ins.rd] = (signed) sim->reg[ins.rs] /
|
||||||
(int32_t)sim->reg[ins.rt];
|
(signed) sim->reg[ins.rt];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MIPS_SOP32_MOD:
|
case MIPS_SOP32_MOD:
|
||||||
sim->reg[ins.rd] = (int32_t)sim->reg[ins.rs] %
|
sim->reg[ins.rd] = (signed) sim->reg[ins.rs] %
|
||||||
(int32_t)sim->reg[ins.rt];
|
(signed) sim->reg[ins.rt];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -87,8 +136,8 @@ static void sim_ins_special(struct simulator *sim,
|
||||||
{
|
{
|
||||||
switch (ins.funct) {
|
switch (ins.funct) {
|
||||||
case MIPS_FUNCT_ADD:
|
case MIPS_FUNCT_ADD:
|
||||||
sim->reg[ins.rd] = (int32_t)sim->reg[ins.rs] +
|
// TODO: trap on overflow
|
||||||
(int32_t)sim->reg[ins.rt];
|
sim->reg[ins.rd] = sim->reg[ins.rs] + sim->reg[ins.rt];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MIPS_FUNCT_ADDU:
|
case MIPS_FUNCT_ADDU:
|
||||||
|
@ -116,9 +165,10 @@ static void sim_ins_special(struct simulator *sim,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MIPS_FUNCT_JALR:
|
case MIPS_FUNCT_JALR:
|
||||||
sim->reg[MIPS_REG_RA] = sim->pc;
|
sim->reg[ins.rd] = sim->pc + 4;
|
||||||
/* 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;
|
||||||
|
|
||||||
|
@ -147,7 +197,8 @@ static void sim_ins_special(struct simulator *sim,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MIPS_FUNCT_SLT:
|
case MIPS_FUNCT_SLT:
|
||||||
sim->reg[ins.rd] = (int32_t)sim->reg[ins.rs] < (int32_t)sim->reg[ins.rt] ? 1 : 0;
|
sim->reg[ins.rd] = (signed) sim->reg[ins.rs] <
|
||||||
|
(signed) sim->reg[ins.rt] ? 1 : 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MIPS_FUNCT_SLTU:
|
case MIPS_FUNCT_SLTU:
|
||||||
|
@ -155,11 +206,12 @@ static void sim_ins_special(struct simulator *sim,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MIPS_FUNCT_SRA:
|
case MIPS_FUNCT_SRA:
|
||||||
sim->reg[ins.rd] = (int32_t)sim->reg[ins.rt] >> ins.shamt;
|
sim->reg[ins.rd] = (signed) sim->reg[ins.rt] >> ins.shamt;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MIPS_FUNCT_SRAV:
|
case MIPS_FUNCT_SRAV:
|
||||||
sim->reg[ins.rd] = (int32_t)sim->reg[ins.rt] >> sim->reg[ins.rs];
|
sim->reg[ins.rd] = (signed) sim->reg[ins.rt] >>
|
||||||
|
sim->reg[ins.rs];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MIPS_FUNCT_SRL:
|
case MIPS_FUNCT_SRL:
|
||||||
|
@ -171,8 +223,8 @@ static void sim_ins_special(struct simulator *sim,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MIPS_FUNCT_SUB:
|
case MIPS_FUNCT_SUB:
|
||||||
sim->reg[ins.rd] = (int32_t)sim->reg[ins.rs] -
|
// TODO: trap on overflow
|
||||||
(int32_t)sim->reg[ins.rt];
|
sim->reg[ins.rd] = sim->reg[ins.rs] - sim->reg[ins.rt];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MIPS_FUNCT_SUBU:
|
case MIPS_FUNCT_SUBU:
|
||||||
|
@ -209,29 +261,33 @@ 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;
|
sim->reg[MIPS_REG_RA] = sim->pc + 4;
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case MIPS_FUNCT_BGEZ:
|
case MIPS_FUNCT_BGEZ:
|
||||||
case MIPS_FUNCT_BGEZL:
|
case MIPS_FUNCT_BGEZL:
|
||||||
if ((int32_t)sim->reg[ins.rs] >= 0)
|
sim_delay_slot(sim);
|
||||||
sim->pc += ins.offset << 2;
|
if ((signed) sim->reg[ins.rs] >= 0)
|
||||||
|
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;
|
sim->reg[MIPS_REG_RA] = sim->pc + 4;
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case MIPS_FUNCT_BLTZ:
|
case MIPS_FUNCT_BLTZ:
|
||||||
case MIPS_FUNCT_BLTZL:
|
case MIPS_FUNCT_BLTZL:
|
||||||
if ((int32_t)sim->reg[ins.rs] < 0)
|
sim_delay_slot(sim);
|
||||||
sim->pc += ins.offset << 2;
|
if ((signed) sim->reg[ins.rs] < 0)
|
||||||
|
sim->pc = pc + SSE(ins.offset, 2);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
sim_dump(sim, "unknown bfunct (0b%06b)", ins.bfunct);
|
sim_dump(sim, "unknown branch funct (0b%06b)", ins.bfunct);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,6 +297,7 @@ 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;
|
||||||
|
@ -256,73 +313,75 @@ 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] +
|
||||||
(int16_t) ins.immd;
|
SE(ins.immd);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MIPS_OP_ADDIU:
|
case MIPS_OP_ADDIU:
|
||||||
sim->reg[ins.rt] = sim->reg[ins.rs] + ins.immd;
|
sim->reg[ins.rt] = sim->reg[ins.rs] + SE(ins.immd);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MIPS_OP_ANDI:
|
case MIPS_OP_ANDI:
|
||||||
sim->reg[ins.rt] = sim->reg[ins.rs] & ins.immd;
|
sim->reg[ins.rt] = sim->reg[ins.rs] & ZE(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 += ins.offs26 << 2;
|
sim->pc += SSE(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 += ins.offset << 2;
|
sim->pc = pc + SSE(ins.offset, 2);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MIPS_OP_BGTZ:
|
case MIPS_OP_BGTZ:
|
||||||
case MIPS_OP_BGTZL:
|
case MIPS_OP_BGTZL:
|
||||||
if ((int32_t)sim->reg[ins.rs] <= 0)
|
sim_delay_slot(sim);
|
||||||
sim->pc += ins.offset << 2;
|
if ((signed) sim->reg[ins.rs] <= 0)
|
||||||
|
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:
|
||||||
if ((int32_t)sim->reg[ins.rs] <= 0)
|
sim_delay_slot(sim);
|
||||||
sim->pc += ins.offset << 2;
|
if ((signed) sim->reg[ins.rs] <= 0)
|
||||||
|
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 += ins.offset << 2;
|
sim->pc = pc + SSE(ins.offset, 2);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MIPS_OP_JAL:
|
case MIPS_OP_JAL:
|
||||||
sim->reg[MIPS_REG_RA] = sim->pc;
|
sim->reg[MIPS_REG_RA] = sim->pc + 4;
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case MIPS_OP_J:
|
case MIPS_OP_J:
|
||||||
sim->pc = ins.target << 2;
|
sim_delay_slot(sim);
|
||||||
|
sim->pc &= 0xF0000000;
|
||||||
|
sim->pc |= ins.target << 2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MIPS_OP_LB:
|
case MIPS_OP_LB:
|
||||||
sim->reg[ins.rt] = * (int8_t *) (uintptr_t) (sim->reg[ins.rs]
|
sim->reg[ins.rt] = *PTR(VADDR(sim, ins), int8_t);
|
||||||
+ ins.offset);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MIPS_OP_LBU:
|
case MIPS_OP_LBU:
|
||||||
sim->reg[ins.rt] = * (uint8_t *) (uintptr_t) (sim->reg[ins.rs]
|
sim->reg[ins.rt] = *PTR(VADDR(sim, ins), uint8_t);
|
||||||
+ ins.offset);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MIPS_OP_LH:
|
case MIPS_OP_LH:
|
||||||
sim->reg[ins.rt] = * (int16_t *) (uintptr_t) (sim->reg[ins.rs]
|
sim->reg[ins.rt] = *PTR(VADDR(sim, ins), int16_t);
|
||||||
+ ins.offset);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MIPS_OP_LHU:
|
case MIPS_OP_LHU:
|
||||||
sim->reg[ins.rt] = * (uint16_t *) (uintptr_t) (sim->reg[ins.rs]
|
sim->reg[ins.rt] = *PTR(VADDR(sim, ins), uint16_t);
|
||||||
+ ins.offset);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MIPS_OP_LUI:
|
case MIPS_OP_LUI:
|
||||||
|
@ -330,32 +389,28 @@ void sim_ins(struct simulator *sim, uint32_t raw)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MIPS_OP_LW:
|
case MIPS_OP_LW:
|
||||||
sim->reg[ins.rt] = * (uint32_t *) (uintptr_t) (sim->reg[ins.rs]
|
sim->reg[ins.rt] = *PTR(VADDR(sim, ins), uint32_t);
|
||||||
+ ins.offset);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MIPS_OP_SB:
|
case MIPS_OP_SB:
|
||||||
* (uint8_t *) (uintptr_t) (sim->reg[ins.rs] +
|
*PTR(VADDR(sim, ins), uint8_t) = sim->reg[ins.rt];
|
||||||
+ ins.offset) = sim->reg[ins.rt];
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MIPS_OP_SH:
|
case MIPS_OP_SH:
|
||||||
* (uint16_t *) (uintptr_t) (sim->reg[ins.rs] +
|
*PTR(VADDR(sim, ins), uint16_t) = sim->reg[ins.rt];
|
||||||
ins.offset) = sim->reg[ins.rt];
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MIPS_OP_SW:
|
case MIPS_OP_SW:
|
||||||
* (uint32_t *) (uintptr_t) (sim->reg[ins.rs] +
|
*PTR(VADDR(sim, ins), uint32_t) = sim->reg[ins.rt];
|
||||||
ins.offset) = sim->reg[ins.rt];
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MIPS_OP_SLTI:
|
case MIPS_OP_SLTI:
|
||||||
sim->reg[ins.rt] = (int32_t)sim->reg[ins.rs] <
|
sim->reg[ins.rt] = (signed) sim->reg[ins.rs] <
|
||||||
(int16_t)ins.immd ? 1 : 0;
|
(signed) SE(ins.immd) ? 1 : 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MIPS_OP_SLTIU:
|
case MIPS_OP_SLTIU:
|
||||||
sim->reg[ins.rt] = sim->reg[ins.rs] < ins.immd ? 1 : 0;
|
sim->reg[ins.rt] = sim->reg[ins.rs] < SE(ins.immd) ? 1 : 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MIPS_OP_ORI:
|
case MIPS_OP_ORI:
|
||||||
|
|
|
@ -52,12 +52,15 @@ 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));
|
||||||
|
|
11
msim/main.c
11
msim/main.c
|
@ -2,7 +2,6 @@
|
||||||
#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"
|
||||||
|
@ -11,7 +10,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-c\t\tdisable runtime memory checks (allows segfault)\n");
|
printf("\t-j\t\tdisable jump delay slot\n");
|
||||||
printf("\t-d\t\truns the debugger\n");
|
printf("\t-d\t\truns the debugger\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,18 +20,18 @@ int main(int argc, char **argv) {
|
||||||
struct simulator_args args = {
|
struct simulator_args args = {
|
||||||
.executable = NULL,
|
.executable = NULL,
|
||||||
.debug = false,
|
.debug = false,
|
||||||
.memchk = true,
|
.jdelay = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
while ((c = getopt(argc, argv, "hcd")) != 1) {
|
while ((c = getopt(argc, argv, "hjd")) != 1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'h':
|
case 'h':
|
||||||
help();
|
help();
|
||||||
return M_SUCCESS;
|
return M_SUCCESS;
|
||||||
case 'c':
|
case 'j':
|
||||||
args.memchk = false;
|
args.jdelay = false;
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
args.debug = true;
|
args.debug = true;
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
/// arguments
|
/// arguments
|
||||||
struct simulator_args {
|
struct simulator_args {
|
||||||
char *executable;
|
char *executable;
|
||||||
bool memchk;
|
bool jdelay;
|
||||||
bool debug;
|
bool debug;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ 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
|
||||||
|
@ -20,6 +21,7 @@ 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)
|
||||||
|
@ -27,3 +29,4 @@ main:
|
||||||
|
|
||||||
# return result
|
# return result
|
||||||
jr $ra
|
jr $ra
|
||||||
|
nop
|
||||||
|
|
|
@ -15,3 +15,4 @@ main:
|
||||||
# return
|
# return
|
||||||
li $v0, 0
|
li $v0, 0
|
||||||
jr $ra
|
jr $ra
|
||||||
|
nop
|
|
@ -24,3 +24,4 @@ main:
|
||||||
# return 1
|
# return 1
|
||||||
li $v0, 0
|
li $v0, 0
|
||||||
jr $ra
|
jr $ra
|
||||||
|
nop
|
||||||
|
|
41
test/masm/recursion.asm
Normal file
41
test/masm/recursion.asm
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
# 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
|
|
@ -13,3 +13,4 @@ main:
|
||||||
# return
|
# return
|
||||||
li $v0, 0
|
li $v0, 0
|
||||||
jr $ra
|
jr $ra
|
||||||
|
nop
|
|
@ -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: 0x0040001c
|
$a3: 0x00000000 $t7: 0x00000000 $s7: 0x00000000 $ra: 0x00400024
|
0
test/out/recursion
Normal file
0
test/out/recursion
Normal file
1
test/out/recursion.status
Normal file
1
test/out/recursion.status
Normal file
|
@ -0,0 +1 @@
|
||||||
|
15
|
|
@ -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: 0x00400018
|
$a3: 0x00000000 $t7: 0x00000000 $s7: 0x00000000 $ra: 0x00400020
|
|
@ -35,7 +35,10 @@ 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"
|
||||||
diff <(echo $out) <(echo $rout)
|
if [ "$status" != "$rstatus" ]; then
|
||||||
|
printf "exit: $rstatus (should be $status)\n"
|
||||||
|
fi
|
||||||
|
diff -Nau <(printf "%s\n" "$out") <(printf "%s\n" "$rout")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
exit $res
|
exit $res
|
||||||
|
|
Loading…
Reference in a new issue