File: | util/cbfstool/elfheaders.c |
Warning: | line 992, column 18 The left expression of the compound assignment is an uninitialized value. The computed value will also be garbage |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* elf header parsing */ | |||
2 | /* SPDX-License-Identifier: GPL-2.0-only */ | |||
3 | ||||
4 | #include <stdio.h> | |||
5 | #include <stdlib.h> | |||
6 | #include <string.h> | |||
7 | ||||
8 | #include "elfparsing.h" | |||
9 | #include "common.h" | |||
10 | #include "cbfs.h" | |||
11 | ||||
12 | /* | |||
13 | * Short form: this is complicated, but we've tried making it simple | |||
14 | * and we keep hitting problems with our ELF parsing. | |||
15 | * | |||
16 | * The ELF parsing situation has always been a bit tricky. In fact, | |||
17 | * we (and most others) have been getting it wrong in small ways for | |||
18 | * years. Recently this has caused real trouble for the ARM V8 build. | |||
19 | * In this file we attempt to finally get it right for all variations | |||
20 | * of endian-ness and word size and target architectures and | |||
21 | * architectures we might get run on. Phew!. To do this we borrow a | |||
22 | * page from the FreeBSD NFS xdr model (see elf_ehdr and elf_phdr), | |||
23 | * the Plan 9 endianness functions (see xdr.c), and Go interfaces (see | |||
24 | * how we use buffer structs in this file). This ends up being a bit | |||
25 | * wordy at the lowest level, but greatly simplifies the elf parsing | |||
26 | * code and removes a common source of bugs, namely, forgetting to | |||
27 | * flip type endianness when referencing a struct member. | |||
28 | * | |||
29 | * ELF files can have four combinations of data layout: 32/64, and | |||
30 | * big/little endian. Further, to add to the fun, depending on the | |||
31 | * word size, the size of the ELF structs varies. The coreboot SELF | |||
32 | * format is simpler in theory: it's supposed to be always BE, and the | |||
33 | * various struct members allow room for growth: the entry point is | |||
34 | * always 64 bits, for example, so the size of a SELF struct is | |||
35 | * constant, regardless of target architecture word size. Hence, we | |||
36 | * need to do some transformation of the ELF files. | |||
37 | * | |||
38 | * A given architecture, realistically, only supports one of the four | |||
39 | * combinations at a time as the 'native' format. Hence, our code has | |||
40 | * been sprinkled with every variation of [nh]to[hn][sll] over the | |||
41 | * years. We've never quite gotten it all right, however, and a quick | |||
42 | * pass over this code revealed another bug. It's all worked because, | |||
43 | * until now, all the working platforms that had CBFS were 32 LE. Even then, | |||
44 | * however, bugs crept in: we recently realized that we're not | |||
45 | * transforming the entry point to big format when we store into the | |||
46 | * SELF image. | |||
47 | * | |||
48 | * The problem is essentially an XDR operation: | |||
49 | * we have something in a foreign format and need to transform it. | |||
50 | * It's most like XDR because: | |||
51 | * 1) the byte order can be wrong | |||
52 | * 2) the word size can be wrong | |||
53 | * 3) the size of elements in the stream depends on the value | |||
54 | * of other elements in the stream | |||
55 | * it's not like XDR because: | |||
56 | * 1) the byte order can be right | |||
57 | * 2) the word size can be right | |||
58 | * 3) the struct members are all on a natural alignment | |||
59 | * | |||
60 | * Hence, this new approach. To cover word size issues, we *always* | |||
61 | * transform the two structs we care about, the file header and | |||
62 | * program header, into a native struct in the 64 bit format: | |||
63 | * | |||
64 | * [32,little] -> [Elf64_Ehdr, Elf64_Phdr] | |||
65 | * [64,little] -> [Elf64_Ehdr, Elf64_Phdr] | |||
66 | * [32,big] -> [Elf64_Ehdr, Elf64_Phdr] | |||
67 | * [64,big] -> [Elf64_Ehdr, Elf64_Phdr] | |||
68 | * Then we just use those structs, and all the need for inline ntoh* goes away, | |||
69 | * as well as all the chances for error. | |||
70 | * This works because all the SELF structs have fields large enough for | |||
71 | * the largest ELF 64 struct members, and all the Elf64 struct members | |||
72 | * are at least large enough for all ELF 32 struct members. | |||
73 | * We end up with one function to do all our ELF parsing, and two functions | |||
74 | * to transform the headers. For the put case, we also have | |||
75 | * XDR functions, and hopefully we'll never again spend 5 years with the | |||
76 | * wrong endian-ness on an output value :-) | |||
77 | * This should work for all word sizes and endianness we hope to target. | |||
78 | * I *really* don't want to be here for 128 bit addresses. | |||
79 | * | |||
80 | * The parse functions are called with a pointer to an input buffer | |||
81 | * struct. One might ask: are there enough bytes in the input buffer? | |||
82 | * We know there need to be at *least* sizeof(Elf32_Ehdr) + | |||
83 | * sizeof(Elf32_Phdr) bytes. Realistically, there has to be some data | |||
84 | * too. If we start to worry, though we have not in the past, we | |||
85 | * might apply the simple test: the input buffer needs to be at least | |||
86 | * sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr) bytes because, even if it's | |||
87 | * ELF 32, there's got to be *some* data! This is not theoretically | |||
88 | * accurate but it is actually good enough in practice. It allows the | |||
89 | * header transformation code to ignore the possibility of underrun. | |||
90 | * | |||
91 | * We also must accommodate different ELF files, and hence formats, | |||
92 | * in the same cbfs invocation. We might load a 64-bit payload | |||
93 | * on a 32-bit machine; we might even have a mixed armv7/armv8 | |||
94 | * SOC or even a system with an x86/ARM! | |||
95 | * | |||
96 | * A possibly problematic (though unlikely to be so) assumption | |||
97 | * is that we expect the BIOS to remain in the lowest 32 bits | |||
98 | * of the physical address space. Since ARMV8 has standardized | |||
99 | * on that, and x86_64 also has, this seems a safe assumption. | |||
100 | * | |||
101 | * To repeat, ELF structs are different sizes because ELF struct | |||
102 | * members are different sizes, depending on values in the ELF file | |||
103 | * header. For this we use the functions defined in xdr.c, which | |||
104 | * consume bytes, convert the endianness, and advance the data pointer | |||
105 | * in the buffer struct. | |||
106 | */ | |||
107 | ||||
108 | ||||
109 | static int iself(const void *input) | |||
110 | { | |||
111 | const Elf32_Ehdr *ehdr = input; | |||
112 | return !memcmp(ehdr->e_ident, ELFMAG"\177ELF", 4); | |||
113 | } | |||
114 | ||||
115 | /* Get the ident array, so we can figure out | |||
116 | * endian-ness, word size, and in future other useful | |||
117 | * parameters | |||
118 | */ | |||
119 | static void | |||
120 | elf_eident(struct buffer *input, Elf64_Ehdr *ehdr) | |||
121 | { | |||
122 | bgets(input, ehdr->e_ident, sizeof(ehdr->e_ident)); | |||
123 | } | |||
124 | ||||
125 | ||||
126 | static int | |||
127 | check_size(const struct buffer *b, size_t offset, size_t size, const char *desc) | |||
128 | { | |||
129 | if (size == 0) | |||
130 | return 0; | |||
131 | ||||
132 | if (offset >= buffer_size(b) || (offset + size) > buffer_size(b)) { | |||
133 | ERROR("The file is not large enough for the '%s'. "fprintf(stderr, "E: " "The file is not large enough for the '%s'. " "%zu bytes @ offset %zu, input %zu bytes.\n", desc, size, offset , buffer_size(b)) | |||
134 | "%zu bytes @ offset %zu, input %zu bytes.\n",fprintf(stderr, "E: " "The file is not large enough for the '%s'. " "%zu bytes @ offset %zu, input %zu bytes.\n", desc, size, offset , buffer_size(b)) | |||
135 | desc, size, offset, buffer_size(b))fprintf(stderr, "E: " "The file is not large enough for the '%s'. " "%zu bytes @ offset %zu, input %zu bytes.\n", desc, size, offset , buffer_size(b)); | |||
136 | return -1; | |||
137 | } | |||
138 | return 0; | |||
139 | } | |||
140 | ||||
141 | static void | |||
142 | elf_ehdr(struct buffer *input, Elf64_Ehdr *ehdr, struct xdr *xdr, int bit64) | |||
143 | { | |||
144 | ehdr->e_type = xdr->get16(input); | |||
145 | ehdr->e_machine = xdr->get16(input); | |||
146 | ehdr->e_version = xdr->get32(input); | |||
147 | if (bit64){ | |||
148 | ehdr->e_entry = xdr->get64(input); | |||
149 | ehdr->e_phoff = xdr->get64(input); | |||
150 | ehdr->e_shoff = xdr->get64(input); | |||
151 | } else { | |||
152 | ehdr->e_entry = xdr->get32(input); | |||
153 | ehdr->e_phoff = xdr->get32(input); | |||
154 | ehdr->e_shoff = xdr->get32(input); | |||
155 | } | |||
156 | ehdr->e_flags = xdr->get32(input); | |||
157 | ehdr->e_ehsize = xdr->get16(input); | |||
158 | ehdr->e_phentsize = xdr->get16(input); | |||
159 | ehdr->e_phnum = xdr->get16(input); | |||
160 | ehdr->e_shentsize = xdr->get16(input); | |||
161 | ehdr->e_shnum = xdr->get16(input); | |||
162 | ehdr->e_shstrndx = xdr->get16(input); | |||
163 | } | |||
164 | ||||
165 | static void | |||
166 | elf_phdr(struct buffer *pinput, Elf64_Phdr *phdr, | |||
167 | int entsize, struct xdr *xdr, int bit64) | |||
168 | { | |||
169 | /* | |||
170 | * The entsize need not be sizeof(*phdr). | |||
171 | * Hence, it is easier to keep a copy of the input, | |||
172 | * as the xdr functions may not advance the input | |||
173 | * pointer the full entsize; rather than get tricky | |||
174 | * we just advance it below. | |||
175 | */ | |||
176 | struct buffer input; | |||
177 | buffer_clone(&input, pinput); | |||
178 | if (bit64){ | |||
179 | phdr->p_type = xdr->get32(&input); | |||
180 | phdr->p_flags = xdr->get32(&input); | |||
181 | phdr->p_offset = xdr->get64(&input); | |||
182 | phdr->p_vaddr = xdr->get64(&input); | |||
183 | phdr->p_paddr = xdr->get64(&input); | |||
184 | phdr->p_filesz = xdr->get64(&input); | |||
185 | phdr->p_memsz = xdr->get64(&input); | |||
186 | phdr->p_align = xdr->get64(&input); | |||
187 | } else { | |||
188 | phdr->p_type = xdr->get32(&input); | |||
189 | phdr->p_offset = xdr->get32(&input); | |||
190 | phdr->p_vaddr = xdr->get32(&input); | |||
191 | phdr->p_paddr = xdr->get32(&input); | |||
192 | phdr->p_filesz = xdr->get32(&input); | |||
193 | phdr->p_memsz = xdr->get32(&input); | |||
194 | phdr->p_flags = xdr->get32(&input); | |||
195 | phdr->p_align = xdr->get32(&input); | |||
196 | } | |||
197 | buffer_seek(pinput, entsize); | |||
198 | } | |||
199 | ||||
200 | static void | |||
201 | elf_shdr(struct buffer *pinput, Elf64_Shdr *shdr, | |||
202 | int entsize, struct xdr *xdr, int bit64) | |||
203 | { | |||
204 | /* | |||
205 | * The entsize need not be sizeof(*shdr). | |||
206 | * Hence, it is easier to keep a copy of the input, | |||
207 | * as the xdr functions may not advance the input | |||
208 | * pointer the full entsize; rather than get tricky | |||
209 | * we just advance it below. | |||
210 | */ | |||
211 | struct buffer input = *pinput; | |||
212 | if (bit64){ | |||
213 | shdr->sh_name = xdr->get32(&input); | |||
214 | shdr->sh_type = xdr->get32(&input); | |||
215 | shdr->sh_flags = xdr->get64(&input); | |||
216 | shdr->sh_addr = xdr->get64(&input); | |||
217 | shdr->sh_offset = xdr->get64(&input); | |||
218 | shdr->sh_size= xdr->get64(&input); | |||
219 | shdr->sh_link = xdr->get32(&input); | |||
220 | shdr->sh_info = xdr->get32(&input); | |||
221 | shdr->sh_addralign = xdr->get64(&input); | |||
222 | shdr->sh_entsize = xdr->get64(&input); | |||
223 | } else { | |||
224 | shdr->sh_name = xdr->get32(&input); | |||
225 | shdr->sh_type = xdr->get32(&input); | |||
226 | shdr->sh_flags = xdr->get32(&input); | |||
227 | shdr->sh_addr = xdr->get32(&input); | |||
228 | shdr->sh_offset = xdr->get32(&input); | |||
229 | shdr->sh_size = xdr->get32(&input); | |||
230 | shdr->sh_link = xdr->get32(&input); | |||
231 | shdr->sh_info = xdr->get32(&input); | |||
232 | shdr->sh_addralign = xdr->get32(&input); | |||
233 | shdr->sh_entsize = xdr->get32(&input); | |||
234 | } | |||
235 | buffer_seek(pinput, entsize); | |||
236 | } | |||
237 | ||||
238 | static int | |||
239 | phdr_read(const struct buffer *in, struct parsed_elf *pelf, | |||
240 | struct xdr *xdr, int bit64) | |||
241 | { | |||
242 | struct buffer b; | |||
243 | Elf64_Phdr *phdr; | |||
244 | Elf64_Ehdr *ehdr; | |||
245 | int i; | |||
246 | ||||
247 | ehdr = &pelf->ehdr; | |||
248 | /* cons up an input buffer for the headers. | |||
249 | * Note that the program headers can be anywhere, | |||
250 | * per the ELF spec, You'd be surprised how many ELF | |||
251 | * readers miss this little detail. | |||
252 | */ | |||
253 | buffer_splice(&b, in, ehdr->e_phoff, | |||
254 | (uint32_t)ehdr->e_phentsize * ehdr->e_phnum); | |||
255 | if (check_size(in, ehdr->e_phoff, buffer_size(&b), "program headers")) | |||
256 | return -1; | |||
257 | ||||
258 | /* gather up all the phdrs. | |||
259 | * We do them all at once because there is more | |||
260 | * than one loop over all the phdrs. | |||
261 | */ | |||
262 | phdr = calloc(ehdr->e_phnum, sizeof(*phdr)); | |||
263 | for (i = 0; i < ehdr->e_phnum; i++) { | |||
264 | DEBUG("Parsing segment %d\n", i)do { if (verbose > 1) fprintf(stderr, "DEBUG: " "Parsing segment %d\n" , i); } while (0); | |||
265 | elf_phdr(&b, &phdr[i], ehdr->e_phentsize, xdr, bit64); | |||
266 | ||||
267 | /* Ensure the contents are valid within the elf file. */ | |||
268 | if (check_size(in, phdr[i].p_offset, phdr[i].p_filesz, | |||
269 | "segment contents")) { | |||
270 | free(phdr); | |||
271 | return -1; | |||
272 | } | |||
273 | } | |||
274 | ||||
275 | pelf->phdr = phdr; | |||
276 | ||||
277 | return 0; | |||
278 | } | |||
279 | ||||
280 | static int | |||
281 | shdr_read(const struct buffer *in, struct parsed_elf *pelf, | |||
282 | struct xdr *xdr, int bit64) | |||
283 | { | |||
284 | struct buffer b; | |||
285 | Elf64_Shdr *shdr; | |||
286 | Elf64_Ehdr *ehdr; | |||
287 | int i; | |||
288 | ||||
289 | ehdr = &pelf->ehdr; | |||
290 | ||||
291 | /* cons up an input buffer for the section headers. | |||
292 | * Note that the section headers can be anywhere, | |||
293 | * per the ELF spec, You'd be surprised how many ELF | |||
294 | * readers miss this little detail. | |||
295 | */ | |||
296 | buffer_splice(&b, in, ehdr->e_shoff, | |||
297 | (uint32_t)ehdr->e_shentsize * ehdr->e_shnum); | |||
298 | if (check_size(in, ehdr->e_shoff, buffer_size(&b), "section headers")) | |||
299 | return -1; | |||
300 | ||||
301 | /* gather up all the shdrs. */ | |||
302 | shdr = calloc(ehdr->e_shnum, sizeof(*shdr)); | |||
303 | for (i = 0; i < ehdr->e_shnum; i++) { | |||
304 | DEBUG("Parsing section %d\n", i)do { if (verbose > 1) fprintf(stderr, "DEBUG: " "Parsing section %d\n" , i); } while (0); | |||
305 | elf_shdr(&b, &shdr[i], ehdr->e_shentsize, xdr, bit64); | |||
306 | } | |||
307 | ||||
308 | pelf->shdr = shdr; | |||
309 | ||||
310 | return 0; | |||
311 | } | |||
312 | ||||
313 | static int | |||
314 | reloc_read(const struct buffer *in, struct parsed_elf *pelf, | |||
315 | struct xdr *xdr, int bit64) | |||
316 | { | |||
317 | struct buffer b; | |||
318 | Elf64_Word i; | |||
319 | Elf64_Ehdr *ehdr; | |||
320 | ||||
321 | ehdr = &pelf->ehdr; | |||
322 | pelf->relocs = calloc(ehdr->e_shnum, sizeof(Elf64_Rela *)); | |||
323 | ||||
324 | /* Allocate array for each section that contains relocation entries. */ | |||
325 | for (i = 0; i < ehdr->e_shnum; i++) { | |||
326 | Elf64_Shdr *shdr; | |||
327 | Elf64_Rela *rela; | |||
328 | Elf64_Xword j; | |||
329 | Elf64_Xword nrelocs; | |||
330 | int is_rela; | |||
331 | ||||
332 | shdr = &pelf->shdr[i]; | |||
333 | ||||
334 | /* Only process REL and RELA sections. */ | |||
335 | if (shdr->sh_type != SHT_REL9 && shdr->sh_type != SHT_RELA4) | |||
336 | continue; | |||
337 | ||||
338 | DEBUG("Checking relocation section %u\n", i)do { if (verbose > 1) fprintf(stderr, "DEBUG: " "Checking relocation section %u\n" , i); } while (0); | |||
339 | ||||
340 | /* Ensure the section that relocations apply is a valid. */ | |||
341 | if (shdr->sh_info >= ehdr->e_shnum || | |||
342 | shdr->sh_info == SHN_UNDEF0) { | |||
343 | ERROR("Relocations apply to an invalid section: %u\n",fprintf(stderr, "E: " "Relocations apply to an invalid section: %u\n" , shdr[i].sh_info) | |||
344 | shdr[i].sh_info)fprintf(stderr, "E: " "Relocations apply to an invalid section: %u\n" , shdr[i].sh_info); | |||
345 | return -1; | |||
346 | } | |||
347 | ||||
348 | is_rela = shdr->sh_type == SHT_RELA4; | |||
349 | ||||
350 | /* Determine the number relocations in this section. */ | |||
351 | nrelocs = shdr->sh_size / shdr->sh_entsize; | |||
352 | ||||
353 | pelf->relocs[i] = calloc(nrelocs, sizeof(Elf64_Rela)); | |||
354 | ||||
355 | buffer_splice(&b, in, shdr->sh_offset, shdr->sh_size); | |||
356 | if (check_size(in, shdr->sh_offset, buffer_size(&b), | |||
357 | "relocation section")) { | |||
358 | ERROR("Relocation section %u failed.\n", i)fprintf(stderr, "E: " "Relocation section %u failed.\n", i); | |||
359 | return -1; | |||
360 | } | |||
361 | ||||
362 | rela = pelf->relocs[i]; | |||
363 | for (j = 0; j < nrelocs; j++) { | |||
364 | if (bit64) { | |||
365 | rela->r_offset = xdr->get64(&b); | |||
366 | rela->r_info = xdr->get64(&b); | |||
367 | if (is_rela) | |||
368 | rela->r_addend = xdr->get64(&b); | |||
369 | } else { | |||
370 | uint32_t r_info; | |||
371 | ||||
372 | rela->r_offset = xdr->get32(&b); | |||
373 | r_info = xdr->get32(&b); | |||
374 | rela->r_info = ELF64_R_INFO(ELF32_R_SYM(r_info),((((Elf64_Xword) (((r_info) >> 8))) << 32) + (((r_info ) & 0xff))) | |||
375 | ELF32_R_TYPE(r_info))((((Elf64_Xword) (((r_info) >> 8))) << 32) + (((r_info ) & 0xff))); | |||
376 | if (is_rela) | |||
377 | rela->r_addend = xdr->get32(&b); | |||
378 | } | |||
379 | rela++; | |||
380 | } | |||
381 | } | |||
382 | ||||
383 | return 0; | |||
384 | } | |||
385 | ||||
386 | static int strtab_read(const struct buffer *in, struct parsed_elf *pelf) | |||
387 | { | |||
388 | Elf64_Ehdr *ehdr; | |||
389 | Elf64_Word i; | |||
390 | ||||
391 | ehdr = &pelf->ehdr; | |||
392 | ||||
393 | if (ehdr->e_shstrndx >= ehdr->e_shnum) { | |||
394 | ERROR("Section header string table index out of range: %d\n",fprintf(stderr, "E: " "Section header string table index out of range: %d\n" , ehdr->e_shstrndx) | |||
395 | ehdr->e_shstrndx)fprintf(stderr, "E: " "Section header string table index out of range: %d\n" , ehdr->e_shstrndx); | |||
396 | return -1; | |||
397 | } | |||
398 | ||||
399 | /* For each section of type SHT_STRTAB create a symtab buffer. */ | |||
400 | pelf->strtabs = calloc(ehdr->e_shnum, sizeof(struct buffer *)); | |||
401 | ||||
402 | for (i = 0; i < ehdr->e_shnum; i++) { | |||
403 | struct buffer *b; | |||
404 | Elf64_Shdr *shdr = &pelf->shdr[i]; | |||
405 | ||||
406 | if (shdr->sh_type != SHT_STRTAB3) | |||
407 | continue; | |||
408 | ||||
409 | b = calloc(1, sizeof(*b)); | |||
410 | buffer_splice(b, in, shdr->sh_offset, shdr->sh_size); | |||
411 | if (check_size(in, shdr->sh_offset, buffer_size(b), "strtab")) { | |||
412 | ERROR("STRTAB section not within bounds: %d\n", i)fprintf(stderr, "E: " "STRTAB section not within bounds: %d\n" , i); | |||
413 | free(b); | |||
414 | return -1; | |||
415 | } | |||
416 | pelf->strtabs[i] = b; | |||
417 | } | |||
418 | ||||
419 | return 0; | |||
420 | } | |||
421 | ||||
422 | static int | |||
423 | symtab_read(const struct buffer *in, struct parsed_elf *pelf, | |||
424 | struct xdr *xdr, int bit64) | |||
425 | { | |||
426 | Elf64_Ehdr *ehdr; | |||
427 | Elf64_Shdr *shdr; | |||
428 | Elf64_Half shnum; | |||
429 | Elf64_Xword i; | |||
430 | Elf64_Xword nsyms; | |||
431 | Elf64_Sym *sym; | |||
432 | struct buffer b; | |||
433 | ||||
434 | ehdr = &pelf->ehdr; | |||
435 | ||||
436 | shdr = NULL((void*)0); | |||
437 | for (shnum = 0; shnum < ehdr->e_shnum; shnum++) { | |||
438 | if (pelf->shdr[shnum].sh_type != SHT_SYMTAB2) | |||
439 | continue; | |||
440 | ||||
441 | if (shdr != NULL((void*)0)) { | |||
442 | ERROR("Multiple symbol sections found. %u and %u\n",fprintf(stderr, "E: " "Multiple symbol sections found. %u and %u\n" , (unsigned int)(shdr - pelf->shdr), shnum) | |||
443 | (unsigned int)(shdr - pelf->shdr), shnum)fprintf(stderr, "E: " "Multiple symbol sections found. %u and %u\n" , (unsigned int)(shdr - pelf->shdr), shnum); | |||
444 | return -1; | |||
445 | } | |||
446 | ||||
447 | shdr = &pelf->shdr[shnum]; | |||
448 | } | |||
449 | ||||
450 | if (shdr == NULL((void*)0)) { | |||
451 | ERROR("No symbol table found.\n")fprintf(stderr, "E: " "No symbol table found.\n"); | |||
452 | return -1; | |||
453 | } | |||
454 | ||||
455 | buffer_splice(&b, in, shdr->sh_offset, shdr->sh_size); | |||
456 | if (check_size(in, shdr->sh_offset, buffer_size(&b), "symtab")) | |||
457 | return -1; | |||
458 | ||||
459 | nsyms = shdr->sh_size / shdr->sh_entsize; | |||
460 | ||||
461 | pelf->syms = calloc(nsyms, sizeof(Elf64_Sym)); | |||
462 | ||||
463 | for (i = 0; i < nsyms; i++) { | |||
464 | sym = &pelf->syms[i]; | |||
465 | ||||
466 | if (bit64) { | |||
467 | sym->st_name = xdr->get32(&b); | |||
468 | sym->st_info = xdr->get8(&b); | |||
469 | sym->st_other = xdr->get8(&b); | |||
470 | sym->st_shndx = xdr->get16(&b); | |||
471 | sym->st_value = xdr->get64(&b); | |||
472 | sym->st_size = xdr->get64(&b); | |||
473 | } else { | |||
474 | sym->st_name = xdr->get32(&b); | |||
475 | sym->st_value = xdr->get32(&b); | |||
476 | sym->st_size = xdr->get32(&b); | |||
477 | sym->st_info = xdr->get8(&b); | |||
478 | sym->st_other = xdr->get8(&b); | |||
479 | sym->st_shndx = xdr->get16(&b); | |||
480 | } | |||
481 | } | |||
482 | ||||
483 | return 0; | |||
484 | } | |||
485 | ||||
486 | int parse_elf(const struct buffer *pinput, struct parsed_elf *pelf, int flags) | |||
487 | { | |||
488 | struct xdr *xdr = &xdr_le; | |||
489 | int bit64 = 0; | |||
490 | struct buffer input; | |||
491 | Elf64_Ehdr *ehdr; | |||
492 | ||||
493 | /* Zero out the parsed elf structure. */ | |||
494 | memset(pelf, 0, sizeof(*pelf)); | |||
495 | ||||
496 | if (!iself(buffer_get(pinput))) { | |||
497 | DEBUG("The stage file is not in ELF format!\n")do { if (verbose > 1) fprintf(stderr, "DEBUG: " "The stage file is not in ELF format!\n" ); } while (0); | |||
498 | return -1; | |||
499 | } | |||
500 | ||||
501 | buffer_clone(&input, pinput); | |||
502 | ehdr = &pelf->ehdr; | |||
503 | elf_eident(&input, ehdr); | |||
504 | bit64 = ehdr->e_ident[EI_CLASS4] == ELFCLASS642; | |||
505 | /* Assume LE unless we are sure otherwise. | |||
506 | * We're not going to take on the task of | |||
507 | * fully validating the ELF file. That way | |||
508 | * lies madness. | |||
509 | */ | |||
510 | if (ehdr->e_ident[EI_DATA5] == ELFDATA2MSB2) | |||
511 | xdr = &xdr_be; | |||
512 | ||||
513 | elf_ehdr(&input, ehdr, xdr, bit64); | |||
514 | ||||
515 | /* Relocation processing requires section header parsing. */ | |||
516 | if (flags & ELF_PARSE_RELOC(1 << 2)) | |||
517 | flags |= ELF_PARSE_SHDR(1 << 1); | |||
518 | ||||
519 | /* String table processing requires section header parsing. */ | |||
520 | if (flags & ELF_PARSE_STRTAB(1 << 3)) | |||
521 | flags |= ELF_PARSE_SHDR(1 << 1); | |||
522 | ||||
523 | /* Symbole table processing requires section header parsing. */ | |||
524 | if (flags & ELF_PARSE_SYMTAB(1 << 4)) | |||
525 | flags |= ELF_PARSE_SHDR(1 << 1); | |||
526 | ||||
527 | if ((flags & ELF_PARSE_PHDR(1 << 0)) && phdr_read(pinput, pelf, xdr, bit64)) | |||
528 | goto fail; | |||
529 | ||||
530 | if ((flags & ELF_PARSE_SHDR(1 << 1)) && shdr_read(pinput, pelf, xdr, bit64)) | |||
531 | goto fail; | |||
532 | ||||
533 | if ((flags & ELF_PARSE_RELOC(1 << 2)) && reloc_read(pinput, pelf, xdr, bit64)) | |||
534 | goto fail; | |||
535 | ||||
536 | if ((flags & ELF_PARSE_STRTAB(1 << 3)) && strtab_read(pinput, pelf)) | |||
537 | goto fail; | |||
538 | ||||
539 | if ((flags & ELF_PARSE_SYMTAB(1 << 4)) && symtab_read(pinput, pelf, xdr, bit64)) | |||
540 | goto fail; | |||
541 | ||||
542 | return 0; | |||
543 | ||||
544 | fail: | |||
545 | parsed_elf_destroy(pelf); | |||
546 | return -1; | |||
547 | } | |||
548 | ||||
549 | void parsed_elf_destroy(struct parsed_elf *pelf) | |||
550 | { | |||
551 | Elf64_Half i; | |||
552 | ||||
553 | free(pelf->phdr); | |||
554 | free(pelf->shdr); | |||
555 | if (pelf->relocs != NULL((void*)0)) { | |||
556 | for (i = 0; i < pelf->ehdr.e_shnum; i++) | |||
557 | free(pelf->relocs[i]); | |||
558 | } | |||
559 | free(pelf->relocs); | |||
560 | ||||
561 | if (pelf->strtabs != NULL((void*)0)) { | |||
562 | for (i = 0; i < pelf->ehdr.e_shnum; i++) | |||
563 | free(pelf->strtabs[i]); | |||
564 | } | |||
565 | free(pelf->strtabs); | |||
566 | free(pelf->syms); | |||
567 | } | |||
568 | ||||
569 | /* Get the headers from the buffer. | |||
570 | * Return -1 in the event of an error. | |||
571 | * The section headers are optional; if NULL | |||
572 | * is passed in for pshdr they won't be parsed. | |||
573 | * We don't (yet) make payload parsing optional | |||
574 | * because we've never seen a use case. | |||
575 | */ | |||
576 | int | |||
577 | elf_headers(const struct buffer *pinput, | |||
578 | Elf64_Ehdr *ehdr, | |||
579 | Elf64_Phdr **pphdr, | |||
580 | Elf64_Shdr **pshdr) | |||
581 | { | |||
582 | struct parsed_elf pelf; | |||
583 | int flags; | |||
584 | ||||
585 | flags = ELF_PARSE_PHDR(1 << 0); | |||
586 | ||||
587 | if (pshdr != NULL((void*)0)) | |||
588 | flags |= ELF_PARSE_SHDR(1 << 1); | |||
589 | ||||
590 | if (parse_elf(pinput, &pelf, flags)) | |||
591 | return -1; | |||
592 | ||||
593 | /* Copy out the parsed elf header. */ | |||
594 | memcpy(ehdr, &pelf.ehdr, sizeof(*ehdr)); | |||
595 | ||||
596 | *pphdr = calloc(ehdr->e_phnum, sizeof(Elf64_Phdr)); | |||
597 | memcpy(*pphdr, pelf.phdr, ehdr->e_phnum * sizeof(Elf64_Phdr)); | |||
598 | ||||
599 | if (pshdr != NULL((void*)0)) { | |||
600 | *pshdr = calloc(ehdr->e_shnum, sizeof(Elf64_Shdr)); | |||
601 | memcpy(*pshdr, pelf.shdr, ehdr->e_shnum * sizeof(Elf64_Shdr)); | |||
602 | } | |||
603 | ||||
604 | parsed_elf_destroy(&pelf); | |||
605 | ||||
606 | return 0; | |||
607 | } | |||
608 | ||||
609 | /* ELF Writing Support | |||
610 | * | |||
611 | * The ELF file is written according to the following layout: | |||
612 | * +------------------+ | |||
613 | * | ELF Header | | |||
614 | * +------------------+ | |||
615 | * | Section Headers | | |||
616 | * +------------------+ | |||
617 | * | Program Headers | | |||
618 | * +------------------+ | |||
619 | * | String table | | |||
620 | * +------------------+ <- 4KiB Aligned | |||
621 | * | Code/Data | | |||
622 | * +------------------+ | |||
623 | */ | |||
624 | ||||
625 | void elf_init_eheader(Elf64_Ehdr *ehdr, int machine, int nbits, int endian) | |||
626 | { | |||
627 | memset(ehdr, 0, sizeof(*ehdr)); | |||
628 | ehdr->e_ident[EI_MAG00] = ELFMAG00x7f; | |||
629 | ehdr->e_ident[EI_MAG11] = ELFMAG1'E'; | |||
630 | ehdr->e_ident[EI_MAG22] = ELFMAG2'L'; | |||
631 | ehdr->e_ident[EI_MAG33] = ELFMAG3'F'; | |||
632 | ehdr->e_ident[EI_CLASS4] = nbits; | |||
633 | ehdr->e_ident[EI_DATA5] = endian; | |||
634 | ehdr->e_ident[EI_VERSION6] = EV_CURRENT1; | |||
635 | ehdr->e_type = ET_EXEC2; | |||
636 | ehdr->e_machine = machine; | |||
637 | ehdr->e_version = EV_CURRENT1; | |||
638 | if (nbits == ELFCLASS642) { | |||
639 | ehdr->e_ehsize = sizeof(Elf64_Ehdr); | |||
640 | ehdr->e_phentsize = sizeof(Elf64_Phdr); | |||
641 | ehdr->e_shentsize = sizeof(Elf64_Shdr); | |||
642 | } else { | |||
643 | ehdr->e_ehsize = sizeof(Elf32_Ehdr); | |||
644 | ehdr->e_phentsize = sizeof(Elf32_Phdr); | |||
645 | ehdr->e_shentsize = sizeof(Elf32_Shdr); | |||
646 | } | |||
647 | } | |||
648 | ||||
649 | /* Arbitrary maximum number of sections. */ | |||
650 | #define MAX_SECTIONS16 16 | |||
651 | struct elf_writer_section { | |||
652 | Elf64_Shdr shdr; | |||
653 | struct buffer content; | |||
654 | const char *name; | |||
655 | }; | |||
656 | ||||
657 | struct elf_writer_string_table { | |||
658 | size_t next_offset; | |||
659 | size_t max_size; | |||
660 | char *buffer; | |||
661 | }; | |||
662 | ||||
663 | struct elf_writer_sym_table { | |||
664 | size_t max_entries; | |||
665 | size_t num_entries; | |||
666 | Elf64_Sym *syms; | |||
667 | }; | |||
668 | ||||
669 | #define MAX_REL_NAME32 32 | |||
670 | struct elf_writer_rel { | |||
671 | size_t num_entries; | |||
672 | size_t max_entries; | |||
673 | Elf64_Rel *rels; | |||
674 | struct elf_writer_section *sec; | |||
675 | char name[MAX_REL_NAME32]; | |||
676 | }; | |||
677 | ||||
678 | struct elf_writer | |||
679 | { | |||
680 | Elf64_Ehdr ehdr; | |||
681 | struct xdr *xdr; | |||
682 | size_t num_secs; | |||
683 | struct elf_writer_section sections[MAX_SECTIONS16]; | |||
684 | struct elf_writer_rel rel_sections[MAX_SECTIONS16]; | |||
685 | Elf64_Phdr *phdrs; | |||
686 | struct elf_writer_section *shstrtab_sec; | |||
687 | struct elf_writer_section *strtab_sec; | |||
688 | struct elf_writer_section *symtab_sec; | |||
689 | struct elf_writer_string_table strtab; | |||
690 | struct elf_writer_sym_table symtab; | |||
691 | int bit64; | |||
692 | }; | |||
693 | ||||
694 | static size_t section_index(struct elf_writer *ew, | |||
695 | struct elf_writer_section *sec) | |||
696 | { | |||
697 | return sec - &ew->sections[0]; | |||
698 | } | |||
699 | ||||
700 | static struct elf_writer_section *last_section(struct elf_writer *ew) | |||
701 | { | |||
702 | return &ew->sections[ew->num_secs - 1]; | |||
703 | } | |||
704 | ||||
705 | static void strtab_init(struct elf_writer *ew, size_t size) | |||
706 | { | |||
707 | struct buffer b; | |||
708 | Elf64_Shdr shdr; | |||
709 | ||||
710 | /* Start adding strings after the initial NUL entry. */ | |||
711 | ew->strtab.next_offset = 1; | |||
712 | ew->strtab.max_size = size; | |||
713 | ew->strtab.buffer = calloc(1, ew->strtab.max_size); | |||
714 | ||||
715 | buffer_init(&b, NULL((void*)0), ew->strtab.buffer, ew->strtab.max_size); | |||
716 | memset(&shdr, 0, sizeof(shdr)); | |||
717 | shdr.sh_type = SHT_STRTAB3; | |||
718 | shdr.sh_addralign = 1; | |||
719 | shdr.sh_size = ew->strtab.max_size; | |||
720 | elf_writer_add_section(ew, &shdr, &b, ".strtab"); | |||
721 | ew->strtab_sec = last_section(ew); | |||
722 | } | |||
723 | ||||
724 | static void symtab_init(struct elf_writer *ew, size_t max_entries) | |||
725 | { | |||
726 | struct buffer b; | |||
727 | Elf64_Shdr shdr; | |||
728 | ||||
729 | memset(&shdr, 0, sizeof(shdr)); | |||
730 | shdr.sh_type = SHT_SYMTAB2; | |||
731 | ||||
732 | if (ew->bit64) { | |||
733 | shdr.sh_entsize = sizeof(Elf64_Sym); | |||
734 | shdr.sh_addralign = sizeof(Elf64_Addr); | |||
735 | } else { | |||
736 | shdr.sh_entsize = sizeof(Elf32_Sym); | |||
737 | shdr.sh_addralign = sizeof(Elf32_Addr); | |||
738 | } | |||
739 | ||||
740 | shdr.sh_size = shdr.sh_entsize * max_entries; | |||
741 | ||||
742 | ew->symtab.syms = calloc(max_entries, sizeof(Elf64_Sym)); | |||
743 | ew->symtab.num_entries = 1; | |||
744 | ew->symtab.max_entries = max_entries; | |||
745 | ||||
746 | buffer_init(&b, NULL((void*)0), ew->symtab.syms, shdr.sh_size); | |||
747 | ||||
748 | elf_writer_add_section(ew, &shdr, &b, ".symtab"); | |||
749 | ew->symtab_sec = last_section(ew); | |||
750 | } | |||
751 | ||||
752 | struct elf_writer *elf_writer_init(const Elf64_Ehdr *ehdr) | |||
753 | { | |||
754 | struct elf_writer *ew; | |||
755 | Elf64_Shdr shdr; | |||
756 | struct buffer empty_buffer; | |||
757 | ||||
758 | if (!iself(ehdr)) | |||
759 | return NULL((void*)0); | |||
760 | ||||
761 | ew = calloc(1, sizeof(*ew)); | |||
762 | ||||
763 | memcpy(&ew->ehdr, ehdr, sizeof(ew->ehdr)); | |||
764 | ||||
765 | ew->bit64 = ew->ehdr.e_ident[EI_CLASS4] == ELFCLASS642; | |||
766 | ||||
767 | /* Set the endinan ops. */ | |||
768 | if (ew->ehdr.e_ident[EI_DATA5] == ELFDATA2MSB2) | |||
769 | ew->xdr = &xdr_be; | |||
770 | else | |||
771 | ew->xdr = &xdr_le; | |||
772 | ||||
773 | /* Reset count and offsets */ | |||
774 | ew->ehdr.e_phoff = 0; | |||
775 | ew->ehdr.e_shoff = 0; | |||
776 | ew->ehdr.e_shnum = 0; | |||
777 | ew->ehdr.e_phnum = 0; | |||
778 | ||||
779 | memset(&empty_buffer, 0, sizeof(empty_buffer)); | |||
780 | memset(&shdr, 0, sizeof(shdr)); | |||
781 | ||||
782 | /* Add SHT_NULL section header. */ | |||
783 | shdr.sh_type = SHT_NULL0; | |||
784 | elf_writer_add_section(ew, &shdr, &empty_buffer, NULL((void*)0)); | |||
785 | ||||
786 | /* Add section header string table and maintain reference to it. */ | |||
787 | shdr.sh_type = SHT_STRTAB3; | |||
788 | elf_writer_add_section(ew, &shdr, &empty_buffer, ".shstrtab"); | |||
789 | ew->shstrtab_sec = last_section(ew); | |||
790 | ew->ehdr.e_shstrndx = section_index(ew, ew->shstrtab_sec); | |||
791 | ||||
792 | /* Add a small string table and symbol table. */ | |||
793 | strtab_init(ew, 4096); | |||
794 | symtab_init(ew, 100); | |||
795 | ||||
796 | return ew; | |||
797 | } | |||
798 | ||||
799 | /* | |||
800 | * Clean up any internal state represented by ew. Aftewards the elf_writer | |||
801 | * is invalid. | |||
802 | * It is safe to call elf_writer_destroy with ew as NULL. It returns without | |||
803 | * performing any action. | |||
804 | */ | |||
805 | void elf_writer_destroy(struct elf_writer *ew) | |||
806 | { | |||
807 | int i; | |||
808 | if (ew == NULL((void*)0)) | |||
809 | return; | |||
810 | if (ew->phdrs != NULL((void*)0)) | |||
811 | free(ew->phdrs); | |||
812 | free(ew->strtab.buffer); | |||
813 | free(ew->symtab.syms); | |||
814 | for (i = 0; i < MAX_SECTIONS16; i++) | |||
815 | free(ew->rel_sections[i].rels); | |||
816 | free(ew); | |||
817 | } | |||
818 | ||||
819 | /* | |||
820 | * Add a section to the ELF file. Section type, flags, and memsize are | |||
821 | * maintained from the passed in Elf64_Shdr. The buffer represents the | |||
822 | * content of the section while the name is the name of section itself. | |||
823 | * Returns < 0 on error, 0 on success. | |||
824 | */ | |||
825 | int elf_writer_add_section(struct elf_writer *ew, const Elf64_Shdr *shdr, | |||
826 | struct buffer *contents, const char *name) | |||
827 | { | |||
828 | struct elf_writer_section *newsh; | |||
829 | ||||
830 | if (ew->num_secs == MAX_SECTIONS16) | |||
831 | return -1; | |||
832 | ||||
833 | newsh = &ew->sections[ew->num_secs]; | |||
834 | ew->num_secs++; | |||
835 | ||||
836 | memcpy(&newsh->shdr, shdr, sizeof(newsh->shdr)); | |||
837 | newsh->shdr.sh_offset = 0; | |||
838 | ||||
839 | newsh->name = name; | |||
840 | if (contents != NULL((void*)0)) | |||
841 | buffer_clone(&newsh->content, contents); | |||
842 | ||||
843 | return 0; | |||
844 | } | |||
845 | ||||
846 | static void ehdr_write(struct elf_writer *ew, struct buffer *m) | |||
847 | { | |||
848 | int i; | |||
849 | ||||
850 | for (i = 0; i < EI_NIDENT(16); i++) | |||
851 | ew->xdr->put8(m, ew->ehdr.e_ident[i]); | |||
852 | ew->xdr->put16(m, ew->ehdr.e_type); | |||
853 | ew->xdr->put16(m, ew->ehdr.e_machine); | |||
854 | ew->xdr->put32(m, ew->ehdr.e_version); | |||
855 | if (ew->bit64) { | |||
856 | ew->xdr->put64(m, ew->ehdr.e_entry); | |||
857 | ew->xdr->put64(m, ew->ehdr.e_phoff); | |||
858 | ew->xdr->put64(m, ew->ehdr.e_shoff); | |||
859 | } else { | |||
860 | ew->xdr->put32(m, ew->ehdr.e_entry); | |||
861 | ew->xdr->put32(m, ew->ehdr.e_phoff); | |||
862 | ew->xdr->put32(m, ew->ehdr.e_shoff); | |||
863 | } | |||
864 | ew->xdr->put32(m, ew->ehdr.e_flags); | |||
865 | ew->xdr->put16(m, ew->ehdr.e_ehsize); | |||
866 | ew->xdr->put16(m, ew->ehdr.e_phentsize); | |||
867 | ew->xdr->put16(m, ew->ehdr.e_phnum); | |||
868 | ew->xdr->put16(m, ew->ehdr.e_shentsize); | |||
869 | ew->xdr->put16(m, ew->ehdr.e_shnum); | |||
870 | ew->xdr->put16(m, ew->ehdr.e_shstrndx); | |||
871 | } | |||
872 | ||||
873 | static void shdr_write(struct elf_writer *ew, size_t n, struct buffer *m) | |||
874 | { | |||
875 | struct xdr *xdr = ew->xdr; | |||
876 | int bit64 = ew->bit64; | |||
877 | struct elf_writer_section *sec = &ew->sections[n]; | |||
878 | Elf64_Shdr *shdr = &sec->shdr; | |||
879 | ||||
880 | xdr->put32(m, shdr->sh_name); | |||
881 | xdr->put32(m, shdr->sh_type); | |||
882 | if (bit64) { | |||
883 | xdr->put64(m, shdr->sh_flags); | |||
884 | xdr->put64(m, shdr->sh_addr); | |||
885 | xdr->put64(m, shdr->sh_offset); | |||
886 | xdr->put64(m, shdr->sh_size); | |||
887 | xdr->put32(m, shdr->sh_link); | |||
888 | xdr->put32(m, shdr->sh_info); | |||
889 | xdr->put64(m, shdr->sh_addralign); | |||
890 | xdr->put64(m, shdr->sh_entsize); | |||
891 | } else { | |||
892 | xdr->put32(m, shdr->sh_flags); | |||
893 | xdr->put32(m, shdr->sh_addr); | |||
894 | xdr->put32(m, shdr->sh_offset); | |||
895 | xdr->put32(m, shdr->sh_size); | |||
896 | xdr->put32(m, shdr->sh_link); | |||
897 | xdr->put32(m, shdr->sh_info); | |||
898 | xdr->put32(m, shdr->sh_addralign); | |||
899 | xdr->put32(m, shdr->sh_entsize); | |||
900 | } | |||
901 | } | |||
902 | ||||
903 | static void | |||
904 | phdr_write(struct elf_writer *ew, struct buffer *m, Elf64_Phdr *phdr) | |||
905 | { | |||
906 | if (ew->bit64) { | |||
907 | ew->xdr->put32(m, phdr->p_type); | |||
908 | ew->xdr->put32(m, phdr->p_flags); | |||
909 | ew->xdr->put64(m, phdr->p_offset); | |||
910 | ew->xdr->put64(m, phdr->p_vaddr); | |||
911 | ew->xdr->put64(m, phdr->p_paddr); | |||
912 | ew->xdr->put64(m, phdr->p_filesz); | |||
913 | ew->xdr->put64(m, phdr->p_memsz); | |||
914 | ew->xdr->put64(m, phdr->p_align); | |||
915 | } else { | |||
916 | ew->xdr->put32(m, phdr->p_type); | |||
917 | ew->xdr->put32(m, phdr->p_offset); | |||
918 | ew->xdr->put32(m, phdr->p_vaddr); | |||
919 | ew->xdr->put32(m, phdr->p_paddr); | |||
920 | ew->xdr->put32(m, phdr->p_filesz); | |||
921 | ew->xdr->put32(m, phdr->p_memsz); | |||
922 | ew->xdr->put32(m, phdr->p_flags); | |||
923 | ew->xdr->put32(m, phdr->p_align); | |||
924 | } | |||
925 | ||||
926 | } | |||
927 | ||||
928 | static int section_consecutive(struct elf_writer *ew, Elf64_Half secidx) | |||
929 | { | |||
930 | Elf64_Half i; | |||
931 | struct elf_writer_section *prev_alloc = NULL((void*)0); | |||
932 | ||||
933 | if (secidx == 0) | |||
934 | return 0; | |||
935 | ||||
936 | for (i = 0; i < secidx; i++) { | |||
937 | if (ew->sections[i].shdr.sh_flags & SHF_ALLOC(1 << 1)) | |||
938 | prev_alloc = &ew->sections[i]; | |||
939 | } | |||
940 | ||||
941 | if (prev_alloc == NULL((void*)0)) | |||
942 | return 0; | |||
943 | ||||
944 | if (prev_alloc->shdr.sh_addr + prev_alloc->shdr.sh_size == | |||
945 | ew->sections[secidx].shdr.sh_addr) | |||
946 | return 1; | |||
947 | ||||
948 | return 0; | |||
949 | } | |||
950 | ||||
951 | static void write_phdrs(struct elf_writer *ew, struct buffer *phdrs) | |||
952 | { | |||
953 | Elf64_Half i; | |||
954 | Elf64_Phdr phdr; | |||
955 | size_t num_written = 0; | |||
956 | size_t num_needs_write = 0; | |||
957 | ||||
958 | for (i = 0; i < ew->num_secs; i++) { | |||
959 | struct elf_writer_section *sec = &ew->sections[i]; | |||
960 | ||||
961 | if (!(sec->shdr.sh_flags & SHF_ALLOC(1 << 1))) | |||
962 | continue; | |||
963 | ||||
964 | if (!section_consecutive(ew, i)) { | |||
965 | /* Write out previously set phdr. */ | |||
966 | if (num_needs_write != num_written) { | |||
967 | phdr_write(ew, phdrs, &phdr); | |||
968 | num_written++; | |||
969 | } | |||
970 | phdr.p_type = PT_LOAD1; | |||
971 | phdr.p_offset = sec->shdr.sh_offset; | |||
972 | phdr.p_vaddr = sec->shdr.sh_addr; | |||
973 | phdr.p_paddr = sec->shdr.sh_addr; | |||
974 | phdr.p_filesz = buffer_size(&sec->content); | |||
975 | phdr.p_memsz = sec->shdr.sh_size; | |||
976 | phdr.p_flags = 0; | |||
977 | if (sec->shdr.sh_flags & SHF_EXECINSTR(1 << 2)) | |||
978 | phdr.p_flags |= PF_X(1 << 0) | PF_R(1 << 2); | |||
979 | if (sec->shdr.sh_flags & SHF_WRITE(1 << 0)) | |||
980 | phdr.p_flags |= PF_W(1 << 1); | |||
981 | phdr.p_align = sec->shdr.sh_addralign; | |||
982 | num_needs_write++; | |||
983 | ||||
984 | } else { | |||
985 | /* Accumulate file size and memsize. The assumption | |||
986 | * is that each section is either NOBITS or full | |||
987 | * (sh_size == file size). This is standard in that | |||
988 | * an ELF section doesn't have a file size component. */ | |||
989 | if (sec->shdr.sh_flags & SHF_EXECINSTR(1 << 2)) | |||
990 | phdr.p_flags |= PF_X(1 << 0) | PF_R(1 << 2); | |||
991 | if (sec->shdr.sh_flags & SHF_WRITE(1 << 0)) | |||
992 | phdr.p_flags |= PF_W(1 << 1); | |||
| ||||
993 | phdr.p_filesz += buffer_size(&sec->content); | |||
994 | phdr.p_memsz += sec->shdr.sh_size; | |||
995 | } | |||
996 | } | |||
997 | ||||
998 | /* Write out the last phdr. */ | |||
999 | if (num_needs_write != num_written) { | |||
1000 | phdr_write(ew, phdrs, &phdr); | |||
1001 | num_written++; | |||
1002 | } | |||
1003 | assert(num_written == ew->ehdr.e_phnum)((num_written == ew->ehdr.e_phnum) ? (void) (0) : __assert_fail ("num_written == ew->ehdr.e_phnum", "/home/coreboot/node-root/workspace/coreboot_scanbuild/util/cbfstool/elfheaders.c" , 1003, __extension__ __PRETTY_FUNCTION__)); | |||
1004 | } | |||
1005 | ||||
1006 | static void fixup_symbol_table(struct elf_writer *ew) | |||
1007 | { | |||
1008 | struct elf_writer_section *sec = ew->symtab_sec; | |||
1009 | ||||
1010 | /* If there is only the NULL section, mark section as inactive. */ | |||
1011 | if (ew->symtab.num_entries == 1) { | |||
1012 | sec->shdr.sh_type = SHT_NULL0; | |||
1013 | sec->shdr.sh_size = 0; | |||
1014 | } else { | |||
1015 | size_t i; | |||
1016 | struct buffer wr; | |||
1017 | ||||
1018 | buffer_clone(&wr, &sec->content); | |||
1019 | /* To appease xdr. */ | |||
1020 | buffer_set_size(&wr, 0); | |||
1021 | for (i = 0; i < ew->symtab.num_entries; i++) { | |||
1022 | /* Create local copy as were over-writing backing | |||
1023 | * store of the symbol. */ | |||
1024 | Elf64_Sym sym = ew->symtab.syms[i]; | |||
1025 | if (ew->bit64) { | |||
1026 | ew->xdr->put32(&wr, sym.st_name); | |||
1027 | ew->xdr->put8(&wr, sym.st_info); | |||
1028 | ew->xdr->put8(&wr, sym.st_other); | |||
1029 | ew->xdr->put16(&wr, sym.st_shndx); | |||
1030 | ew->xdr->put64(&wr, sym.st_value); | |||
1031 | ew->xdr->put64(&wr, sym.st_size); | |||
1032 | } else { | |||
1033 | ew->xdr->put32(&wr, sym.st_name); | |||
1034 | ew->xdr->put32(&wr, sym.st_value); | |||
1035 | ew->xdr->put32(&wr, sym.st_size); | |||
1036 | ew->xdr->put8(&wr, sym.st_info); | |||
1037 | ew->xdr->put8(&wr, sym.st_other); | |||
1038 | ew->xdr->put16(&wr, sym.st_shndx); | |||
1039 | } | |||
1040 | } | |||
1041 | ||||
1042 | /* Update section size. */ | |||
1043 | sec->shdr.sh_size = sec->shdr.sh_entsize; | |||
1044 | sec->shdr.sh_size *= ew->symtab.num_entries; | |||
1045 | ||||
1046 | /* Fix up sh_link to point to string table. */ | |||
1047 | sec->shdr.sh_link = section_index(ew, ew->strtab_sec); | |||
1048 | /* sh_info is supposed to be 1 greater than symbol table | |||
1049 | * index of last local binding. Just use max symbols. */ | |||
1050 | sec->shdr.sh_info = ew->symtab.num_entries; | |||
1051 | } | |||
1052 | ||||
1053 | buffer_set_size(&sec->content, sec->shdr.sh_size); | |||
1054 | } | |||
1055 | ||||
1056 | static void fixup_relocations(struct elf_writer *ew) | |||
1057 | { | |||
1058 | int i; | |||
1059 | Elf64_Xword type; | |||
1060 | ||||
1061 | switch (ew->ehdr.e_machine) { | |||
1062 | case EM_3863: | |||
1063 | type = R_386_321; | |||
1064 | break; | |||
1065 | case EM_X86_6462: | |||
1066 | type = R_AMD64_641; | |||
1067 | break; | |||
1068 | case EM_ARM40: | |||
1069 | type = R_ARM_ABS322; | |||
1070 | break; | |||
1071 | case EM_AARCH64183: | |||
1072 | type = R_AARCH64_ABS64257; | |||
1073 | break; | |||
1074 | case EM_MIPS8: | |||
1075 | type = R_MIPS_322; | |||
1076 | break; | |||
1077 | case EM_RISCV0xF3: | |||
1078 | type = R_RISCV_322; | |||
1079 | break; | |||
1080 | case EM_PPC6421: | |||
1081 | type = R_PPC64_ADDR321; | |||
1082 | break; | |||
1083 | default: | |||
1084 | ERROR("Unable to handle relocations for e_machine %x\n",fprintf(stderr, "E: " "Unable to handle relocations for e_machine %x\n" , ew->ehdr.e_machine) | |||
1085 | ew->ehdr.e_machine)fprintf(stderr, "E: " "Unable to handle relocations for e_machine %x\n" , ew->ehdr.e_machine); | |||
1086 | return; | |||
1087 | } | |||
1088 | ||||
1089 | for (i = 0; i < MAX_SECTIONS16; i++) { | |||
1090 | struct elf_writer_rel *rel_sec = &ew->rel_sections[i]; | |||
1091 | struct elf_writer_section *sec = rel_sec->sec; | |||
1092 | struct buffer writer; | |||
1093 | size_t j; | |||
1094 | ||||
1095 | if (sec == NULL((void*)0)) | |||
1096 | continue; | |||
1097 | ||||
1098 | /* Update section header size as well as content size. */ | |||
1099 | buffer_init(&sec->content, sec->content.name, rel_sec->rels, | |||
1100 | rel_sec->num_entries * sec->shdr.sh_entsize); | |||
1101 | sec->shdr.sh_size = buffer_size(&sec->content); | |||
1102 | buffer_clone(&writer, &sec->content); | |||
1103 | /* To make xdr happy. */ | |||
1104 | buffer_set_size(&writer, 0); | |||
1105 | ||||
1106 | for (j = 0; j < ew->rel_sections[i].num_entries; j++) { | |||
1107 | /* Make copy as we're overwriting backing store. */ | |||
1108 | Elf64_Rel rel = rel_sec->rels[j]; | |||
1109 | rel.r_info = ELF64_R_INFO(ELF64_R_SYM(rel.r_info),((((Elf64_Xword) (((rel.r_info) >> 32))) << 32) + (((type) & 0xffffffff))) | |||
1110 | ELF64_R_TYPE(type))((((Elf64_Xword) (((rel.r_info) >> 32))) << 32) + (((type) & 0xffffffff))); | |||
1111 | ||||
1112 | if (ew->bit64) { | |||
1113 | ew->xdr->put64(&writer, rel.r_offset); | |||
1114 | ew->xdr->put64(&writer, rel.r_info); | |||
1115 | } else { | |||
1116 | Elf32_Rel rel32; | |||
1117 | rel32.r_offset = rel.r_offset; | |||
1118 | rel32.r_info = | |||
1119 | ELF32_R_INFO(ELF64_R_SYM(rel.r_info),(((((rel.r_info) >> 32)) << 8) + ((((rel.r_info) & 0xffffffff)) & 0xff)) | |||
1120 | ELF64_R_TYPE(rel.r_info))(((((rel.r_info) >> 32)) << 8) + ((((rel.r_info) & 0xffffffff)) & 0xff)); | |||
1121 | ew->xdr->put32(&writer, rel32.r_offset); | |||
1122 | ew->xdr->put32(&writer, rel32.r_info); | |||
1123 | } | |||
1124 | } | |||
1125 | } | |||
1126 | } | |||
1127 | ||||
1128 | /* | |||
1129 | * Serialize the ELF file to the output buffer. Return < 0 on error, | |||
1130 | * 0 on success. | |||
1131 | */ | |||
1132 | int elf_writer_serialize(struct elf_writer *ew, struct buffer *out) | |||
1133 | { | |||
1134 | Elf64_Half i; | |||
1135 | Elf64_Xword metadata_size; | |||
1136 | Elf64_Xword program_size; | |||
1137 | Elf64_Off shstroffset; | |||
1138 | size_t shstrlen; | |||
1139 | struct buffer metadata; | |||
1140 | struct buffer phdrs; | |||
1141 | struct buffer data; | |||
1142 | struct buffer *strtab; | |||
1143 | ||||
1144 | INFO("Writing %zu sections.\n", ew->num_secs)do { if (verbose > 0) fprintf(stderr, "INFO: " "Writing %zu sections.\n" , ew->num_secs); } while (0); | |||
| ||||
1145 | ||||
1146 | /* Perform any necessary work for special sections. */ | |||
1147 | fixup_symbol_table(ew); | |||
1148 | fixup_relocations(ew); | |||
1149 | ||||
1150 | /* Determine size of sections to be written. */ | |||
1151 | program_size = 0; | |||
1152 | /* Start with 1 byte for first byte of section header string table. */ | |||
1153 | shstrlen = 1; | |||
1154 | for (i = 0; i < ew->num_secs; i++) { | |||
1155 | struct elf_writer_section *sec = &ew->sections[i]; | |||
1156 | ||||
1157 | if (sec->shdr.sh_flags & SHF_ALLOC(1 << 1)) { | |||
1158 | if (!section_consecutive(ew, i)) | |||
1159 | ew->ehdr.e_phnum++; | |||
1160 | } | |||
1161 | ||||
1162 | program_size += buffer_size(&sec->content); | |||
1163 | ||||
1164 | /* Keep track of the length sections' names. */ | |||
1165 | if (sec->name != NULL((void*)0)) { | |||
1166 | sec->shdr.sh_name = shstrlen; | |||
1167 | shstrlen += strlen(sec->name) + 1; | |||
1168 | } | |||
1169 | } | |||
1170 | ew->ehdr.e_shnum = ew->num_secs; | |||
1171 | metadata_size = 0; | |||
1172 | metadata_size += ew->ehdr.e_ehsize; | |||
1173 | metadata_size += (Elf64_Xword)ew->ehdr.e_shnum * ew->ehdr.e_shentsize; | |||
1174 | metadata_size += (Elf64_Xword)ew->ehdr.e_phnum * ew->ehdr.e_phentsize; | |||
1175 | shstroffset = metadata_size; | |||
1176 | /* Align up section header string size and metadata size to 4KiB */ | |||
1177 | metadata_size = ALIGN_UP(metadata_size + shstrlen, 4096)((((metadata_size + shstrlen))+((__typeof__((metadata_size + shstrlen )))((4096))-1UL))&~((__typeof__((metadata_size + shstrlen )))((4096))-1UL)); | |||
1178 | ||||
1179 | if (buffer_create(out, metadata_size + program_size, "elfout")) { | |||
1180 | ERROR("Could not create output buffer for ELF.\n")fprintf(stderr, "E: " "Could not create output buffer for ELF.\n" ); | |||
1181 | return -1; | |||
1182 | } | |||
1183 | ||||
1184 | INFO("Created %zu output buffer for ELF file.\n", buffer_size(out))do { if (verbose > 0) fprintf(stderr, "INFO: " "Created %zu output buffer for ELF file.\n" , buffer_size(out)); } while (0); | |||
1185 | ||||
1186 | /* | |||
1187 | * Write out ELF header. Section headers come right after ELF header | |||
1188 | * followed by the program headers. Buffers need to be created first | |||
1189 | * to do the writing. | |||
1190 | */ | |||
1191 | ew->ehdr.e_shoff = ew->ehdr.e_ehsize; | |||
1192 | ew->ehdr.e_phoff = ew->ehdr.e_shoff + | |||
1193 | (Elf64_Off)ew->ehdr.e_shnum * ew->ehdr.e_shentsize; | |||
1194 | ||||
1195 | buffer_splice(&metadata, out, 0, metadata_size); | |||
1196 | buffer_splice(&phdrs, out, ew->ehdr.e_phoff, | |||
1197 | (uint32_t)ew->ehdr.e_phnum * ew->ehdr.e_phentsize); | |||
1198 | buffer_splice(&data, out, metadata_size, program_size); | |||
1199 | /* Set up the section header string table contents. */ | |||
1200 | strtab = &ew->shstrtab_sec->content; | |||
1201 | buffer_splice(strtab, out, shstroffset, shstrlen); | |||
1202 | ew->shstrtab_sec->shdr.sh_size = shstrlen; | |||
1203 | ||||
1204 | /* Reset current locations. */ | |||
1205 | buffer_set_size(&metadata, 0); | |||
1206 | buffer_set_size(&data, 0); | |||
1207 | buffer_set_size(&phdrs, 0); | |||
1208 | buffer_set_size(strtab, 0); | |||
1209 | ||||
1210 | /* ELF Header */ | |||
1211 | ehdr_write(ew, &metadata); | |||
1212 | ||||
1213 | /* Write out section headers, section strings, section content, and | |||
1214 | * program headers. */ | |||
1215 | ew->xdr->put8(strtab, 0); | |||
1216 | for (i = 0; i < ew->num_secs; i++) { | |||
1217 | struct elf_writer_section *sec = &ew->sections[i]; | |||
1218 | ||||
1219 | /* Update section offsets. Be sure to not update SHN_UNDEF. */ | |||
1220 | if (sec == ew->shstrtab_sec) | |||
1221 | sec->shdr.sh_offset = shstroffset; | |||
1222 | else if (i != SHN_UNDEF0) | |||
1223 | sec->shdr.sh_offset = buffer_size(&data) + | |||
1224 | metadata_size; | |||
1225 | ||||
1226 | shdr_write(ew, i, &metadata); | |||
1227 | ||||
1228 | /* Add section name to string table. */ | |||
1229 | if (sec->name != NULL((void*)0)) | |||
1230 | bputs(strtab, sec->name, strlen(sec->name) + 1); | |||
1231 | ||||
1232 | /* Output section data for all sections but SHN_UNDEF and | |||
1233 | * section header string table. */ | |||
1234 | if (i
| |||
1235 | bputs(&data, buffer_get(&sec->content), | |||
1236 | buffer_size(&sec->content)); | |||
1237 | } | |||
1238 | ||||
1239 | write_phdrs(ew, &phdrs); | |||
1240 | ||||
1241 | return 0; | |||
1242 | } | |||
1243 | ||||
1244 | /* Add a string to the string table returning index on success, < 0 on error. */ | |||
1245 | static int elf_writer_add_string(struct elf_writer *ew, const char *new) | |||
1246 | { | |||
1247 | size_t current_offset; | |||
1248 | size_t new_len; | |||
1249 | ||||
1250 | for (current_offset = 0; current_offset < ew->strtab.next_offset; ) { | |||
1251 | const char *str = ew->strtab.buffer + current_offset; | |||
1252 | size_t len = strlen(str) + 1; | |||
1253 | ||||
1254 | if (!strcmp(str, new)) | |||
1255 | return current_offset; | |||
1256 | current_offset += len; | |||
1257 | } | |||
1258 | ||||
1259 | new_len = strlen(new) + 1; | |||
1260 | ||||
1261 | if (current_offset + new_len > ew->strtab.max_size) { | |||
1262 | ERROR("No space for string in .strtab.\n")fprintf(stderr, "E: " "No space for string in .strtab.\n"); | |||
1263 | return -1; | |||
1264 | } | |||
1265 | ||||
1266 | memcpy(ew->strtab.buffer + current_offset, new, new_len); | |||
1267 | ew->strtab.next_offset = current_offset + new_len; | |||
1268 | ||||
1269 | return current_offset; | |||
1270 | } | |||
1271 | ||||
1272 | static int elf_writer_section_index(struct elf_writer *ew, const char *name) | |||
1273 | { | |||
1274 | size_t i; | |||
1275 | ||||
1276 | for (i = 0; i < ew->num_secs; i++) { | |||
1277 | if (ew->sections[i].name == NULL((void*)0)) | |||
1278 | continue; | |||
1279 | if (!strcmp(ew->sections[i].name, name)) | |||
1280 | return i; | |||
1281 | } | |||
1282 | ||||
1283 | ERROR("ELF Section not found: %s\n", name)fprintf(stderr, "E: " "ELF Section not found: %s\n", name); | |||
1284 | ||||
1285 | return -1; | |||
1286 | } | |||
1287 | ||||
1288 | int elf_writer_add_symbol(struct elf_writer *ew, const char *name, | |||
1289 | const char *section_name, | |||
1290 | Elf64_Addr value, Elf64_Word size, | |||
1291 | int binding, int type) | |||
1292 | { | |||
1293 | int i; | |||
1294 | Elf64_Sym sym = { | |||
1295 | .st_value = value, | |||
1296 | .st_size = size, | |||
1297 | .st_info = ELF64_ST_INFO(binding, type)((((binding)) << 4) + (((type)) & 0xf)), | |||
1298 | }; | |||
1299 | ||||
1300 | if (ew->symtab.max_entries == ew->symtab.num_entries) { | |||
1301 | ERROR("No more symbol entries left.\n")fprintf(stderr, "E: " "No more symbol entries left.\n"); | |||
1302 | return -1; | |||
1303 | } | |||
1304 | ||||
1305 | i = elf_writer_add_string(ew, name); | |||
1306 | if (i < 0) | |||
1307 | return -1; | |||
1308 | sym.st_name = i; | |||
1309 | ||||
1310 | i = elf_writer_section_index(ew, section_name); | |||
1311 | if (i < 0) | |||
1312 | return -1; | |||
1313 | sym.st_shndx = i; | |||
1314 | ||||
1315 | ew->symtab.syms[ew->symtab.num_entries++] = sym; | |||
1316 | ||||
1317 | return 0; | |||
1318 | } | |||
1319 | ||||
1320 | static int elf_sym_index(struct elf_writer *ew, const char *sym) | |||
1321 | { | |||
1322 | int j; | |||
1323 | size_t i; | |||
1324 | Elf64_Word st_name; | |||
1325 | ||||
1326 | /* Determine index of symbol in the string table. */ | |||
1327 | j = elf_writer_add_string(ew, sym); | |||
1328 | if (j < 0) | |||
1329 | return -1; | |||
1330 | ||||
1331 | st_name = j; | |||
1332 | ||||
1333 | for (i = 0; i < ew->symtab.num_entries; i++) | |||
1334 | if (ew->symtab.syms[i].st_name == st_name) | |||
1335 | return i; | |||
1336 | ||||
1337 | return -1; | |||
1338 | } | |||
1339 | ||||
1340 | static struct elf_writer_rel *rel_section(struct elf_writer *ew, | |||
1341 | const Elf64_Rel *r) | |||
1342 | { | |||
1343 | Elf64_Sym *sym; | |||
1344 | struct elf_writer_rel *rel; | |||
1345 | Elf64_Shdr shdr; | |||
1346 | struct buffer b; | |||
1347 | ||||
1348 | sym = &ew->symtab.syms[ELF64_R_SYM(r->r_info)((r->r_info) >> 32)]; | |||
1349 | ||||
1350 | /* Determine if section has been initialized yet. */ | |||
1351 | rel = &ew->rel_sections[sym->st_shndx]; | |||
1352 | if (rel->sec != NULL((void*)0)) | |||
1353 | return rel; | |||
1354 | ||||
1355 | memset(&shdr, 0, sizeof(shdr)); | |||
1356 | shdr.sh_type = SHT_REL9; | |||
1357 | shdr.sh_link = section_index(ew, ew->symtab_sec); | |||
1358 | shdr.sh_info = sym->st_shndx; | |||
1359 | ||||
1360 | if (ew->bit64) { | |||
1361 | shdr.sh_addralign = sizeof(Elf64_Addr); | |||
1362 | shdr.sh_entsize = sizeof(Elf64_Rel); | |||
1363 | } else { | |||
1364 | shdr.sh_addralign = sizeof(Elf32_Addr); | |||
1365 | shdr.sh_entsize = sizeof(Elf32_Rel); | |||
1366 | } | |||
1367 | ||||
1368 | if ((strlen(".rel") + strlen(ew->sections[sym->st_shndx].name) + 1) > | |||
1369 | MAX_REL_NAME32) { | |||
1370 | ERROR("Rel Section name won't fit\n")fprintf(stderr, "E: " "Rel Section name won't fit\n"); | |||
1371 | return NULL((void*)0); | |||
1372 | } | |||
1373 | ||||
1374 | strcat(rel->name, ".rel"); | |||
1375 | strcat(rel->name, ew->sections[sym->st_shndx].name); | |||
1376 | buffer_init(&b, rel->name, NULL((void*)0), 0); | |||
1377 | ||||
1378 | elf_writer_add_section(ew, &shdr, &b, rel->name); | |||
1379 | rel->sec = last_section(ew); | |||
1380 | ||||
1381 | return rel; | |||
1382 | } | |||
1383 | ||||
1384 | static int add_rel(struct elf_writer_rel *rel_sec, const Elf64_Rel *rel) | |||
1385 | { | |||
1386 | if (rel_sec->num_entries == rel_sec->max_entries) { | |||
1387 | size_t num = rel_sec->max_entries * 2; | |||
1388 | Elf64_Rel *old_rels; | |||
1389 | ||||
1390 | if (num == 0) | |||
1391 | num = 128; | |||
1392 | ||||
1393 | old_rels = rel_sec->rels; | |||
1394 | rel_sec->rels = calloc(num, sizeof(Elf64_Rel)); | |||
1395 | ||||
1396 | memcpy(rel_sec->rels, old_rels, | |||
1397 | rel_sec->num_entries * sizeof(Elf64_Rel)); | |||
1398 | free(old_rels); | |||
1399 | ||||
1400 | rel_sec->max_entries = num; | |||
1401 | } | |||
1402 | ||||
1403 | rel_sec->rels[rel_sec->num_entries] = *rel; | |||
1404 | rel_sec->num_entries++; | |||
1405 | ||||
1406 | return 0; | |||
1407 | } | |||
1408 | ||||
1409 | int elf_writer_add_rel(struct elf_writer *ew, const char *sym, Elf64_Addr addr) | |||
1410 | { | |||
1411 | Elf64_Rel rel; | |||
1412 | Elf64_Xword sym_info; | |||
1413 | int sym_index; | |||
1414 | struct elf_writer_rel *rel_sec; | |||
1415 | ||||
1416 | sym_index = elf_sym_index(ew, sym); | |||
1417 | ||||
1418 | if (sym_index < 0) { | |||
1419 | ERROR("Unable to locate symbol: %s\n", sym)fprintf(stderr, "E: " "Unable to locate symbol: %s\n", sym); | |||
1420 | return -1; | |||
1421 | } | |||
1422 | ||||
1423 | sym_info = sym_index; | |||
1424 | ||||
1425 | /* The relocation type will get fixed prior to serialization. */ | |||
1426 | rel.r_offset = addr; | |||
1427 | rel.r_info = ELF64_R_INFO(sym_info, 0)((((Elf64_Xword) (sym_info)) << 32) + (0)); | |||
1428 | ||||
1429 | rel_sec = rel_section(ew, &rel); | |||
1430 | ||||
1431 | if (rel_sec == NULL((void*)0)) | |||
1432 | return -1; | |||
1433 | ||||
1434 | return add_rel(rel_sec, &rel); | |||
1435 | } | |||
1436 | ||||
1437 | int elf_program_file_size(const struct buffer *input, size_t *file_size) | |||
1438 | { | |||
1439 | Elf64_Ehdr ehdr; | |||
1440 | Elf64_Phdr *phdr; | |||
1441 | int i; | |||
1442 | size_t loadable_file_size = 0; | |||
1443 | ||||
1444 | if (elf_headers(input, &ehdr, &phdr, NULL((void*)0))) | |||
1445 | return -1; | |||
1446 | ||||
1447 | for (i = 0; i < ehdr.e_phnum; i++) { | |||
1448 | if (phdr[i].p_type != PT_LOAD1) | |||
1449 | continue; | |||
1450 | loadable_file_size += phdr[i].p_filesz; | |||
1451 | } | |||
1452 | ||||
1453 | *file_size = loadable_file_size; | |||
1454 | ||||
1455 | free(phdr); | |||
1456 | ||||
1457 | return 0; | |||
1458 | } |