diff options
-rw-r--r-- | init/Kconfig | 18 | ||||
-rw-r--r-- | kernel/kallsyms.c | 42 | ||||
-rw-r--r-- | scripts/kallsyms.c | 79 | ||||
-rwxr-xr-x | scripts/link-vmlinux.sh | 4 | ||||
-rwxr-xr-x | scripts/namespace.pl | 2 |
5 files changed, 126 insertions, 19 deletions
diff --git a/init/Kconfig b/init/Kconfig index b17824a875fa..fd664b3ab99e 100644 --- a/init/Kconfig +++ b/init/Kconfig | |||
@@ -1424,6 +1424,24 @@ config KALLSYMS_ABSOLUTE_PERCPU | |||
1424 | bool | 1424 | bool |
1425 | default X86_64 && SMP | 1425 | default X86_64 && SMP |
1426 | 1426 | ||
1427 | config KALLSYMS_BASE_RELATIVE | ||
1428 | bool | ||
1429 | depends on KALLSYMS | ||
1430 | default !IA64 && !(TILE && 64BIT) | ||
1431 | help | ||
1432 | Instead of emitting them as absolute values in the native word size, | ||
1433 | emit the symbol references in the kallsyms table as 32-bit entries, | ||
1434 | each containing a relative value in the range [base, base + U32_MAX] | ||
1435 | or, when KALLSYMS_ABSOLUTE_PERCPU is in effect, each containing either | ||
1436 | an absolute value in the range [0, S32_MAX] or a relative value in the | ||
1437 | range [base, base + S32_MAX], where base is the lowest relative symbol | ||
1438 | address encountered in the image. | ||
1439 | |||
1440 | On 64-bit builds, this reduces the size of the address table by 50%, | ||
1441 | but more importantly, it results in entries whose values are build | ||
1442 | time constants, and no relocation pass is required at runtime to fix | ||
1443 | up the entries based on the runtime load address of the kernel. | ||
1444 | |||
1427 | config PRINTK | 1445 | config PRINTK |
1428 | default y | 1446 | default y |
1429 | bool "Enable support for printk" if EXPERT | 1447 | bool "Enable support for printk" if EXPERT |
diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c index 5c5987f10819..fafd1a3ef0da 100644 --- a/kernel/kallsyms.c +++ b/kernel/kallsyms.c | |||
@@ -38,6 +38,7 @@ | |||
38 | * during the second link stage. | 38 | * during the second link stage. |
39 | */ | 39 | */ |
40 | extern const unsigned long kallsyms_addresses[] __weak; | 40 | extern const unsigned long kallsyms_addresses[] __weak; |
41 | extern const int kallsyms_offsets[] __weak; | ||
41 | extern const u8 kallsyms_names[] __weak; | 42 | extern const u8 kallsyms_names[] __weak; |
42 | 43 | ||
43 | /* | 44 | /* |
@@ -47,6 +48,9 @@ extern const u8 kallsyms_names[] __weak; | |||
47 | extern const unsigned long kallsyms_num_syms | 48 | extern const unsigned long kallsyms_num_syms |
48 | __attribute__((weak, section(".rodata"))); | 49 | __attribute__((weak, section(".rodata"))); |
49 | 50 | ||
51 | extern const unsigned long kallsyms_relative_base | ||
52 | __attribute__((weak, section(".rodata"))); | ||
53 | |||
50 | extern const u8 kallsyms_token_table[] __weak; | 54 | extern const u8 kallsyms_token_table[] __weak; |
51 | extern const u16 kallsyms_token_index[] __weak; | 55 | extern const u16 kallsyms_token_index[] __weak; |
52 | 56 | ||
@@ -176,6 +180,23 @@ static unsigned int get_symbol_offset(unsigned long pos) | |||
176 | return name - kallsyms_names; | 180 | return name - kallsyms_names; |
177 | } | 181 | } |
178 | 182 | ||
183 | static unsigned long kallsyms_sym_address(int idx) | ||
184 | { | ||
185 | if (!IS_ENABLED(CONFIG_KALLSYMS_BASE_RELATIVE)) | ||
186 | return kallsyms_addresses[idx]; | ||
187 | |||
188 | /* values are unsigned offsets if --absolute-percpu is not in effect */ | ||
189 | if (!IS_ENABLED(CONFIG_KALLSYMS_ABSOLUTE_PERCPU)) | ||
190 | return kallsyms_relative_base + (u32)kallsyms_offsets[idx]; | ||
191 | |||
192 | /* ...otherwise, positive offsets are absolute values */ | ||
193 | if (kallsyms_offsets[idx] >= 0) | ||
194 | return kallsyms_offsets[idx]; | ||
195 | |||
196 | /* ...and negative offsets are relative to kallsyms_relative_base - 1 */ | ||
197 | return kallsyms_relative_base - 1 - kallsyms_offsets[idx]; | ||
198 | } | ||
199 | |||
179 | /* Lookup the address for this symbol. Returns 0 if not found. */ | 200 | /* Lookup the address for this symbol. Returns 0 if not found. */ |
180 | unsigned long kallsyms_lookup_name(const char *name) | 201 | unsigned long kallsyms_lookup_name(const char *name) |
181 | { | 202 | { |
@@ -187,7 +208,7 @@ unsigned long kallsyms_lookup_name(const char *name) | |||
187 | off = kallsyms_expand_symbol(off, namebuf, ARRAY_SIZE(namebuf)); | 208 | off = kallsyms_expand_symbol(off, namebuf, ARRAY_SIZE(namebuf)); |
188 | 209 | ||
189 | if (strcmp(namebuf, name) == 0) | 210 | if (strcmp(namebuf, name) == 0) |
190 | return kallsyms_addresses[i]; | 211 | return kallsyms_sym_address(i); |
191 | } | 212 | } |
192 | return module_kallsyms_lookup_name(name); | 213 | return module_kallsyms_lookup_name(name); |
193 | } | 214 | } |
@@ -204,7 +225,7 @@ int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *, | |||
204 | 225 | ||
205 | for (i = 0, off = 0; i < kallsyms_num_syms; i++) { | 226 | for (i = 0, off = 0; i < kallsyms_num_syms; i++) { |
206 | off = kallsyms_expand_symbol(off, namebuf, ARRAY_SIZE(namebuf)); | 227 | off = kallsyms_expand_symbol(off, namebuf, ARRAY_SIZE(namebuf)); |
207 | ret = fn(data, namebuf, NULL, kallsyms_addresses[i]); | 228 | ret = fn(data, namebuf, NULL, kallsyms_sym_address(i)); |
208 | if (ret != 0) | 229 | if (ret != 0) |
209 | return ret; | 230 | return ret; |
210 | } | 231 | } |
@@ -220,7 +241,10 @@ static unsigned long get_symbol_pos(unsigned long addr, | |||
220 | unsigned long i, low, high, mid; | 241 | unsigned long i, low, high, mid; |
221 | 242 | ||
222 | /* This kernel should never had been booted. */ | 243 | /* This kernel should never had been booted. */ |
223 | BUG_ON(!kallsyms_addresses); | 244 | if (!IS_ENABLED(CONFIG_KALLSYMS_BASE_RELATIVE)) |
245 | BUG_ON(!kallsyms_addresses); | ||
246 | else | ||
247 | BUG_ON(!kallsyms_offsets); | ||
224 | 248 | ||
225 | /* Do a binary search on the sorted kallsyms_addresses array. */ | 249 | /* Do a binary search on the sorted kallsyms_addresses array. */ |
226 | low = 0; | 250 | low = 0; |
@@ -228,7 +252,7 @@ static unsigned long get_symbol_pos(unsigned long addr, | |||
228 | 252 | ||
229 | while (high - low > 1) { | 253 | while (high - low > 1) { |
230 | mid = low + (high - low) / 2; | 254 | mid = low + (high - low) / 2; |
231 | if (kallsyms_addresses[mid] <= addr) | 255 | if (kallsyms_sym_address(mid) <= addr) |
232 | low = mid; | 256 | low = mid; |
233 | else | 257 | else |
234 | high = mid; | 258 | high = mid; |
@@ -238,15 +262,15 @@ static unsigned long get_symbol_pos(unsigned long addr, | |||
238 | * Search for the first aliased symbol. Aliased | 262 | * Search for the first aliased symbol. Aliased |
239 | * symbols are symbols with the same address. | 263 | * symbols are symbols with the same address. |
240 | */ | 264 | */ |
241 | while (low && kallsyms_addresses[low-1] == kallsyms_addresses[low]) | 265 | while (low && kallsyms_sym_address(low-1) == kallsyms_sym_address(low)) |
242 | --low; | 266 | --low; |
243 | 267 | ||
244 | symbol_start = kallsyms_addresses[low]; | 268 | symbol_start = kallsyms_sym_address(low); |
245 | 269 | ||
246 | /* Search for next non-aliased symbol. */ | 270 | /* Search for next non-aliased symbol. */ |
247 | for (i = low + 1; i < kallsyms_num_syms; i++) { | 271 | for (i = low + 1; i < kallsyms_num_syms; i++) { |
248 | if (kallsyms_addresses[i] > symbol_start) { | 272 | if (kallsyms_sym_address(i) > symbol_start) { |
249 | symbol_end = kallsyms_addresses[i]; | 273 | symbol_end = kallsyms_sym_address(i); |
250 | break; | 274 | break; |
251 | } | 275 | } |
252 | } | 276 | } |
@@ -470,7 +494,7 @@ static unsigned long get_ksymbol_core(struct kallsym_iter *iter) | |||
470 | unsigned off = iter->nameoff; | 494 | unsigned off = iter->nameoff; |
471 | 495 | ||
472 | iter->module_name[0] = '\0'; | 496 | iter->module_name[0] = '\0'; |
473 | iter->value = kallsyms_addresses[iter->pos]; | 497 | iter->value = kallsyms_sym_address(iter->pos); |
474 | 498 | ||
475 | iter->type = kallsyms_get_symbol_type(off); | 499 | iter->type = kallsyms_get_symbol_type(off); |
476 | 500 | ||
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(); |
diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index 7a08bf9a9576..453ede9d2f3d 100755 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh | |||
@@ -90,6 +90,10 @@ kallsyms() | |||
90 | kallsymopt="${kallsymopt} --absolute-percpu" | 90 | kallsymopt="${kallsymopt} --absolute-percpu" |
91 | fi | 91 | fi |
92 | 92 | ||
93 | if [ -n "${CONFIG_KALLSYMS_BASE_RELATIVE}" ]; then | ||
94 | kallsymopt="${kallsymopt} --base-relative" | ||
95 | fi | ||
96 | |||
93 | local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \ | 97 | local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \ |
94 | ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}" | 98 | ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}" |
95 | 99 | ||
diff --git a/scripts/namespace.pl b/scripts/namespace.pl index a71be6b7cdec..9f3c9d47a4a5 100755 --- a/scripts/namespace.pl +++ b/scripts/namespace.pl | |||
@@ -117,6 +117,8 @@ my %nameexception = ( | |||
117 | 'kallsyms_names' => 1, | 117 | 'kallsyms_names' => 1, |
118 | 'kallsyms_num_syms' => 1, | 118 | 'kallsyms_num_syms' => 1, |
119 | 'kallsyms_addresses'=> 1, | 119 | 'kallsyms_addresses'=> 1, |
120 | 'kallsyms_offsets' => 1, | ||
121 | 'kallsyms_relative_base'=> 1, | ||
120 | '__this_module' => 1, | 122 | '__this_module' => 1, |
121 | '_etext' => 1, | 123 | '_etext' => 1, |
122 | '_edata' => 1, | 124 | '_edata' => 1, |