diff options
author | Kees Cook <keescook@chromium.org> | 2013-04-12 16:13:44 -0400 |
---|---|---|
committer | H. Peter Anvin <hpa@linux.intel.com> | 2013-04-16 18:19:22 -0400 |
commit | 946166af95d1defacfbc21e7c902d0556a2a7660 (patch) | |
tree | c3de26414a9728ca2a04331a5dcc1d900c0a641b /arch/x86/tools | |
parent | 5d442e63d6a1b5736fd48a907bd7d2d87e411816 (diff) |
x86, relocs: Add 64-bit ELF support to relocs tool
This adds the ability to process relocations from the 64-bit kernel ELF,
if built with ELF_BITS=64 defined. The special case for the percpu area is
handled, along with some other symbols specific to the 64-bit kernel.
Based on work by Neill Clift and Michael Davidson.
Signed-off-by: Kees Cook <keescook@chromium.org>
Link: http://lkml.kernel.org/r/1365797627-20874-4-git-send-email-keescook@chromium.org
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'arch/x86/tools')
-rw-r--r-- | arch/x86/tools/relocs.c | 267 |
1 files changed, 261 insertions, 6 deletions
diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c index bdc5930b3a1b..1f7ff3d11a05 100644 --- a/arch/x86/tools/relocs.c +++ b/arch/x86/tools/relocs.c | |||
@@ -17,19 +17,39 @@ | |||
17 | #define _ElfW(bits, type) __ElfW(bits, type) | 17 | #define _ElfW(bits, type) __ElfW(bits, type) |
18 | #define __ElfW(bits, type) Elf##bits##_##type | 18 | #define __ElfW(bits, type) Elf##bits##_##type |
19 | 19 | ||
20 | #ifndef ELF_BITS | ||
20 | #define ELF_BITS 32 | 21 | #define ELF_BITS 32 |
22 | #endif | ||
23 | |||
24 | #if (ELF_BITS == 64) | ||
25 | #define ELF_MACHINE EM_X86_64 | ||
26 | #define ELF_MACHINE_NAME "x86_64" | ||
27 | #define SHT_REL_TYPE SHT_RELA | ||
28 | #define Elf_Rel Elf64_Rela | ||
29 | #else | ||
21 | #define ELF_MACHINE EM_386 | 30 | #define ELF_MACHINE EM_386 |
22 | #define ELF_MACHINE_NAME "i386" | 31 | #define ELF_MACHINE_NAME "i386" |
23 | #define SHT_REL_TYPE SHT_REL | 32 | #define SHT_REL_TYPE SHT_REL |
33 | #define Elf_Rel ElfW(Rel) | ||
34 | #endif | ||
24 | 35 | ||
36 | #if (ELF_BITS == 64) | ||
37 | #define ELF_CLASS ELFCLASS64 | ||
38 | #define ELF_R_SYM(val) ELF64_R_SYM(val) | ||
39 | #define ELF_R_TYPE(val) ELF64_R_TYPE(val) | ||
40 | #define ELF_ST_TYPE(o) ELF64_ST_TYPE(o) | ||
41 | #define ELF_ST_BIND(o) ELF64_ST_BIND(o) | ||
42 | #define ELF_ST_VISIBILITY(o) ELF64_ST_VISIBILITY(o) | ||
43 | #else | ||
25 | #define ELF_CLASS ELFCLASS32 | 44 | #define ELF_CLASS ELFCLASS32 |
26 | #define ELF_R_SYM(val) ELF32_R_SYM(val) | 45 | #define ELF_R_SYM(val) ELF32_R_SYM(val) |
27 | #define ELF_R_TYPE(val) ELF32_R_TYPE(val) | 46 | #define ELF_R_TYPE(val) ELF32_R_TYPE(val) |
28 | #define ELF_ST_TYPE(o) ELF32_ST_TYPE(o) | 47 | #define ELF_ST_TYPE(o) ELF32_ST_TYPE(o) |
29 | #define ELF_ST_BIND(o) ELF32_ST_BIND(o) | 48 | #define ELF_ST_BIND(o) ELF32_ST_BIND(o) |
30 | #define ELF_ST_VISIBILITY(o) ELF32_ST_VISIBILITY(o) | 49 | #define ELF_ST_VISIBILITY(o) ELF32_ST_VISIBILITY(o) |
50 | #endif | ||
31 | 51 | ||
32 | #define Elf_Rel ElfW(Rel) | 52 | #define Elf_Addr ElfW(Addr) |
33 | #define Elf_Ehdr ElfW(Ehdr) | 53 | #define Elf_Ehdr ElfW(Ehdr) |
34 | #define Elf_Phdr ElfW(Phdr) | 54 | #define Elf_Phdr ElfW(Phdr) |
35 | #define Elf_Shdr ElfW(Shdr) | 55 | #define Elf_Shdr ElfW(Shdr) |
@@ -48,6 +68,7 @@ struct relocs { | |||
48 | 68 | ||
49 | static struct relocs relocs16; | 69 | static struct relocs relocs16; |
50 | static struct relocs relocs32; | 70 | static struct relocs relocs32; |
71 | static struct relocs relocs64; | ||
51 | 72 | ||
52 | struct section { | 73 | struct section { |
53 | Elf_Shdr shdr; | 74 | Elf_Shdr shdr; |
@@ -77,6 +98,9 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = { | |||
77 | "^(xen_irq_disable_direct_reloc$|" | 98 | "^(xen_irq_disable_direct_reloc$|" |
78 | "xen_save_fl_direct_reloc$|" | 99 | "xen_save_fl_direct_reloc$|" |
79 | "VDSO|" | 100 | "VDSO|" |
101 | #if (ELF_BITS == 64) | ||
102 | "__vvar_page|" | ||
103 | #endif | ||
80 | "__crc_)", | 104 | "__crc_)", |
81 | 105 | ||
82 | /* | 106 | /* |
@@ -100,6 +124,11 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = { | |||
100 | "__end_rodata|" | 124 | "__end_rodata|" |
101 | "__initramfs_start|" | 125 | "__initramfs_start|" |
102 | "(jiffies|jiffies_64)|" | 126 | "(jiffies|jiffies_64)|" |
127 | #if (ELF_BITS == 64) | ||
128 | "__per_cpu_load|" | ||
129 | "init_per_cpu__.*|" | ||
130 | "__end_rodata_hpage_align|" | ||
131 | #endif | ||
103 | "_end)$" | 132 | "_end)$" |
104 | }; | 133 | }; |
105 | 134 | ||
@@ -226,6 +255,24 @@ static const char *rel_type(unsigned type) | |||
226 | { | 255 | { |
227 | static const char *type_name[] = { | 256 | static const char *type_name[] = { |
228 | #define REL_TYPE(X) [X] = #X | 257 | #define REL_TYPE(X) [X] = #X |
258 | #if (ELF_BITS == 64) | ||
259 | REL_TYPE(R_X86_64_NONE), | ||
260 | REL_TYPE(R_X86_64_64), | ||
261 | REL_TYPE(R_X86_64_PC32), | ||
262 | REL_TYPE(R_X86_64_GOT32), | ||
263 | REL_TYPE(R_X86_64_PLT32), | ||
264 | REL_TYPE(R_X86_64_COPY), | ||
265 | REL_TYPE(R_X86_64_GLOB_DAT), | ||
266 | REL_TYPE(R_X86_64_JUMP_SLOT), | ||
267 | REL_TYPE(R_X86_64_RELATIVE), | ||
268 | REL_TYPE(R_X86_64_GOTPCREL), | ||
269 | REL_TYPE(R_X86_64_32), | ||
270 | REL_TYPE(R_X86_64_32S), | ||
271 | REL_TYPE(R_X86_64_16), | ||
272 | REL_TYPE(R_X86_64_PC16), | ||
273 | REL_TYPE(R_X86_64_8), | ||
274 | REL_TYPE(R_X86_64_PC8), | ||
275 | #else | ||
229 | REL_TYPE(R_386_NONE), | 276 | REL_TYPE(R_386_NONE), |
230 | REL_TYPE(R_386_32), | 277 | REL_TYPE(R_386_32), |
231 | REL_TYPE(R_386_PC32), | 278 | REL_TYPE(R_386_PC32), |
@@ -241,6 +288,7 @@ static const char *rel_type(unsigned type) | |||
241 | REL_TYPE(R_386_PC8), | 288 | REL_TYPE(R_386_PC8), |
242 | REL_TYPE(R_386_16), | 289 | REL_TYPE(R_386_16), |
243 | REL_TYPE(R_386_PC16), | 290 | REL_TYPE(R_386_PC16), |
291 | #endif | ||
244 | #undef REL_TYPE | 292 | #undef REL_TYPE |
245 | }; | 293 | }; |
246 | const char *name = "unknown type rel type name"; | 294 | const char *name = "unknown type rel type name"; |
@@ -281,15 +329,42 @@ static const char *sym_name(const char *sym_strtab, Elf_Sym *sym) | |||
281 | return name; | 329 | return name; |
282 | } | 330 | } |
283 | 331 | ||
332 | static Elf_Sym *sym_lookup(const char *symname) | ||
333 | { | ||
334 | int i; | ||
335 | for (i = 0; i < ehdr.e_shnum; i++) { | ||
336 | struct section *sec = &secs[i]; | ||
337 | long nsyms; | ||
338 | char *strtab; | ||
339 | Elf_Sym *symtab; | ||
340 | Elf_Sym *sym; | ||
284 | 341 | ||
342 | if (sec->shdr.sh_type != SHT_SYMTAB) | ||
343 | continue; | ||
344 | |||
345 | nsyms = sec->shdr.sh_size/sizeof(Elf_Sym); | ||
346 | symtab = sec->symtab; | ||
347 | strtab = sec->link->strtab; | ||
348 | |||
349 | for (sym = symtab; --nsyms >= 0; sym++) { | ||
350 | if (!sym->st_name) | ||
351 | continue; | ||
352 | if (strcmp(symname, strtab + sym->st_name) == 0) | ||
353 | return sym; | ||
354 | } | ||
355 | } | ||
356 | return 0; | ||
357 | } | ||
285 | 358 | ||
286 | #if BYTE_ORDER == LITTLE_ENDIAN | 359 | #if BYTE_ORDER == LITTLE_ENDIAN |
287 | #define le16_to_cpu(val) (val) | 360 | #define le16_to_cpu(val) (val) |
288 | #define le32_to_cpu(val) (val) | 361 | #define le32_to_cpu(val) (val) |
362 | #define le64_to_cpu(val) (val) | ||
289 | #endif | 363 | #endif |
290 | #if BYTE_ORDER == BIG_ENDIAN | 364 | #if BYTE_ORDER == BIG_ENDIAN |
291 | #define le16_to_cpu(val) bswap_16(val) | 365 | #define le16_to_cpu(val) bswap_16(val) |
292 | #define le32_to_cpu(val) bswap_32(val) | 366 | #define le32_to_cpu(val) bswap_32(val) |
367 | #define le64_to_cpu(val) bswap_64(val) | ||
293 | #endif | 368 | #endif |
294 | 369 | ||
295 | static uint16_t elf16_to_cpu(uint16_t val) | 370 | static uint16_t elf16_to_cpu(uint16_t val) |
@@ -304,9 +379,20 @@ static uint32_t elf32_to_cpu(uint32_t val) | |||
304 | 379 | ||
305 | #define elf_half_to_cpu(x) elf16_to_cpu(x) | 380 | #define elf_half_to_cpu(x) elf16_to_cpu(x) |
306 | #define elf_word_to_cpu(x) elf32_to_cpu(x) | 381 | #define elf_word_to_cpu(x) elf32_to_cpu(x) |
382 | |||
383 | #if (ELF_BITS == 64) | ||
384 | static uint64_t elf64_to_cpu(uint64_t val) | ||
385 | { | ||
386 | return le64_to_cpu(val); | ||
387 | } | ||
388 | #define elf_addr_to_cpu(x) elf64_to_cpu(x) | ||
389 | #define elf_off_to_cpu(x) elf64_to_cpu(x) | ||
390 | #define elf_xword_to_cpu(x) elf64_to_cpu(x) | ||
391 | #else | ||
307 | #define elf_addr_to_cpu(x) elf32_to_cpu(x) | 392 | #define elf_addr_to_cpu(x) elf32_to_cpu(x) |
308 | #define elf_off_to_cpu(x) elf32_to_cpu(x) | 393 | #define elf_off_to_cpu(x) elf32_to_cpu(x) |
309 | #define elf_xword_to_cpu(x) elf32_to_cpu(x) | 394 | #define elf_xword_to_cpu(x) elf32_to_cpu(x) |
395 | #endif | ||
310 | 396 | ||
311 | static void read_ehdr(FILE *fp) | 397 | static void read_ehdr(FILE *fp) |
312 | { | 398 | { |
@@ -483,6 +569,9 @@ static void read_relocs(FILE *fp) | |||
483 | Elf_Rel *rel = &sec->reltab[j]; | 569 | Elf_Rel *rel = &sec->reltab[j]; |
484 | rel->r_offset = elf_addr_to_cpu(rel->r_offset); | 570 | rel->r_offset = elf_addr_to_cpu(rel->r_offset); |
485 | rel->r_info = elf_xword_to_cpu(rel->r_info); | 571 | rel->r_info = elf_xword_to_cpu(rel->r_info); |
572 | #if (SHT_REL_TYPE == SHT_RELA) | ||
573 | rel->r_addend = elf_xword_to_cpu(rel->r_addend); | ||
574 | #endif | ||
486 | } | 575 | } |
487 | } | 576 | } |
488 | } | 577 | } |
@@ -491,6 +580,13 @@ static void read_relocs(FILE *fp) | |||
491 | static void print_absolute_symbols(void) | 580 | static void print_absolute_symbols(void) |
492 | { | 581 | { |
493 | int i; | 582 | int i; |
583 | const char *format; | ||
584 | |||
585 | if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) | ||
586 | format = "%5d %016"PRIx64" %5"PRId64" %10s %10s %12s %s\n"; | ||
587 | else | ||
588 | format = "%5d %08"PRIx32" %5"PRId32" %10s %10s %12s %s\n"; | ||
589 | |||
494 | printf("Absolute symbols\n"); | 590 | printf("Absolute symbols\n"); |
495 | printf(" Num: Value Size Type Bind Visibility Name\n"); | 591 | printf(" Num: Value Size Type Bind Visibility Name\n"); |
496 | for (i = 0; i < ehdr.e_shnum; i++) { | 592 | for (i = 0; i < ehdr.e_shnum; i++) { |
@@ -510,7 +606,7 @@ static void print_absolute_symbols(void) | |||
510 | if (sym->st_shndx != SHN_ABS) { | 606 | if (sym->st_shndx != SHN_ABS) { |
511 | continue; | 607 | continue; |
512 | } | 608 | } |
513 | printf("%5d %08x %5d %10s %10s %12s %s\n", | 609 | printf(format, |
514 | j, sym->st_value, sym->st_size, | 610 | j, sym->st_value, sym->st_size, |
515 | sym_type(ELF_ST_TYPE(sym->st_info)), | 611 | sym_type(ELF_ST_TYPE(sym->st_info)), |
516 | sym_bind(ELF_ST_BIND(sym->st_info)), | 612 | sym_bind(ELF_ST_BIND(sym->st_info)), |
@@ -524,6 +620,12 @@ static void print_absolute_symbols(void) | |||
524 | static void print_absolute_relocs(void) | 620 | static void print_absolute_relocs(void) |
525 | { | 621 | { |
526 | int i, printed = 0; | 622 | int i, printed = 0; |
623 | const char *format; | ||
624 | |||
625 | if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) | ||
626 | format = "%016"PRIx64" %016"PRIx64" %10s %016"PRIx64" %s\n"; | ||
627 | else | ||
628 | format = "%08"PRIx32" %08"PRIx32" %10s %08"PRIx32" %s\n"; | ||
527 | 629 | ||
528 | for (i = 0; i < ehdr.e_shnum; i++) { | 630 | for (i = 0; i < ehdr.e_shnum; i++) { |
529 | struct section *sec = &secs[i]; | 631 | struct section *sec = &secs[i]; |
@@ -576,7 +678,7 @@ static void print_absolute_relocs(void) | |||
576 | printed = 1; | 678 | printed = 1; |
577 | } | 679 | } |
578 | 680 | ||
579 | printf("%08x %08x %10s %08x %s\n", | 681 | printf(format, |
580 | rel->r_offset, | 682 | rel->r_offset, |
581 | rel->r_info, | 683 | rel->r_info, |
582 | rel_type(ELF_R_TYPE(rel->r_info)), | 684 | rel_type(ELF_R_TYPE(rel->r_info)), |
@@ -636,8 +738,140 @@ static void walk_relocs(int (*process)(struct section *sec, Elf_Rel *rel, | |||
636 | } | 738 | } |
637 | } | 739 | } |
638 | 740 | ||
639 | static int do_reloc(struct section *sec, Elf_Rel *rel, Elf_Sym *sym, | 741 | /* |
640 | const char *symname) | 742 | * The .data..percpu section is a special case for x86_64 SMP kernels. |
743 | * It is used to initialize the actual per_cpu areas and to provide | ||
744 | * definitions for the per_cpu variables that correspond to their offsets | ||
745 | * within the percpu area. Since the values of all of the symbols need | ||
746 | * to be offsets from the start of the per_cpu area the virtual address | ||
747 | * (sh_addr) of .data..percpu is 0 in SMP kernels. | ||
748 | * | ||
749 | * This means that: | ||
750 | * | ||
751 | * Relocations that reference symbols in the per_cpu area do not | ||
752 | * need further relocation (since the value is an offset relative | ||
753 | * to the start of the per_cpu area that does not change). | ||
754 | * | ||
755 | * Relocations that apply to the per_cpu area need to have their | ||
756 | * offset adjusted by by the value of __per_cpu_load to make them | ||
757 | * point to the correct place in the loaded image (because the | ||
758 | * virtual address of .data..percpu is 0). | ||
759 | * | ||
760 | * For non SMP kernels .data..percpu is linked as part of the normal | ||
761 | * kernel data and does not require special treatment. | ||
762 | * | ||
763 | */ | ||
764 | static int per_cpu_shndx = -1; | ||
765 | Elf_Addr per_cpu_load_addr; | ||
766 | |||
767 | static void percpu_init(void) | ||
768 | { | ||
769 | int i; | ||
770 | for (i = 0; i < ehdr.e_shnum; i++) { | ||
771 | ElfW(Sym) *sym; | ||
772 | if (strcmp(sec_name(i), ".data..percpu")) | ||
773 | continue; | ||
774 | |||
775 | if (secs[i].shdr.sh_addr != 0) /* non SMP kernel */ | ||
776 | return; | ||
777 | |||
778 | sym = sym_lookup("__per_cpu_load"); | ||
779 | if (!sym) | ||
780 | die("can't find __per_cpu_load\n"); | ||
781 | |||
782 | per_cpu_shndx = i; | ||
783 | per_cpu_load_addr = sym->st_value; | ||
784 | return; | ||
785 | } | ||
786 | } | ||
787 | |||
788 | /* | ||
789 | * Check to see if a symbol lies in the .data..percpu section. | ||
790 | * For some as yet not understood reason the "__init_begin" | ||
791 | * symbol which immediately preceeds the .data..percpu section | ||
792 | * also shows up as it it were part of it so we do an explict | ||
793 | * check for that symbol name and ignore it. | ||
794 | */ | ||
795 | static int is_percpu_sym(ElfW(Sym) *sym, const char *symname) | ||
796 | { | ||
797 | return (sym->st_shndx == per_cpu_shndx) && | ||
798 | strcmp(symname, "__init_begin"); | ||
799 | } | ||
800 | |||
801 | static int do_reloc64(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym, | ||
802 | const char *symname) | ||
803 | { | ||
804 | unsigned r_type = ELF64_R_TYPE(rel->r_info); | ||
805 | ElfW(Addr) offset = rel->r_offset; | ||
806 | int shn_abs = (sym->st_shndx == SHN_ABS) && !is_reloc(S_REL, symname); | ||
807 | |||
808 | if (sym->st_shndx == SHN_UNDEF) | ||
809 | return 0; | ||
810 | |||
811 | /* | ||
812 | * Adjust the offset if this reloc applies to the percpu section. | ||
813 | */ | ||
814 | if (sec->shdr.sh_info == per_cpu_shndx) | ||
815 | offset += per_cpu_load_addr; | ||
816 | |||
817 | switch (r_type) { | ||
818 | case R_X86_64_NONE: | ||
819 | case R_X86_64_PC32: | ||
820 | /* | ||
821 | * NONE can be ignored and PC relative relocations don't | ||
822 | * need to be adjusted. | ||
823 | */ | ||
824 | break; | ||
825 | |||
826 | case R_X86_64_32: | ||
827 | case R_X86_64_32S: | ||
828 | case R_X86_64_64: | ||
829 | /* | ||
830 | * References to the percpu area don't need to be adjusted. | ||
831 | */ | ||
832 | if (is_percpu_sym(sym, symname)) | ||
833 | break; | ||
834 | |||
835 | if (shn_abs) { | ||
836 | /* | ||
837 | * Whitelisted absolute symbols do not require | ||
838 | * relocation. | ||
839 | */ | ||
840 | if (is_reloc(S_ABS, symname)) | ||
841 | break; | ||
842 | |||
843 | die("Invalid absolute %s relocation: %s\n", | ||
844 | rel_type(r_type), symname); | ||
845 | break; | ||
846 | } | ||
847 | |||
848 | /* | ||
849 | * Relocation offsets for 64 bit kernels are output | ||
850 | * as 32 bits and sign extended back to 64 bits when | ||
851 | * the relocations are processed. | ||
852 | * Make sure that the offset will fit. | ||
853 | */ | ||
854 | if ((int32_t)offset != (int64_t)offset) | ||
855 | die("Relocation offset doesn't fit in 32 bits\n"); | ||
856 | |||
857 | if (r_type == R_X86_64_64) | ||
858 | add_reloc(&relocs64, offset); | ||
859 | else | ||
860 | add_reloc(&relocs32, offset); | ||
861 | break; | ||
862 | |||
863 | default: | ||
864 | die("Unsupported relocation type: %s (%d)\n", | ||
865 | rel_type(r_type), r_type); | ||
866 | break; | ||
867 | } | ||
868 | |||
869 | return 0; | ||
870 | } | ||
871 | |||
872 | |||
873 | static int do_reloc32(struct section *sec, Elf_Rel *rel, Elf_Sym *sym, | ||
874 | const char *symname) | ||
641 | { | 875 | { |
642 | unsigned r_type = ELF32_R_TYPE(rel->r_info); | 876 | unsigned r_type = ELF32_R_TYPE(rel->r_info); |
643 | int shn_abs = (sym->st_shndx == SHN_ABS) && !is_reloc(S_REL, symname); | 877 | int shn_abs = (sym->st_shndx == SHN_ABS) && !is_reloc(S_REL, symname); |
@@ -779,9 +1013,18 @@ static void emit_relocs(int as_text, int use_real_mode) | |||
779 | { | 1013 | { |
780 | int i; | 1014 | int i; |
781 | int (*write_reloc)(uint32_t, FILE *) = write32; | 1015 | int (*write_reloc)(uint32_t, FILE *) = write32; |
1016 | int (*do_reloc)(struct section *sec, Elf_Rel *rel, Elf_Sym *sym, | ||
1017 | const char *symname); | ||
1018 | |||
1019 | if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) | ||
1020 | do_reloc = do_reloc64; | ||
1021 | else if (!use_real_mode) | ||
1022 | do_reloc = do_reloc32; | ||
1023 | else | ||
1024 | do_reloc = do_reloc_real; | ||
782 | 1025 | ||
783 | /* Collect up the relocations */ | 1026 | /* Collect up the relocations */ |
784 | walk_relocs(use_real_mode ? do_reloc_real : do_reloc); | 1027 | walk_relocs(do_reloc); |
785 | 1028 | ||
786 | if (relocs16.count && !use_real_mode) | 1029 | if (relocs16.count && !use_real_mode) |
787 | die("Segment relocations found but --realmode not specified\n"); | 1030 | die("Segment relocations found but --realmode not specified\n"); |
@@ -789,6 +1032,7 @@ static void emit_relocs(int as_text, int use_real_mode) | |||
789 | /* Order the relocations for more efficient processing */ | 1032 | /* Order the relocations for more efficient processing */ |
790 | sort_relocs(&relocs16); | 1033 | sort_relocs(&relocs16); |
791 | sort_relocs(&relocs32); | 1034 | sort_relocs(&relocs32); |
1035 | sort_relocs(&relocs64); | ||
792 | 1036 | ||
793 | /* Print the relocations */ | 1037 | /* Print the relocations */ |
794 | if (as_text) { | 1038 | if (as_text) { |
@@ -809,6 +1053,15 @@ static void emit_relocs(int as_text, int use_real_mode) | |||
809 | for (i = 0; i < relocs32.count; i++) | 1053 | for (i = 0; i < relocs32.count; i++) |
810 | write_reloc(relocs32.offset[i], stdout); | 1054 | write_reloc(relocs32.offset[i], stdout); |
811 | } else { | 1055 | } else { |
1056 | if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) { | ||
1057 | /* Print a stop */ | ||
1058 | write_reloc(0, stdout); | ||
1059 | |||
1060 | /* Now print each relocation */ | ||
1061 | for (i = 0; i < relocs64.count; i++) | ||
1062 | write_reloc(relocs64.offset[i], stdout); | ||
1063 | } | ||
1064 | |||
812 | /* Print a stop */ | 1065 | /* Print a stop */ |
813 | write_reloc(0, stdout); | 1066 | write_reloc(0, stdout); |
814 | 1067 | ||
@@ -876,6 +1129,8 @@ int main(int argc, char **argv) | |||
876 | read_strtabs(fp); | 1129 | read_strtabs(fp); |
877 | read_symtabs(fp); | 1130 | read_symtabs(fp); |
878 | read_relocs(fp); | 1131 | read_relocs(fp); |
1132 | if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) | ||
1133 | percpu_init(); | ||
879 | if (show_absolute_syms) { | 1134 | if (show_absolute_syms) { |
880 | print_absolute_symbols(); | 1135 | print_absolute_symbols(); |
881 | goto out; | 1136 | goto out; |