]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
kallsyms: Get rid of kallsyms relative base
authorArd Biesheuvel <ardb@kernel.org>
Fri, 16 Jan 2026 09:34:02 +0000 (10:34 +0100)
committerNathan Chancellor <nathan@kernel.org>
Thu, 22 Jan 2026 22:58:22 +0000 (15:58 -0700)
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>
kernel/kallsyms.c
kernel/kallsyms_internal.h
kernel/vmcore_info.c
scripts/kallsyms.c
scripts/link-vmlinux.sh
tools/perf/tests/vmlinux-kallsyms.c

index 049e296f586ccdc6ada9bacd71d05f6681a537bb..6125724aadb1555ec180636ff4a89029ac0ede19 100644 (file)
@@ -151,8 +151,10 @@ static unsigned int get_symbol_offset(unsigned long pos)
 
 unsigned long kallsyms_sym_address(int idx)
 {
-       /* values are unsigned offsets */
-       return kallsyms_relative_base + (u32)kallsyms_offsets[idx];
+       /* non-relocatable 32-bit kernels just embed the value directly */
+       if (!IS_ENABLED(CONFIG_64BIT) && !IS_ENABLED(CONFIG_RELOCATABLE))
+               return (u32)kallsyms_offsets[idx];
+       return (unsigned long)offset_to_ptr(kallsyms_offsets + idx);
 }
 
 static unsigned int get_symbol_seq(int index)
index 9633782f8250090281a68c14605f3ab414e31f1e..81a867dbe57d480e96e635e33a8adc53947f4b32 100644 (file)
@@ -8,7 +8,6 @@ extern const int kallsyms_offsets[];
 extern const u8 kallsyms_names[];
 
 extern const unsigned int kallsyms_num_syms;
-extern const unsigned long kallsyms_relative_base;
 
 extern const char kallsyms_token_table[];
 extern const u16 kallsyms_token_index[];
index fe9bf8db1922e6a269e3d4034b238266751dcbcb..f114719f6cb561b2d4b5bd5453e8e957aeb7ba0c 100644 (file)
@@ -238,7 +238,6 @@ static int __init crash_save_vmcoreinfo_init(void)
        VMCOREINFO_SYMBOL(kallsyms_token_table);
        VMCOREINFO_SYMBOL(kallsyms_token_index);
        VMCOREINFO_SYMBOL(kallsyms_offsets);
-       VMCOREINFO_SYMBOL(kallsyms_relative_base);
 #endif /* CONFIG_KALLSYMS */
 
        arch_crash_save_vmcoreinfo();
index 4b0234e4b12f3275491257f954f46ee6efacaab8..37d5c095ad22a5b6fa7e2fb37b4dc09781ff4917 100644 (file)
@@ -46,7 +46,6 @@ struct addr_range {
 };
 
 static unsigned long long _text;
-static unsigned long long relative_base;
 static struct addr_range text_ranges[] = {
        { "_stext",     "_etext"     },
        { "_sinittext", "_einittext" },
@@ -57,6 +56,7 @@ static struct addr_range text_ranges[] = {
 static struct sym_entry **table;
 static unsigned int table_size, table_cnt;
 static int all_symbols;
+static int pc_relative;
 
 static int token_profit[0x10000];
 
@@ -280,7 +280,7 @@ static void read_map(const char *in)
 static void output_label(const char *label)
 {
        printf(".globl %s\n", label);
-       printf("\tALGN\n");
+       printf("\t.balign 4\n");
        printf("%s:\n", label);
 }
 
@@ -343,15 +343,6 @@ static void write_src(void)
        unsigned int *markers, markers_cnt;
        char buf[KSYM_NAME_LEN];
 
-       printf("#include <asm/bitsperlong.h>\n");
-       printf("#if BITS_PER_LONG == 64\n");
-       printf("#define PTR .quad\n");
-       printf("#define ALGN .balign 8\n");
-       printf("#else\n");
-       printf("#define PTR .long\n");
-       printf("#define ALGN .balign 4\n");
-       printf("#endif\n");
-
        printf("\t.section .rodata, \"a\"\n");
 
        output_label("kallsyms_num_syms");
@@ -434,34 +425,24 @@ static void write_src(void)
        output_label("kallsyms_offsets");
 
        for (i = 0; i < table_cnt; i++) {
-               /*
-                * Use the offset relative to the lowest value
-                * encountered of all relative symbols, and emit
-                * non-relocatable fixed offsets that will be fixed
-                * up at runtime.
-                */
-
-               long long offset;
-
-               offset = table[i]->addr - relative_base;
-               if (offset < 0 || offset > UINT_MAX) {
-                       fprintf(stderr, "kallsyms failure: "
-                               "relative symbol value %#llx out of range\n",
-                               table[i]->addr);
-                       exit(EXIT_FAILURE);
+               if (pc_relative) {
+                       long long offset = table[i]->addr - _text;
+
+                       if (offset < INT_MIN || offset > INT_MAX) {
+                               fprintf(stderr, "kallsyms failure: "
+                                       "relative symbol value %#llx out of range\n",
+                                       table[i]->addr);
+                               exit(EXIT_FAILURE);
+                       }
+                       printf("\t.long\t_text - . + (%d)\t/* %s */\n",
+                              (int)offset, table[i]->sym);
+               } else {
+                       printf("\t.long\t%#x\t/* %s */\n",
+                              (unsigned int)table[i]->addr, table[i]->sym);
                }
-               printf("\t.long\t%#x\t/* %s */\n", (int)offset, table[i]->sym);
        }
        printf("\n");
 
-       output_label("kallsyms_relative_base");
-       /* Provide proper symbols relocatability by their '_text' relativeness. */
-       if (_text <= relative_base)
-               printf("\tPTR\t_text + %#llx\n", relative_base - _text);
-       else
-               printf("\tPTR\t_text - %#llx\n", _text - relative_base);
-       printf("\n");
-
        sort_symbols_by_name();
        output_label("kallsyms_seqs_of_names");
        for (i = 0; i < table_cnt; i++)
@@ -701,22 +682,12 @@ static void sort_symbols(void)
        qsort(table, table_cnt, sizeof(table[0]), compare_symbols);
 }
 
-/* find the minimum non-absolute symbol address */
-static void record_relative_base(void)
-{
-       /*
-        * The table is sorted by address.
-        * Take the first symbol value.
-        */
-       if (table_cnt)
-               relative_base = table[0]->addr;
-}
-
 int main(int argc, char **argv)
 {
        while (1) {
                static const struct option long_options[] = {
                        {"all-symbols",     no_argument, &all_symbols,     1},
+                       {"pc-relative",     no_argument, &pc_relative,     1},
                        {},
                };
 
@@ -734,7 +705,6 @@ int main(int argc, char **argv)
        read_map(argv[optind]);
        shrink_table();
        sort_symbols();
-       record_relative_base();
        optimize_token_table();
        write_src();
 
index 4ab44c73da4df43630a1b8ed58dc2a43a910243f..73531cb63efcb362f34d8f1d1332e1b382992db2 100755 (executable)
@@ -143,6 +143,10 @@ kallsyms()
                kallsymopt="${kallsymopt} --all-symbols"
        fi
 
+       if is_enabled CONFIG_64BIT || is_enabled CONFIG_RELOCATABLE; then
+               kallsymopt="${kallsymopt} --pc-relative"
+       fi
+
        info KSYMS "${2}.S"
        scripts/kallsyms ${kallsymopt} "${1}" > "${2}.S"
 
index 74cdbd2ce9d0acbd420e10afd0886d33ae24ca09..524d46478364d9dd9e2c4d8e59c1a66480595991 100644 (file)
@@ -27,7 +27,6 @@ static bool is_ignored_symbol(const char *name, char type)
                 * stable symbol list.
                 */
                "kallsyms_offsets",
-               "kallsyms_relative_base",
                "kallsyms_num_syms",
                "kallsyms_names",
                "kallsyms_markers",