]> git.openfabrics.org - ~shefty/rdma-dev.git/blob - arch/x86/tools/relocs.c
x86/boot: Fix minor fd leakage in tools/relocs.c
[~shefty/rdma-dev.git] / arch / x86 / tools / relocs.c
1 #include <stdio.h>
2 #include <stdarg.h>
3 #include <stdlib.h>
4 #include <stdint.h>
5 #include <string.h>
6 #include <errno.h>
7 #include <unistd.h>
8 #include <elf.h>
9 #include <byteswap.h>
10 #define USE_BSD
11 #include <endian.h>
12 #include <regex.h>
13 #include <tools/le_byteshift.h>
14
15 static void die(char *fmt, ...);
16
17 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
18 static Elf32_Ehdr ehdr;
19 static unsigned long reloc_count, reloc_idx;
20 static unsigned long *relocs;
21 static unsigned long reloc16_count, reloc16_idx;
22 static unsigned long *relocs16;
23
24 struct section {
25         Elf32_Shdr     shdr;
26         struct section *link;
27         Elf32_Sym      *symtab;
28         Elf32_Rel      *reltab;
29         char           *strtab;
30 };
31 static struct section *secs;
32
33 enum symtype {
34         S_ABS,
35         S_REL,
36         S_SEG,
37         S_LIN,
38         S_NSYMTYPES
39 };
40
41 static const char * const sym_regex_kernel[S_NSYMTYPES] = {
42 /*
43  * Following symbols have been audited. There values are constant and do
44  * not change if bzImage is loaded at a different physical address than
45  * the address for which it has been compiled. Don't warn user about
46  * absolute relocations present w.r.t these symbols.
47  */
48         [S_ABS] =
49         "^(xen_irq_disable_direct_reloc$|"
50         "xen_save_fl_direct_reloc$|"
51         "VDSO|"
52         "__crc_)",
53
54 /*
55  * These symbols are known to be relative, even if the linker marks them
56  * as absolute (typically defined outside any section in the linker script.)
57  */
58         [S_REL] =
59         "^(__init_(begin|end)|"
60         "__x86_cpu_dev_(start|end)|"
61         "(__parainstructions|__alt_instructions)(|_end)|"
62         "(__iommu_table|__apicdrivers|__smp_locks)(|_end)|"
63         "__(start|end)_pci_.*|"
64         "__(start|end)_builtin_fw|"
65         "__(start|stop)___ksymtab(|_gpl|_unused|_unused_gpl|_gpl_future)|"
66         "__(start|stop)___kcrctab(|_gpl|_unused|_unused_gpl|_gpl_future)|"
67         "__(start|stop)___param|"
68         "__(start|stop)___modver|"
69         "__(start|stop)___bug_table|"
70         "__tracedata_(start|end)|"
71         "__(start|stop)_notes|"
72         "__end_rodata|"
73         "__initramfs_start|"
74         "(jiffies|jiffies_64)|"
75         "_end)$"
76 };
77
78
79 static const char * const sym_regex_realmode[S_NSYMTYPES] = {
80 /*
81  * These symbols are known to be relative, even if the linker marks them
82  * as absolute (typically defined outside any section in the linker script.)
83  */
84         [S_REL] =
85         "^pa_",
86
87 /*
88  * These are 16-bit segment symbols when compiling 16-bit code.
89  */
90         [S_SEG] =
91         "^real_mode_seg$",
92
93 /*
94  * These are offsets belonging to segments, as opposed to linear addresses,
95  * when compiling 16-bit code.
96  */
97         [S_LIN] =
98         "^pa_",
99 };
100
101 static const char * const *sym_regex;
102
103 static regex_t sym_regex_c[S_NSYMTYPES];
104 static int is_reloc(enum symtype type, const char *sym_name)
105 {
106         return sym_regex[type] &&
107                 !regexec(&sym_regex_c[type], sym_name, 0, NULL, 0);
108 }
109
110 static void regex_init(int use_real_mode)
111 {
112         char errbuf[128];
113         int err;
114         int i;
115
116         if (use_real_mode)
117                 sym_regex = sym_regex_realmode;
118         else
119                 sym_regex = sym_regex_kernel;
120
121         for (i = 0; i < S_NSYMTYPES; i++) {
122                 if (!sym_regex[i])
123                         continue;
124
125                 err = regcomp(&sym_regex_c[i], sym_regex[i],
126                               REG_EXTENDED|REG_NOSUB);
127
128                 if (err) {
129                         regerror(err, &sym_regex_c[i], errbuf, sizeof errbuf);
130                         die("%s", errbuf);
131                 }
132         }
133 }
134
135 static void die(char *fmt, ...)
136 {
137         va_list ap;
138         va_start(ap, fmt);
139         vfprintf(stderr, fmt, ap);
140         va_end(ap);
141         exit(1);
142 }
143
144 static const char *sym_type(unsigned type)
145 {
146         static const char *type_name[] = {
147 #define SYM_TYPE(X) [X] = #X
148                 SYM_TYPE(STT_NOTYPE),
149                 SYM_TYPE(STT_OBJECT),
150                 SYM_TYPE(STT_FUNC),
151                 SYM_TYPE(STT_SECTION),
152                 SYM_TYPE(STT_FILE),
153                 SYM_TYPE(STT_COMMON),
154                 SYM_TYPE(STT_TLS),
155 #undef SYM_TYPE
156         };
157         const char *name = "unknown sym type name";
158         if (type < ARRAY_SIZE(type_name)) {
159                 name = type_name[type];
160         }
161         return name;
162 }
163
164 static const char *sym_bind(unsigned bind)
165 {
166         static const char *bind_name[] = {
167 #define SYM_BIND(X) [X] = #X
168                 SYM_BIND(STB_LOCAL),
169                 SYM_BIND(STB_GLOBAL),
170                 SYM_BIND(STB_WEAK),
171 #undef SYM_BIND
172         };
173         const char *name = "unknown sym bind name";
174         if (bind < ARRAY_SIZE(bind_name)) {
175                 name = bind_name[bind];
176         }
177         return name;
178 }
179
180 static const char *sym_visibility(unsigned visibility)
181 {
182         static const char *visibility_name[] = {
183 #define SYM_VISIBILITY(X) [X] = #X
184                 SYM_VISIBILITY(STV_DEFAULT),
185                 SYM_VISIBILITY(STV_INTERNAL),
186                 SYM_VISIBILITY(STV_HIDDEN),
187                 SYM_VISIBILITY(STV_PROTECTED),
188 #undef SYM_VISIBILITY
189         };
190         const char *name = "unknown sym visibility name";
191         if (visibility < ARRAY_SIZE(visibility_name)) {
192                 name = visibility_name[visibility];
193         }
194         return name;
195 }
196
197 static const char *rel_type(unsigned type)
198 {
199         static const char *type_name[] = {
200 #define REL_TYPE(X) [X] = #X
201                 REL_TYPE(R_386_NONE),
202                 REL_TYPE(R_386_32),
203                 REL_TYPE(R_386_PC32),
204                 REL_TYPE(R_386_GOT32),
205                 REL_TYPE(R_386_PLT32),
206                 REL_TYPE(R_386_COPY),
207                 REL_TYPE(R_386_GLOB_DAT),
208                 REL_TYPE(R_386_JMP_SLOT),
209                 REL_TYPE(R_386_RELATIVE),
210                 REL_TYPE(R_386_GOTOFF),
211                 REL_TYPE(R_386_GOTPC),
212                 REL_TYPE(R_386_8),
213                 REL_TYPE(R_386_PC8),
214                 REL_TYPE(R_386_16),
215                 REL_TYPE(R_386_PC16),
216 #undef REL_TYPE
217         };
218         const char *name = "unknown type rel type name";
219         if (type < ARRAY_SIZE(type_name) && type_name[type]) {
220                 name = type_name[type];
221         }
222         return name;
223 }
224
225 static const char *sec_name(unsigned shndx)
226 {
227         const char *sec_strtab;
228         const char *name;
229         sec_strtab = secs[ehdr.e_shstrndx].strtab;
230         name = "<noname>";
231         if (shndx < ehdr.e_shnum) {
232                 name = sec_strtab + secs[shndx].shdr.sh_name;
233         }
234         else if (shndx == SHN_ABS) {
235                 name = "ABSOLUTE";
236         }
237         else if (shndx == SHN_COMMON) {
238                 name = "COMMON";
239         }
240         return name;
241 }
242
243 static const char *sym_name(const char *sym_strtab, Elf32_Sym *sym)
244 {
245         const char *name;
246         name = "<noname>";
247         if (sym->st_name) {
248                 name = sym_strtab + sym->st_name;
249         }
250         else {
251                 name = sec_name(sym->st_shndx);
252         }
253         return name;
254 }
255
256
257
258 #if BYTE_ORDER == LITTLE_ENDIAN
259 #define le16_to_cpu(val) (val)
260 #define le32_to_cpu(val) (val)
261 #endif
262 #if BYTE_ORDER == BIG_ENDIAN
263 #define le16_to_cpu(val) bswap_16(val)
264 #define le32_to_cpu(val) bswap_32(val)
265 #endif
266
267 static uint16_t elf16_to_cpu(uint16_t val)
268 {
269         return le16_to_cpu(val);
270 }
271
272 static uint32_t elf32_to_cpu(uint32_t val)
273 {
274         return le32_to_cpu(val);
275 }
276
277 static void read_ehdr(FILE *fp)
278 {
279         if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) {
280                 die("Cannot read ELF header: %s\n",
281                         strerror(errno));
282         }
283         if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) {
284                 die("No ELF magic\n");
285         }
286         if (ehdr.e_ident[EI_CLASS] != ELFCLASS32) {
287                 die("Not a 32 bit executable\n");
288         }
289         if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB) {
290                 die("Not a LSB ELF executable\n");
291         }
292         if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) {
293                 die("Unknown ELF version\n");
294         }
295         /* Convert the fields to native endian */
296         ehdr.e_type      = elf16_to_cpu(ehdr.e_type);
297         ehdr.e_machine   = elf16_to_cpu(ehdr.e_machine);
298         ehdr.e_version   = elf32_to_cpu(ehdr.e_version);
299         ehdr.e_entry     = elf32_to_cpu(ehdr.e_entry);
300         ehdr.e_phoff     = elf32_to_cpu(ehdr.e_phoff);
301         ehdr.e_shoff     = elf32_to_cpu(ehdr.e_shoff);
302         ehdr.e_flags     = elf32_to_cpu(ehdr.e_flags);
303         ehdr.e_ehsize    = elf16_to_cpu(ehdr.e_ehsize);
304         ehdr.e_phentsize = elf16_to_cpu(ehdr.e_phentsize);
305         ehdr.e_phnum     = elf16_to_cpu(ehdr.e_phnum);
306         ehdr.e_shentsize = elf16_to_cpu(ehdr.e_shentsize);
307         ehdr.e_shnum     = elf16_to_cpu(ehdr.e_shnum);
308         ehdr.e_shstrndx  = elf16_to_cpu(ehdr.e_shstrndx);
309
310         if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN)) {
311                 die("Unsupported ELF header type\n");
312         }
313         if (ehdr.e_machine != EM_386) {
314                 die("Not for x86\n");
315         }
316         if (ehdr.e_version != EV_CURRENT) {
317                 die("Unknown ELF version\n");
318         }
319         if (ehdr.e_ehsize != sizeof(Elf32_Ehdr)) {
320                 die("Bad Elf header size\n");
321         }
322         if (ehdr.e_phentsize != sizeof(Elf32_Phdr)) {
323                 die("Bad program header entry\n");
324         }
325         if (ehdr.e_shentsize != sizeof(Elf32_Shdr)) {
326                 die("Bad section header entry\n");
327         }
328         if (ehdr.e_shstrndx >= ehdr.e_shnum) {
329                 die("String table index out of bounds\n");
330         }
331 }
332
333 static void read_shdrs(FILE *fp)
334 {
335         int i;
336         Elf32_Shdr shdr;
337
338         secs = calloc(ehdr.e_shnum, sizeof(struct section));
339         if (!secs) {
340                 die("Unable to allocate %d section headers\n",
341                     ehdr.e_shnum);
342         }
343         if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0) {
344                 die("Seek to %d failed: %s\n",
345                         ehdr.e_shoff, strerror(errno));
346         }
347         for (i = 0; i < ehdr.e_shnum; i++) {
348                 struct section *sec = &secs[i];
349                 if (fread(&shdr, sizeof shdr, 1, fp) != 1)
350                         die("Cannot read ELF section headers %d/%d: %s\n",
351                             i, ehdr.e_shnum, strerror(errno));
352                 sec->shdr.sh_name      = elf32_to_cpu(shdr.sh_name);
353                 sec->shdr.sh_type      = elf32_to_cpu(shdr.sh_type);
354                 sec->shdr.sh_flags     = elf32_to_cpu(shdr.sh_flags);
355                 sec->shdr.sh_addr      = elf32_to_cpu(shdr.sh_addr);
356                 sec->shdr.sh_offset    = elf32_to_cpu(shdr.sh_offset);
357                 sec->shdr.sh_size      = elf32_to_cpu(shdr.sh_size);
358                 sec->shdr.sh_link      = elf32_to_cpu(shdr.sh_link);
359                 sec->shdr.sh_info      = elf32_to_cpu(shdr.sh_info);
360                 sec->shdr.sh_addralign = elf32_to_cpu(shdr.sh_addralign);
361                 sec->shdr.sh_entsize   = elf32_to_cpu(shdr.sh_entsize);
362                 if (sec->shdr.sh_link < ehdr.e_shnum)
363                         sec->link = &secs[sec->shdr.sh_link];
364         }
365
366 }
367
368 static void read_strtabs(FILE *fp)
369 {
370         int i;
371         for (i = 0; i < ehdr.e_shnum; i++) {
372                 struct section *sec = &secs[i];
373                 if (sec->shdr.sh_type != SHT_STRTAB) {
374                         continue;
375                 }
376                 sec->strtab = malloc(sec->shdr.sh_size);
377                 if (!sec->strtab) {
378                         die("malloc of %d bytes for strtab failed\n",
379                                 sec->shdr.sh_size);
380                 }
381                 if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
382                         die("Seek to %d failed: %s\n",
383                                 sec->shdr.sh_offset, strerror(errno));
384                 }
385                 if (fread(sec->strtab, 1, sec->shdr.sh_size, fp)
386                     != sec->shdr.sh_size) {
387                         die("Cannot read symbol table: %s\n",
388                                 strerror(errno));
389                 }
390         }
391 }
392
393 static void read_symtabs(FILE *fp)
394 {
395         int i,j;
396         for (i = 0; i < ehdr.e_shnum; i++) {
397                 struct section *sec = &secs[i];
398                 if (sec->shdr.sh_type != SHT_SYMTAB) {
399                         continue;
400                 }
401                 sec->symtab = malloc(sec->shdr.sh_size);
402                 if (!sec->symtab) {
403                         die("malloc of %d bytes for symtab failed\n",
404                                 sec->shdr.sh_size);
405                 }
406                 if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
407                         die("Seek to %d failed: %s\n",
408                                 sec->shdr.sh_offset, strerror(errno));
409                 }
410                 if (fread(sec->symtab, 1, sec->shdr.sh_size, fp)
411                     != sec->shdr.sh_size) {
412                         die("Cannot read symbol table: %s\n",
413                                 strerror(errno));
414                 }
415                 for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) {
416                         Elf32_Sym *sym = &sec->symtab[j];
417                         sym->st_name  = elf32_to_cpu(sym->st_name);
418                         sym->st_value = elf32_to_cpu(sym->st_value);
419                         sym->st_size  = elf32_to_cpu(sym->st_size);
420                         sym->st_shndx = elf16_to_cpu(sym->st_shndx);
421                 }
422         }
423 }
424
425
426 static void read_relocs(FILE *fp)
427 {
428         int i,j;
429         for (i = 0; i < ehdr.e_shnum; i++) {
430                 struct section *sec = &secs[i];
431                 if (sec->shdr.sh_type != SHT_REL) {
432                         continue;
433                 }
434                 sec->reltab = malloc(sec->shdr.sh_size);
435                 if (!sec->reltab) {
436                         die("malloc of %d bytes for relocs failed\n",
437                                 sec->shdr.sh_size);
438                 }
439                 if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
440                         die("Seek to %d failed: %s\n",
441                                 sec->shdr.sh_offset, strerror(errno));
442                 }
443                 if (fread(sec->reltab, 1, sec->shdr.sh_size, fp)
444                     != sec->shdr.sh_size) {
445                         die("Cannot read symbol table: %s\n",
446                                 strerror(errno));
447                 }
448                 for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
449                         Elf32_Rel *rel = &sec->reltab[j];
450                         rel->r_offset = elf32_to_cpu(rel->r_offset);
451                         rel->r_info   = elf32_to_cpu(rel->r_info);
452                 }
453         }
454 }
455
456
457 static void print_absolute_symbols(void)
458 {
459         int i;
460         printf("Absolute symbols\n");
461         printf(" Num:    Value Size  Type       Bind        Visibility  Name\n");
462         for (i = 0; i < ehdr.e_shnum; i++) {
463                 struct section *sec = &secs[i];
464                 char *sym_strtab;
465                 int j;
466
467                 if (sec->shdr.sh_type != SHT_SYMTAB) {
468                         continue;
469                 }
470                 sym_strtab = sec->link->strtab;
471                 for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) {
472                         Elf32_Sym *sym;
473                         const char *name;
474                         sym = &sec->symtab[j];
475                         name = sym_name(sym_strtab, sym);
476                         if (sym->st_shndx != SHN_ABS) {
477                                 continue;
478                         }
479                         printf("%5d %08x %5d %10s %10s %12s %s\n",
480                                 j, sym->st_value, sym->st_size,
481                                 sym_type(ELF32_ST_TYPE(sym->st_info)),
482                                 sym_bind(ELF32_ST_BIND(sym->st_info)),
483                                 sym_visibility(ELF32_ST_VISIBILITY(sym->st_other)),
484                                 name);
485                 }
486         }
487         printf("\n");
488 }
489
490 static void print_absolute_relocs(void)
491 {
492         int i, printed = 0;
493
494         for (i = 0; i < ehdr.e_shnum; i++) {
495                 struct section *sec = &secs[i];
496                 struct section *sec_applies, *sec_symtab;
497                 char *sym_strtab;
498                 Elf32_Sym *sh_symtab;
499                 int j;
500                 if (sec->shdr.sh_type != SHT_REL) {
501                         continue;
502                 }
503                 sec_symtab  = sec->link;
504                 sec_applies = &secs[sec->shdr.sh_info];
505                 if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) {
506                         continue;
507                 }
508                 sh_symtab  = sec_symtab->symtab;
509                 sym_strtab = sec_symtab->link->strtab;
510                 for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
511                         Elf32_Rel *rel;
512                         Elf32_Sym *sym;
513                         const char *name;
514                         rel = &sec->reltab[j];
515                         sym = &sh_symtab[ELF32_R_SYM(rel->r_info)];
516                         name = sym_name(sym_strtab, sym);
517                         if (sym->st_shndx != SHN_ABS) {
518                                 continue;
519                         }
520
521                         /* Absolute symbols are not relocated if bzImage is
522                          * loaded at a non-compiled address. Display a warning
523                          * to user at compile time about the absolute
524                          * relocations present.
525                          *
526                          * User need to audit the code to make sure
527                          * some symbols which should have been section
528                          * relative have not become absolute because of some
529                          * linker optimization or wrong programming usage.
530                          *
531                          * Before warning check if this absolute symbol
532                          * relocation is harmless.
533                          */
534                         if (is_reloc(S_ABS, name) || is_reloc(S_REL, name))
535                                 continue;
536
537                         if (!printed) {
538                                 printf("WARNING: Absolute relocations"
539                                         " present\n");
540                                 printf("Offset     Info     Type     Sym.Value "
541                                         "Sym.Name\n");
542                                 printed = 1;
543                         }
544
545                         printf("%08x %08x %10s %08x  %s\n",
546                                 rel->r_offset,
547                                 rel->r_info,
548                                 rel_type(ELF32_R_TYPE(rel->r_info)),
549                                 sym->st_value,
550                                 name);
551                 }
552         }
553
554         if (printed)
555                 printf("\n");
556 }
557
558 static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym),
559                         int use_real_mode)
560 {
561         int i;
562         /* Walk through the relocations */
563         for (i = 0; i < ehdr.e_shnum; i++) {
564                 char *sym_strtab;
565                 Elf32_Sym *sh_symtab;
566                 struct section *sec_applies, *sec_symtab;
567                 int j;
568                 struct section *sec = &secs[i];
569
570                 if (sec->shdr.sh_type != SHT_REL) {
571                         continue;
572                 }
573                 sec_symtab  = sec->link;
574                 sec_applies = &secs[sec->shdr.sh_info];
575                 if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) {
576                         continue;
577                 }
578                 sh_symtab = sec_symtab->symtab;
579                 sym_strtab = sec_symtab->link->strtab;
580                 for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
581                         Elf32_Rel *rel;
582                         Elf32_Sym *sym;
583                         unsigned r_type;
584                         const char *symname;
585                         int shn_abs;
586
587                         rel = &sec->reltab[j];
588                         sym = &sh_symtab[ELF32_R_SYM(rel->r_info)];
589                         r_type = ELF32_R_TYPE(rel->r_info);
590
591                         shn_abs = sym->st_shndx == SHN_ABS;
592
593                         switch (r_type) {
594                         case R_386_NONE:
595                         case R_386_PC32:
596                         case R_386_PC16:
597                         case R_386_PC8:
598                                 /*
599                                  * NONE can be ignored and and PC relative
600                                  * relocations don't need to be adjusted.
601                                  */
602                                 break;
603
604                         case R_386_16:
605                                 symname = sym_name(sym_strtab, sym);
606                                 if (!use_real_mode)
607                                         goto bad;
608                                 if (shn_abs) {
609                                         if (is_reloc(S_ABS, symname))
610                                                 break;
611                                         else if (!is_reloc(S_SEG, symname))
612                                                 goto bad;
613                                 } else {
614                                         if (is_reloc(S_LIN, symname))
615                                                 goto bad;
616                                         else
617                                                 break;
618                                 }
619                                 visit(rel, sym);
620                                 break;
621
622                         case R_386_32:
623                                 symname = sym_name(sym_strtab, sym);
624                                 if (shn_abs) {
625                                         if (is_reloc(S_ABS, symname))
626                                                 break;
627                                         else if (!is_reloc(S_REL, symname))
628                                                 goto bad;
629                                 } else {
630                                         if (use_real_mode &&
631                                             !is_reloc(S_LIN, symname))
632                                                 break;
633                                 }
634                                 visit(rel, sym);
635                                 break;
636                         default:
637                                 die("Unsupported relocation type: %s (%d)\n",
638                                     rel_type(r_type), r_type);
639                                 break;
640                         bad:
641                                 symname = sym_name(sym_strtab, sym);
642                                 die("Invalid %s %s relocation: %s\n",
643                                     shn_abs ? "absolute" : "relative",
644                                     rel_type(r_type), symname);
645                         }
646                 }
647         }
648 }
649
650 static void count_reloc(Elf32_Rel *rel, Elf32_Sym *sym)
651 {
652         if (ELF32_R_TYPE(rel->r_info) == R_386_16)
653                 reloc16_count++;
654         else
655                 reloc_count++;
656 }
657
658 static void collect_reloc(Elf32_Rel *rel, Elf32_Sym *sym)
659 {
660         /* Remember the address that needs to be adjusted. */
661         if (ELF32_R_TYPE(rel->r_info) == R_386_16)
662                 relocs16[reloc16_idx++] = rel->r_offset;
663         else
664                 relocs[reloc_idx++] = rel->r_offset;
665 }
666
667 static int cmp_relocs(const void *va, const void *vb)
668 {
669         const unsigned long *a, *b;
670         a = va; b = vb;
671         return (*a == *b)? 0 : (*a > *b)? 1 : -1;
672 }
673
674 static int write32(unsigned int v, FILE *f)
675 {
676         unsigned char buf[4];
677
678         put_unaligned_le32(v, buf);
679         return fwrite(buf, 1, 4, f) == 4 ? 0 : -1;
680 }
681
682 static void emit_relocs(int as_text, int use_real_mode)
683 {
684         int i;
685         /* Count how many relocations I have and allocate space for them. */
686         reloc_count = 0;
687         walk_relocs(count_reloc, use_real_mode);
688         relocs = malloc(reloc_count * sizeof(relocs[0]));
689         if (!relocs) {
690                 die("malloc of %d entries for relocs failed\n",
691                         reloc_count);
692         }
693
694         relocs16 = malloc(reloc16_count * sizeof(relocs[0]));
695         if (!relocs16) {
696                 die("malloc of %d entries for relocs16 failed\n",
697                         reloc16_count);
698         }
699         /* Collect up the relocations */
700         reloc_idx = 0;
701         walk_relocs(collect_reloc, use_real_mode);
702
703         if (reloc16_count && !use_real_mode)
704                 die("Segment relocations found but --realmode not specified\n");
705
706         /* Order the relocations for more efficient processing */
707         qsort(relocs, reloc_count, sizeof(relocs[0]), cmp_relocs);
708         qsort(relocs16, reloc16_count, sizeof(relocs16[0]), cmp_relocs);
709
710         /* Print the relocations */
711         if (as_text) {
712                 /* Print the relocations in a form suitable that
713                  * gas will like.
714                  */
715                 printf(".section \".data.reloc\",\"a\"\n");
716                 printf(".balign 4\n");
717                 if (use_real_mode) {
718                         printf("\t.long %lu\n", reloc16_count);
719                         for (i = 0; i < reloc16_count; i++)
720                                 printf("\t.long 0x%08lx\n", relocs16[i]);
721                         printf("\t.long %lu\n", reloc_count);
722                         for (i = 0; i < reloc_count; i++) {
723                                 printf("\t.long 0x%08lx\n", relocs[i]);
724                         }
725                 } else {
726                         /* Print a stop */
727                         printf("\t.long 0x%08lx\n", (unsigned long)0);
728                         for (i = 0; i < reloc_count; i++) {
729                                 printf("\t.long 0x%08lx\n", relocs[i]);
730                         }
731                 }
732
733                 printf("\n");
734         }
735         else {
736                 if (use_real_mode) {
737                         write32(reloc16_count, stdout);
738                         for (i = 0; i < reloc16_count; i++)
739                                 write32(relocs16[i], stdout);
740                         write32(reloc_count, stdout);
741
742                         /* Now print each relocation */
743                         for (i = 0; i < reloc_count; i++)
744                                 write32(relocs[i], stdout);
745                 } else {
746                         /* Print a stop */
747                         write32(0, stdout);
748
749                         /* Now print each relocation */
750                         for (i = 0; i < reloc_count; i++) {
751                                 write32(relocs[i], stdout);
752                         }
753                 }
754         }
755 }
756
757 static void usage(void)
758 {
759         die("relocs [--abs-syms|--abs-relocs|--text|--realmode] vmlinux\n");
760 }
761
762 int main(int argc, char **argv)
763 {
764         int show_absolute_syms, show_absolute_relocs;
765         int as_text, use_real_mode;
766         const char *fname;
767         FILE *fp;
768         int i;
769
770         show_absolute_syms = 0;
771         show_absolute_relocs = 0;
772         as_text = 0;
773         use_real_mode = 0;
774         fname = NULL;
775         for (i = 1; i < argc; i++) {
776                 char *arg = argv[i];
777                 if (*arg == '-') {
778                         if (strcmp(arg, "--abs-syms") == 0) {
779                                 show_absolute_syms = 1;
780                                 continue;
781                         }
782                         if (strcmp(arg, "--abs-relocs") == 0) {
783                                 show_absolute_relocs = 1;
784                                 continue;
785                         }
786                         if (strcmp(arg, "--text") == 0) {
787                                 as_text = 1;
788                                 continue;
789                         }
790                         if (strcmp(arg, "--realmode") == 0) {
791                                 use_real_mode = 1;
792                                 continue;
793                         }
794                 }
795                 else if (!fname) {
796                         fname = arg;
797                         continue;
798                 }
799                 usage();
800         }
801         if (!fname) {
802                 usage();
803         }
804         regex_init(use_real_mode);
805         fp = fopen(fname, "r");
806         if (!fp) {
807                 die("Cannot open %s: %s\n",
808                         fname, strerror(errno));
809         }
810         read_ehdr(fp);
811         read_shdrs(fp);
812         read_strtabs(fp);
813         read_symtabs(fp);
814         read_relocs(fp);
815         if (show_absolute_syms) {
816                 print_absolute_symbols();
817                 goto out;
818         }
819         if (show_absolute_relocs) {
820                 print_absolute_relocs();
821                 goto out;
822         }
823         emit_relocs(as_text, use_real_mode);
824 out:
825         fclose(fp);
826         return 0;
827 }