diff options
author | David Daney <david.daney@cavium.com> | 2012-04-19 17:59:55 -0400 |
---|---|---|
committer | H. Peter Anvin <hpa@linux.intel.com> | 2012-04-19 18:06:55 -0400 |
commit | a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720 (patch) | |
tree | bab3fe4ac76370948b4ca62b41253c488ca96c38 /scripts/sortextable.h | |
parent | e816b57a337ea3b755de72bec38c10c864f23015 (diff) |
scripts: Add sortextable to sort the kernel's exception table.
Using this build-time sort saves time booting as we don't have to burn
cycles sorting the exception table.
Signed-off-by: David Daney <david.daney@cavium.com>
Link: http://lkml.kernel.org/r/1334872799-14589-2-git-send-email-ddaney.cavm@gmail.com
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'scripts/sortextable.h')
-rw-r--r-- | scripts/sortextable.h | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/scripts/sortextable.h b/scripts/sortextable.h new file mode 100644 index 000000000000..bb6aaf166002 --- /dev/null +++ b/scripts/sortextable.h | |||
@@ -0,0 +1,168 @@ | |||
1 | /* | ||
2 | * sortextable.h | ||
3 | * | ||
4 | * Copyright 2011 Cavium, Inc. | ||
5 | * | ||
6 | * Some of this code was taken out of recordmcount.h written by: | ||
7 | * | ||
8 | * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved. | ||
9 | * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc. | ||
10 | * | ||
11 | * | ||
12 | * Licensed under the GNU General Public License, version 2 (GPLv2). | ||
13 | */ | ||
14 | |||
15 | #undef extable_ent_size | ||
16 | #undef compare_extable | ||
17 | #undef do_func | ||
18 | #undef Elf_Addr | ||
19 | #undef Elf_Ehdr | ||
20 | #undef Elf_Shdr | ||
21 | #undef Elf_Rel | ||
22 | #undef Elf_Rela | ||
23 | #undef Elf_Sym | ||
24 | #undef ELF_R_SYM | ||
25 | #undef Elf_r_sym | ||
26 | #undef ELF_R_INFO | ||
27 | #undef Elf_r_info | ||
28 | #undef ELF_ST_BIND | ||
29 | #undef ELF_ST_TYPE | ||
30 | #undef fn_ELF_R_SYM | ||
31 | #undef fn_ELF_R_INFO | ||
32 | #undef uint_t | ||
33 | #undef _w | ||
34 | |||
35 | #ifdef SORTEXTABLE_64 | ||
36 | # define extable_ent_size 16 | ||
37 | # define compare_extable compare_extable_64 | ||
38 | # define do_func do64 | ||
39 | # define Elf_Addr Elf64_Addr | ||
40 | # define Elf_Ehdr Elf64_Ehdr | ||
41 | # define Elf_Shdr Elf64_Shdr | ||
42 | # define Elf_Rel Elf64_Rel | ||
43 | # define Elf_Rela Elf64_Rela | ||
44 | # define Elf_Sym Elf64_Sym | ||
45 | # define ELF_R_SYM ELF64_R_SYM | ||
46 | # define Elf_r_sym Elf64_r_sym | ||
47 | # define ELF_R_INFO ELF64_R_INFO | ||
48 | # define Elf_r_info Elf64_r_info | ||
49 | # define ELF_ST_BIND ELF64_ST_BIND | ||
50 | # define ELF_ST_TYPE ELF64_ST_TYPE | ||
51 | # define fn_ELF_R_SYM fn_ELF64_R_SYM | ||
52 | # define fn_ELF_R_INFO fn_ELF64_R_INFO | ||
53 | # define uint_t uint64_t | ||
54 | # define _w w8 | ||
55 | #else | ||
56 | # define extable_ent_size 8 | ||
57 | # define compare_extable compare_extable_32 | ||
58 | # define do_func do32 | ||
59 | # define Elf_Addr Elf32_Addr | ||
60 | # define Elf_Ehdr Elf32_Ehdr | ||
61 | # define Elf_Shdr Elf32_Shdr | ||
62 | # define Elf_Rel Elf32_Rel | ||
63 | # define Elf_Rela Elf32_Rela | ||
64 | # define Elf_Sym Elf32_Sym | ||
65 | # define ELF_R_SYM ELF32_R_SYM | ||
66 | # define Elf_r_sym Elf32_r_sym | ||
67 | # define ELF_R_INFO ELF32_R_INFO | ||
68 | # define Elf_r_info Elf32_r_info | ||
69 | # define ELF_ST_BIND ELF32_ST_BIND | ||
70 | # define ELF_ST_TYPE ELF32_ST_TYPE | ||
71 | # define fn_ELF_R_SYM fn_ELF32_R_SYM | ||
72 | # define fn_ELF_R_INFO fn_ELF32_R_INFO | ||
73 | # define uint_t uint32_t | ||
74 | # define _w w | ||
75 | #endif | ||
76 | |||
77 | static int compare_extable(const void *a, const void *b) | ||
78 | { | ||
79 | const uint_t *aa = a; | ||
80 | const uint_t *bb = b; | ||
81 | |||
82 | if (_w(*aa) < _w(*bb)) | ||
83 | return -1; | ||
84 | if (_w(*aa) > _w(*bb)) | ||
85 | return 1; | ||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | static void | ||
90 | do_func(Elf_Ehdr *const ehdr, char const *const fname) | ||
91 | { | ||
92 | Elf_Shdr *shdr; | ||
93 | Elf_Shdr *shstrtab_sec; | ||
94 | Elf_Shdr *strtab_sec = NULL; | ||
95 | Elf_Shdr *symtab_sec = NULL; | ||
96 | Elf_Shdr *extab_sec = NULL; | ||
97 | Elf_Sym *sym; | ||
98 | Elf_Sym *sort_needed_sym; | ||
99 | Elf_Shdr *sort_needed_sec; | ||
100 | uint32_t *sort_done_location; | ||
101 | const char *secstrtab; | ||
102 | const char *strtab; | ||
103 | int i; | ||
104 | int idx; | ||
105 | |||
106 | shdr = (Elf_Shdr *)((void *)ehdr + _w(ehdr->e_shoff)); | ||
107 | shstrtab_sec = shdr + w2(ehdr->e_shstrndx); | ||
108 | secstrtab = (const char *)ehdr + _w(shstrtab_sec->sh_offset); | ||
109 | for (i = 0; i < w2(ehdr->e_shnum); i++) { | ||
110 | idx = w(shdr[i].sh_name); | ||
111 | if (strcmp(secstrtab + idx, "__ex_table") == 0) | ||
112 | extab_sec = shdr + i; | ||
113 | if (strcmp(secstrtab + idx, ".symtab") == 0) | ||
114 | symtab_sec = shdr + i; | ||
115 | if (strcmp(secstrtab + idx, ".strtab") == 0) | ||
116 | strtab_sec = shdr + i; | ||
117 | } | ||
118 | if (strtab_sec == NULL) { | ||
119 | fprintf(stderr, "no .strtab in file: %s\n", fname); | ||
120 | fail_file(); | ||
121 | } | ||
122 | if (symtab_sec == NULL) { | ||
123 | fprintf(stderr, "no .symtab in file: %s\n", fname); | ||
124 | fail_file(); | ||
125 | } | ||
126 | if (extab_sec == NULL) { | ||
127 | fprintf(stderr, "no __ex_table in file: %s\n", fname); | ||
128 | fail_file(); | ||
129 | } | ||
130 | strtab = (const char *)ehdr + _w(strtab_sec->sh_offset); | ||
131 | |||
132 | /* Sort the table in place */ | ||
133 | qsort((void *)ehdr + _w(extab_sec->sh_offset), | ||
134 | (_w(extab_sec->sh_size) / extable_ent_size), | ||
135 | extable_ent_size, compare_extable); | ||
136 | |||
137 | /* find main_extable_sort_needed */ | ||
138 | sort_needed_sym = NULL; | ||
139 | for (i = 0; i < _w(symtab_sec->sh_size) / sizeof(Elf_Sym); i++) { | ||
140 | sym = (void *)ehdr + _w(symtab_sec->sh_offset); | ||
141 | sym += i; | ||
142 | if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT) | ||
143 | continue; | ||
144 | idx = w(sym->st_name); | ||
145 | if (strcmp(strtab + idx, "main_extable_sort_needed") == 0) { | ||
146 | sort_needed_sym = sym; | ||
147 | break; | ||
148 | } | ||
149 | } | ||
150 | if (sort_needed_sym == NULL) { | ||
151 | fprintf(stderr, | ||
152 | "no main_extable_sort_needed symbol in file: %s\n", | ||
153 | fname); | ||
154 | fail_file(); | ||
155 | } | ||
156 | sort_needed_sec = &shdr[w2(sort_needed_sym->st_shndx)]; | ||
157 | sort_done_location = (void *)ehdr + | ||
158 | _w(sort_needed_sec->sh_offset) + | ||
159 | _w(sort_needed_sym->st_value) - | ||
160 | _w(sort_needed_sec->sh_addr); | ||
161 | |||
162 | printf("sort done marker at %lx\n", | ||
163 | (unsigned long) (_w(sort_needed_sec->sh_offset) + | ||
164 | _w(sort_needed_sym->st_value) - | ||
165 | _w(sort_needed_sec->sh_addr))); | ||
166 | /* We sorted it, clear the flag. */ | ||
167 | *sort_done_location = 0; | ||
168 | } | ||