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]);
}
}
|