diff options
Diffstat (limited to 'scripts/kallsyms.c')
-rw-r--r-- | scripts/kallsyms.c | 79 |
1 files changed, 69 insertions, 10 deletions
diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c index d39a1eeb080e..638b143ee60f 100644 --- a/scripts/kallsyms.c +++ b/scripts/kallsyms.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <stdlib.h> | 22 | #include <stdlib.h> |
23 | #include <string.h> | 23 | #include <string.h> |
24 | #include <ctype.h> | 24 | #include <ctype.h> |
25 | #include <limits.h> | ||
25 | 26 | ||
26 | #ifndef ARRAY_SIZE | 27 | #ifndef ARRAY_SIZE |
27 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) | 28 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) |
@@ -43,6 +44,7 @@ struct addr_range { | |||
43 | }; | 44 | }; |
44 | 45 | ||
45 | static unsigned long long _text; | 46 | static unsigned long long _text; |
47 | static unsigned long long relative_base; | ||
46 | static struct addr_range text_ranges[] = { | 48 | static struct addr_range text_ranges[] = { |
47 | { "_stext", "_etext" }, | 49 | { "_stext", "_etext" }, |
48 | { "_sinittext", "_einittext" }, | 50 | { "_sinittext", "_einittext" }, |
@@ -62,6 +64,7 @@ static int all_symbols = 0; | |||
62 | static int absolute_percpu = 0; | 64 | static int absolute_percpu = 0; |
63 | static char symbol_prefix_char = '\0'; | 65 | static char symbol_prefix_char = '\0'; |
64 | static unsigned long long kernel_start_addr = 0; | 66 | static unsigned long long kernel_start_addr = 0; |
67 | static int base_relative = 0; | ||
65 | 68 | ||
66 | int token_profit[0x10000]; | 69 | int token_profit[0x10000]; |
67 | 70 | ||
@@ -75,7 +78,7 @@ static void usage(void) | |||
75 | fprintf(stderr, "Usage: kallsyms [--all-symbols] " | 78 | fprintf(stderr, "Usage: kallsyms [--all-symbols] " |
76 | "[--symbol-prefix=<prefix char>] " | 79 | "[--symbol-prefix=<prefix char>] " |
77 | "[--page-offset=<CONFIG_PAGE_OFFSET>] " | 80 | "[--page-offset=<CONFIG_PAGE_OFFSET>] " |
78 | "< in.map > out.S\n"); | 81 | "[--base-relative] < in.map > out.S\n"); |
79 | exit(1); | 82 | exit(1); |
80 | } | 83 | } |
81 | 84 | ||
@@ -205,6 +208,8 @@ static int symbol_valid(struct sym_entry *s) | |||
205 | */ | 208 | */ |
206 | static char *special_symbols[] = { | 209 | static char *special_symbols[] = { |
207 | "kallsyms_addresses", | 210 | "kallsyms_addresses", |
211 | "kallsyms_offsets", | ||
212 | "kallsyms_relative_base", | ||
208 | "kallsyms_num_syms", | 213 | "kallsyms_num_syms", |
209 | "kallsyms_names", | 214 | "kallsyms_names", |
210 | "kallsyms_markers", | 215 | "kallsyms_markers", |
@@ -349,16 +354,48 @@ static void write_src(void) | |||
349 | 354 | ||
350 | printf("\t.section .rodata, \"a\"\n"); | 355 | printf("\t.section .rodata, \"a\"\n"); |
351 | 356 | ||
352 | /* Provide proper symbols relocatability by their '_text' | 357 | /* Provide proper symbols relocatability by their relativeness |
353 | * relativeness. The symbol names cannot be used to construct | 358 | * to a fixed anchor point in the runtime image, either '_text' |
354 | * normal symbol references as the list of symbols contains | 359 | * for absolute address tables, in which case the linker will |
355 | * symbols that are declared static and are private to their | 360 | * emit the final addresses at build time. Otherwise, use the |
356 | * .o files. This prevents .tmp_kallsyms.o or any other | 361 | * offset relative to the lowest value encountered of all relative |
357 | * object from referencing them. | 362 | * symbols, and emit non-relocatable fixed offsets that will be fixed |
363 | * up at runtime. | ||
364 | * | ||
365 | * The symbol names cannot be used to construct normal symbol | ||
366 | * references as the list of symbols contains symbols that are | ||
367 | * declared static and are private to their .o files. This prevents | ||
368 | * .tmp_kallsyms.o or any other object from referencing them. | ||
358 | */ | 369 | */ |
359 | output_label("kallsyms_addresses"); | 370 | if (!base_relative) |
371 | output_label("kallsyms_addresses"); | ||
372 | else | ||
373 | output_label("kallsyms_offsets"); | ||
374 | |||
360 | for (i = 0; i < table_cnt; i++) { | 375 | for (i = 0; i < table_cnt; i++) { |
361 | if (!symbol_absolute(&table[i])) { | 376 | if (base_relative) { |
377 | long long offset; | ||
378 | int overflow; | ||
379 | |||
380 | if (!absolute_percpu) { | ||
381 | offset = table[i].addr - relative_base; | ||
382 | overflow = (offset < 0 || offset > UINT_MAX); | ||
383 | } else if (symbol_absolute(&table[i])) { | ||
384 | offset = table[i].addr; | ||
385 | overflow = (offset < 0 || offset > INT_MAX); | ||
386 | } else { | ||
387 | offset = relative_base - table[i].addr - 1; | ||
388 | overflow = (offset < INT_MIN || offset >= 0); | ||
389 | } | ||
390 | if (overflow) { | ||
391 | fprintf(stderr, "kallsyms failure: " | ||
392 | "%s symbol value %#llx out of range in relative mode\n", | ||
393 | symbol_absolute(&table[i]) ? "absolute" : "relative", | ||
394 | table[i].addr); | ||
395 | exit(EXIT_FAILURE); | ||
396 | } | ||
397 | printf("\t.long\t%#x\n", (int)offset); | ||
398 | } else if (!symbol_absolute(&table[i])) { | ||
362 | if (_text <= table[i].addr) | 399 | if (_text <= table[i].addr) |
363 | printf("\tPTR\t_text + %#llx\n", | 400 | printf("\tPTR\t_text + %#llx\n", |
364 | table[i].addr - _text); | 401 | table[i].addr - _text); |
@@ -371,6 +408,12 @@ static void write_src(void) | |||
371 | } | 408 | } |
372 | printf("\n"); | 409 | printf("\n"); |
373 | 410 | ||
411 | if (base_relative) { | ||
412 | output_label("kallsyms_relative_base"); | ||
413 | printf("\tPTR\t_text - %#llx\n", _text - relative_base); | ||
414 | printf("\n"); | ||
415 | } | ||
416 | |||
374 | output_label("kallsyms_num_syms"); | 417 | output_label("kallsyms_num_syms"); |
375 | printf("\tPTR\t%d\n", table_cnt); | 418 | printf("\tPTR\t%d\n", table_cnt); |
376 | printf("\n"); | 419 | printf("\n"); |
@@ -695,6 +738,18 @@ static void make_percpus_absolute(void) | |||
695 | } | 738 | } |
696 | } | 739 | } |
697 | 740 | ||
741 | /* find the minimum non-absolute symbol address */ | ||
742 | static void record_relative_base(void) | ||
743 | { | ||
744 | unsigned int i; | ||
745 | |||
746 | relative_base = -1ULL; | ||
747 | for (i = 0; i < table_cnt; i++) | ||
748 | if (!symbol_absolute(&table[i]) && | ||
749 | table[i].addr < relative_base) | ||
750 | relative_base = table[i].addr; | ||
751 | } | ||
752 | |||
698 | int main(int argc, char **argv) | 753 | int main(int argc, char **argv) |
699 | { | 754 | { |
700 | if (argc >= 2) { | 755 | if (argc >= 2) { |
@@ -713,7 +768,9 @@ int main(int argc, char **argv) | |||
713 | } else if (strncmp(argv[i], "--page-offset=", 14) == 0) { | 768 | } else if (strncmp(argv[i], "--page-offset=", 14) == 0) { |
714 | const char *p = &argv[i][14]; | 769 | const char *p = &argv[i][14]; |
715 | kernel_start_addr = strtoull(p, NULL, 16); | 770 | kernel_start_addr = strtoull(p, NULL, 16); |
716 | } else | 771 | } else if (strcmp(argv[i], "--base-relative") == 0) |
772 | base_relative = 1; | ||
773 | else | ||
717 | usage(); | 774 | usage(); |
718 | } | 775 | } |
719 | } else if (argc != 1) | 776 | } else if (argc != 1) |
@@ -722,6 +779,8 @@ int main(int argc, char **argv) | |||
722 | read_map(stdin); | 779 | read_map(stdin); |
723 | if (absolute_percpu) | 780 | if (absolute_percpu) |
724 | make_percpus_absolute(); | 781 | make_percpus_absolute(); |
782 | if (base_relative) | ||
783 | record_relative_base(); | ||
725 | sort_symbols(); | 784 | sort_symbols(); |
726 | optimize_token_table(); | 785 | optimize_token_table(); |
727 | write_src(); | 786 | write_src(); |