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
|
#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_reloc(dso_info.base, dso_info.reladyn.entries, dso_info.reladyn.size, dso_info.reladyn.entsize);
kc_reloc(dso_info.base, dso_info.jmprel.entries, dso_info.jmprel.size, dso_info.jmprel.entsize);
}
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;
if (strcmp(name, "write") == 0)
{
*fixup = (uintptr_t)*entry_params->interface->write;
return fixup;
}
return nullptr;
}
|