1 /* mod-extract.c: module extractor for signing
3 * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
22 #include <asm/byteorder.h>
24 void extract_elf64(void *buffer, size_t size, Elf64_Ehdr *hdr);
25 void extract_elf32(void *buffer, size_t size, Elf32_Ehdr *hdr);
28 uint16_t (*get16)(const uint16_t *);
29 uint32_t (*get32)(const uint32_t *);
30 uint64_t (*get64)(const uint64_t *);
31 void (*set16)(uint16_t *, uint16_t);
32 void (*set32)(uint32_t *, uint32_t);
33 void (*set64)(uint64_t *, uint64_t);
36 uint16_t get16_le(const uint16_t *p) { return __le16_to_cpu(*p); }
37 uint32_t get32_le(const uint32_t *p) { return __le32_to_cpu(*p); }
38 uint64_t get64_le(const uint64_t *p) { return __le64_to_cpu(*p); }
39 uint16_t get16_be(const uint16_t *p) { return __be16_to_cpu(*p); }
40 uint32_t get32_be(const uint32_t *p) { return __be32_to_cpu(*p); }
41 uint64_t get64_be(const uint64_t *p) { return __be64_to_cpu(*p); }
43 void set16_le(uint16_t *p, uint16_t n) { *p = __cpu_to_le16(n); }
44 void set32_le(uint32_t *p, uint32_t n) { *p = __cpu_to_le32(n); }
45 void set64_le(uint64_t *p, uint64_t n) { *p = __cpu_to_le64(n); }
46 void set16_be(uint16_t *p, uint16_t n) { *p = __cpu_to_be16(n); }
47 void set32_be(uint32_t *p, uint32_t n) { *p = __cpu_to_be32(n); }
48 void set64_be(uint64_t *p, uint64_t n) { *p = __cpu_to_be64(n); }
50 const struct byteorder byteorder_le = {
51 get16_le, get32_le, get64_le,
52 set16_le, set32_le, set64_le
54 const struct byteorder byteorder_be = {
55 get16_be, get32_be, get64_be,
56 set16_be, set32_be, set64_be
58 const struct byteorder *order;
60 uint16_t get16(const uint16_t *p) { return order->get16(p); }
61 uint32_t get32(const uint32_t *p) { return order->get32(p); }
62 uint64_t get64(const uint64_t *p) { return order->get64(p); }
63 void set16(uint16_t *p, uint16_t n) { order->set16(p, n); }
64 void set32(uint32_t *p, uint32_t n) { order->set32(p, n); }
65 void set64(uint64_t *p, uint64_t n) { order->set64(p, n); }
70 void write_out(const void *data, size_t size)
72 const uint8_t *p = data;
75 for (loop = 0; loop < size; loop++) {
80 if (fwrite(data, 1, size, outfd) != size) {
86 #define write_out_val(VAL) write_out(&(VAL), sizeof(VAL))
90 void verbose(const char *fmt, ...) __attribute__((format(printf,1,2)));
91 void verbose(const char *fmt, ...)
102 void usage(void) __attribute__((noreturn));
105 fprintf(stderr, "Usage: mod-extract [-v] <modulefile> <extractfile>\n");
109 /*****************************************************************************/
113 int main(int argc, char **argv)
122 while (argc > 1 && strcmp("-v", argv[1]) == 0) {
131 /* map the module into memory */
132 fd = open(argv[1], O_RDONLY);
134 perror("open input");
138 if (fstat(fd, &st) < 0) {
145 buffer = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
146 if (buffer == MAP_FAILED) {
152 perror("close input");
156 /* check it's an ELF object */
160 if (hdr32->e_ident[EI_MAG0] != ELFMAG0 ||
161 hdr32->e_ident[EI_MAG1] != ELFMAG1 ||
162 hdr32->e_ident[EI_MAG2] != ELFMAG2 ||
163 hdr32->e_ident[EI_MAG3] != ELFMAG3
165 fprintf(stderr, "Module does not appear to be ELF\n");
169 /* determine endianness and word size */
170 b64 = (hdr32->e_ident[EI_CLASS] == ELFCLASS64);
171 be = (hdr32->e_ident[EI_DATA] == ELFDATA2MSB);
172 order = be ? &byteorder_be : &byteorder_le;
174 verbose("Module is %s-bit %s-endian\n",
176 be ? "big" : "little");
178 /* open the output file */
179 outfd = fopen(argv[2], "w");
181 perror("open output");
185 /* perform the extraction */
187 extract_elf64(buffer, len, hdr64);
189 extract_elf32(buffer, len, hdr32);
192 if (fclose(outfd) == EOF) {
193 perror("close output");
201 /*****************************************************************************/
203 * extract a RELA table
204 * - need to canonicalise the entries in case section addition/removal has
205 * rearranged the symbol table and the section table
207 void extract_elf64_rela(const void *buffer, int secix, int targetix,
208 const Elf64_Rela *relatab, size_t nrels,
209 const Elf64_Sym *symbols, size_t nsyms,
210 const Elf64_Shdr *sections, size_t nsects, int *canonmap,
211 const char *strings, size_t nstrings,
224 } __attribute__((packed)) relocation;
226 const Elf64_Sym *symbol;
229 /* contribute the relevant bits from a join of { RELA, SYMBOL, SECTION } */
230 for (loop = 0; loop < nrels; loop++) {
231 Elf64_Section st_shndx;
234 /* decode the relocation */
235 r_info = get64(&relatab[loop].r_info);
236 relocation.r_offset = relatab[loop].r_offset;
237 relocation.r_addend = relatab[loop].r_addend;
238 set32(&relocation.r_type, ELF64_R_TYPE(r_info));
240 if (ELF64_R_SYM(r_info) >= nsyms) {
241 fprintf(stderr, "Invalid symbol ID %lx in relocation %zu\n",
242 ELF64_R_SYM(r_info), loop);
246 /* decode the symbol referenced by the relocation */
247 symbol = &symbols[ELF64_R_SYM(r_info)];
248 relocation.st_info = symbol->st_info;
249 relocation.st_other = symbol->st_other;
250 relocation.st_value = symbol->st_value;
251 relocation.st_size = symbol->st_size;
252 relocation.st_shndx = symbol->st_shndx;
253 st_shndx = get16(&symbol->st_shndx);
255 /* canonicalise the section used by the symbol */
256 if (st_shndx > SHN_UNDEF && st_shndx < nsects)
257 set16(&relocation.st_shndx, canonmap[st_shndx]);
259 write_out_val(relocation);
261 /* undefined symbols must be named if referenced */
262 if (st_shndx == SHN_UNDEF) {
263 const char *name = strings + get32(&symbol->st_name);
264 write_out(name, strlen(name) + 1);
268 verbose("%02x %4d %s [canon]\n", csum, secix, sh_name);
270 } /* end extract_elf64_rela() */
272 /*****************************************************************************/
274 * extract a REL table
275 * - need to canonicalise the entries in case section addition/removal has
276 * rearranged the symbol table and the section table
278 void extract_elf64_rel(const void *buffer, int secix, int targetix,
279 const Elf64_Rel *relatab, size_t nrels,
280 const Elf64_Sym *symbols, size_t nsyms,
281 const Elf64_Shdr *sections, size_t nsects, int *canonmap,
282 const char *strings, size_t nstrings,
294 } __attribute__((packed)) relocation;
296 const Elf64_Sym *symbol;
299 /* contribute the relevant bits from a join of { RELA, SYMBOL, SECTION } */
300 for (loop = 0; loop < nrels; loop++) {
301 Elf64_Section st_shndx;
304 /* decode the relocation */
305 r_info = get64(&relatab[loop].r_info);
306 relocation.r_offset = relatab[loop].r_offset;
307 set32(&relocation.r_type, ELF64_R_TYPE(r_info));
309 if (ELF64_R_SYM(r_info) >= nsyms) {
310 fprintf(stderr, "Invalid symbol ID %lx in relocation %zi\n",
311 ELF64_R_SYM(r_info), loop);
315 /* decode the symbol referenced by the relocation */
316 symbol = &symbols[ELF64_R_SYM(r_info)];
317 relocation.st_info = symbol->st_info;
318 relocation.st_other = symbol->st_other;
319 relocation.st_value = symbol->st_value;
320 relocation.st_size = symbol->st_size;
321 relocation.st_shndx = symbol->st_shndx;
322 st_shndx = get16(&symbol->st_shndx);
324 /* canonicalise the section used by the symbol */
325 if (st_shndx > SHN_UNDEF && st_shndx < nsects)
326 set16(&relocation.st_shndx, canonmap[st_shndx]);
328 write_out_val(relocation);
330 /* undefined symbols must be named if referenced */
331 if (st_shndx == SHN_UNDEF) {
332 const char *name = strings + get32(&symbol->st_name);
333 write_out(name, strlen(name) + 1);
337 verbose("%02x %4d %s [canon]\n", csum, secix, sh_name);
339 } /* end extract_elf64_rel() */
341 /*****************************************************************************/
343 * extract the data from a 64-bit module
345 void extract_elf64(void *buffer, size_t len, Elf64_Ehdr *hdr)
347 const Elf64_Sym *symbols;
348 Elf64_Shdr *sections;
349 const char *secstrings, *strings;
350 size_t nsyms, nstrings;
351 int loop, shnum, *canonlist, *canonmap, canon, changed, tmp;
353 sections = buffer + get64(&hdr->e_shoff);
354 secstrings = buffer + get64(§ions[get16(&hdr->e_shstrndx)].sh_offset);
355 shnum = get16(&hdr->e_shnum);
357 /* find the symbol table and the string table and produce a list of
358 * index numbers of sections that contribute to the kernel's module
361 canonlist = calloc(sizeof(int), shnum * 2);
366 canonmap = canonlist + shnum;
372 for (loop = 1; loop < shnum; loop++) {
373 const char *sh_name = secstrings + get32(§ions[loop].sh_name);
374 Elf64_Word sh_type = get32(§ions[loop].sh_type);
375 Elf64_Xword sh_size = get64(§ions[loop].sh_size);
376 Elf64_Xword sh_flags = get64(§ions[loop].sh_flags);
377 Elf64_Off sh_offset = get64(§ions[loop].sh_offset);
378 void *data = buffer + sh_offset;
380 /* quick sanity check */
381 if (sh_type != SHT_NOBITS && len < sh_offset + sh_size) {
382 fprintf(stderr, "Section goes beyond EOF\n");
386 /* we only need to canonicalise allocatable sections */
387 if (sh_flags & SHF_ALLOC)
388 canonlist[canon++] = loop;
390 /* keep track of certain special sections */
393 if (strcmp(sh_name, ".symtab") == 0) {
395 nsyms = sh_size / sizeof(Elf64_Sym);
400 if (strcmp(sh_name, ".strtab") == 0) {
412 fprintf(stderr, "Couldn't locate symbol table\n");
417 fprintf(stderr, "Couldn't locate strings table\n");
421 /* canonicalise the index numbers of the contributing section */
425 for (loop = 0; loop < canon - 1; loop++) {
426 const char *x = secstrings + get32(§ions[canonlist[loop + 0]].sh_name);
427 const char *y = secstrings + get32(§ions[canonlist[loop + 1]].sh_name);
428 if (strcmp(x, y) > 0) {
429 tmp = canonlist[loop + 0];
430 canonlist[loop + 0] = canonlist[loop + 1];
431 canonlist[loop + 1] = tmp;
438 for (loop = 0; loop < canon; loop++)
439 canonmap[canonlist[loop]] = loop + 1;
441 if (is_verbose > 1) {
442 printf("\nSection canonicalisation map:\n");
443 for (loop = 1; loop < shnum; loop++) {
444 const char *x = secstrings + get32(§ions[loop].sh_name);
445 printf("%4d %s\n", canonmap[loop], x);
448 printf("\nAllocated section list in canonical order:\n");
449 for (loop = 0; loop < canon; loop++) {
450 const char *x = secstrings + get32(§ions[canonlist[loop]].sh_name);
451 printf("%4d %s\n", canonlist[loop], x);
455 memset(canonlist, 0, sizeof(int) * shnum);
457 /* iterate through the section table looking for sections we want to
458 * contribute to the signature */
460 verbose("FILE POS CS SECT NAME\n");
461 verbose("======== == ==== ==============================\n");
463 for (loop = 1; loop < shnum; loop++) {
464 const char *sh_name = secstrings + get32(§ions[loop].sh_name);
465 Elf64_Word sh_type = get32(§ions[loop].sh_type);
466 Elf64_Xword sh_size = get64(§ions[loop].sh_size);
467 Elf64_Xword sh_flags = get64(§ions[loop].sh_flags);
468 Elf64_Word sh_info = get32(§ions[loop].sh_info);
469 Elf64_Off sh_offset = get64(§ions[loop].sh_offset);
470 void *data = buffer + sh_offset;
474 /* include canonicalised relocation sections */
475 if (sh_type == SHT_REL || sh_type == SHT_RELA) {
476 if (sh_info <= 0 && sh_info >= hdr->e_shnum) {
478 "Invalid ELF - REL/RELA sh_info does"
479 " not refer to a valid section\n");
483 if (canonlist[sh_info]) {
486 verbose("%08lx ", ftell(outfd));
488 set32(&xsh_info, canonmap[sh_info]);
490 /* write out selected portions of the section
492 write_out(sh_name, strlen(sh_name));
493 write_out_val(sections[loop].sh_type);
494 write_out_val(sections[loop].sh_flags);
495 write_out_val(sections[loop].sh_size);
496 write_out_val(sections[loop].sh_addralign);
497 write_out_val(xsh_info);
499 if (sh_type == SHT_RELA)
500 extract_elf64_rela(buffer, loop, sh_info,
501 data, sh_size / sizeof(Elf64_Rela),
503 sections, shnum, canonmap,
507 extract_elf64_rel(buffer, loop, sh_info,
508 data, sh_size / sizeof(Elf64_Rel),
510 sections, shnum, canonmap,
518 /* include allocatable loadable sections */
519 if (sh_type != SHT_NOBITS && sh_flags & SHF_ALLOC)
520 goto include_section;
522 /* not this section */
526 verbose("%08lx ", ftell(outfd));
528 /* write out selected portions of the section header */
529 write_out(sh_name, strlen(sh_name));
530 write_out_val(sections[loop].sh_type);
531 write_out_val(sections[loop].sh_flags);
532 write_out_val(sections[loop].sh_size);
533 write_out_val(sections[loop].sh_addralign);
535 /* write out the section data */
536 write_out(data, sh_size);
538 verbose("%02x %4d %s\n", csum, loop, sh_name);
540 /* note the section has been written */
544 verbose("%08lx (%lu bytes csum 0x%02x)\n",
545 ftell(outfd), ftell(outfd), xcsum);
547 } /* end extract_elf64() */
549 /*****************************************************************************/
551 * extract a RELA table
552 * - need to canonicalise the entries in case section addition/removal has
553 * rearranged the symbol table and the section table
555 void extract_elf32_rela(const void *buffer, int secix, int targetix,
556 const Elf32_Rela *relatab, size_t nrels,
557 const Elf32_Sym *symbols, size_t nsyms,
558 const Elf32_Shdr *sections, size_t nsects, int *canonmap,
559 const char *strings, size_t nstrings,
572 } __attribute__((packed)) relocation;
574 const Elf32_Sym *symbol;
577 /* contribute the relevant bits from a join of { RELA, SYMBOL, SECTION } */
578 for (loop = 0; loop < nrels; loop++) {
579 Elf32_Section st_shndx;
582 /* decode the relocation */
583 r_info = get32(&relatab[loop].r_info);
584 relocation.r_offset = relatab[loop].r_offset;
585 relocation.r_addend = relatab[loop].r_addend;
586 relocation.r_type = ELF32_R_TYPE(r_info);
588 if (ELF32_R_SYM(r_info) >= nsyms) {
589 fprintf(stderr, "Invalid symbol ID %x in relocation %zu\n",
590 ELF32_R_SYM(r_info), loop);
594 /* decode the symbol referenced by the relocation */
595 symbol = &symbols[ELF32_R_SYM(r_info)];
596 relocation.st_info = symbol->st_info;
597 relocation.st_other = symbol->st_other;
598 relocation.st_value = symbol->st_value;
599 relocation.st_size = symbol->st_size;
600 relocation.st_shndx = symbol->st_shndx;
601 st_shndx = get16(&symbol->st_shndx);
603 /* canonicalise the section used by the symbol */
604 if (st_shndx > SHN_UNDEF && st_shndx < nsects)
605 set16(&relocation.st_shndx, canonmap[st_shndx]);
607 write_out_val(relocation);
609 /* undefined symbols must be named if referenced */
610 if (st_shndx == SHN_UNDEF) {
611 const char *name = strings + get32(&symbol->st_name);
612 write_out(name, strlen(name) + 1);
616 verbose("%02x %4d %s [canon]\n", csum, secix, sh_name);
618 } /* end extract_elf32_rela() */
620 /*****************************************************************************/
622 * extract a REL table
623 * - need to canonicalise the entries in case section addition/removal has
624 * rearranged the symbol table and the section table
626 void extract_elf32_rel(const void *buffer, int secix, int targetix,
627 const Elf32_Rel *relatab, size_t nrels,
628 const Elf32_Sym *symbols, size_t nsyms,
629 const Elf32_Shdr *sections, size_t nsects, int *canonmap,
630 const char *strings, size_t nstrings,
642 } __attribute__((packed)) relocation;
644 const Elf32_Sym *symbol;
647 /* contribute the relevant bits from a join of { RELA, SYMBOL, SECTION } */
648 for (loop = 0; loop < nrels; loop++) {
649 Elf32_Section st_shndx;
652 /* decode the relocation */
653 r_info = get32(&relatab[loop].r_info);
654 relocation.r_offset = relatab[loop].r_offset;
655 relocation.r_type = ELF32_R_TYPE(r_info);
657 if (ELF32_R_SYM(r_info) >= nsyms) {
658 fprintf(stderr, "Invalid symbol ID %x in relocation %zu\n",
659 ELF32_R_SYM(r_info), loop);
663 /* decode the symbol referenced by the relocation */
664 symbol = &symbols[ELF32_R_SYM(r_info)];
665 relocation.st_info = symbol->st_info;
666 relocation.st_other = symbol->st_other;
667 relocation.st_value = symbol->st_value;
668 relocation.st_size = symbol->st_size;
669 relocation.st_shndx = symbol->st_shndx;
670 st_shndx = get16(&symbol->st_shndx);
672 /* canonicalise the section used by the symbol */
673 if (st_shndx > SHN_UNDEF && st_shndx < nsects)
674 set16(&relocation.st_shndx, canonmap[st_shndx]);
676 write_out_val(relocation);
678 /* undefined symbols must be named if referenced */
679 if (st_shndx == SHN_UNDEF) {
680 const char *name = strings + get32(&symbol->st_name);
681 write_out(name, strlen(name) + 1);
685 verbose("%02x %4d %s [canon]\n", csum, secix, sh_name);
687 } /* end extract_elf32_rel() */
689 /*****************************************************************************/
691 * extract the data from a 32-bit module
693 void extract_elf32(void *buffer, size_t len, Elf32_Ehdr *hdr)
695 const Elf32_Sym *symbols;
696 Elf32_Shdr *sections;
697 const char *secstrings, *strings;
698 size_t nsyms, nstrings;
699 int loop, shnum, *canonlist, *canonmap, canon, changed, tmp;
701 sections = buffer + get32(&hdr->e_shoff);
702 secstrings = buffer + get32(§ions[get16(&hdr->e_shstrndx)].sh_offset);
703 shnum = get16(&hdr->e_shnum);
705 /* find the symbol table and the string table and produce a list of
706 * index numbers of sections that contribute to the kernel's module
709 canonlist = calloc(sizeof(int), shnum * 2);
714 canonmap = canonlist + shnum;
720 for (loop = 1; loop < shnum; loop++) {
721 const char *sh_name = secstrings + get32(§ions[loop].sh_name);
722 Elf32_Word sh_type = get32(§ions[loop].sh_type);
723 Elf32_Xword sh_size = get32(§ions[loop].sh_size);
724 Elf32_Xword sh_flags = get32(§ions[loop].sh_flags);
725 Elf32_Off sh_offset = get32(§ions[loop].sh_offset);
726 void *data = buffer + sh_offset;
728 /* quick sanity check */
729 if (sh_type != SHT_NOBITS && len < sh_offset + sh_size) {
730 fprintf(stderr, "Section goes beyond EOF\n");
734 /* we only need to canonicalise allocatable sections */
735 if (sh_flags & SHF_ALLOC)
736 canonlist[canon++] = loop;
738 /* keep track of certain special sections */
741 if (strcmp(sh_name, ".symtab") == 0) {
743 nsyms = sh_size / sizeof(Elf32_Sym);
748 if (strcmp(sh_name, ".strtab") == 0) {
760 fprintf(stderr, "Couldn't locate symbol table\n");
765 fprintf(stderr, "Couldn't locate strings table\n");
769 /* canonicalise the index numbers of the contributing section */
773 for (loop = 0; loop < canon - 1; loop++) {
774 const char *x = secstrings + get32(§ions[canonlist[loop + 0]].sh_name);
775 const char *y = secstrings + get32(§ions[canonlist[loop + 1]].sh_name);
776 if (strcmp(x, y) > 0) {
777 tmp = canonlist[loop + 0];
778 canonlist[loop + 0] = canonlist[loop + 1];
779 canonlist[loop + 1] = tmp;
786 for (loop = 0; loop < canon; loop++)
787 canonmap[canonlist[loop]] = loop + 1;
789 if (is_verbose > 1) {
790 printf("\nSection canonicalisation map:\n");
791 for (loop = 1; loop < shnum; loop++) {
792 const char *x = secstrings + get32(§ions[loop].sh_name);
793 printf("%4d %s\n", canonmap[loop], x);
796 printf("\nAllocated section list in canonical order:\n");
797 for (loop = 0; loop < canon; loop++) {
798 const char *x = secstrings + get32(§ions[canonlist[loop]].sh_name);
799 printf("%4d %s\n", canonlist[loop], x);
803 memset(canonlist, 0, sizeof(int) * shnum);
805 /* iterate through the section table looking for sections we want to
806 * contribute to the signature */
808 verbose("FILE POS CS SECT NAME\n");
809 verbose("======== == ==== ==============================\n");
811 for (loop = 1; loop < shnum; loop++) {
812 const char *sh_name = secstrings + get32(§ions[loop].sh_name);
813 Elf32_Word sh_type = get32(§ions[loop].sh_type);
814 Elf32_Xword sh_size = get32(§ions[loop].sh_size);
815 Elf32_Xword sh_flags = get32(§ions[loop].sh_flags);
816 Elf32_Word sh_info = get32(§ions[loop].sh_info);
817 Elf32_Off sh_offset = get32(§ions[loop].sh_offset);
818 void *data = buffer + sh_offset;
822 /* quick sanity check */
823 if (sh_type != SHT_NOBITS && len < sh_offset + sh_size) {
824 fprintf(stderr, "section goes beyond EOF\n");
828 /* include canonicalised relocation sections */
829 if (sh_type == SHT_REL || sh_type == SHT_RELA) {
830 if (sh_info <= 0 && sh_info >= hdr->e_shnum) {
832 "Invalid ELF - REL/RELA sh_info does"
833 " not refer to a valid section\n");
837 if (canonlist[sh_info]) {
840 verbose("%08lx ", ftell(outfd));
842 set32(&xsh_info, canonmap[sh_info]);
844 /* write out selected portions of the section header */
845 write_out(sh_name, strlen(sh_name));
846 write_out_val(sections[loop].sh_type);
847 write_out_val(sections[loop].sh_flags);
848 write_out_val(sections[loop].sh_size);
849 write_out_val(sections[loop].sh_addralign);
850 write_out_val(xsh_info);
852 if (sh_type == SHT_RELA)
853 extract_elf32_rela(buffer, loop, sh_info,
854 data, sh_size / sizeof(Elf32_Rela),
856 sections, shnum, canonmap,
860 extract_elf32_rel(buffer, loop, sh_info,
861 data, sh_size / sizeof(Elf32_Rel),
863 sections, shnum, canonmap,
871 /* include allocatable loadable sections */
872 if (sh_type != SHT_NOBITS && sh_flags & SHF_ALLOC)
873 goto include_section;
875 /* not this section */
879 verbose("%08lx ", ftell(outfd));
881 /* write out selected portions of the section header */
882 write_out(sh_name, strlen(sh_name));
883 write_out_val(sections[loop].sh_type);
884 write_out_val(sections[loop].sh_flags);
885 write_out_val(sections[loop].sh_size);
886 write_out_val(sections[loop].sh_addralign);
888 /* write out the section data */
889 write_out(data, sh_size);
891 verbose("%02x %4d %s\n", csum, loop, sh_name);
893 /* note the section has been written */
897 verbose("%08lx (%lu bytes csum 0x%02x)\n",
898 ftell(outfd), ftell(outfd), xcsum);
900 } /* end extract_elf32() */