aboutsummaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2014-03-16 23:35:46 -0400
committerRusty Russell <rusty@rustcorp.com.au>2014-03-17 00:25:27 -0400
commitc6bda7c988a57958108741cde9b1f12e9727a938 (patch)
tree70d2e0c3806467b6689617a9cf1a6e472d9d29fa /scripts
parent78eb71594b3265f3cfe871480235be158feebd0f (diff)
kallsyms: fix percpu vars on x86-64 with relocation.
x86-64 has a problem: per-cpu variables are actually represented by their absolute offsets within the per-cpu area, but the symbols are not emitted as absolute. Thus kallsyms naively creates them as offsets from _text, meaning their values change if the kernel is relocated (especially noticeable with CONFIG_RANDOMIZE_BASE): $ egrep ' (gdt_|_(stext|_per_cpu_))' /root/kallsyms.nokaslr 0000000000000000 D __per_cpu_start 0000000000004000 D gdt_page 0000000000014280 D __per_cpu_end ffffffff810001c8 T _stext ffffffff81ee53c0 D __per_cpu_offset $ egrep ' (gdt_|_(stext|_per_cpu_))' /root/kallsyms.kaslr1 000000001f200000 D __per_cpu_start 000000001f204000 D gdt_page 000000001f214280 D __per_cpu_end ffffffffa02001c8 T _stext ffffffffa10e53c0 D __per_cpu_offset Making them absolute symbols is the Right Thing, but requires fixes to the relocs tool. So for the moment, we add a --absolute-percpu option which makes them absolute from a kallsyms perspective: $ egrep ' (gdt_|_(stext|_per_cpu_))' /proc/kallsyms # no KASLR 0000000000000000 A __per_cpu_start 000000000000a000 A gdt_page 0000000000013040 A __per_cpu_end ffffffff802001c8 T _stext ffffffff8099b180 D __per_cpu_offset ffffffff809a3000 D __per_cpu_load $ egrep ' (gdt_|_(stext|_per_cpu_))' /proc/kallsyms # With KASLR 0000000000000000 A __per_cpu_start 000000000000a000 A gdt_page 0000000000013040 A __per_cpu_end ffffffff89c001c8 T _stext ffffffff8a39d180 D __per_cpu_offset ffffffff8a3a5000 D __per_cpu_load Based-on-the-original-screenplay-by: Andy Honig <ahonig@google.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Acked-by: Kees Cook <keescook@chromium.org>
Diffstat (limited to 'scripts')
-rw-r--r--scripts/kallsyms.c21
-rw-r--r--scripts/link-vmlinux.sh4
2 files changed, 25 insertions, 0 deletions
diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index 3df15f5e7c55..1237dd7fb4ca 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -51,9 +51,14 @@ static struct addr_range text_ranges[] = {
51#define text_range_text (&text_ranges[0]) 51#define text_range_text (&text_ranges[0])
52#define text_range_inittext (&text_ranges[1]) 52#define text_range_inittext (&text_ranges[1])
53 53
54static struct addr_range percpu_range = {
55 "__per_cpu_start", "__per_cpu_end", -1ULL, 0
56};
57
54static struct sym_entry *table; 58static struct sym_entry *table;
55static unsigned int table_size, table_cnt; 59static unsigned int table_size, table_cnt;
56static int all_symbols = 0; 60static int all_symbols = 0;
61static int absolute_percpu = 0;
57static char symbol_prefix_char = '\0'; 62static char symbol_prefix_char = '\0';
58static unsigned long long kernel_start_addr = 0; 63static unsigned long long kernel_start_addr = 0;
59 64
@@ -166,6 +171,9 @@ static int read_symbol(FILE *in, struct sym_entry *s)
166 strcpy((char *)s->sym + 1, str); 171 strcpy((char *)s->sym + 1, str);
167 s->sym[0] = stype; 172 s->sym[0] = stype;
168 173
174 /* Record if we've found __per_cpu_start/end. */
175 check_symbol_range(sym, s->addr, &percpu_range, 1);
176
169 return 0; 177 return 0;
170} 178}
171 179
@@ -657,6 +665,15 @@ static void sort_symbols(void)
657 qsort(table, table_cnt, sizeof(struct sym_entry), compare_symbols); 665 qsort(table, table_cnt, sizeof(struct sym_entry), compare_symbols);
658} 666}
659 667
668static void make_percpus_absolute(void)
669{
670 unsigned int i;
671
672 for (i = 0; i < table_cnt; i++)
673 if (symbol_in_range(&table[i], &percpu_range, 1))
674 table[i].sym[0] = 'A';
675}
676
660int main(int argc, char **argv) 677int main(int argc, char **argv)
661{ 678{
662 if (argc >= 2) { 679 if (argc >= 2) {
@@ -664,6 +681,8 @@ int main(int argc, char **argv)
664 for (i = 1; i < argc; i++) { 681 for (i = 1; i < argc; i++) {
665 if(strcmp(argv[i], "--all-symbols") == 0) 682 if(strcmp(argv[i], "--all-symbols") == 0)
666 all_symbols = 1; 683 all_symbols = 1;
684 else if (strcmp(argv[i], "--absolute-percpu") == 0)
685 absolute_percpu = 1;
667 else if (strncmp(argv[i], "--symbol-prefix=", 16) == 0) { 686 else if (strncmp(argv[i], "--symbol-prefix=", 16) == 0) {
668 char *p = &argv[i][16]; 687 char *p = &argv[i][16];
669 /* skip quote */ 688 /* skip quote */
@@ -680,6 +699,8 @@ int main(int argc, char **argv)
680 usage(); 699 usage();
681 700
682 read_map(stdin); 701 read_map(stdin);
702 if (absolute_percpu)
703 make_percpus_absolute();
683 sort_symbols(); 704 sort_symbols();
684 optimize_token_table(); 705 optimize_token_table();
685 write_src(); 706 write_src();
diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index 2dcb37736d84..86a4fe75f453 100644
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -86,6 +86,10 @@ kallsyms()
86 kallsymopt="${kallsymopt} --page-offset=$CONFIG_PAGE_OFFSET" 86 kallsymopt="${kallsymopt} --page-offset=$CONFIG_PAGE_OFFSET"
87 fi 87 fi
88 88
89 if [ -n "${CONFIG_X86_64}" ]; then
90 kallsymopt="${kallsymopt} --absolute-percpu"
91 fi
92
89 local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \ 93 local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \
90 ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}" 94 ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}"
91 95