Skip to content

Commit a081b57

Browse files
ardbiesheuvelnathanchance
authored andcommitted
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>
1 parent ff79d31 commit a081b57

6 files changed

Lines changed: 25 additions & 52 deletions

File tree

kernel/kallsyms.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,10 @@ static unsigned int get_symbol_offset(unsigned long pos)
151151

152152
unsigned long kallsyms_sym_address(int idx)
153153
{
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);
156158
}
157159

158160
static unsigned int get_symbol_seq(int index)

kernel/kallsyms_internal.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ extern const int kallsyms_offsets[];
88
extern const u8 kallsyms_names[];
99

1010
extern const unsigned int kallsyms_num_syms;
11-
extern const unsigned long kallsyms_relative_base;
1211

1312
extern const char kallsyms_token_table[];
1413
extern const u16 kallsyms_token_index[];

kernel/vmcore_info.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,6 @@ static int __init crash_save_vmcoreinfo_init(void)
238238
VMCOREINFO_SYMBOL(kallsyms_token_table);
239239
VMCOREINFO_SYMBOL(kallsyms_token_index);
240240
VMCOREINFO_SYMBOL(kallsyms_offsets);
241-
VMCOREINFO_SYMBOL(kallsyms_relative_base);
242241
#endif /* CONFIG_KALLSYMS */
243242

244243
arch_crash_save_vmcoreinfo();

scripts/kallsyms.c

Lines changed: 17 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ struct addr_range {
4646
};
4747

4848
static unsigned long long _text;
49-
static unsigned long long relative_base;
5049
static struct addr_range text_ranges[] = {
5150
{ "_stext", "_etext" },
5251
{ "_sinittext", "_einittext" },
@@ -57,6 +56,7 @@ static struct addr_range text_ranges[] = {
5756
static struct sym_entry **table;
5857
static unsigned int table_size, table_cnt;
5958
static int all_symbols;
59+
static int pc_relative;
6060

6161
static int token_profit[0x10000];
6262

@@ -280,7 +280,7 @@ static void read_map(const char *in)
280280
static void output_label(const char *label)
281281
{
282282
printf(".globl %s\n", label);
283-
printf("\tALGN\n");
283+
printf("\t.balign 4\n");
284284
printf("%s:\n", label);
285285
}
286286

@@ -343,15 +343,6 @@ static void write_src(void)
343343
unsigned int *markers, markers_cnt;
344344
char buf[KSYM_NAME_LEN];
345345

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-
355346
printf("\t.section .rodata, \"a\"\n");
356347

357348
output_label("kallsyms_num_syms");
@@ -434,34 +425,24 @@ static void write_src(void)
434425
output_label("kallsyms_offsets");
435426

436427
for (i = 0; i < table_cnt; i++) {
437-
/*
438-
* Use the offset relative to the lowest value
439-
* encountered of all relative symbols, and emit
440-
* non-relocatable fixed offsets that will be fixed
441-
* up at runtime.
442-
*/
443-
444-
long long offset;
445-
446-
offset = table[i]->addr - relative_base;
447-
if (offset < 0 || offset > UINT_MAX) {
448-
fprintf(stderr, "kallsyms failure: "
449-
"relative symbol value %#llx out of range\n",
450-
table[i]->addr);
451-
exit(EXIT_FAILURE);
428+
if (pc_relative) {
429+
long long offset = table[i]->addr - _text;
430+
431+
if (offset < INT_MIN || offset > INT_MAX) {
432+
fprintf(stderr, "kallsyms failure: "
433+
"relative symbol value %#llx out of range\n",
434+
table[i]->addr);
435+
exit(EXIT_FAILURE);
436+
}
437+
printf("\t.long\t_text - . + (%d)\t/* %s */\n",
438+
(int)offset, table[i]->sym);
439+
} else {
440+
printf("\t.long\t%#x\t/* %s */\n",
441+
(unsigned int)table[i]->addr, table[i]->sym);
452442
}
453-
printf("\t.long\t%#x\t/* %s */\n", (int)offset, table[i]->sym);
454443
}
455444
printf("\n");
456445

457-
output_label("kallsyms_relative_base");
458-
/* Provide proper symbols relocatability by their '_text' relativeness. */
459-
if (_text <= relative_base)
460-
printf("\tPTR\t_text + %#llx\n", relative_base - _text);
461-
else
462-
printf("\tPTR\t_text - %#llx\n", _text - relative_base);
463-
printf("\n");
464-
465446
sort_symbols_by_name();
466447
output_label("kallsyms_seqs_of_names");
467448
for (i = 0; i < table_cnt; i++)
@@ -701,22 +682,12 @@ static void sort_symbols(void)
701682
qsort(table, table_cnt, sizeof(table[0]), compare_symbols);
702683
}
703684

704-
/* find the minimum non-absolute symbol address */
705-
static void record_relative_base(void)
706-
{
707-
/*
708-
* The table is sorted by address.
709-
* Take the first symbol value.
710-
*/
711-
if (table_cnt)
712-
relative_base = table[0]->addr;
713-
}
714-
715685
int main(int argc, char **argv)
716686
{
717687
while (1) {
718688
static const struct option long_options[] = {
719689
{"all-symbols", no_argument, &all_symbols, 1},
690+
{"pc-relative", no_argument, &pc_relative, 1},
720691
{},
721692
};
722693

@@ -734,7 +705,6 @@ int main(int argc, char **argv)
734705
read_map(argv[optind]);
735706
shrink_table();
736707
sort_symbols();
737-
record_relative_base();
738708
optimize_token_table();
739709
write_src();
740710

scripts/link-vmlinux.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,10 @@ kallsyms()
143143
kallsymopt="${kallsymopt} --all-symbols"
144144
fi
145145

146+
if is_enabled CONFIG_64BIT || is_enabled CONFIG_RELOCATABLE; then
147+
kallsymopt="${kallsymopt} --pc-relative"
148+
fi
149+
146150
info KSYMS "${2}.S"
147151
scripts/kallsyms ${kallsymopt} "${1}" > "${2}.S"
148152

tools/perf/tests/vmlinux-kallsyms.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ static bool is_ignored_symbol(const char *name, char type)
2727
* stable symbol list.
2828
*/
2929
"kallsyms_offsets",
30-
"kallsyms_relative_base",
3130
"kallsyms_num_syms",
3231
"kallsyms_names",
3332
"kallsyms_markers",

0 commit comments

Comments
 (0)