Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

kallsyms: Get rid of kallsyms relative base

When the kallsyms relative base was introduced, per-CPU variable
references on x86_64 SMP were implemented as offsets into the respective
per-CPU region, rather than offsets relative to the location of the
variable's template in the kernel image, which is how other
architectures implement it.

This required kallsyms to reason about the difference between the two,
and the sign of the value in the kallsyms_offsets[] array was used to
distinguish them. This meant that negative offsets were not permitted
for ordinary variables, and so it was crucial that the relative base was
chosen such that all offsets were positive numbers.

This is no longer needed: instead, the offsets can simply be encoded as
values in the range -/+ 2 GiB, which is precisely what PC32 relocations
provide on most architectures. So it is possible to simplify the logic,
and just use _text as the anchor directly, and let the linker calculate
the final value based on the location of the entry itself.

Some architectures (nios2, extensa) do not support place-relative
relocations at all, but these are all 32-bit and non-relocatable, and so
there is no need for place-relative relocations in the first place, and
the actual symbol values can just be stored directly.

This makes all entries in the kallsyms_offsets[] array visible as
place-relative references in the ELF metadata, which will be important
when implementing ELF-based fg-kaslr.

Reviewed-by: Kees Cook <kees@kernel.org>
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://patch.msgid.link/20260116093359.2442297-6-ardb+git@google.com
Signed-off-by: Nathan Chancellor <nathan@kernel.org>

authored by

Ard Biesheuvel and committed by
Nathan Chancellor
a081b578 ff79d31e

+24 -51
+4 -2
kernel/kallsyms.c
··· 151 151 152 152 unsigned long kallsyms_sym_address(int idx) 153 153 { 154 - /* values are unsigned offsets */ 155 - return kallsyms_relative_base + (u32)kallsyms_offsets[idx]; 154 + /* non-relocatable 32-bit kernels just embed the value directly */ 155 + if (!IS_ENABLED(CONFIG_64BIT) && !IS_ENABLED(CONFIG_RELOCATABLE)) 156 + return (u32)kallsyms_offsets[idx]; 157 + return (unsigned long)offset_to_ptr(kallsyms_offsets + idx); 156 158 } 157 159 158 160 static unsigned int get_symbol_seq(int index)
-1
kernel/kallsyms_internal.h
··· 8 8 extern const u8 kallsyms_names[]; 9 9 10 10 extern const unsigned int kallsyms_num_syms; 11 - extern const unsigned long kallsyms_relative_base; 12 11 13 12 extern const char kallsyms_token_table[]; 14 13 extern const u16 kallsyms_token_index[];
-1
kernel/vmcore_info.c
··· 238 238 VMCOREINFO_SYMBOL(kallsyms_token_table); 239 239 VMCOREINFO_SYMBOL(kallsyms_token_index); 240 240 VMCOREINFO_SYMBOL(kallsyms_offsets); 241 - VMCOREINFO_SYMBOL(kallsyms_relative_base); 242 241 #endif /* CONFIG_KALLSYMS */ 243 242 244 243 arch_crash_save_vmcoreinfo();
+16 -46
scripts/kallsyms.c
··· 46 46 }; 47 47 48 48 static unsigned long long _text; 49 - static unsigned long long relative_base; 50 49 static struct addr_range text_ranges[] = { 51 50 { "_stext", "_etext" }, 52 51 { "_sinittext", "_einittext" }, ··· 56 57 static struct sym_entry **table; 57 58 static unsigned int table_size, table_cnt; 58 59 static int all_symbols; 60 + static int pc_relative; 59 61 60 62 static int token_profit[0x10000]; 61 63 ··· 280 280 static void output_label(const char *label) 281 281 { 282 282 printf(".globl %s\n", label); 283 - printf("\tALGN\n"); 283 + printf("\t.balign 4\n"); 284 284 printf("%s:\n", label); 285 285 } 286 286 ··· 342 342 unsigned int best_idx[256]; 343 343 unsigned int *markers, markers_cnt; 344 344 char buf[KSYM_NAME_LEN]; 345 - 346 - printf("#include <asm/bitsperlong.h>\n"); 347 - printf("#if BITS_PER_LONG == 64\n"); 348 - printf("#define PTR .quad\n"); 349 - printf("#define ALGN .balign 8\n"); 350 - printf("#else\n"); 351 - printf("#define PTR .long\n"); 352 - printf("#define ALGN .balign 4\n"); 353 - printf("#endif\n"); 354 345 355 346 printf("\t.section .rodata, \"a\"\n"); 356 347 ··· 425 434 output_label("kallsyms_offsets"); 426 435 427 436 for (i = 0; i < table_cnt; i++) { 428 - /* 429 - * Use the offset relative to the lowest value 430 - * encountered of all relative symbols, and emit 431 - * non-relocatable fixed offsets that will be fixed 432 - * up at runtime. 433 - */ 437 + if (pc_relative) { 438 + long long offset = table[i]->addr - _text; 434 439 435 - long long offset; 436 - 437 - offset = table[i]->addr - relative_base; 438 - if (offset < 0 || offset > UINT_MAX) { 439 - fprintf(stderr, "kallsyms failure: " 440 - "relative symbol value %#llx out of range\n", 441 - table[i]->addr); 442 - exit(EXIT_FAILURE); 440 + if (offset < INT_MIN || offset > INT_MAX) { 441 + fprintf(stderr, "kallsyms failure: " 442 + "relative symbol value %#llx out of range\n", 443 + table[i]->addr); 444 + exit(EXIT_FAILURE); 445 + } 446 + printf("\t.long\t_text - . + (%d)\t/* %s */\n", 447 + (int)offset, table[i]->sym); 448 + } else { 449 + printf("\t.long\t%#x\t/* %s */\n", 450 + (unsigned int)table[i]->addr, table[i]->sym); 443 451 } 444 - printf("\t.long\t%#x\t/* %s */\n", (int)offset, table[i]->sym); 445 452 } 446 - printf("\n"); 447 - 448 - output_label("kallsyms_relative_base"); 449 - /* Provide proper symbols relocatability by their '_text' relativeness. */ 450 - if (_text <= relative_base) 451 - printf("\tPTR\t_text + %#llx\n", relative_base - _text); 452 - else 453 - printf("\tPTR\t_text - %#llx\n", _text - relative_base); 454 453 printf("\n"); 455 454 456 455 sort_symbols_by_name(); ··· 682 701 qsort(table, table_cnt, sizeof(table[0]), compare_symbols); 683 702 } 684 703 685 - /* find the minimum non-absolute symbol address */ 686 - static void record_relative_base(void) 687 - { 688 - /* 689 - * The table is sorted by address. 690 - * Take the first symbol value. 691 - */ 692 - if (table_cnt) 693 - relative_base = table[0]->addr; 694 - } 695 - 696 704 int main(int argc, char **argv) 697 705 { 698 706 while (1) { 699 707 static const struct option long_options[] = { 700 708 {"all-symbols", no_argument, &all_symbols, 1}, 709 + {"pc-relative", no_argument, &pc_relative, 1}, 701 710 {}, 702 711 }; 703 712 ··· 705 734 read_map(argv[optind]); 706 735 shrink_table(); 707 736 sort_symbols(); 708 - record_relative_base(); 709 737 optimize_token_table(); 710 738 write_src(); 711 739
-1
tools/perf/tests/vmlinux-kallsyms.c
··· 27 27 * stable symbol list. 28 28 */ 29 29 "kallsyms_offsets", 30 - "kallsyms_relative_base", 31 30 "kallsyms_num_syms", 32 31 "kallsyms_names", 33 32 "kallsyms_markers",