elf64read.c - scc - simple c99 compiler
(HTM) git clone git://git.simple-cc.org/scc
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) Submodules
(DIR) README
(DIR) LICENSE
---
elf64read.c (6503B)
---
1 #include <assert.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4
5 #include <scc/mach.h>
6 #include <scc/elf64.h>
7
8 #include "../libmach.h"
9 #include "fun.h"
10
11 static int
12 unpack_hdr(int order, unsigned char *buf, Elf_Ehdr *hdr)
13 {
14 int n;
15
16 n = unpack(order,
17 buf,
18 "'16sslqqqlssssss",
19 hdr->e_ident,
20 &hdr->e_type,
21 &hdr->e_machine,
22 &hdr->e_version,
23 &hdr->e_entry,
24 &hdr->e_phoff,
25 &hdr->e_shoff,
26 &hdr->e_flags,
27 &hdr->e_ehsize,
28 &hdr->e_phentsize,
29 &hdr->e_phnum,
30 &hdr->e_shentsize,
31 &hdr->e_shnum,
32 &hdr->e_shstrndx);
33
34 assert(n == ELFHSZ);
35
36 return n;
37 }
38
39 static int
40 unpack_phdr(int order, unsigned char *buf, Elf_Phdr *phdr)
41 {
42 int n;
43
44 n = unpack(order,
45 buf,
46 "llqqqqqq",
47 &phdr->p_type,
48 &phdr->p_flags,
49 &phdr->p_offset,
50 &phdr->p_vaddr,
51 &phdr->p_paddr,
52 &phdr->p_filesz,
53 &phdr->p_memsz,
54 &phdr->p_align);
55
56 assert(n == ELFPSZ);
57
58 return n;
59 }
60
61 static int
62 unpack_shdr(int order, unsigned char *buf, Elf_Shdr *shdr)
63 {
64 int n;
65
66 n = unpack(order,
67 buf,
68 "llqqqqllqq",
69 &shdr->sh_name,
70 &shdr->sh_type,
71 &shdr->sh_flags,
72 &shdr->sh_addr,
73 &shdr->sh_offset,
74 &shdr->sh_size,
75 &shdr->sh_link,
76 &shdr->sh_info,
77 &shdr->sh_addralign,
78 &shdr->sh_entsize);
79
80 assert(n == ELFSSZ);
81
82 return n;
83 }
84
85 static int
86 unpack_sym(int order, unsigned char *buf, Elf_Sym *sym)
87 {
88 int n;
89
90 n = unpack(order,
91 buf,
92 "lccsqq",
93 &sym->st_name,
94 &sym->st_info,
95 &sym->st_other,
96 &sym->st_shndx,
97 &sym->st_value,
98 &sym->st_size);
99 assert(n == ELFESZ);
100
101 return n;
102 }
103
104 static int
105 readhdr(Obj *obj, FILE *fp)
106 {
107 Elf64 *elf;
108 Elf_Ehdr *hdr;
109 unsigned char buf[ELFHSZ];
110
111 elf = obj->data;
112 hdr = &elf->hdr;
113
114 if (fread(buf, ELFHSZ, 1, fp) != 1)
115 return 0;
116 unpack_hdr(ORDER(obj->type), buf, hdr);
117
118 switch (hdr->e_type) {
119 case ET_REL:
120 case ET_EXEC:
121 case ET_DYN:
122 return 1;
123 default:
124 return 0;
125 }
126 }
127
128 static int
129 readphdr(Obj *obj, FILE *fp)
130 {
131 long long i;
132 Elf_Ehdr *hdr;
133 Elf_Phdr *phdr;
134 Elf64 *elf;
135 unsigned char buf[ELFPSZ];
136
137 elf = obj->data;
138 hdr = &elf->hdr;
139
140 if (hdr->e_phoff == 0 || hdr->e_phnum == 0)
141 return 1;
142
143 phdr = calloc(hdr->e_phnum, sizeof(*phdr));
144 if (!phdr)
145 return 0;
146 elf->phdr = phdr;
147
148 if (!objpos(obj, fp, hdr->e_phoff))
149 return 0;
150 for (i = 0; i < hdr->e_phnum; i++) {
151 if (fread(buf, ELFPSZ, 1, fp) != 1)
152 return 0;
153 unpack_phdr(ORDER(obj->type), buf, &phdr[i]);
154 }
155
156 return 1;
157 }
158
159 static int
160 readshdr(Obj *obj, FILE *fp)
161 {
162 unsigned long long i, nsec;
163 Elf_Ehdr *hdr;
164 Elf_Shdr *shdr;
165 Elf64 *elf;
166 unsigned char buf[ELFSSZ + ELFHSZ];
167
168 elf = obj->data;
169 hdr = &elf->hdr;
170 elf->nsec = 0;
171 elf->shdr = NULL;
172
173 if (hdr->e_shoff == 0)
174 return 1;
175
176 if (!objpos(obj, fp, hdr->e_shoff))
177 return 0;
178
179 if (hdr->e_shnum != SHN_UNDEF) {
180 nsec = hdr->e_shnum;
181 } else {
182 Elf_Shdr sec0;
183 fpos_t pos;
184
185 fgetpos(fp, &pos);
186 fread(buf, ELFHSZ, 1, fp);
187 fsetpos(fp, &pos);
188
189 if (ferror(fp))
190 return 0;
191
192 unpack_shdr(ORDER(obj->type), buf, &sec0);
193 nsec = sec0.sh_size;
194 }
195
196 if (nsec > SIZE_MAX)
197 return 0;
198 if (nsec == 0)
199 return 1;
200
201 shdr = calloc(nsec, sizeof(*shdr));
202 if (!shdr)
203 return 0;
204 elf->shdr = shdr;
205 elf->nsec = nsec;
206
207 for (i = 0; i < nsec; i++) {
208 if (fread(buf, ELFSSZ, 1, fp) != 1)
209 return 0;
210 unpack_shdr(ORDER(obj->type), buf, &shdr[i]);
211 if (shdr[i].sh_type == SHT_SYMTAB) {
212 /*
213 * elf supports multiple symbol table, but we don't
214 * care and we only support one, and we reject elf
215 * files with more of one symbol table.
216 */
217 if (elf->symtab)
218 return 0;
219 elf->symtab = &shdr[i];
220 }
221 }
222
223 return 1;
224 }
225
226 static int
227 readsecstr(Obj *obj, FILE *fp)
228 {
229 long idx;
230 size_t siz;
231 char *str;
232 Elf_Shdr *shdr;
233 Elf64 *elf;
234 Elf_Ehdr *hdr;
235
236 elf = obj->data;
237 hdr = &elf->hdr;
238 idx = hdr->e_shstrndx;
239 if (idx == SHN_UNDEF)
240 return 0;
241 if (idx == SHN_XINDEX) {
242 if (hdr->e_shnum == 0)
243 return 0;
244 idx = elf->shdr[0].sh_link;
245 }
246
247 if (idx >= hdr->e_shnum)
248 return 0;
249 shdr = &elf->shdr[idx];
250
251 if (shdr->sh_size > SIZE_MAX)
252 return 0;
253
254 siz = shdr->sh_size;
255 if (siz == 0)
256 return 1;
257 str = malloc(siz);
258 if (!str)
259 return 0;
260
261 elf->strtbl[SEC_STRTBL] = str;
262 elf->strsiz[SEC_STRTBL] = siz;
263
264 if (!objpos(obj, fp, shdr->sh_offset))
265 return 0;
266 if (fread(str, siz, 1, fp) != 1)
267 return 0;
268
269 return 1;
270 }
271
272 static int
273 readsymstr(Obj *obj, FILE *fp)
274 {
275 long idx;
276 size_t siz;
277 char *str;
278 Elf64 *elf;
279 Elf_Shdr *shdr;
280
281 elf = obj->data;
282 if (!elf->symtab)
283 return 1;
284
285 idx = elf->symtab->sh_link;
286 if (idx >= elf->nsec)
287 return 0;
288 shdr = &elf->shdr[idx];
289
290 if (shdr->sh_size > SIZE_MAX)
291 return 0;
292
293 siz = shdr->sh_size;
294 if (siz == 0)
295 return 1;
296 str = malloc(siz);
297 if (!str)
298 return 0;
299
300 elf->strtbl[SYM_STRTBL] = str;
301 elf->strsiz[SYM_STRTBL] = siz;
302
303 if (!objpos(obj, fp, shdr->sh_offset))
304 return 0;
305 if (fread(str, siz, 1, fp) != 1)
306 return 0;
307
308 return 1;
309 }
310
311 static int
312 readsym(Obj *obj, FILE *fp)
313 {
314 long nsym, i;
315 int sec;
316 Elf64 *elf;
317 Elf_Sym *syms;
318 Elf_Shdr *shdr;
319 unsigned char buf[ELFSSZ];
320
321 elf = obj->data;
322 if (!elf->symtab)
323 return 1;
324 shdr = elf->symtab;
325
326 assert(shdr->sh_type == SHT_SYMTAB);
327
328 nsym = shdr->sh_size / shdr->sh_entsize;
329 if (nsym >= SIZE_MAX)
330 return 0;
331
332 syms = calloc(nsym, sizeof(*syms));
333 if (!syms)
334 return 0;
335 elf->syms = syms;
336 elf->nsym = nsym;
337
338 if (!objpos(obj, fp, shdr->sh_offset))
339 return 0;
340
341 for (i = 0; i < nsym; i++) {
342 if (fread(buf, ELFESZ, 1, fp) != 1)
343 return 0;
344 unpack_sym(ORDER(obj->type), buf, &syms[i]);
345
346 sec = syms[i].st_shndx;
347 switch (sec) {
348 case SHN_XINDEX:
349 /*
350 * Elf supports an extension mechanism to allow
351 * indexes bigger than 4 bytes. We don't care
352 * and we reject elf files using this feature.
353 */
354 return 0;
355 case SHN_UNDEF:
356 case SHN_ABS:
357 case SHN_COMMON:
358 break;
359 default:
360 if (sec >= elf->nsec)
361 return 0;
362 break;
363 }
364 }
365
366 return 1;
367 }
368
369 int
370 elf64read(Obj *obj, FILE *fp)
371 {
372 if (!readhdr(obj, fp))
373 return -1;
374 if (!readphdr(obj, fp))
375 return -1;
376 if (!readshdr(obj, fp))
377 return -1;
378 if (!readsym(obj, fp))
379 return -1;
380 if (!readsecstr(obj, fp))
381 return -1;
382 if (!readsymstr(obj, fp))
383 return -1;
384
385 return 0;
386 }