summaryrefslogtreecommitdiff
path: root/mld/link.c
diff options
context:
space:
mode:
Diffstat (limited to 'mld/link.c')
-rw-r--r--mld/link.c57
1 files changed, 37 insertions, 20 deletions
diff --git a/mld/link.c b/mld/link.c
index 5a8e151..64cffe5 100644
--- a/mld/link.c
+++ b/mld/link.c
@@ -16,8 +16,11 @@
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->args->in_count);
+ max_entries);
linker->obj_len = 0;
if (linker->objects == NULL) {
@@ -46,6 +49,19 @@ static int load_objects(struct linker *linker)
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;
}
@@ -161,7 +177,7 @@ static int relocate_symbol(struct linker *linker, struct object *obj,
struct segment *sec = NULL;
for (size_t i = 0; i < obj->phdr_len; i++) {
Elf32_Phdr *temp = &obj->phdr[i];
- if (shdr->sh_offset == temp->p_offset) {
+ if (PHDR_SHDR_MATCH(temp, shdr)) {
sec = &obj->segments[i];
break;
}
@@ -386,30 +402,22 @@ static int relocate_instruction_rela(struct linker *linker,
return M_ERROR;
}
Elf32_Sym *sym = &symtab->syms[idx];
- const char *symname = symtab->strtab->data + B32(sym->st_name);
-
- /// get the section header that the symbol is related to
- Elf32_Shdr *shdr = NULL;
- if (B16(sym->st_shndx) >= seg->obj->shdr_len) {
- ERROR("shndx index [%d] out of bounds", B16(sym->st_shndx));
+ char const *sym_name = symtab->strtab->data + B32(sym->st_name);
+ if (B32(sym->st_name) >= symtab->strtab->len) {
+ ERROR("relocation symbol name out of bounds");
return M_ERROR;
}
- shdr = &seg->obj->shdr[B16(sym->st_shndx)];
- /// get the segment that the symbol is in
- struct segment_table_entry *ent;
- 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");
+ // 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;
}
- uint32_t sym_vaddr = B32(sym->st_value) + ent->vaddr;
+ /// get the segment that the symbol is in
+ uint32_t sym_vaddr = B32(new_sym->st_value);
uint32_t *ins_raw = (uint32_t *) &seg->bytes[off];
union mips_instruction_data ins;
@@ -462,7 +470,7 @@ static int relocate_instruction_rela(struct linker *linker,
*ins_raw = B32(ins.raw);
if (warn)
- WARNING("truncating relocation for symbol '%s'", symname);
+ WARNING("truncating relocation for symbol '%s'", sym_name);
return M_SUCCESS;
@@ -647,6 +655,15 @@ static int link_executable(struct linker *linker)
ehdr->e_shnum = B16(linker->shdr_len);
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);
if (write_file(linker))