aboutsummaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-05-23 13:44:35 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-05-23 13:44:35 -0400
commit269af9a1a08d368b46d72e74126564d04c354f7e (patch)
treef0f2a8dd54075edebbb728602822e2b7378588d0 /scripts
parent8ca038dc10eec80f280d9d483f1835ac2763a787 (diff)
parent8b5ad472991796b2347464922c72de2ca5a028f3 (diff)
Merge branch 'x86-extable-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull exception table generation updates from Ingo Molnar: "The biggest change here is to allow the build-time sorting of the exception table, to speed up booting. This is achieved by the architecture enabling BUILDTIME_EXTABLE_SORT. This option is enabled for x86 and MIPS currently. On x86 a number of fixes and changes were needed to allow build-time sorting of the exception table, in particular a relocation invariant exception table format was needed. This required the abstracting out of exception table protocol and the removal of 20 years of accumulated assumptions about the x86 exception table format. While at it, this tree also cleans up various other aspects of exception handling, such as early(er) exception handling for rdmsr_safe() et al. All in one, as the result of these changes the x86 exception code is now pretty nice and modern. As an added bonus any regressions in this code will be early and violent crashes, so if you see any of those, you'll know whom to blame!" Fix up trivial conflicts in arch/{mips,x86}/Kconfig files due to nearby modifications of other core architecture options. * 'x86-extable-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (35 commits) Revert "x86, extable: Disable presorted exception table for now" scripts/sortextable: Handle relative entries, and other cleanups x86, extable: Switch to relative exception table entries x86, extable: Disable presorted exception table for now x86, extable: Add _ASM_EXTABLE_EX() macro x86, extable: Remove open-coded exception table entries in arch/x86/ia32/ia32entry.S x86, extable: Remove open-coded exception table entries in arch/x86/include/asm/xsave.h x86, extable: Remove open-coded exception table entries in arch/x86/include/asm/kvm_host.h x86, extable: Remove the now-unused __ASM_EX_SEC macros x86, extable: Remove open-coded exception table entries in arch/x86/xen/xen-asm_32.S x86, extable: Remove open-coded exception table entries in arch/x86/um/checksum_32.S x86, extable: Remove open-coded exception table entries in arch/x86/lib/usercopy_32.c x86, extable: Remove open-coded exception table entries in arch/x86/lib/putuser.S x86, extable: Remove open-coded exception table entries in arch/x86/lib/getuser.S x86, extable: Remove open-coded exception table entries in arch/x86/lib/csum-copy_64.S x86, extable: Remove open-coded exception table entries in arch/x86/lib/copy_user_nocache_64.S x86, extable: Remove open-coded exception table entries in arch/x86/lib/copy_user_64.S x86, extable: Remove open-coded exception table entries in arch/x86/lib/checksum_32.S x86, extable: Remove open-coded exception table entries in arch/x86/kernel/test_rodata.c x86, extable: Remove open-coded exception table entries in arch/x86/kernel/entry_64.S ...
Diffstat (limited to 'scripts')
-rw-r--r--scripts/.gitignore1
-rw-r--r--scripts/Makefile3
-rw-r--r--scripts/sortextable.c322
-rw-r--r--scripts/sortextable.h191
4 files changed, 517 insertions, 0 deletions
diff --git a/scripts/.gitignore b/scripts/.gitignore
index 105b21f08185..65f362d931b5 100644
--- a/scripts/.gitignore
+++ b/scripts/.gitignore
@@ -9,3 +9,4 @@ unifdef
9ihex2fw 9ihex2fw
10recordmcount 10recordmcount
11docproc 11docproc
12sortextable
diff --git a/scripts/Makefile b/scripts/Makefile
index 36266665dbcb..a55b0067758a 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -15,6 +15,9 @@ hostprogs-$(CONFIG_LOGO) += pnmtologo
15hostprogs-$(CONFIG_VT) += conmakehash 15hostprogs-$(CONFIG_VT) += conmakehash
16hostprogs-$(CONFIG_IKCONFIG) += bin2c 16hostprogs-$(CONFIG_IKCONFIG) += bin2c
17hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount 17hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount
18hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable
19
20HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include
18 21
19always := $(hostprogs-y) $(hostprogs-m) 22always := $(hostprogs-y) $(hostprogs-m)
20 23
diff --git a/scripts/sortextable.c b/scripts/sortextable.c
new file mode 100644
index 000000000000..1ca9ceb95eb6
--- /dev/null
+++ b/scripts/sortextable.c
@@ -0,0 +1,322 @@
1/*
2 * sortextable.c: Sort the kernel's exception table
3 *
4 * Copyright 2011 - 2012 Cavium, Inc.
5 *
6 * Based on code taken from recortmcount.c which is:
7 *
8 * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved.
9 * Licensed under the GNU General Public License, version 2 (GPLv2).
10 *
11 * Restructured to fit Linux format, as well as other updates:
12 * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
13 */
14
15/*
16 * Strategy: alter the vmlinux file in-place.
17 */
18
19#include <sys/types.h>
20#include <sys/mman.h>
21#include <sys/stat.h>
22#include <getopt.h>
23#include <elf.h>
24#include <fcntl.h>
25#include <setjmp.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <unistd.h>
30
31#include <tools/be_byteshift.h>
32#include <tools/le_byteshift.h>
33
34static int fd_map; /* File descriptor for file being modified. */
35static int mmap_failed; /* Boolean flag. */
36static void *ehdr_curr; /* current ElfXX_Ehdr * for resource cleanup */
37static struct stat sb; /* Remember .st_size, etc. */
38static jmp_buf jmpenv; /* setjmp/longjmp per-file error escape */
39
40/* setjmp() return values */
41enum {
42 SJ_SETJMP = 0, /* hardwired first return */
43 SJ_FAIL,
44 SJ_SUCCEED
45};
46
47/* Per-file resource cleanup when multiple files. */
48static void
49cleanup(void)
50{
51 if (!mmap_failed)
52 munmap(ehdr_curr, sb.st_size);
53 close(fd_map);
54}
55
56static void __attribute__((noreturn))
57fail_file(void)
58{
59 cleanup();
60 longjmp(jmpenv, SJ_FAIL);
61}
62
63static void __attribute__((noreturn))
64succeed_file(void)
65{
66 cleanup();
67 longjmp(jmpenv, SJ_SUCCEED);
68}
69
70
71/*
72 * Get the whole file as a programming convenience in order to avoid
73 * malloc+lseek+read+free of many pieces. If successful, then mmap
74 * avoids copying unused pieces; else just read the whole file.
75 * Open for both read and write.
76 */
77static void *mmap_file(char const *fname)
78{
79 void *addr;
80
81 fd_map = open(fname, O_RDWR);
82 if (fd_map < 0 || fstat(fd_map, &sb) < 0) {
83 perror(fname);
84 fail_file();
85 }
86 if (!S_ISREG(sb.st_mode)) {
87 fprintf(stderr, "not a regular file: %s\n", fname);
88 fail_file();
89 }
90 addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED,
91 fd_map, 0);
92 if (addr == MAP_FAILED) {
93 mmap_failed = 1;
94 fprintf(stderr, "Could not mmap file: %s\n", fname);
95 fail_file();
96 }
97 return addr;
98}
99
100static uint64_t r8be(const uint64_t *x)
101{
102 return get_unaligned_be64(x);
103}
104static uint32_t rbe(const uint32_t *x)
105{
106 return get_unaligned_be32(x);
107}
108static uint16_t r2be(const uint16_t *x)
109{
110 return get_unaligned_be16(x);
111}
112static uint64_t r8le(const uint64_t *x)
113{
114 return get_unaligned_le64(x);
115}
116static uint32_t rle(const uint32_t *x)
117{
118 return get_unaligned_le32(x);
119}
120static uint16_t r2le(const uint16_t *x)
121{
122 return get_unaligned_le16(x);
123}
124
125static void w8be(uint64_t val, uint64_t *x)
126{
127 put_unaligned_be64(val, x);
128}
129static void wbe(uint32_t val, uint32_t *x)
130{
131 put_unaligned_be32(val, x);
132}
133static void w2be(uint16_t val, uint16_t *x)
134{
135 put_unaligned_be16(val, x);
136}
137static void w8le(uint64_t val, uint64_t *x)
138{
139 put_unaligned_le64(val, x);
140}
141static void wle(uint32_t val, uint32_t *x)
142{
143 put_unaligned_le32(val, x);
144}
145static void w2le(uint16_t val, uint16_t *x)
146{
147 put_unaligned_le16(val, x);
148}
149
150static uint64_t (*r8)(const uint64_t *);
151static uint32_t (*r)(const uint32_t *);
152static uint16_t (*r2)(const uint16_t *);
153static void (*w8)(uint64_t, uint64_t *);
154static void (*w)(uint32_t, uint32_t *);
155static void (*w2)(uint16_t, uint16_t *);
156
157typedef void (*table_sort_t)(char *, int);
158
159/* 32 bit and 64 bit are very similar */
160#include "sortextable.h"
161#define SORTEXTABLE_64
162#include "sortextable.h"
163
164static int compare_x86_table(const void *a, const void *b)
165{
166 int32_t av = (int32_t)r(a);
167 int32_t bv = (int32_t)r(b);
168
169 if (av < bv)
170 return -1;
171 if (av > bv)
172 return 1;
173 return 0;
174}
175
176static void sort_x86_table(char *extab_image, int image_size)
177{
178 int i;
179
180 /*
181 * Do the same thing the runtime sort does, first normalize to
182 * being relative to the start of the section.
183 */
184 i = 0;
185 while (i < image_size) {
186 uint32_t *loc = (uint32_t *)(extab_image + i);
187 w(r(loc) + i, loc);
188 i += 4;
189 }
190
191 qsort(extab_image, image_size / 8, 8, compare_x86_table);
192
193 /* Now denormalize. */
194 i = 0;
195 while (i < image_size) {
196 uint32_t *loc = (uint32_t *)(extab_image + i);
197 w(r(loc) - i, loc);
198 i += 4;
199 }
200}
201
202static void
203do_file(char const *const fname)
204{
205 table_sort_t custom_sort;
206 Elf32_Ehdr *ehdr = mmap_file(fname);
207
208 ehdr_curr = ehdr;
209 switch (ehdr->e_ident[EI_DATA]) {
210 default:
211 fprintf(stderr, "unrecognized ELF data encoding %d: %s\n",
212 ehdr->e_ident[EI_DATA], fname);
213 fail_file();
214 break;
215 case ELFDATA2LSB:
216 r = rle;
217 r2 = r2le;
218 r8 = r8le;
219 w = wle;
220 w2 = w2le;
221 w8 = w8le;
222 break;
223 case ELFDATA2MSB:
224 r = rbe;
225 r2 = r2be;
226 r8 = r8be;
227 w = wbe;
228 w2 = w2be;
229 w8 = w8be;
230 break;
231 } /* end switch */
232 if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0
233 || r2(&ehdr->e_type) != ET_EXEC
234 || ehdr->e_ident[EI_VERSION] != EV_CURRENT) {
235 fprintf(stderr, "unrecognized ET_EXEC file %s\n", fname);
236 fail_file();
237 }
238
239 custom_sort = NULL;
240 switch (r2(&ehdr->e_machine)) {
241 default:
242 fprintf(stderr, "unrecognized e_machine %d %s\n",
243 r2(&ehdr->e_machine), fname);
244 fail_file();
245 break;
246 case EM_386:
247 case EM_X86_64:
248 custom_sort = sort_x86_table;
249 break;
250 case EM_MIPS:
251 break;
252 } /* end switch */
253
254 switch (ehdr->e_ident[EI_CLASS]) {
255 default:
256 fprintf(stderr, "unrecognized ELF class %d %s\n",
257 ehdr->e_ident[EI_CLASS], fname);
258 fail_file();
259 break;
260 case ELFCLASS32:
261 if (r2(&ehdr->e_ehsize) != sizeof(Elf32_Ehdr)
262 || r2(&ehdr->e_shentsize) != sizeof(Elf32_Shdr)) {
263 fprintf(stderr,
264 "unrecognized ET_EXEC file: %s\n", fname);
265 fail_file();
266 }
267 do32(ehdr, fname, custom_sort);
268 break;
269 case ELFCLASS64: {
270 Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr;
271 if (r2(&ghdr->e_ehsize) != sizeof(Elf64_Ehdr)
272 || r2(&ghdr->e_shentsize) != sizeof(Elf64_Shdr)) {
273 fprintf(stderr,
274 "unrecognized ET_EXEC file: %s\n", fname);
275 fail_file();
276 }
277 do64(ghdr, fname, custom_sort);
278 break;
279 }
280 } /* end switch */
281
282 cleanup();
283}
284
285int
286main(int argc, char *argv[])
287{
288 int n_error = 0; /* gcc-4.3.0 false positive complaint */
289 int i;
290
291 if (argc < 2) {
292 fprintf(stderr, "usage: sortextable vmlinux...\n");
293 return 0;
294 }
295
296 /* Process each file in turn, allowing deep failure. */
297 for (i = 1; i < argc; i++) {
298 char *file = argv[i];
299 int const sjval = setjmp(jmpenv);
300
301 switch (sjval) {
302 default:
303 fprintf(stderr, "internal error: %s\n", file);
304 exit(1);
305 break;
306 case SJ_SETJMP: /* normal sequence */
307 /* Avoid problems if early cleanup() */
308 fd_map = -1;
309 ehdr_curr = NULL;
310 mmap_failed = 1;
311 do_file(file);
312 break;
313 case SJ_FAIL: /* error in do_file or below */
314 ++n_error;
315 break;
316 case SJ_SUCCEED: /* premature success */
317 /* do nothing */
318 break;
319 } /* end switch */
320 }
321 return !!n_error;
322}
diff --git a/scripts/sortextable.h b/scripts/sortextable.h
new file mode 100644
index 000000000000..e4fd45b7e456
--- /dev/null
+++ b/scripts/sortextable.h
@@ -0,0 +1,191 @@
1/*
2 * sortextable.h
3 *
4 * Copyright 2011 - 2012 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 _r
34#undef _w
35
36#ifdef SORTEXTABLE_64
37# define extable_ent_size 16
38# define compare_extable compare_extable_64
39# define do_func do64
40# define Elf_Addr Elf64_Addr
41# define Elf_Ehdr Elf64_Ehdr
42# define Elf_Shdr Elf64_Shdr
43# define Elf_Rel Elf64_Rel
44# define Elf_Rela Elf64_Rela
45# define Elf_Sym Elf64_Sym
46# define ELF_R_SYM ELF64_R_SYM
47# define Elf_r_sym Elf64_r_sym
48# define ELF_R_INFO ELF64_R_INFO
49# define Elf_r_info Elf64_r_info
50# define ELF_ST_BIND ELF64_ST_BIND
51# define ELF_ST_TYPE ELF64_ST_TYPE
52# define fn_ELF_R_SYM fn_ELF64_R_SYM
53# define fn_ELF_R_INFO fn_ELF64_R_INFO
54# define uint_t uint64_t
55# define _r r8
56# define _w w8
57#else
58# define extable_ent_size 8
59# define compare_extable compare_extable_32
60# define do_func do32
61# define Elf_Addr Elf32_Addr
62# define Elf_Ehdr Elf32_Ehdr
63# define Elf_Shdr Elf32_Shdr
64# define Elf_Rel Elf32_Rel
65# define Elf_Rela Elf32_Rela
66# define Elf_Sym Elf32_Sym
67# define ELF_R_SYM ELF32_R_SYM
68# define Elf_r_sym Elf32_r_sym
69# define ELF_R_INFO ELF32_R_INFO
70# define Elf_r_info Elf32_r_info
71# define ELF_ST_BIND ELF32_ST_BIND
72# define ELF_ST_TYPE ELF32_ST_TYPE
73# define fn_ELF_R_SYM fn_ELF32_R_SYM
74# define fn_ELF_R_INFO fn_ELF32_R_INFO
75# define uint_t uint32_t
76# define _r r
77# define _w w
78#endif
79
80static int compare_extable(const void *a, const void *b)
81{
82 Elf_Addr av = _r(a);
83 Elf_Addr bv = _r(b);
84
85 if (av < bv)
86 return -1;
87 if (av > bv)
88 return 1;
89 return 0;
90}
91
92static void
93do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort)
94{
95 Elf_Shdr *shdr;
96 Elf_Shdr *shstrtab_sec;
97 Elf_Shdr *strtab_sec = NULL;
98 Elf_Shdr *symtab_sec = NULL;
99 Elf_Shdr *extab_sec = NULL;
100 Elf_Sym *sym;
101 Elf_Sym *sort_needed_sym;
102 Elf_Shdr *sort_needed_sec;
103 Elf_Rel *relocs = NULL;
104 int relocs_size;
105 uint32_t *sort_done_location;
106 const char *secstrtab;
107 const char *strtab;
108 char *extab_image;
109 int extab_index = 0;
110 int i;
111 int idx;
112
113 shdr = (Elf_Shdr *)((char *)ehdr + _r(&ehdr->e_shoff));
114 shstrtab_sec = shdr + r2(&ehdr->e_shstrndx);
115 secstrtab = (const char *)ehdr + _r(&shstrtab_sec->sh_offset);
116 for (i = 0; i < r2(&ehdr->e_shnum); i++) {
117 idx = r(&shdr[i].sh_name);
118 if (strcmp(secstrtab + idx, "__ex_table") == 0) {
119 extab_sec = shdr + i;
120 extab_index = i;
121 }
122 if ((r(&shdr[i].sh_type) == SHT_REL ||
123 r(&shdr[i].sh_type) == SHT_RELA) &&
124 r(&shdr[i].sh_info) == extab_index) {
125 relocs = (void *)ehdr + _r(&shdr[i].sh_offset);
126 relocs_size = _r(&shdr[i].sh_size);
127 }
128 if (strcmp(secstrtab + idx, ".symtab") == 0)
129 symtab_sec = shdr + i;
130 if (strcmp(secstrtab + idx, ".strtab") == 0)
131 strtab_sec = shdr + i;
132 }
133 if (strtab_sec == NULL) {
134 fprintf(stderr, "no .strtab in file: %s\n", fname);
135 fail_file();
136 }
137 if (symtab_sec == NULL) {
138 fprintf(stderr, "no .symtab in file: %s\n", fname);
139 fail_file();
140 }
141 if (extab_sec == NULL) {
142 fprintf(stderr, "no __ex_table in file: %s\n", fname);
143 fail_file();
144 }
145 strtab = (const char *)ehdr + _r(&strtab_sec->sh_offset);
146
147 extab_image = (void *)ehdr + _r(&extab_sec->sh_offset);
148
149 if (custom_sort) {
150 custom_sort(extab_image, _r(&extab_sec->sh_size));
151 } else {
152 int num_entries = _r(&extab_sec->sh_size) / extable_ent_size;
153 qsort(extab_image, num_entries,
154 extable_ent_size, compare_extable);
155 }
156 /* If there were relocations, we no longer need them. */
157 if (relocs)
158 memset(relocs, 0, relocs_size);
159
160 /* find main_extable_sort_needed */
161 sort_needed_sym = NULL;
162 for (i = 0; i < _r(&symtab_sec->sh_size) / sizeof(Elf_Sym); i++) {
163 sym = (void *)ehdr + _r(&symtab_sec->sh_offset);
164 sym += i;
165 if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT)
166 continue;
167 idx = r(&sym->st_name);
168 if (strcmp(strtab + idx, "main_extable_sort_needed") == 0) {
169 sort_needed_sym = sym;
170 break;
171 }
172 }
173 if (sort_needed_sym == NULL) {
174 fprintf(stderr,
175 "no main_extable_sort_needed symbol in file: %s\n",
176 fname);
177 fail_file();
178 }
179 sort_needed_sec = &shdr[r2(&sort_needed_sym->st_shndx)];
180 sort_done_location = (void *)ehdr +
181 _r(&sort_needed_sec->sh_offset) +
182 _r(&sort_needed_sym->st_value) -
183 _r(&sort_needed_sec->sh_addr);
184
185#if 1
186 printf("sort done marker at %lx\n",
187 (unsigned long)((char *)sort_done_location - (char *)ehdr));
188#endif
189 /* We sorted it, clear the flag. */
190 w(0, sort_done_location);
191}