multitude of mld fixes, add entrypoint
This commit is contained in:
parent
fff0444f6c
commit
49af3bfc62
7 changed files with 88 additions and 30 deletions
29
lib/runtime.asm
Normal file
29
lib/runtime.asm
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#
|
||||||
|
# MIPS32r6 ASSEMBLY RUNTIME
|
||||||
|
# - sets up the stack
|
||||||
|
# - calls main
|
||||||
|
# - exits
|
||||||
|
#
|
||||||
|
|
||||||
|
.extern main
|
||||||
|
|
||||||
|
.stack
|
||||||
|
.align 2
|
||||||
|
|
||||||
|
.space 4096
|
||||||
|
__mips_stack:
|
||||||
|
|
||||||
|
.text
|
||||||
|
.align 2
|
||||||
|
|
||||||
|
_start:
|
||||||
|
# setup stack
|
||||||
|
la $sp, __mips_stack
|
||||||
|
|
||||||
|
# call main
|
||||||
|
jal main
|
||||||
|
|
||||||
|
# exit
|
||||||
|
move $a0, $v0
|
||||||
|
li $v0, 1
|
||||||
|
syscall
|
|
@ -4,4 +4,6 @@ SRC=.
|
||||||
BIN=../bin/mld
|
BIN=../bin/mld
|
||||||
OUT=mld
|
OUT=mld
|
||||||
|
|
||||||
|
CFLAGS += -DPREFIX=$(PREFIX)
|
||||||
|
|
||||||
include ../makefile.mk
|
include ../makefile.mk
|
||||||
|
|
61
mld/link.c
61
mld/link.c
|
@ -16,8 +16,11 @@
|
||||||
|
|
||||||
static int load_objects(struct linker *linker)
|
static int load_objects(struct linker *linker)
|
||||||
{
|
{
|
||||||
|
int max_entries = linker->args->in_count + 1;
|
||||||
|
// 1 needed for the runtime
|
||||||
|
|
||||||
linker->objects = malloc(sizeof(struct object) *
|
linker->objects = malloc(sizeof(struct object) *
|
||||||
linker->args->in_count);
|
max_entries);
|
||||||
linker->obj_len = 0;
|
linker->obj_len = 0;
|
||||||
|
|
||||||
if (linker->objects == NULL) {
|
if (linker->objects == NULL) {
|
||||||
|
@ -46,6 +49,19 @@ static int load_objects(struct linker *linker)
|
||||||
skip_obj:
|
skip_obj:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (linker->args->freestanding == false) {
|
||||||
|
#define _STR(x) _STR2(x)
|
||||||
|
#define _STR2(x) #x
|
||||||
|
|
||||||
|
char *path = _STR(PREFIX) "/lib/mips/runtime.o";
|
||||||
|
struct object *obj = &linker->objects[linker->obj_len++];
|
||||||
|
if (object_load(obj, path))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
#undef _STR
|
||||||
|
#undef _STR2
|
||||||
|
}
|
||||||
|
|
||||||
return M_SUCCESS;
|
return M_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,7 +177,7 @@ static int relocate_symbol(struct linker *linker, struct object *obj,
|
||||||
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];
|
Elf32_Phdr *temp = &obj->phdr[i];
|
||||||
if (shdr->sh_offset == temp->p_offset) {
|
if (PHDR_SHDR_MATCH(temp, shdr)) {
|
||||||
sec = &obj->segments[i];
|
sec = &obj->segments[i];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -386,30 +402,22 @@ static int relocate_instruction_rela(struct linker *linker,
|
||||||
return M_ERROR;
|
return M_ERROR;
|
||||||
}
|
}
|
||||||
Elf32_Sym *sym = &symtab->syms[idx];
|
Elf32_Sym *sym = &symtab->syms[idx];
|
||||||
const char *symname = symtab->strtab->data + B32(sym->st_name);
|
|
||||||
|
|
||||||
|
char const *sym_name = symtab->strtab->data + B32(sym->st_name);
|
||||||
/// get the section header that the symbol is related to
|
if (B32(sym->st_name) >= symtab->strtab->len) {
|
||||||
Elf32_Shdr *shdr = NULL;
|
ERROR("relocation symbol name out of bounds");
|
||||||
if (B16(sym->st_shndx) >= seg->obj->shdr_len) {
|
return M_ERROR;
|
||||||
ERROR("shndx index [%d] out of bounds", B16(sym->st_shndx));
|
}
|
||||||
|
|
||||||
|
// get the new sym for the new vaddr
|
||||||
|
Elf32_Sym *new_sym = NULL;
|
||||||
|
if (symtab_get(&linker->symtab, &new_sym, sym_name)) {
|
||||||
|
ERROR("relocation symbol not found");
|
||||||
return M_ERROR;
|
return M_ERROR;
|
||||||
}
|
}
|
||||||
shdr = &seg->obj->shdr[B16(sym->st_shndx)];
|
|
||||||
|
|
||||||
/// get the segment that the symbol is in
|
/// get the segment that the symbol is in
|
||||||
struct segment_table_entry *ent;
|
uint32_t sym_vaddr = B32(new_sym->st_value);
|
||||||
const char *segname = seg->obj->shstrtab->data + B32(shdr->sh_name);
|
|
||||||
if (B32(shdr->sh_name) >= seg->obj->shstrtab->len) {
|
|
||||||
ERROR("relocation segment name out of bounds");
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
if (segtab_get(&linker->segments, &ent, segname)) {
|
|
||||||
ERROR("could not locate segment for relocation");
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t sym_vaddr = B32(sym->st_value) + ent->vaddr;
|
|
||||||
uint32_t *ins_raw = (uint32_t *) &seg->bytes[off];
|
uint32_t *ins_raw = (uint32_t *) &seg->bytes[off];
|
||||||
|
|
||||||
union mips_instruction_data ins;
|
union mips_instruction_data ins;
|
||||||
|
@ -462,7 +470,7 @@ static int relocate_instruction_rela(struct linker *linker,
|
||||||
*ins_raw = B32(ins.raw);
|
*ins_raw = B32(ins.raw);
|
||||||
|
|
||||||
if (warn)
|
if (warn)
|
||||||
WARNING("truncating relocation for symbol '%s'", symname);
|
WARNING("truncating relocation for symbol '%s'", sym_name);
|
||||||
|
|
||||||
return M_SUCCESS;
|
return M_SUCCESS;
|
||||||
|
|
||||||
|
@ -647,6 +655,15 @@ static int link_executable(struct linker *linker)
|
||||||
ehdr->e_shnum = B16(linker->shdr_len);
|
ehdr->e_shnum = B16(linker->shdr_len);
|
||||||
ehdr->e_shstrndx = B16(linker->shstrtab_shidx);
|
ehdr->e_shstrndx = B16(linker->shstrtab_shidx);
|
||||||
|
|
||||||
|
Elf32_Sym *entry = NULL;
|
||||||
|
if (symtab_get(&linker->symtab, &entry, "_start")) {
|
||||||
|
ERROR("undefined symbol _start");
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BE to BE, no endiness conversion needed
|
||||||
|
ehdr->e_entry = entry->st_value;
|
||||||
|
|
||||||
update_offsets(linker);
|
update_offsets(linker);
|
||||||
|
|
||||||
if (write_file(linker))
|
if (write_file(linker))
|
||||||
|
|
|
@ -26,6 +26,11 @@
|
||||||
#define ADDR_CHK(lnk_f, seg_f, max) \
|
#define ADDR_CHK(lnk_f, seg_f, max) \
|
||||||
((lnk_f) > max - (seg_f) || (lnk_f) + (seg_f) > max)
|
((lnk_f) > max - (seg_f) || (lnk_f) + (seg_f) > max)
|
||||||
|
|
||||||
|
// checks if a phdr and shdr are matches
|
||||||
|
#define PHDR_SHDR_MATCH(phdr, shdr) ( \
|
||||||
|
((phdr)->p_offset == (shdr)->sh_offset) && \
|
||||||
|
((phdr)->p_filesz == (shdr)->sh_size)) \
|
||||||
|
|
||||||
// start addresses for each tyoe of segment
|
// start addresses for each tyoe of segment
|
||||||
#define TEXT_VADDR_MIN 0x00400000
|
#define TEXT_VADDR_MIN 0x00400000
|
||||||
#define DATA_VADDR_MIN 0x10000000
|
#define DATA_VADDR_MIN 0x10000000
|
||||||
|
@ -119,6 +124,8 @@ struct segment {
|
||||||
|
|
||||||
// object im related to
|
// object im related to
|
||||||
struct object *obj;
|
struct object *obj;
|
||||||
|
// segment table entry im related to
|
||||||
|
struct segment_table_entry *ent;
|
||||||
|
|
||||||
// relocation table
|
// relocation table
|
||||||
struct relocation_table reltab;
|
struct relocation_table reltab;
|
||||||
|
@ -252,6 +259,7 @@ struct linker_arguments {
|
||||||
char **in_files;
|
char **in_files;
|
||||||
int in_count;
|
int in_count;
|
||||||
char *out_file;
|
char *out_file;
|
||||||
|
bool freestanding;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* link object files */
|
/* link object files */
|
||||||
|
|
|
@ -10,6 +10,7 @@ void help(void) {
|
||||||
printf("options:\n");
|
printf("options:\n");
|
||||||
printf("\t-h\t\tprints this help message\n");
|
printf("\t-h\t\tprints this help message\n");
|
||||||
printf("\t-o <output>\tselect a output file destination\n");
|
printf("\t-o <output>\tselect a output file destination\n");
|
||||||
|
printf("\t-f\t\tmake this binary freestanding (no runtime)\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
|
@ -18,11 +19,12 @@ int main(int argc, char **argv) {
|
||||||
.in_files = NULL,
|
.in_files = NULL,
|
||||||
.in_count = 0,
|
.in_count = 0,
|
||||||
.out_file = "a.out",
|
.out_file = "a.out",
|
||||||
|
.freestanding = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
while ((c = getopt(argc, argv, "ho:")) != 1) {
|
while ((c = getopt(argc, argv, "ho:f")) != 1) {
|
||||||
switch(c) {
|
switch(c) {
|
||||||
case 'h':
|
case 'h':
|
||||||
help();
|
help();
|
||||||
|
@ -30,6 +32,9 @@ int main(int argc, char **argv) {
|
||||||
case 'o':
|
case 'o':
|
||||||
args.out_file = optarg;
|
args.out_file = optarg;
|
||||||
break;
|
break;
|
||||||
|
case 'f':
|
||||||
|
args.freestanding = true;
|
||||||
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
return M_ERROR;
|
return M_ERROR;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -31,10 +31,9 @@ static int load_shdr(struct object *obj, struct segment *seg, size_t index)
|
||||||
Elf32_Shdr *hdr = &obj->shdr[i];
|
Elf32_Shdr *hdr = &obj->shdr[i];
|
||||||
|
|
||||||
// find shdr that matches the offset in phdr
|
// find shdr that matches the offset in phdr
|
||||||
if (seg->phdr->p_offset != hdr->sh_offset)
|
if (!PHDR_SHDR_MATCH(seg->phdr, hdr))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
||||||
// get name
|
// get name
|
||||||
uint32_t name = B32(hdr->sh_name);
|
uint32_t name = B32(hdr->sh_name);
|
||||||
if (name >= obj->shstrtab->len) {
|
if (name >= obj->shstrtab->len) {
|
||||||
|
@ -43,11 +42,6 @@ static int load_shdr(struct object *obj, struct segment *seg, size_t index)
|
||||||
}
|
}
|
||||||
seg->name = &obj->shstrtab->data[name];
|
seg->name = &obj->shstrtab->data[name];
|
||||||
|
|
||||||
if (seg->phdr->p_filesz != hdr->sh_size) {
|
|
||||||
ERROR("segment phdr and shdr file sizes to not match");
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
// map bytes
|
// map bytes
|
||||||
uint32_t len = B32(hdr->sh_size);
|
uint32_t len = B32(hdr->sh_size);
|
||||||
uint32_t off = B32(hdr->sh_offset);
|
uint32_t off = B32(hdr->sh_offset);
|
||||||
|
@ -154,6 +148,7 @@ int segment_load(struct object *obj, struct segment *seg, size_t index)
|
||||||
seg->align = B32(seg->phdr->p_align);
|
seg->align = B32(seg->phdr->p_align);
|
||||||
|
|
||||||
seg->obj = obj;
|
seg->obj = obj;
|
||||||
|
seg->ent = NULL;
|
||||||
|
|
||||||
return M_SUCCESS;
|
return M_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,6 +136,8 @@ int segtab_ent_push(struct segment_table_entry *ent, struct segment *seg)
|
||||||
}
|
}
|
||||||
|
|
||||||
ent->parts[ent->len++] = seg;
|
ent->parts[ent->len++] = seg;
|
||||||
|
seg->ent = ent;
|
||||||
|
|
||||||
return M_SUCCESS;
|
return M_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue