Skip to content

Commit 7290d58

Browse files
Ard Biesheuveltorvalds
authored andcommitted
module: use relative references for __ksymtab entries
An ordinary arm64 defconfig build has ~64 KB worth of __ksymtab entries, each consisting of two 64-bit fields containing absolute references, to the symbol itself and to a char array containing its name, respectively. When we build the same configuration with KASLR enabled, we end up with an additional ~192 KB of relocations in the .init section, i.e., one 24 byte entry for each absolute reference, which all need to be processed at boot time. Given how the struct kernel_symbol that describes each entry is completely local to module.c (except for the references emitted by EXPORT_SYMBOL() itself), we can easily modify it to contain two 32-bit relative references instead. This reduces the size of the __ksymtab section by 50% for all 64-bit architectures, and gets rid of the runtime relocations entirely for architectures implementing KASLR, either via standard PIE linking (arm64) or using custom host tools (x86). Note that the binary search involving __ksymtab contents relies on each section being sorted by symbol name. This is implemented based on the input section names, not the names in the ksymtab entries, so this patch does not interfere with that. Given that the use of place-relative relocations requires support both in the toolchain and in the module loader, we cannot enable this feature for all architectures. So make it dependent on whether CONFIG_HAVE_ARCH_PREL32_RELOCATIONS is defined. Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Ard Biesheuvel <[email protected]> Acked-by: Jessica Yu <[email protected]> Acked-by: Michael Ellerman <[email protected]> Reviewed-by: Will Deacon <[email protected]> Acked-by: Ingo Molnar <[email protected]> Cc: Arnd Bergmann <[email protected]> Cc: Benjamin Herrenschmidt <[email protected]> Cc: Bjorn Helgaas <[email protected]> Cc: Catalin Marinas <[email protected]> Cc: James Morris <[email protected]> Cc: James Morris <[email protected]> Cc: Josh Poimboeuf <[email protected]> Cc: Kees Cook <[email protected]> Cc: Nicolas Pitre <[email protected]> Cc: Paul Mackerras <[email protected]> Cc: Petr Mladek <[email protected]> Cc: Russell King <[email protected]> Cc: "Serge E. Hallyn" <[email protected]> Cc: Sergey Senozhatsky <[email protected]> Cc: Steven Rostedt <[email protected]> Cc: Thomas Garnier <[email protected]> Cc: Thomas Gleixner <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent f922c4a commit 7290d58

File tree

6 files changed

+91
-24
lines changed

6 files changed

+91
-24
lines changed

arch/x86/include/asm/Kbuild

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@ generated-y += xen-hypercalls.h
88

99
generic-y += dma-contiguous.h
1010
generic-y += early_ioremap.h
11+
generic-y += export.h
1112
generic-y += mcs_spinlock.h
1213
generic-y += mm-arch-hooks.h

arch/x86/include/asm/export.h

Lines changed: 0 additions & 5 deletions
This file was deleted.

include/asm-generic/export.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,10 @@
55
#define KSYM_FUNC(x) x
66
#endif
77
#ifdef CONFIG_64BIT
8-
#define __put .quad
98
#ifndef KSYM_ALIGN
109
#define KSYM_ALIGN 8
1110
#endif
1211
#else
13-
#define __put .long
1412
#ifndef KSYM_ALIGN
1513
#define KSYM_ALIGN 4
1614
#endif
@@ -19,6 +17,16 @@
1917
#define KCRC_ALIGN 4
2018
#endif
2119

20+
.macro __put, val, name
21+
#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
22+
.long \val - ., \name - .
23+
#elif defined(CONFIG_64BIT)
24+
.quad \val, \name
25+
#else
26+
.long \val, \name
27+
#endif
28+
.endm
29+
2230
/*
2331
* note on .section use: @progbits vs %progbits nastiness doesn't matter,
2432
* since we immediately emit into those sections anyway.

include/linux/compiler.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,25 @@ unsigned long read_word_at_a_time(const void *addr)
280280

281281
#endif /* __KERNEL__ */
282282

283+
/*
284+
* Force the compiler to emit 'sym' as a symbol, so that we can reference
285+
* it from inline assembler. Necessary in case 'sym' could be inlined
286+
* otherwise, or eliminated entirely due to lack of references that are
287+
* visible to the compiler.
288+
*/
289+
#define __ADDRESSABLE(sym) \
290+
static void * __attribute__((section(".discard.addressable"), used)) \
291+
__PASTE(__addressable_##sym, __LINE__) = (void *)&sym;
292+
293+
/**
294+
* offset_to_ptr - convert a relative memory offset to an absolute pointer
295+
* @off: the address of the 32-bit offset value
296+
*/
297+
static inline void *offset_to_ptr(const int *off)
298+
{
299+
return (void *)((unsigned long)off + *off);
300+
}
301+
283302
#endif /* __ASSEMBLY__ */
284303

285304
#ifndef __optimize

include/linux/export.h

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,6 @@
1818
#define VMLINUX_SYMBOL_STR(x) __VMLINUX_SYMBOL_STR(x)
1919

2020
#ifndef __ASSEMBLY__
21-
struct kernel_symbol
22-
{
23-
unsigned long value;
24-
const char *name;
25-
};
26-
2721
#ifdef MODULE
2822
extern struct module __this_module;
2923
#define THIS_MODULE (&__this_module)
@@ -54,17 +48,47 @@ extern struct module __this_module;
5448
#define __CRC_SYMBOL(sym, sec)
5549
#endif
5650

51+
#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
52+
#include <linux/compiler.h>
53+
/*
54+
* Emit the ksymtab entry as a pair of relative references: this reduces
55+
* the size by half on 64-bit architectures, and eliminates the need for
56+
* absolute relocations that require runtime processing on relocatable
57+
* kernels.
58+
*/
59+
#define __KSYMTAB_ENTRY(sym, sec) \
60+
__ADDRESSABLE(sym) \
61+
asm(" .section \"___ksymtab" sec "+" #sym "\", \"a\" \n" \
62+
" .balign 8 \n" \
63+
"__ksymtab_" #sym ": \n" \
64+
" .long " #sym "- . \n" \
65+
" .long __kstrtab_" #sym "- . \n" \
66+
" .previous \n")
67+
68+
struct kernel_symbol {
69+
int value_offset;
70+
int name_offset;
71+
};
72+
#else
73+
#define __KSYMTAB_ENTRY(sym, sec) \
74+
static const struct kernel_symbol __ksymtab_##sym \
75+
__attribute__((section("___ksymtab" sec "+" #sym), used)) \
76+
= { (unsigned long)&sym, __kstrtab_##sym }
77+
78+
struct kernel_symbol {
79+
unsigned long value;
80+
const char *name;
81+
};
82+
#endif
83+
5784
/* For every exported symbol, place a struct in the __ksymtab section */
5885
#define ___EXPORT_SYMBOL(sym, sec) \
5986
extern typeof(sym) sym; \
6087
__CRC_SYMBOL(sym, sec) \
6188
static const char __kstrtab_##sym[] \
62-
__attribute__((section("__ksymtab_strings"), aligned(1))) \
89+
__attribute__((section("__ksymtab_strings"), used, aligned(1))) \
6390
= #sym; \
64-
static const struct kernel_symbol __ksymtab_##sym \
65-
__used \
66-
__attribute__((section("___ksymtab" sec "+" #sym), used)) \
67-
= { (unsigned long)&sym, __kstrtab_##sym }
91+
__KSYMTAB_ENTRY(sym, sec)
6892

6993
#if defined(__DISABLE_EXPORTS)
7094

kernel/module.c

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -529,12 +529,30 @@ static bool check_symbol(const struct symsearch *syms,
529529
return true;
530530
}
531531

532+
static unsigned long kernel_symbol_value(const struct kernel_symbol *sym)
533+
{
534+
#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
535+
return (unsigned long)offset_to_ptr(&sym->value_offset);
536+
#else
537+
return sym->value;
538+
#endif
539+
}
540+
541+
static const char *kernel_symbol_name(const struct kernel_symbol *sym)
542+
{
543+
#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
544+
return offset_to_ptr(&sym->name_offset);
545+
#else
546+
return sym->name;
547+
#endif
548+
}
549+
532550
static int cmp_name(const void *va, const void *vb)
533551
{
534552
const char *a;
535553
const struct kernel_symbol *b;
536554
a = va; b = vb;
537-
return strcmp(a, b->name);
555+
return strcmp(a, kernel_symbol_name(b));
538556
}
539557

540558
static bool find_symbol_in_section(const struct symsearch *syms,
@@ -2170,7 +2188,7 @@ void *__symbol_get(const char *symbol)
21702188
sym = NULL;
21712189
preempt_enable();
21722190

2173-
return sym ? (void *)sym->value : NULL;
2191+
return sym ? (void *)kernel_symbol_value(sym) : NULL;
21742192
}
21752193
EXPORT_SYMBOL_GPL(__symbol_get);
21762194

@@ -2200,10 +2218,12 @@ static int verify_export_symbols(struct module *mod)
22002218

22012219
for (i = 0; i < ARRAY_SIZE(arr); i++) {
22022220
for (s = arr[i].sym; s < arr[i].sym + arr[i].num; s++) {
2203-
if (find_symbol(s->name, &owner, NULL, true, false)) {
2221+
if (find_symbol(kernel_symbol_name(s), &owner, NULL,
2222+
true, false)) {
22042223
pr_err("%s: exports duplicate symbol %s"
22052224
" (owned by %s)\n",
2206-
mod->name, s->name, module_name(owner));
2225+
mod->name, kernel_symbol_name(s),
2226+
module_name(owner));
22072227
return -ENOEXEC;
22082228
}
22092229
}
@@ -2252,7 +2272,7 @@ static int simplify_symbols(struct module *mod, const struct load_info *info)
22522272
ksym = resolve_symbol_wait(mod, info, name);
22532273
/* Ok if resolved. */
22542274
if (ksym && !IS_ERR(ksym)) {
2255-
sym[i].st_value = ksym->value;
2275+
sym[i].st_value = kernel_symbol_value(ksym);
22562276
break;
22572277
}
22582278

@@ -2516,7 +2536,7 @@ static int is_exported(const char *name, unsigned long value,
25162536
ks = lookup_symbol(name, __start___ksymtab, __stop___ksymtab);
25172537
else
25182538
ks = lookup_symbol(name, mod->syms, mod->syms + mod->num_syms);
2519-
return ks != NULL && ks->value == value;
2539+
return ks != NULL && kernel_symbol_value(ks) == value;
25202540
}
25212541

25222542
/* As per nm */

0 commit comments

Comments
 (0)