multitude of mld fixes, add entrypoint

This commit is contained in:
Freya Murphy 2024-09-22 23:39:22 -04:00
parent fff0444f6c
commit 49af3bfc62
Signed by: freya
GPG key ID: 744AB800E383AE52
7 changed files with 88 additions and 30 deletions

29
lib/runtime.asm Normal file
View 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

View file

@ -4,4 +4,6 @@ SRC=.
BIN=../bin/mld BIN=../bin/mld
OUT=mld OUT=mld
CFLAGS += -DPREFIX=$(PREFIX)
include ../makefile.mk include ../makefile.mk

View file

@ -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))

View file

@ -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 */

View file

@ -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:

View file

@ -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;
} }

View file

@ -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;
} }