summaryrefslogtreecommitdiff
path: root/mld/link.c
diff options
context:
space:
mode:
Diffstat (limited to 'mld/link.c')
-rw-r--r--mld/link.c46
1 files changed, 31 insertions, 15 deletions
diff --git a/mld/link.c b/mld/link.c
index 032c275..8e61ce2 100644
--- a/mld/link.c
+++ b/mld/link.c
@@ -12,8 +12,6 @@
#include "link.h"
#include "mips.h"
-#define SEC_ALIGN 0x1000
-
static int load_objects(struct linker *linker)
{
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)
{
size_t shndx = B16(sym->st_shndx);
- if (shndx == 0)
+ if (shndx == 0 || shndx == SHN_ABS)
return M_SUCCESS; // ignore this symbol
// find the given section
@@ -184,11 +182,9 @@ static int relocate_symbol(struct linker *linker, struct object *obj,
return M_ERROR;
}
- Elf32_Shdr const *shdr = &obj->shdr[shndx];
struct segment *sec = NULL;
for (size_t i = 0; i < obj->phdr_len; i++) {
- Elf32_Phdr *temp = &obj->phdr[i];
- if (PHDR_SHDR_MATCH(temp, shdr)) {
+ if (obj->phdr_to_shdr_mapping[i] == shndx) {
sec = &obj->segments[i];
break;
}
@@ -219,6 +215,20 @@ static int relocate_symbol(struct linker *linker, struct object *obj,
new.st_shndx = B16(new_shndx);
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) {
ERROR("cannot link doubly defiend symbol '%s'", name);
return M_ERROR;
@@ -447,33 +457,38 @@ static int relocate_instruction_rela(struct linker *linker,
// 16bit absolute
if (vaddr_abs > UINT16_MAX)
warn = true;
- ins.immd = (uint16_t)vaddr_abs;
+ ins.immd += (uint16_t)vaddr_abs;
break;
case R_MIPS_PC16:
// 16bit relative shifted
if (vaddr_rel > INT16_MAX || vaddr_rel < INT16_MIN)
warn = true;
- ins.offset = vaddr_rel;
+ ins.offset += vaddr_rel;
break;
case R_MIPS_26:
+ case R_MIPS_JALR:
// 26bit absolute shifted
if (vaddr_abs >= (1 << 25))
warn = true;
- ins.target = (vaddr_abs & 0x0FFFFFFF) >> 2;
+ ins.target += (vaddr_abs & 0x0FFFFFFF) >> 2;
break;
case R_MIPS_PC26_S2:
// 26bit relative shifted
if (vaddr_rel >= (1 << 24) || -vaddr_rel > (1 << 24))
warn = true;
- ins.offs26 = vaddr_rel;
+ ins.offs26 += vaddr_rel;
break;
case R_MIPS_LO16:
// lo 16bit absolute
- ins.immd = (uint16_t)(vaddr_abs & 0xFFFF);
+ ins.immd += (uint16_t)(vaddr_abs & 0xFFFF);
break;
case R_MIPS_HI16:
// 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;
default:
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)
{
- extern char *current_file;
- current_file = linker->args->out_file;
-
int fd = open(linker->args->out_file, O_RDWR | O_CREAT, 0711);
if (fd < 0) {
PERROR("cannot write");
@@ -739,12 +751,16 @@ static void linker_free(struct linker *linker)
int link_files(struct linker_arguments args) {
struct linker linker;
+ extern char *current_file;
+
int res = M_SUCCESS;
if (res == M_SUCCESS)
res = linker_init(&linker, &args);
if (res == M_SUCCESS)
res = load_objects(&linker);
+
+ current_file = args.out_file;
if (res == M_SUCCESS)
res = relocate_segments(&linker);
if (res == M_SUCCESS)