From c1dc646f73bd948edbf0c4a7f1baa93ecf8c208e Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 6 Sep 2020 08:11:32 +0900 Subject: [PATCH] lto: test module Here is a great example for LTO: https://llvm.org/docs/LinkTimeOptimization.html LTO removes foo2() and foo3() from the final executable file, "main". (and foo4() is also dropped if you pass -flto to main.c) This patch integrates the example code into a kernel module. a.c -> kernel/lto-test-a.c main.c -> kernel/lto-test-main.c Of course, I replaced printf() with printk(). I applied this test patch on top of Sami's v2: https://patchwork.kernel.org/project/linux-kbuild/list/?series=343153 I compiled arm64 defconfig + CONFIG_LTO_CLANG. This is the result: $ aarch64-linux-gnu-nm kernel/lto-test.ko 0000000000000010 T foo1 0000000000000000 T foo2 000000000000004c T foo4 0000000000000000 B i.llvm.7710645642085602891 0000000000000000 r __kstrtab_lto_test_main 000000000000000e r __kstrtabns_lto_test_main 0000000000000000 r __ksymtab_lto_test_main 0000000000000068 T lto_test_main 0000000000000000 r _note_7 U printk 0000000000000000 R .str.llvm.887650332484512380 0000000000000000 D __this_module 0000000000000063 r __UNIQUE_ID_depends254 000000000000005a r __UNIQUE_ID_intree253 000000000000004c r __UNIQUE_ID_name252 0000000000000000 r __UNIQUE_ID_vermagic251 Modules are relocatable objects, not executables. How can clang LTO know unreachable symbols are really unreachable? According to the result above, foo2 is remaining. The behavior is the same for obj-y because LTO is run against vmlinux.o, which is a relocatable ELF. Signed-off-by: Masahiro Yamada --- kernel/Makefile | 3 +++ kernel/lto-test-a.c | 22 ++++++++++++++++++++++ kernel/lto-test-a.h | 3 +++ kernel/lto-test-main.c | 12 ++++++++++++ 4 files changed, 40 insertions(+) create mode 100644 kernel/lto-test-a.c create mode 100644 kernel/lto-test-a.h create mode 100644 kernel/lto-test-main.c diff --git a/kernel/Makefile b/kernel/Makefile index 9a20016d4900..2111251c2093 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -147,3 +147,6 @@ $(obj)/kheaders_data.tar.xz: FORCE $(call cmd,genikh) clean-files := kheaders_data.tar.xz kheaders.md5 + +obj-m += lto-test.o +lto-test-objs := lto-test-a.o lto-test-main.o diff --git a/kernel/lto-test-a.c b/kernel/lto-test-a.c new file mode 100644 index 000000000000..15cdc320ec1e --- /dev/null +++ b/kernel/lto-test-a.c @@ -0,0 +1,22 @@ +#include "lto-test-a.h" + +static signed int i = 0; + +void foo2(void) { + i = -1; +} + +static int foo3(void) { + foo4(); + return 10; +} + +int foo1(void) { + int data = 0; + + if (i < 0) + data = foo3(); + + data = data + 42; + return data; +} diff --git a/kernel/lto-test-a.h b/kernel/lto-test-a.h new file mode 100644 index 000000000000..fca4d13a52e0 --- /dev/null +++ b/kernel/lto-test-a.h @@ -0,0 +1,3 @@ +extern int foo1(void); +extern void foo2(void); +extern void foo4(void); diff --git a/kernel/lto-test-main.c b/kernel/lto-test-main.c new file mode 100644 index 000000000000..6e8caa2c7667 --- /dev/null +++ b/kernel/lto-test-main.c @@ -0,0 +1,12 @@ +#include +#include +#include "lto-test-a.h" + +void foo4(void) { + printk("Hi\n"); +} + +int lto_test_main(void) { + return foo1(); +} +EXPORT_SYMBOL(lto_test_main); -- 2.25.1