summaryrefslogtreecommitdiff
path: root/service/arch/x86_64/dynamic.c
blob: d338dce0558a1f661c5ad6613a5ea8e0aa88af92 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include <kc.h>

#include <libc/string.h>
#include <lib/elf.h>

extern void _rtld_link(void);

struct elf64_relatab
{
	Elf64_Rela *entries;
	size_t size;
	size_t entsize;
};

struct elf64_symtab
{
	Elf64_Sym *entries;
	const char *strings;
	size_t strsize;
};

struct elf64_dso_info
{
	char *base;
	struct elf64_relatab jmprel;
	struct elf64_relatab reladyn;
	struct elf64_symtab dynsym;
	Elf64_Addr *pltgot;
};

static struct elf64_dso_info dso_info;

void kc_dynamic_init(char *base, Elf64_Dyn *dyn)
{
	dso_info = (struct elf64_dso_info)
	{
		base,
		{
			elf64_dt_ptr(base, dyn, DT_JMPREL),
			elf64_dt_val(dyn, DT_PLTRELSZ),
			elf64_dt_val(dyn, DT_PLTREL) == DT_RELA ? sizeof(Elf64_Rela) : -1 
		},
		{
			elf64_dt_ptr(base, dyn, DT_RELA),
			elf64_dt_val(dyn, DT_RELASZ),
			elf64_dt_val(dyn, DT_RELAENT)
		},
		{
			elf64_dt_ptr(base, dyn, DT_SYMTAB),
			elf64_dt_ptr(base, dyn, DT_STRTAB),
			elf64_dt_val(dyn, DT_STRSZ)
		},
		elf64_dt_ptr(base, dyn, DT_PLTGOT)
	};

	if (dso_info.pltgot != nullptr)
	{
		dso_info.pltgot[1] = (uintptr_t)&dso_info;
		dso_info.pltgot[2] = (uintptr_t)_rtld_link;
	}

	kc_dynamic_reloc(base, &dso_info.jmprel);
	kc_dynamic_reloc(base, &dso_info.reladyn);
}

void *kc_dynamic_link(struct elf64_dso_info *dso, int index)
{
	/*
	int symindex = ELF64_R_SYM(dso->jmprel.entries[index].r_info);
	int strindex = dso->dynsym.entries[symindex].st_name;
	const char *name = &dso->dynsym.strings[strindex];
	uintptr_t *fixup = (uintptr_t *)(dso->base + dso->jmprel.entries[index].r_offset);

	return fixup;
	*/

	(void)dso;
	(void)index;
	return nullptr;
}

static void do_rela(char *base, Elf64_Rela *rela)
{
	uintptr_t *fixup = (uintptr_t *)(base + rela->r_offset);

    switch (ELF64_R_TYPE(rela->r_info))
    {
        case R_X86_64_JUMP_SLOT:
            *fixup += (uintptr_t)base;
            break;
        case R_X86_64_RELATIVE:
            *fixup = (uintptr_t)(rela->r_addend + base);
            break;
        default:
            break;
    }
}

void kc_dynamic_reloc(char *base, struct elf64_relatab *rela)
{
	size_t entries = rela->size / rela->entsize;

    for (size_t i = 0; rela->entries && (i < entries); i++)
    {
        do_rela(base, &rela->entries[i]);
    }
}