Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / scripts / modsign / mod-extract.c
1 /* mod-extract.c: module extractor for signing
2  *
3  * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
4  * Written by David Howells (dhowells@redhat.com)
5  *
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.
10  */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <stdint.h>
15 #include <stdarg.h>
16 #include <string.h>
17 #include <unistd.h>
18 #include <fcntl.h>
19 #include <sys/mman.h>
20 #include <sys/stat.h>
21 #include <elf.h>
22 #include <asm/byteorder.h>
23
24 void extract_elf64(void *buffer, size_t size, Elf64_Ehdr *hdr);
25 void extract_elf32(void *buffer, size_t size, Elf32_Ehdr *hdr);
26
27 struct byteorder {
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);
34 };
35
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); }
42
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); }
49
50 const struct byteorder byteorder_le = {
51         get16_le, get32_le, get64_le,
52         set16_le, set32_le, set64_le
53 };
54 const struct byteorder byteorder_be = {
55         get16_be, get32_be, get64_be,
56         set16_be, set32_be, set64_be
57 };
58 const struct byteorder *order;
59
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); }
66
67 FILE *outfd;
68 uint8_t csum, xcsum;
69
70 void write_out(const void *data, size_t size)
71 {
72         const uint8_t *p = data;
73         size_t loop;
74
75         for (loop = 0; loop < size; loop++) {
76                 csum += p[loop];
77                 xcsum += p[loop];
78         }
79
80         if (fwrite(data, 1, size, outfd) != size) {
81                 perror("write");
82                 exit(1);
83         }
84 }
85
86 #define write_out_val(VAL) write_out(&(VAL), sizeof(VAL))
87
88 int is_verbose;
89
90 void verbose(const char *fmt, ...) __attribute__((format(printf,1,2)));
91 void verbose(const char *fmt, ...)
92 {
93         va_list va;
94
95         if (is_verbose) {
96                 va_start(va, fmt);
97                 vprintf(fmt, va);
98                 va_end(va);
99         }
100 }
101
102 void usage(void) __attribute__((noreturn));
103 void usage(void)
104 {
105         fprintf(stderr, "Usage: mod-extract [-v] <modulefile> <extractfile>\n");
106         exit(2);
107 }
108
109 /*****************************************************************************/
110 /*
111  *
112  */
113 int main(int argc, char **argv)
114 {
115         struct stat st;
116         Elf32_Ehdr *hdr32;
117         Elf64_Ehdr *hdr64;
118         size_t len;
119         void *buffer;
120         int fd, be, b64;
121
122         while (argc > 1 && strcmp("-v", argv[1]) == 0) {
123                 argv++;
124                 argc--;
125                 is_verbose++;
126         }
127
128         if (argc != 3)
129                 usage();
130
131         /* map the module into memory */
132         fd = open(argv[1], O_RDONLY);
133         if (fd < 0) {
134                 perror("open input");
135                 exit(1);
136         }
137
138         if (fstat(fd, &st) < 0) {
139                 perror("fstat");
140                 exit(1);
141         }
142
143         len = st.st_size;
144
145         buffer = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
146         if (buffer == MAP_FAILED) {
147                 perror("mmap");
148                 exit(1);
149         }
150
151         if (close(fd) < 0) {
152                 perror("close input");
153                 exit(1);
154         }
155
156         /* check it's an ELF object */
157         hdr32 = buffer;
158         hdr64 = buffer;
159
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
164             ) {
165                 fprintf(stderr, "Module does not appear to be ELF\n");
166                 exit(3);
167         }
168
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;
173
174         verbose("Module is %s-bit %s-endian\n",
175                 b64 ? "64" : "32",
176                 be ? "big" : "little");
177
178         /* open the output file */
179         outfd = fopen(argv[2], "w");
180         if (!outfd) {
181                 perror("open output");
182                 exit(1);
183         }
184
185         /* perform the extraction */
186         if (b64)
187                 extract_elf64(buffer, len, hdr64);
188         else
189                 extract_elf32(buffer, len, hdr32);
190
191         /* done */
192         if (fclose(outfd) == EOF) {
193                 perror("close output");
194                 exit(1);
195         }
196
197         return 0;
198
199 } /* end main() */
200
201 /*****************************************************************************/
202 /*
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
206  */
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,
212                         const char *sh_name)
213 {
214         struct {
215                 uint64_t        r_offset;
216                 uint64_t        r_addend;
217                 uint64_t        st_value;
218                 uint64_t        st_size;
219                 uint32_t        r_type;
220                 uint16_t        st_shndx;
221                 uint8_t         st_info;
222                 uint8_t         st_other;
223
224         } __attribute__((packed)) relocation;
225
226         const Elf64_Sym *symbol;
227         size_t loop;
228
229         /* contribute the relevant bits from a join of { RELA, SYMBOL, SECTION } */
230         for (loop = 0; loop < nrels; loop++) {
231                 Elf64_Section st_shndx;
232                 Elf64_Xword r_info;
233
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));
239
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);
243                         exit(1);
244                 }
245
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);
254
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]);
258
259                 write_out_val(relocation);
260
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);
265                 }
266         }
267
268         verbose("%02x %4d %s [canon]\n", csum, secix, sh_name);
269
270 } /* end extract_elf64_rela() */
271
272 /*****************************************************************************/
273 /*
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
277  */
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,
283                        const char *sh_name)
284 {
285         struct {
286                 uint64_t        r_offset;
287                 uint64_t        st_value;
288                 uint64_t        st_size;
289                 uint32_t        r_type;
290                 uint16_t        st_shndx;
291                 uint8_t         st_info;
292                 uint8_t         st_other;
293
294         } __attribute__((packed)) relocation;
295
296         const Elf64_Sym *symbol;
297         size_t loop;
298
299         /* contribute the relevant bits from a join of { RELA, SYMBOL, SECTION } */
300         for (loop = 0; loop < nrels; loop++) {
301                 Elf64_Section st_shndx;
302                 Elf64_Xword r_info;
303
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));
308
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);
312                         exit(1);
313                 }
314
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);
323
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]);
327
328                 write_out_val(relocation);
329
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);
334                 }
335         }
336
337         verbose("%02x %4d %s [canon]\n", csum, secix, sh_name);
338
339 } /* end extract_elf64_rel() */
340
341 /*****************************************************************************/
342 /*
343  * extract the data from a 64-bit module
344  */
345 void extract_elf64(void *buffer, size_t len, Elf64_Ehdr *hdr)
346 {
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;
352
353         sections = buffer + get64(&hdr->e_shoff);
354         secstrings = buffer + get64(&sections[get16(&hdr->e_shstrndx)].sh_offset);
355         shnum = get16(&hdr->e_shnum);
356
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
359          * image
360          */
361         canonlist = calloc(sizeof(int), shnum * 2);
362         if (!canonlist) {
363                 perror("calloc");
364                 exit(1);
365         }
366         canonmap = canonlist + shnum;
367         canon = 0;
368
369         symbols = NULL;
370         strings = NULL;
371
372         for (loop = 1; loop < shnum; loop++) {
373                 const char *sh_name = secstrings + get32(&sections[loop].sh_name);
374                 Elf64_Word  sh_type     = get32(&sections[loop].sh_type);
375                 Elf64_Xword sh_size     = get64(&sections[loop].sh_size);
376                 Elf64_Xword sh_flags    = get64(&sections[loop].sh_flags);
377                 Elf64_Off   sh_offset   = get64(&sections[loop].sh_offset);
378                 void *data = buffer + sh_offset;
379
380                 /* quick sanity check */
381                 if (sh_type != SHT_NOBITS && len < sh_offset + sh_size) {
382                         fprintf(stderr, "Section goes beyond EOF\n");
383                         exit(3);
384                 }
385
386                 /* we only need to canonicalise allocatable sections */
387                 if (sh_flags & SHF_ALLOC)
388                         canonlist[canon++] = loop;
389
390                 /* keep track of certain special sections */
391                 switch (sh_type) {
392                 case SHT_SYMTAB:
393                         if (strcmp(sh_name, ".symtab") == 0) {
394                                 symbols = data;
395                                 nsyms = sh_size / sizeof(Elf64_Sym);
396                         }
397                         break;
398
399                 case SHT_STRTAB:
400                         if (strcmp(sh_name, ".strtab") == 0) {
401                                 strings = data;
402                                 nstrings = sh_size;
403                         }
404                         break;
405
406                 default:
407                         break;
408                 }
409         }
410
411         if (!symbols) {
412                 fprintf(stderr, "Couldn't locate symbol table\n");
413                 exit(3);
414         }
415
416         if (!strings) {
417                 fprintf(stderr, "Couldn't locate strings table\n");
418                 exit(3);
419         }
420
421         /* canonicalise the index numbers of the contributing section */
422         do {
423                 changed = 0;
424
425                 for (loop = 0; loop < canon - 1; loop++) {
426                         const char *x = secstrings + get32(&sections[canonlist[loop + 0]].sh_name);
427                         const char *y = secstrings + get32(&sections[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;
432                                 changed = 1;
433                         }
434                 }
435
436         } while(changed);
437
438         for (loop = 0; loop < canon; loop++)
439                 canonmap[canonlist[loop]] = loop + 1;
440
441         if (is_verbose > 1) {
442                 printf("\nSection canonicalisation map:\n");
443                 for (loop = 1; loop < shnum; loop++) {
444                         const char *x = secstrings + get32(&sections[loop].sh_name);
445                         printf("%4d %s\n", canonmap[loop], x);
446                 }
447
448                 printf("\nAllocated section list in canonical order:\n");
449                 for (loop = 0; loop < canon; loop++) {
450                         const char *x = secstrings + get32(&sections[canonlist[loop]].sh_name);
451                         printf("%4d %s\n", canonlist[loop], x);
452                 }
453         }
454
455         memset(canonlist, 0, sizeof(int) * shnum);
456
457         /* iterate through the section table looking for sections we want to
458          * contribute to the signature */
459         verbose("\n");
460         verbose("FILE POS CS SECT NAME\n");
461         verbose("======== == ==== ==============================\n");
462
463         for (loop = 1; loop < shnum; loop++) {
464                 const char *sh_name = secstrings + get32(&sections[loop].sh_name);
465                 Elf64_Word  sh_type     = get32(&sections[loop].sh_type);
466                 Elf64_Xword sh_size     = get64(&sections[loop].sh_size);
467                 Elf64_Xword sh_flags    = get64(&sections[loop].sh_flags);
468                 Elf64_Word  sh_info     = get32(&sections[loop].sh_info);
469                 Elf64_Off   sh_offset   = get64(&sections[loop].sh_offset);
470                 void *data = buffer + sh_offset;
471
472                 csum = 0;
473
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) {
477                                 fprintf(stderr,
478                                         "Invalid ELF - REL/RELA sh_info does"
479                                         " not refer to a valid section\n");
480                                 exit(3);
481                         }
482
483                         if (canonlist[sh_info]) {
484                                 Elf32_Word xsh_info;
485
486                                 verbose("%08lx ", ftell(outfd));
487
488                                 set32(&xsh_info, canonmap[sh_info]);
489
490                                 /* write out selected portions of the section
491                                  * header */
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);
498
499                                 if (sh_type == SHT_RELA)
500                                         extract_elf64_rela(buffer, loop, sh_info,
501                                                            data, sh_size / sizeof(Elf64_Rela),
502                                                            symbols, nsyms,
503                                                            sections, shnum, canonmap,
504                                                            strings, nstrings,
505                                                            sh_name);
506                                 else
507                                         extract_elf64_rel(buffer, loop, sh_info,
508                                                           data, sh_size / sizeof(Elf64_Rel),
509                                                           symbols, nsyms,
510                                                           sections, shnum, canonmap,
511                                                           strings, nstrings,
512                                                           sh_name);
513                         }
514
515                         continue;
516                 }
517
518                 /* include allocatable loadable sections */
519                 if (sh_type != SHT_NOBITS && sh_flags & SHF_ALLOC)
520                         goto include_section;
521
522                 /* not this section */
523                 continue;
524
525         include_section:
526                 verbose("%08lx ", ftell(outfd));
527
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);
534
535                 /* write out the section data */
536                 write_out(data, sh_size);
537
538                 verbose("%02x %4d %s\n", csum, loop, sh_name);
539
540                 /* note the section has been written */
541                 canonlist[loop] = 1;
542         }
543
544         verbose("%08lx         (%lu bytes csum 0x%02x)\n",
545                 ftell(outfd), ftell(outfd), xcsum);
546
547 } /* end extract_elf64() */
548
549 /*****************************************************************************/
550 /*
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
554  */
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,
560                         const char *sh_name)
561 {
562         struct {
563                 uint32_t        r_offset;
564                 uint32_t        r_addend;
565                 uint32_t        st_value;
566                 uint32_t        st_size;
567                 uint16_t        st_shndx;
568                 uint8_t         r_type;
569                 uint8_t         st_info;
570                 uint8_t         st_other;
571
572         } __attribute__((packed)) relocation;
573
574         const Elf32_Sym *symbol;
575         size_t loop;
576
577         /* contribute the relevant bits from a join of { RELA, SYMBOL, SECTION } */
578         for (loop = 0; loop < nrels; loop++) {
579                 Elf32_Section st_shndx;
580                 Elf32_Word r_info;
581
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);
587
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);
591                         exit(1);
592                 }
593
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);
602
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]);
606
607                 write_out_val(relocation);
608
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);
613                 }
614         }
615
616         verbose("%02x %4d %s [canon]\n", csum, secix, sh_name);
617
618 } /* end extract_elf32_rela() */
619
620 /*****************************************************************************/
621 /*
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
625  */
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,
631                        const char *sh_name)
632 {
633         struct {
634                 uint32_t        r_offset;
635                 uint32_t        st_value;
636                 uint32_t        st_size;
637                 uint16_t        st_shndx;
638                 uint8_t         r_type;
639                 uint8_t         st_info;
640                 uint8_t         st_other;
641
642         } __attribute__((packed)) relocation;
643
644         const Elf32_Sym *symbol;
645         size_t loop;
646
647         /* contribute the relevant bits from a join of { RELA, SYMBOL, SECTION } */
648         for (loop = 0; loop < nrels; loop++) {
649                 Elf32_Section st_shndx;
650                 Elf32_Word r_info;
651
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);
656
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);
660                         exit(1);
661                 }
662
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);
671
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]);
675                 
676                 write_out_val(relocation);
677
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);
682                 }
683         }
684
685         verbose("%02x %4d %s [canon]\n", csum, secix, sh_name);
686
687 } /* end extract_elf32_rel() */
688
689 /*****************************************************************************/
690 /*
691  * extract the data from a 32-bit module
692  */
693 void extract_elf32(void *buffer, size_t len, Elf32_Ehdr *hdr)
694 {
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;
700
701         sections = buffer + get32(&hdr->e_shoff);
702         secstrings = buffer + get32(&sections[get16(&hdr->e_shstrndx)].sh_offset);
703         shnum = get16(&hdr->e_shnum);
704
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
707          * image
708          */
709         canonlist = calloc(sizeof(int), shnum * 2);
710         if (!canonlist) {
711                 perror("calloc");
712                 exit(1);
713         }
714         canonmap = canonlist + shnum;
715         canon = 0;
716
717         symbols = NULL;
718         strings = NULL;
719
720         for (loop = 1; loop < shnum; loop++) {
721                 const char *sh_name = secstrings + get32(&sections[loop].sh_name);
722                 Elf32_Word  sh_type     = get32(&sections[loop].sh_type);
723                 Elf32_Xword sh_size     = get32(&sections[loop].sh_size);
724                 Elf32_Xword sh_flags    = get32(&sections[loop].sh_flags);
725                 Elf32_Off   sh_offset   = get32(&sections[loop].sh_offset);
726                 void *data = buffer + sh_offset;
727
728                 /* quick sanity check */
729                 if (sh_type != SHT_NOBITS && len < sh_offset + sh_size) {
730                         fprintf(stderr, "Section goes beyond EOF\n");
731                         exit(3);
732                 }
733
734                 /* we only need to canonicalise allocatable sections */
735                 if (sh_flags & SHF_ALLOC)
736                         canonlist[canon++] = loop;
737
738                 /* keep track of certain special sections */
739                 switch (sh_type) {
740                 case SHT_SYMTAB:
741                         if (strcmp(sh_name, ".symtab") == 0) {
742                                 symbols = data;
743                                 nsyms = sh_size / sizeof(Elf32_Sym);
744                         }
745                         break;
746
747                 case SHT_STRTAB:
748                         if (strcmp(sh_name, ".strtab") == 0) {
749                                 strings = data;
750                                 nstrings = sh_size;
751                         }
752                         break;
753
754                 default:
755                         break;
756                 }
757         }
758
759         if (!symbols) {
760                 fprintf(stderr, "Couldn't locate symbol table\n");
761                 exit(3);
762         }
763
764         if (!strings) {
765                 fprintf(stderr, "Couldn't locate strings table\n");
766                 exit(3);
767         }
768
769         /* canonicalise the index numbers of the contributing section */
770         do {
771                 changed = 0;
772
773                 for (loop = 0; loop < canon - 1; loop++) {
774                         const char *x = secstrings + get32(&sections[canonlist[loop + 0]].sh_name);
775                         const char *y = secstrings + get32(&sections[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;
780                                 changed = 1;
781                         }
782                 }
783
784         } while(changed);
785
786         for (loop = 0; loop < canon; loop++)
787                 canonmap[canonlist[loop]] = loop + 1;
788
789         if (is_verbose > 1) {
790                 printf("\nSection canonicalisation map:\n");
791                 for (loop = 1; loop < shnum; loop++) {
792                         const char *x = secstrings + get32(&sections[loop].sh_name);
793                         printf("%4d %s\n", canonmap[loop], x);
794                 }
795
796                 printf("\nAllocated section list in canonical order:\n");
797                 for (loop = 0; loop < canon; loop++) {
798                         const char *x = secstrings + get32(&sections[canonlist[loop]].sh_name);
799                         printf("%4d %s\n", canonlist[loop], x);
800                 }
801         }
802
803         memset(canonlist, 0, sizeof(int) * shnum);
804
805         /* iterate through the section table looking for sections we want to
806          * contribute to the signature */
807         verbose("\n");
808         verbose("FILE POS CS SECT NAME\n");
809         verbose("======== == ==== ==============================\n");
810
811         for (loop = 1; loop < shnum; loop++) {
812                 const char *sh_name = secstrings + get32(&sections[loop].sh_name);
813                 Elf32_Word  sh_type     = get32(&sections[loop].sh_type);
814                 Elf32_Xword sh_size     = get32(&sections[loop].sh_size);
815                 Elf32_Xword sh_flags    = get32(&sections[loop].sh_flags);
816                 Elf32_Word  sh_info     = get32(&sections[loop].sh_info);
817                 Elf32_Off   sh_offset   = get32(&sections[loop].sh_offset);
818                 void *data = buffer + sh_offset;
819
820                 csum = 0;
821
822                 /* quick sanity check */
823                 if (sh_type != SHT_NOBITS && len < sh_offset + sh_size) {
824                         fprintf(stderr, "section goes beyond EOF\n");
825                         exit(3);
826                 }
827
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) {
831                                 fprintf(stderr,
832                                         "Invalid ELF - REL/RELA sh_info does"
833                                         " not refer to a valid section\n");
834                                 exit(3);
835                         }
836
837                         if (canonlist[sh_info]) {
838                                 Elf32_Word xsh_info;
839
840                                 verbose("%08lx ", ftell(outfd));
841
842                                 set32(&xsh_info, canonmap[sh_info]);
843
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);
851
852                                 if (sh_type == SHT_RELA)
853                                         extract_elf32_rela(buffer, loop, sh_info,
854                                                            data, sh_size / sizeof(Elf32_Rela),
855                                                            symbols, nsyms,
856                                                            sections, shnum, canonmap,
857                                                            strings, nstrings,
858                                                            sh_name);
859                                 else
860                                         extract_elf32_rel(buffer, loop, sh_info,
861                                                           data, sh_size / sizeof(Elf32_Rel),
862                                                           symbols, nsyms,
863                                                           sections, shnum, canonmap,
864                                                           strings, nstrings,
865                                                           sh_name);
866                         }
867
868                         continue;
869                 }
870
871                 /* include allocatable loadable sections */
872                 if (sh_type != SHT_NOBITS && sh_flags & SHF_ALLOC)
873                         goto include_section;
874
875                 /* not this section */
876                 continue;
877
878         include_section:
879                 verbose("%08lx ", ftell(outfd));
880
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);
887
888                 /* write out the section data */
889                 write_out(data, sh_size);
890
891                 verbose("%02x %4d %s\n", csum, loop, sh_name);
892
893                 /* note the section has been written */
894                 canonlist[loop] = 1;
895         }
896
897         verbose("%08lx         (%lu bytes csum 0x%02x)\n",
898                 ftell(outfd), ftell(outfd), xcsum);
899
900 } /* end extract_elf32() */