lto, workaround: Add workaround for initcall reordering
authorAndi Kleen <ak@linux.intel.com>
Sat, 8 Feb 2014 08:01:08 +0000 (09:01 +0100)
committerH. Peter Anvin <hpa@linux.intel.com>
Fri, 14 Feb 2014 04:24:13 +0000 (20:24 -0800)
Work around a LTO gcc problem: when there is no reference to a variable
in a module it will be moved to the end of the program. This causes
reordering of initcalls which the kernel does not like.
Add a dummy reference function to avoid this. The function is
deleted by the linker.

This replaces a previous much slower workaround.

Thanks to Jan "Honza" Hubička for suggesting this technique.

Suggested-by: Jan Hubička <hubicka@ucw.cz>
Signed-off-by: Andi Kleen <ak@linux.intel.com>
Link: http://lkml.kernel.org/r/1391846481-31491-4-git-send-email-ak@linux.intel.com
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
include/linux/init.h

index e168880..a3ba270 100644 (file)
@@ -163,6 +163,23 @@ extern bool initcall_debug;
 
 #ifndef __ASSEMBLY__
 
+#ifdef CONFIG_LTO
+/* Work around a LTO gcc problem: when there is no reference to a variable
+ * in a module it will be moved to the end of the program. This causes
+ * reordering of initcalls which the kernel does not like.
+ * Add a dummy reference function to avoid this. The function is
+ * deleted by the linker.
+ */
+#define LTO_REFERENCE_INITCALL(x) \
+       ; /* yes this is needed */                      \
+       static __used __exit void *reference_##x(void)  \
+       {                                               \
+               return &x;                              \
+       }
+#else
+#define LTO_REFERENCE_INITCALL(x)
+#endif
+
 /* initcalls are now grouped by functionality into separate 
  * subsections. Ordering inside the subsections is determined
  * by link order. 
@@ -175,7 +192,8 @@ extern bool initcall_debug;
 
 #define __define_initcall(fn, id) \
        static initcall_t __initcall_##fn##id __used \
-       __attribute__((__section__(".initcall" #id ".init"))) = fn
+       __attribute__((__section__(".initcall" #id ".init"))) = fn; \
+       LTO_REFERENCE_INITCALL(__initcall_##fn##id)
 
 /*
  * Early initcalls run before initializing SMP.