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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
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;
}
}
|