Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
CTCaer
GitHub Repository: CTCaer/hekate
Path: blob/master/bdk/ianos/elfload/elfload.c
1476 views
1
/*
2
* Copyright © 2018, M4xw
3
* Copyright © 2014, Owen Shepherd
4
*
5
* Permission to use, copy, modify, and/or distribute this software for any
6
* purpose with or without fee is hereby granted, provided that the above
7
* copyright notice appear in all copies.
8
*
9
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
14
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15
* PERFORMANCE OF THIS SOFTWARE.
16
*/
17
18
#include <string.h>
19
20
#include "elfload.h"
21
22
el_status el_pread(el_ctx *ctx, void *def, size_t nb, size_t offset)
23
{
24
return ctx->pread(ctx, def, nb, offset) ? EL_OK : EL_EIO;
25
}
26
27
#define EL_PHOFF(ctx, num) (((ctx)->ehdr.e_phoff + (num) *(ctx)->ehdr.e_phentsize))
28
el_status el_findphdr(el_ctx *ctx, Elf_Phdr *phdr, u32 type, unsigned *i)
29
{
30
el_status rv = EL_OK;
31
for (; *i < ctx->ehdr.e_phnum; (*i)++)
32
{
33
if ((rv = el_pread(ctx, phdr, sizeof *phdr, EL_PHOFF(ctx, *i))))
34
return rv;
35
36
if (phdr->p_type == type)
37
{
38
return rv;
39
}
40
}
41
42
*i = -1;
43
return rv;
44
}
45
46
#define EL_SHOFF(ctx, num) (((ctx)->ehdr.e_shoff + (num) *(ctx)->ehdr.e_shentsize))
47
el_status el_findshdr(el_ctx *ctx, Elf_Shdr *shdr, u32 type, unsigned *i)
48
{
49
el_status rv = EL_OK;
50
51
for (; *i < ctx->ehdr.e_shnum; (*i)++)
52
{
53
if ((rv = el_pread(ctx, shdr, sizeof *shdr, EL_SHOFF(ctx, *i))))
54
55
return rv;
56
57
if (shdr->sh_type == type)
58
{
59
return rv;
60
}
61
}
62
63
*i = -1;
64
65
return rv;
66
}
67
68
el_status el_init(el_ctx *ctx)
69
{
70
el_status rv = EL_OK;
71
if ((rv = el_pread(ctx, &ctx->ehdr, sizeof ctx->ehdr, 0)))
72
return rv;
73
74
/* validate header */
75
76
if (!IS_ELF(ctx->ehdr))
77
return EL_NOTELF;
78
79
if (ctx->ehdr.e_ident[EI_CLASS] != ELFCLASS)
80
return EL_WRONGBITS;
81
82
if (ctx->ehdr.e_ident[EI_DATA] != ELFDATATHIS)
83
return EL_WRONGENDIAN;
84
85
if (ctx->ehdr.e_ident[EI_VERSION] != EV_CURRENT)
86
return EL_NOTELF;
87
88
if (ctx->ehdr.e_type != ET_EXEC && ctx->ehdr.e_type != ET_DYN)
89
return EL_NOTEXEC;
90
91
if (ctx->ehdr.e_machine != EM_THIS)
92
return EL_WRONGARCH;
93
94
if (ctx->ehdr.e_version != EV_CURRENT)
95
return EL_NOTELF;
96
97
/* load phdrs */
98
Elf_Phdr ph;
99
100
/* iterate through, calculate extents */
101
ctx->base_load_paddr = ctx->base_load_vaddr = 0;
102
ctx->align = 1;
103
ctx->memsz = 0;
104
105
unsigned i = 0;
106
for (;;)
107
{
108
if ((rv = el_findphdr(ctx, &ph, PT_LOAD, &i)))
109
return rv;
110
111
if (i == (unsigned)-1)
112
break;
113
114
Elf_Addr phend = ph.p_vaddr + ph.p_memsz;
115
if (phend > ctx->memsz)
116
ctx->memsz = phend;
117
118
if (ph.p_align > ctx->align)
119
ctx->align = ph.p_align;
120
121
i++;
122
}
123
124
// Program Header
125
if (ctx->ehdr.e_type == ET_DYN)
126
{
127
i = 0;
128
129
if ((rv = el_findphdr(ctx, &ph, PT_DYNAMIC, &i)))
130
return rv;
131
132
if (i == (unsigned)-1)
133
return EL_NODYN;
134
135
ctx->dynoff = ph.p_offset;
136
ctx->dynsize = ph.p_filesz;
137
}
138
else
139
{
140
ctx->dynoff = 0;
141
ctx->dynsize = 0;
142
}
143
144
// Section String Table
145
if (ctx->ehdr.e_type == ET_DYN)
146
{
147
i = ctx->ehdr.e_shstrndx - 1;
148
149
if ((rv = el_findshdr(ctx, &ctx->shstr, SHT_STRTAB, &i)))
150
return rv;
151
152
// Reset
153
i = 0;
154
155
if ((rv = el_findshdr(ctx, &ctx->symtab, SHT_SYMTAB, &i)))
156
return rv;
157
158
if (i == (unsigned)-1)
159
return EL_NODYN;
160
}
161
162
return rv;
163
}
164
165
/*
166
typedef void* (*el_alloc_cb)(
167
el_ctx *ctx,
168
Elf_Addr phys,
169
Elf_Addr virt,
170
Elf_Addr size);
171
*/
172
173
el_status el_load(el_ctx *ctx, el_alloc_cb alloc)
174
{
175
el_status rv = EL_OK;
176
177
/* address deltas */
178
Elf_Addr pdelta = ctx->base_load_paddr;
179
Elf_Addr vdelta = ctx->base_load_vaddr;
180
181
/* iterate paddrs */
182
Elf_Phdr ph;
183
unsigned i = 0;
184
for (;;)
185
{
186
if ((rv = el_findphdr(ctx, &ph, PT_LOAD, &i)))
187
return rv;
188
189
if (i == (unsigned)-1)
190
break;
191
192
Elf_Addr pload = ph.p_paddr + pdelta;
193
Elf_Addr vload = ph.p_vaddr + vdelta;
194
195
/* allocate mem */
196
char *dest = alloc(ctx, pload, vload, ph.p_memsz);
197
if (!dest)
198
return EL_ENOMEM;
199
200
EL_DEBUG("Loading seg fileoff %x, vaddr %x to %p\n",
201
ph.p_offset, ph.p_vaddr, dest);
202
203
/* read loaded portion */
204
if ((rv = el_pread(ctx, dest, ph.p_filesz, ph.p_offset)))
205
return rv;
206
207
/* zero mem-only portion */
208
memset(dest + ph.p_filesz, 0, ph.p_memsz - ph.p_filesz);
209
210
i++;
211
}
212
213
return rv;
214
}
215
216
el_status el_finddyn(el_ctx *ctx, Elf_Dyn *dyn, u32 tag)
217
{
218
el_status rv = EL_OK;
219
size_t ndyn = ctx->dynsize / sizeof(Elf_Dyn);
220
221
for (unsigned i = 0; i < ndyn; i++)
222
{
223
if ((rv = el_pread(ctx, dyn, sizeof *dyn, ctx->dynoff + i * sizeof *dyn)))
224
return rv;
225
226
if (dyn->d_tag == tag)
227
return EL_OK;
228
}
229
230
dyn->d_tag = DT_NULL;
231
return EL_OK;
232
}
233
234
el_status el_findrelocs(el_ctx *ctx, el_relocinfo *ri, u32 type)
235
{
236
el_status rv = EL_OK;
237
238
Elf_Dyn rel, relsz, relent;
239
240
if ((rv = el_finddyn(ctx, &rel, type)))
241
return rv;
242
243
if ((rv = el_finddyn(ctx, &relsz, type + 1)))
244
return rv;
245
246
if ((rv = el_finddyn(ctx, &relent, type + 2)))
247
return rv;
248
249
if (rel.d_tag == DT_NULL || relsz.d_tag == DT_NULL || relent.d_tag == DT_NULL)
250
{
251
ri->entrysize = 0;
252
ri->tablesize = 0;
253
ri->tableoff = 0;
254
}
255
else
256
{
257
ri->tableoff = rel.d_un.d_ptr;
258
ri->tablesize = relsz.d_un.d_val;
259
ri->entrysize = relent.d_un.d_val;
260
}
261
262
return rv;
263
}
264
265
extern el_status el_applyrel(el_ctx *ctx, Elf_Rel *rel);
266
extern el_status el_applyrela(el_ctx *ctx, Elf_RelA *rela);
267
268
el_status el_relocate(el_ctx *ctx)
269
{
270
el_status rv = EL_OK;
271
272
// not dynamic
273
if (ctx->ehdr.e_type != ET_DYN)
274
return EL_OK;
275
276
char *base = (char *)ctx->base_load_paddr;
277
278
el_relocinfo ri;
279
#ifdef EL_ARCH_USES_REL
280
if ((rv = el_findrelocs(ctx, &ri, DT_REL)))
281
return rv;
282
283
if (ri.entrysize != sizeof(Elf_Rel) && ri.tablesize)
284
{
285
EL_DEBUG("Relocation size %u doesn't match expected %u\n",
286
ri.entrysize, sizeof(Elf_Rel));
287
return EL_BADREL;
288
}
289
290
size_t relcnt = ri.tablesize / sizeof(Elf_Rel);
291
Elf_Rel *reltab = (Elf_Rel *)(base + ri.tableoff);
292
for (size_t i = 0; i < relcnt; i++)
293
{
294
if ((rv = el_applyrel(ctx, &reltab[i])))
295
return rv;
296
}
297
#endif
298
299
#ifdef EL_ARCH_USES_RELA
300
if ((rv = el_findrelocs(ctx, &ri, DT_RELA)))
301
return rv;
302
303
if (ri.entrysize != sizeof(Elf_RelA) && ri.tablesize)
304
{
305
EL_DEBUG("Relocation size %u doesn't match expected %u\n",
306
ri.entrysize, sizeof(Elf_RelA));
307
return EL_BADREL;
308
}
309
310
size_t relacnt = ri.tablesize / sizeof(Elf_RelA);
311
Elf_RelA *relatab = (Elf_RelA *)(base + ri.tableoff);
312
for (size_t i = 0; i < relacnt; i++)
313
{
314
if ((rv = el_applyrela(ctx, &relatab[i])))
315
return rv;
316
}
317
#endif
318
319
#if !defined(EL_ARCH_USES_REL) && !defined(EL_ARCH_USES_RELA)
320
#error No relocation type defined!
321
#endif
322
323
return rv;
324
}
325
326