Message ID | 20201013003203.4168817-17-samitolvanen@google.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Add support for Clang LTO | expand |
On Mon, Oct 12, 2020 at 05:31:54PM -0700, Sami Tolvanen wrote: > 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. > > Signed-off-by: Sami Tolvanen <samitolvanen@google.com> > Reviewed-by: Kees Cook <keescook@chromium.org> This is another independent improvement... this could land before the other portions of the series. -Kees > --- > include/linux/init.h | 31 +++++++++++++++++++++++++++---- > 1 file changed, 27 insertions(+), 4 deletions(-) > > diff --git a/include/linux/init.h b/include/linux/init.h > index af638cd6dd52..cea63f7e7705 100644 > --- a/include/linux/init.h > +++ b/include/linux/init.h > @@ -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)) > > -- > 2.28.0.1011.ga647a8990f-goog >
On Tue, Oct 13, 2020 at 2:34 AM Sami Tolvanen <samitolvanen@google.com> wrote: > 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. While I understand that this may be necessary for now, are there any plans to fix this in the compiler in the future? There was a thread about this issue at <http://lists.llvm.org/pipermail/llvm-dev/2016-April/thread.html#98047>, and possible solutions were discussed there, but it looks like that fizzled out...
diff --git a/include/linux/init.h b/include/linux/init.h index af638cd6dd52..cea63f7e7705 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -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))