aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/tools
diff options
context:
space:
mode:
authorKees Cook <keescook@chromium.org>2013-04-12 16:13:44 -0400
committerH. Peter Anvin <hpa@linux.intel.com>2013-04-16 18:19:22 -0400
commit946166af95d1defacfbc21e7c902d0556a2a7660 (patch)
treec3de26414a9728ca2a04331a5dcc1d900c0a641b /arch/x86/tools
parent5d442e63d6a1b5736fd48a907bd7d2d87e411816 (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.c267
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
49static struct relocs relocs16; 69static struct relocs relocs16;
50static struct relocs relocs32; 70static struct relocs relocs32;
71static struct relocs relocs64;
51 72
52struct section { 73struct 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
332static 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
295static uint16_t elf16_to_cpu(uint16_t val) 370static 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)
384static 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
311static void read_ehdr(FILE *fp) 397static 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)
491static void print_absolute_symbols(void) 580static 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)
524static void print_absolute_relocs(void) 620static 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
639static 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 */
764static int per_cpu_shndx = -1;
765Elf_Addr per_cpu_load_addr;
766
767static 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 */
795static 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
801static 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
873static 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;