summaryrefslogtreecommitdiff
path: root/scripts/sortextable.h
diff options
context:
space:
mode:
authorDavid Daney <david.daney@cavium.com>2012-04-19 14:59:55 -0700
committerH. Peter Anvin <hpa@linux.intel.com>2012-04-19 15:06:55 -0700
commita79f248b9b309ebb5f34ca6a8fd1eb9e18db5720 (patch)
treebab3fe4ac76370948b4ca62b41253c488ca96c38 /scripts/sortextable.h
parente816b57a337ea3b755de72bec38c10c864f23015 (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.h168
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 @@
+/*
+ * sortextable.h
+ *
+ * Copyright 2011 Cavium, Inc.
+ *
+ * Some of this code was taken out of recordmcount.h written by:
+ *
+ * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved.
+ * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
+ *
+ *
+ * Licensed under the GNU General Public License, version 2 (GPLv2).
+ */
+
+#undef extable_ent_size
+#undef compare_extable
+#undef do_func
+#undef Elf_Addr
+#undef Elf_Ehdr
+#undef Elf_Shdr
+#undef Elf_Rel
+#undef Elf_Rela
+#undef Elf_Sym
+#undef ELF_R_SYM
+#undef Elf_r_sym
+#undef ELF_R_INFO
+#undef Elf_r_info
+#undef ELF_ST_BIND
+#undef ELF_ST_TYPE
+#undef fn_ELF_R_SYM
+#undef fn_ELF_R_INFO
+#undef uint_t
+#undef _w
+
+#ifdef SORTEXTABLE_64
+# define extable_ent_size 16
+# define compare_extable compare_extable_64
+# define do_func do64
+# define Elf_Addr Elf64_Addr
+# define Elf_Ehdr Elf64_Ehdr
+# define Elf_Shdr Elf64_Shdr
+# define Elf_Rel Elf64_Rel
+# define Elf_Rela Elf64_Rela
+# define Elf_Sym Elf64_Sym
+# define ELF_R_SYM ELF64_R_SYM
+# define Elf_r_sym Elf64_r_sym
+# define ELF_R_INFO ELF64_R_INFO
+# define Elf_r_info Elf64_r_info
+# define ELF_ST_BIND ELF64_ST_BIND
+# define ELF_ST_TYPE ELF64_ST_TYPE
+# define fn_ELF_R_SYM fn_ELF64_R_SYM
+# define fn_ELF_R_INFO fn_ELF64_R_INFO
+# define uint_t uint64_t
+# define _w w8
+#else
+# define extable_ent_size 8
+# define compare_extable compare_extable_32
+# define do_func do32
+# define Elf_Addr Elf32_Addr
+# define Elf_Ehdr Elf32_Ehdr
+# define Elf_Shdr Elf32_Shdr
+# define Elf_Rel Elf32_Rel
+# define Elf_Rela Elf32_Rela
+# define Elf_Sym Elf32_Sym
+# define ELF_R_SYM ELF32_R_SYM
+# define Elf_r_sym Elf32_r_sym
+# define ELF_R_INFO ELF32_R_INFO
+# define Elf_r_info Elf32_r_info
+# define ELF_ST_BIND ELF32_ST_BIND
+# define ELF_ST_TYPE ELF32_ST_TYPE
+# define fn_ELF_R_SYM fn_ELF32_R_SYM
+# define fn_ELF_R_INFO fn_ELF32_R_INFO
+# define uint_t uint32_t
+# define _w w
+#endif
+
+static int compare_extable(const void *a, const void *b)
+{
+ const uint_t *aa = a;
+ const uint_t *bb = b;
+
+ if (_w(*aa) < _w(*bb))
+ return -1;
+ if (_w(*aa) > _w(*bb))
+ return 1;
+ return 0;
+}
+
+static void
+do_func(Elf_Ehdr *const ehdr, char const *const fname)
+{
+ Elf_Shdr *shdr;
+ Elf_Shdr *shstrtab_sec;
+ Elf_Shdr *strtab_sec = NULL;
+ Elf_Shdr *symtab_sec = NULL;
+ Elf_Shdr *extab_sec = NULL;
+ Elf_Sym *sym;
+ Elf_Sym *sort_needed_sym;
+ Elf_Shdr *sort_needed_sec;
+ uint32_t *sort_done_location;
+ const char *secstrtab;
+ const char *strtab;
+ int i;
+ int idx;
+
+ shdr = (Elf_Shdr *)((void *)ehdr + _w(ehdr->e_shoff));
+ shstrtab_sec = shdr + w2(ehdr->e_shstrndx);
+ secstrtab = (const char *)ehdr + _w(shstrtab_sec->sh_offset);
+ for (i = 0; i < w2(ehdr->e_shnum); i++) {
+ idx = w(shdr[i].sh_name);
+ if (strcmp(secstrtab + idx, "__ex_table") == 0)
+ extab_sec = shdr + i;
+ if (strcmp(secstrtab + idx, ".symtab") == 0)
+ symtab_sec = shdr + i;
+ if (strcmp(secstrtab + idx, ".strtab") == 0)
+ strtab_sec = shdr + i;
+ }
+ if (strtab_sec == NULL) {
+ fprintf(stderr, "no .strtab in file: %s\n", fname);
+ fail_file();
+ }
+ if (symtab_sec == NULL) {
+ fprintf(stderr, "no .symtab in file: %s\n", fname);
+ fail_file();
+ }
+ if (extab_sec == NULL) {
+ fprintf(stderr, "no __ex_table in file: %s\n", fname);
+ fail_file();
+ }
+ strtab = (const char *)ehdr + _w(strtab_sec->sh_offset);
+
+ /* Sort the table in place */
+ qsort((void *)ehdr + _w(extab_sec->sh_offset),
+ (_w(extab_sec->sh_size) / extable_ent_size),
+ extable_ent_size, compare_extable);
+
+ /* find main_extable_sort_needed */
+ sort_needed_sym = NULL;
+ for (i = 0; i < _w(symtab_sec->sh_size) / sizeof(Elf_Sym); i++) {
+ sym = (void *)ehdr + _w(symtab_sec->sh_offset);
+ sym += i;
+ if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT)
+ continue;
+ idx = w(sym->st_name);
+ if (strcmp(strtab + idx, "main_extable_sort_needed") == 0) {
+ sort_needed_sym = sym;
+ break;
+ }
+ }
+ if (sort_needed_sym == NULL) {
+ fprintf(stderr,
+ "no main_extable_sort_needed symbol in file: %s\n",
+ fname);
+ fail_file();
+ }
+ sort_needed_sec = &shdr[w2(sort_needed_sym->st_shndx)];
+ sort_done_location = (void *)ehdr +
+ _w(sort_needed_sec->sh_offset) +
+ _w(sort_needed_sym->st_value) -
+ _w(sort_needed_sec->sh_addr);
+
+ printf("sort done marker at %lx\n",
+ (unsigned long) (_w(sort_needed_sec->sh_offset) +
+ _w(sort_needed_sym->st_value) -
+ _w(sort_needed_sec->sh_addr)));
+ /* We sorted it, clear the flag. */
+ *sort_done_location = 0;
+}