FROMLIST: init: lto: fix PREL32 relocations
With LTO, the compiler can rename static functions to avoid global naming collisions. As initcall functions are typically static, renaming can break references to them in inline assembly. This change adds a global stub with a stable name for each initcall to fix the issue when PREL32 relocations are used. Bug: 145210207 Change-Id: I4e82728d472c72236cf1374300b5b71d53712687 Link: https://lore.kernel.org/lkml/20201211184633.3213045-9-samitolvanen@google.com/ Signed-off-by: Sami Tolvanen <samitolvanen@google.com> Reviewed-by: Kees Cook <keescook@chromium.org>
This commit is contained in:
@@ -209,26 +209,49 @@ extern bool initcall_debug;
|
||||
*/
|
||||
#define __initcall_section(__sec, __iid) \
|
||||
#__sec ".init.." #__iid
|
||||
|
||||
/*
|
||||
* With LTO, the compiler can rename static functions to avoid
|
||||
* global naming collisions. We use a global stub function for
|
||||
* initcalls to create a stable symbol name whose address can be
|
||||
* taken in inline assembly when PREL32 relocations are used.
|
||||
*/
|
||||
#define __initcall_stub(fn, __iid, id) \
|
||||
__initcall_name(initstub, __iid, id)
|
||||
|
||||
#define __define_initcall_stub(__stub, fn) \
|
||||
int __init __stub(void); \
|
||||
int __init __stub(void) \
|
||||
{ \
|
||||
return fn(); \
|
||||
} \
|
||||
__ADDRESSABLE(__stub)
|
||||
#else
|
||||
#define __initcall_section(__sec, __iid) \
|
||||
#__sec ".init"
|
||||
|
||||
#define __initcall_stub(fn, __iid, id) fn
|
||||
|
||||
#define __define_initcall_stub(__stub, fn) \
|
||||
__ADDRESSABLE(fn)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
|
||||
#define ____define_initcall(fn, __name, __sec) \
|
||||
__ADDRESSABLE(fn) \
|
||||
#define ____define_initcall(fn, __stub, __name, __sec) \
|
||||
__define_initcall_stub(__stub, fn) \
|
||||
asm(".section \"" __sec "\", \"a\" \n" \
|
||||
__stringify(__name) ": \n" \
|
||||
".long " #fn " - . \n" \
|
||||
".long " __stringify(__stub) " - . \n" \
|
||||
".previous \n");
|
||||
#else
|
||||
#define ____define_initcall(fn, __name, __sec) \
|
||||
#define ____define_initcall(fn, __unused, __name, __sec) \
|
||||
static initcall_t __name __used \
|
||||
__attribute__((__section__(__sec))) = fn;
|
||||
#endif
|
||||
|
||||
#define __unique_initcall(fn, id, __sec, __iid) \
|
||||
____define_initcall(fn, \
|
||||
__initcall_stub(fn, __iid, id), \
|
||||
__initcall_name(initcall, __iid, id), \
|
||||
__initcall_section(__sec, __iid))
|
||||
|
||||
|
Reference in New Issue
Block a user