aboutsummaryrefslogtreecommitdiff
path: root/user/lib/ld-weenix/ldreloc_x86_64.c
diff options
context:
space:
mode:
authornthnluu <nate1299@me.com>2024-01-28 21:20:27 -0500
committernthnluu <nate1299@me.com>2024-01-28 21:20:27 -0500
commitc63f340d90800895f007de64b7d2d14624263331 (patch)
tree2c0849fa597dd6da831c8707b6f2603403778d7b /user/lib/ld-weenix/ldreloc_x86_64.c
Created student weenix repository
Diffstat (limited to 'user/lib/ld-weenix/ldreloc_x86_64.c')
-rw-r--r--user/lib/ld-weenix/ldreloc_x86_64.c184
1 files changed, 184 insertions, 0 deletions
diff --git a/user/lib/ld-weenix/ldreloc_x86_64.c b/user/lib/ld-weenix/ldreloc_x86_64.c
new file mode 100644
index 0000000..dddd418
--- /dev/null
+++ b/user/lib/ld-weenix/ldreloc_x86_64.c
@@ -0,0 +1,184 @@
+/*
+ * File: ldreloc_x86_64.c
+ * Date: Mar 26 2019
+ * Acct: Sandy Harvie (charvie)
+ * Desc: x86-64 ELF dynamic linker
+ */
+
+#include "stdio.h"
+#include "stdlib.h"
+#include "string.h"
+#include "sys/types.h"
+
+#include "ldresolve.h"
+#include "ldtypes.h"
+#include "ldutil.h"
+
+extern void _ld_bind(void);
+
+ldinit_t _ldloadrtld(int argc, char **argv, char **envp, Elf64_auxv_t *auxv)
+{
+ /* Find our own base address in the auxiliary vector */
+ Elf64_Addr base = 0;
+ for (size_t i = 0; auxv[i].a_type != AT_NULL; i++)
+ {
+ if (auxv[i].a_type == AT_BASE)
+ {
+ base = (Elf64_Addr)auxv[i].a_un.a_val;
+ break;
+ }
+ }
+ if (!base)
+ exit(1);
+
+ /* Make sure we are ourselves */
+ Elf64_Ehdr *hdr = (Elf64_Ehdr *)base;
+ if (hdr->e_ident[EI_MAG0] != ELFMAG0 || hdr->e_ident[EI_MAG1] != ELFMAG1 ||
+ hdr->e_ident[EI_MAG2] != ELFMAG2 || hdr->e_ident[EI_MAG3] != ELFMAG3)
+ {
+ exit(1);
+ }
+
+ /* Find our program header */
+ Elf64_Phdr *phdr = (Elf64_Phdr *)(base + hdr->e_phoff);
+
+ /* Find our dynamic segment */
+ while (phdr->p_type != PT_DYNAMIC)
+ {
+ phdr++;
+ }
+
+ /* Find relocation entries in the dynamic segment */
+ size_t d_reloff = 0;
+ size_t d_relcount = 0;
+ Elf64_Dyn *dyn = (Elf64_Dyn *)(base + phdr->p_vaddr);
+ for (; dyn->d_tag != DT_NULL; dyn++)
+ {
+ if (dyn->d_tag == DT_RELA)
+ {
+ d_reloff = dyn->d_un.d_ptr;
+ }
+ else if (dyn->d_tag == DT_RELACOUNT)
+ {
+ d_relcount = dyn->d_un.d_val;
+ }
+ }
+
+ /* Relocate ourselves */
+ Elf64_Rela *rel = (Elf64_Rela *)(base + d_reloff);
+ for (size_t i = 0; i < d_relcount; i++)
+ {
+ size_t type = ELF64_R_TYPE(rel[i].r_info);
+ if (type == R_X86_64_RELATIVE)
+ {
+ Elf64_Addr *addr = (Elf64_Addr *)(base + rel[i].r_offset);
+ *addr = base + rel[i].r_addend;
+ }
+ else
+ {
+ fprintf(stderr, "_ldloadrtld: unsupported relocation type: %lu\n",
+ type);
+ exit(1);
+ }
+ }
+
+ /* Relocate the executable */
+ return _ldstart(envp, auxv);
+}
+
+void _ldrelocobj(module_t *module)
+{
+ Elf64_Addr base = module->base;
+
+ for (size_t i = 0; i < module->nreloc; i++)
+ {
+ Elf64_Rela rel = module->reloc[i];
+
+ uint64_t sym = ELF64_R_SYM(rel.r_info);
+ uint64_t type = ELF64_R_TYPE(rel.r_info);
+ const char *name = module->dynstr + module->dynsym[sym].st_name;
+ void *addr = (void *)(base + rel.r_offset);
+
+ Elf64_Word size;
+ ldsym_t symbol;
+ switch (type)
+ {
+ case R_X86_64_RELATIVE:
+ *(Elf64_Addr *)addr = base + rel.r_addend;
+ break;
+ case R_X86_64_COPY:
+ symbol = _ldresolve(module, name, -1, &size, 1);
+ memcpy(addr, symbol, size);
+ break;
+ case R_X86_64_JUMP_SLOT:
+ case R_X86_64_GLOB_DAT:
+ symbol = _ldresolve(module, name, -1, 0, 0);
+ *(Elf64_Addr *)addr = (Elf64_Addr)symbol;
+ break;
+ case R_X86_64_32:
+ symbol = _ldresolve(module, name, -1, 0, 0);
+ *(Elf64_Addr *)addr = (Elf64_Addr)symbol + rel.r_addend;
+ break;
+ case R_X86_64_PC32:
+ symbol = _ldresolve(module, name, -1, 0, 0);
+ *(Elf64_Addr *)addr =
+ (Elf64_Addr)symbol + rel.r_addend - (Elf64_Addr)addr;
+ break;
+ default:
+ fprintf(stderr,
+ "_ldrelocobj: unsupported relocation type: %lu\n",
+ type);
+ exit(1);
+ }
+ }
+}
+
+void _ldrelocplt(module_t *module)
+{
+ for (size_t i = 0; i < module->npltreloc; i++)
+ {
+ Elf64_Rela rel = module->pltreloc[i];
+
+ uint64_t type = ELF64_R_TYPE(rel.r_info);
+ if (type != R_X86_64_JUMP_SLOT)
+ {
+ fprintf(stderr, "_ldrelocplt: unsupported relocation type: %lu\n",
+ type);
+ exit(1);
+ }
+
+ *(Elf64_Addr *)(module->base + rel.r_offset) += module->base;
+ }
+}
+
+void _ldpltgot_init(module_t *module)
+{
+ Elf64_Addr *pltbase = module->pltgot;
+ pltbase[1] = (Elf64_Addr)module;
+ pltbase[2] = (Elf64_Addr)&_ld_bind;
+}
+
+void _ldbindnow(module_t *module)
+{
+ Elf64_Addr base = module->base;
+
+ for (size_t i = 0; i < module->npltreloc; i++)
+ {
+ Elf64_Rela rel = module->pltreloc[i];
+
+ uint64_t sym = ELF64_R_SYM(rel.r_info);
+ uint64_t type = ELF64_R_TYPE(rel.r_info);
+ const char *name = module->dynstr + module->dynsym[sym].st_name;
+ void *addr = (void *)(base + rel.r_offset);
+
+ if (type != R_X86_64_JUMP_SLOT)
+ {
+ fprintf(stderr, "_ldbindnow: unsupported relocation type: %lu\n",
+ type);
+ exit(1);
+ }
+
+ ldsym_t symbol = _ldresolve(module, name, -1, 0, 0);
+ *(Elf64_Addr *)addr = (Elf64_Addr)symbol;
+ }
+}