Skip to content

Commit dc5723b

Browse files
samitolvanenkees
authored andcommitted
kbuild: add support for Clang LTO
This change adds build system support for Clang's Link Time Optimization (LTO). With -flto, instead of ELF object files, Clang produces LLVM bitcode, which is compiled into native code at link time, allowing the final binary to be optimized globally. For more details, see: https://llvm.org/docs/LinkTimeOptimization.html The Kconfig option CONFIG_LTO_CLANG is implemented as a choice, which defaults to LTO being disabled. To use LTO, the architecture must select ARCH_SUPPORTS_LTO_CLANG and support: - compiling with Clang, - compiling all assembly code with Clang's integrated assembler, - and linking with LLD. While using CONFIG_LTO_CLANG_FULL results in the best runtime performance, the compilation is not scalable in time or memory. CONFIG_LTO_CLANG_THIN enables ThinLTO, which allows parallel optimization and faster incremental builds. ThinLTO is used by default if the architecture also selects ARCH_SUPPORTS_LTO_CLANG_THIN: https://clang.llvm.org/docs/ThinLTO.html To enable LTO, LLVM tools must be used to handle bitcode files, by passing LLVM=1 and LLVM_IAS=1 options to make: $ make LLVM=1 LLVM_IAS=1 defconfig $ scripts/config -e LTO_CLANG_THIN $ make LLVM=1 LLVM_IAS=1 To prepare for LTO support with other compilers, common parts are gated behind the CONFIG_LTO option, and LTO can be disabled for specific files by filtering out CC_FLAGS_LTO. Signed-off-by: Sami Tolvanen <[email protected]> Reviewed-by: Kees Cook <[email protected]> Signed-off-by: Kees Cook <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 3b15cdc commit dc5723b

File tree

7 files changed

+174
-18
lines changed

7 files changed

+174
-18
lines changed

Makefile

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -893,6 +893,21 @@ KBUILD_CFLAGS += $(CC_FLAGS_SCS)
893893
export CC_FLAGS_SCS
894894
endif
895895

896+
ifdef CONFIG_LTO_CLANG
897+
ifdef CONFIG_LTO_CLANG_THIN
898+
CC_FLAGS_LTO += -flto=thin -fsplit-lto-unit
899+
KBUILD_LDFLAGS += --thinlto-cache-dir=$(extmod-prefix).thinlto-cache
900+
else
901+
CC_FLAGS_LTO += -flto
902+
endif
903+
CC_FLAGS_LTO += -fvisibility=hidden
904+
endif
905+
906+
ifdef CONFIG_LTO
907+
KBUILD_CFLAGS += $(CC_FLAGS_LTO)
908+
export CC_FLAGS_LTO
909+
endif
910+
896911
ifdef CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_32B
897912
KBUILD_CFLAGS += -falign-functions=32
898913
endif
@@ -1479,7 +1494,7 @@ MRPROPER_FILES += include/config include/generated \
14791494
*.spec
14801495

14811496
# Directories & files removed with 'make distclean'
1482-
DISTCLEAN_FILES += tags TAGS cscope* GPATH GTAGS GRTAGS GSYMS
1497+
DISTCLEAN_FILES += tags TAGS cscope* GPATH GTAGS GRTAGS GSYMS .thinlto-cache
14831498

14841499
# clean - Delete most, but leave enough to build external modules
14851500
#
@@ -1725,7 +1740,7 @@ PHONY += compile_commands.json
17251740

17261741
clean-dirs := $(KBUILD_EXTMOD)
17271742
clean: rm-files := $(KBUILD_EXTMOD)/Module.symvers $(KBUILD_EXTMOD)/modules.nsdeps \
1728-
$(KBUILD_EXTMOD)/compile_commands.json
1743+
$(KBUILD_EXTMOD)/compile_commands.json $(KBUILD_EXTMOD)/.thinlto-cache
17291744

17301745
PHONY += help
17311746
help:

arch/Kconfig

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,97 @@ config SHADOW_CALL_STACK
631631
reading and writing arbitrary memory may be able to locate them
632632
and hijack control flow by modifying the stacks.
633633

634+
config LTO
635+
bool
636+
help
637+
Selected if the kernel will be built using the compiler's LTO feature.
638+
639+
config LTO_CLANG
640+
bool
641+
select LTO
642+
help
643+
Selected if the kernel will be built using Clang's LTO feature.
644+
645+
config ARCH_SUPPORTS_LTO_CLANG
646+
bool
647+
help
648+
An architecture should select this option if it supports:
649+
- compiling with Clang,
650+
- compiling inline assembly with Clang's integrated assembler,
651+
- and linking with LLD.
652+
653+
config ARCH_SUPPORTS_LTO_CLANG_THIN
654+
bool
655+
help
656+
An architecture should select this option if it can support Clang's
657+
ThinLTO mode.
658+
659+
config HAS_LTO_CLANG
660+
def_bool y
661+
# Clang >= 11: https://github.com/ClangBuiltLinux/linux/issues/510
662+
depends on CC_IS_CLANG && CLANG_VERSION >= 110000 && LD_IS_LLD
663+
depends on $(success,test $(LLVM) -eq 1)
664+
depends on $(success,test $(LLVM_IAS) -eq 1)
665+
depends on $(success,$(NM) --help | head -n 1 | grep -qi llvm)
666+
depends on $(success,$(AR) --help | head -n 1 | grep -qi llvm)
667+
depends on ARCH_SUPPORTS_LTO_CLANG
668+
depends on !FTRACE_MCOUNT_USE_RECORDMCOUNT
669+
depends on !KASAN
670+
depends on !GCOV_KERNEL
671+
depends on !MODVERSIONS
672+
help
673+
The compiler and Kconfig options support building with Clang's
674+
LTO.
675+
676+
choice
677+
prompt "Link Time Optimization (LTO)"
678+
default LTO_NONE
679+
help
680+
This option enables Link Time Optimization (LTO), which allows the
681+
compiler to optimize binaries globally.
682+
683+
If unsure, select LTO_NONE. Note that LTO is very resource-intensive
684+
so it's disabled by default.
685+
686+
config LTO_NONE
687+
bool "None"
688+
help
689+
Build the kernel normally, without Link Time Optimization (LTO).
690+
691+
config LTO_CLANG_FULL
692+
bool "Clang Full LTO (EXPERIMENTAL)"
693+
depends on HAS_LTO_CLANG
694+
depends on !COMPILE_TEST
695+
select LTO_CLANG
696+
help
697+
This option enables Clang's full Link Time Optimization (LTO), which
698+
allows the compiler to optimize the kernel globally. If you enable
699+
this option, the compiler generates LLVM bitcode instead of ELF
700+
object files, and the actual compilation from bitcode happens at
701+
the LTO link step, which may take several minutes depending on the
702+
kernel configuration. More information can be found from LLVM's
703+
documentation:
704+
705+
https://llvm.org/docs/LinkTimeOptimization.html
706+
707+
During link time, this option can use a large amount of RAM, and
708+
may take much longer than the ThinLTO option.
709+
710+
config LTO_CLANG_THIN
711+
bool "Clang ThinLTO (EXPERIMENTAL)"
712+
depends on HAS_LTO_CLANG && ARCH_SUPPORTS_LTO_CLANG_THIN
713+
select LTO_CLANG
714+
help
715+
This option enables Clang's ThinLTO, which allows for parallel
716+
optimization and faster incremental compiles compared to the
717+
CONFIG_LTO_CLANG_FULL option. More information can be found
718+
from Clang's documentation:
719+
720+
https://clang.llvm.org/docs/ThinLTO.html
721+
722+
If unsure, say Y.
723+
endchoice
724+
634725
config HAVE_ARCH_WITHIN_STACK_FRAMES
635726
bool
636727
help

include/asm-generic/vmlinux.lds.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,15 +90,18 @@
9090
* .data. We don't want to pull in .data..other sections, which Linux
9191
* has defined. Same for text and bss.
9292
*
93+
* With LTO_CLANG, the linker also splits sections by default, so we need
94+
* these macros to combine the sections during the final link.
95+
*
9396
* RODATA_MAIN is not used because existing code already defines .rodata.x
9497
* sections to be brought in with rodata.
9598
*/
96-
#ifdef CONFIG_LD_DEAD_CODE_DATA_ELIMINATION
99+
#if defined(CONFIG_LD_DEAD_CODE_DATA_ELIMINATION) || defined(CONFIG_LTO_CLANG)
97100
#define TEXT_MAIN .text .text.[0-9a-zA-Z_]*
98-
#define DATA_MAIN .data .data.[0-9a-zA-Z_]* .data..LPBX*
101+
#define DATA_MAIN .data .data.[0-9a-zA-Z_]* .data..L* .data..compoundliteral*
99102
#define SDATA_MAIN .sdata .sdata.[0-9a-zA-Z_]*
100-
#define RODATA_MAIN .rodata .rodata.[0-9a-zA-Z_]*
101-
#define BSS_MAIN .bss .bss.[0-9a-zA-Z_]*
103+
#define RODATA_MAIN .rodata .rodata.[0-9a-zA-Z_]* .rodata..L*
104+
#define BSS_MAIN .bss .bss.[0-9a-zA-Z_]* .bss..compoundliteral*
102105
#define SBSS_MAIN .sbss .sbss.[0-9a-zA-Z_]*
103106
#else
104107
#define TEXT_MAIN .text

scripts/Makefile.build

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ endif
111111
# ---------------------------------------------------------------------------
112112

113113
quiet_cmd_cc_s_c = CC $(quiet_modtag) $@
114-
cmd_cc_s_c = $(CC) $(filter-out $(DEBUG_CFLAGS), $(c_flags)) -fverbose-asm -S -o $@ $<
114+
cmd_cc_s_c = $(CC) $(filter-out $(DEBUG_CFLAGS) $(CC_FLAGS_LTO), $(c_flags)) -fverbose-asm -S -o $@ $<
115115

116116
$(obj)/%.s: $(src)/%.c FORCE
117117
$(call if_changed_dep,cc_s_c)
@@ -421,8 +421,15 @@ $(obj)/lib.a: $(lib-y) FORCE
421421
# Do not replace $(filter %.o,^) with $(real-prereqs). When a single object
422422
# module is turned into a multi object module, $^ will contain header file
423423
# dependencies recorded in the .*.cmd file.
424+
ifdef CONFIG_LTO_CLANG
425+
quiet_cmd_link_multi-m = AR [M] $@
426+
cmd_link_multi-m = \
427+
rm -f $@; \
428+
$(AR) cDPrsT $@ $(filter %.o,$^)
429+
else
424430
quiet_cmd_link_multi-m = LD [M] $@
425431
cmd_link_multi-m = $(LD) $(ld_flags) -r -o $@ $(filter %.o,$^)
432+
endif
426433

427434
$(multi-used-m): FORCE
428435
$(call if_changed,link_multi-m)

scripts/Makefile.modfinal

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ quiet_cmd_cc_o_c = CC [M] $@
3030

3131
ARCH_POSTLINK := $(wildcard $(srctree)/arch/$(SRCARCH)/Makefile.postlink)
3232

33+
ifdef CONFIG_LTO_CLANG
34+
# With CONFIG_LTO_CLANG, reuse the object file we compiled for modpost to
35+
# avoid a second slow LTO link
36+
prelink-ext := .lto
37+
endif
38+
3339
quiet_cmd_ld_ko_o = LD [M] $@
3440
cmd_ld_ko_o = \
3541
$(LD) -r $(KBUILD_LDFLAGS) \
@@ -53,8 +59,9 @@ if_changed_except = $(if $(call newer_prereqs_except,$(2))$(cmd-check), \
5359
$(cmd); \
5460
printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd, @:)
5561

62+
5663
# Re-generate module BTFs if either module's .ko or vmlinux changed
57-
$(modules): %.ko: %.o %.mod.o scripts/module.lds $(if $(KBUILD_BUILTIN),vmlinux) FORCE
64+
$(modules): %.ko: %$(prelink-ext).o %.mod.o scripts/module.lds $(if $(KBUILD_BUILTIN),vmlinux) FORCE
5865
+$(call if_changed_except,ld_ko_o,vmlinux)
5966
ifdef CONFIG_DEBUG_INFO_BTF_MODULES
6067
+$(if $(newer-prereqs),$(call cmd,btf_ko))

scripts/Makefile.modpost

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ __modpost:
4343
include include/config/auto.conf
4444
include scripts/Kbuild.include
4545

46+
# for ld_flags
47+
include scripts/Makefile.lib
48+
4649
MODPOST = scripts/mod/modpost \
4750
$(if $(CONFIG_MODVERSIONS),-m) \
4851
$(if $(CONFIG_MODULE_SRCVERSION_ALL),-a) \
@@ -102,12 +105,26 @@ $(input-symdump):
102105
@echo >&2 'WARNING: Symbol version dump "$@" is missing.'
103106
@echo >&2 ' Modules may not have dependencies or modversions.'
104107

108+
ifdef CONFIG_LTO_CLANG
109+
# With CONFIG_LTO_CLANG, .o files might be LLVM bitcode, so we need to run
110+
# LTO to compile them into native code before running modpost
111+
prelink-ext := .lto
112+
113+
quiet_cmd_cc_lto_link_modules = LTO [M] $@
114+
cmd_cc_lto_link_modules = $(LD) $(ld_flags) -r -o $@ --whole-archive $^
115+
116+
%.lto.o: %.o
117+
$(call if_changed,cc_lto_link_modules)
118+
endif
119+
120+
modules := $(sort $(shell cat $(MODORDER)))
121+
105122
# Read out modules.order to pass in modpost.
106123
# Otherwise, allmodconfig would fail with "Argument list too long".
107124
quiet_cmd_modpost = MODPOST $@
108-
cmd_modpost = sed 's/ko$$/o/' $< | $(MODPOST) -T -
125+
cmd_modpost = sed 's/\.ko$$/$(prelink-ext)\.o/' $< | $(MODPOST) -T -
109126

110-
$(output-symdump): $(MODORDER) $(input-symdump) FORCE
127+
$(output-symdump): $(MODORDER) $(input-symdump) $(modules:.ko=$(prelink-ext).o) FORCE
111128
$(call if_changed,modpost)
112129

113130
targets += $(output-symdump)

scripts/link-vmlinux.sh

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,14 @@ modpost_link()
5656
${KBUILD_VMLINUX_LIBS} \
5757
--end-group"
5858

59+
if [ -n "${CONFIG_LTO_CLANG}" ]; then
60+
# This might take a while, so indicate that we're doing
61+
# an LTO link
62+
info LTO ${1}
63+
else
64+
info LD ${1}
65+
fi
66+
5967
${LD} ${KBUILD_LDFLAGS} -r -o ${1} ${objects}
6068
}
6169

@@ -103,13 +111,22 @@ vmlinux_link()
103111
fi
104112

105113
if [ "${SRCARCH}" != "um" ]; then
106-
objects="--whole-archive \
107-
${KBUILD_VMLINUX_OBJS} \
108-
--no-whole-archive \
109-
--start-group \
110-
${KBUILD_VMLINUX_LIBS} \
111-
--end-group \
112-
${@}"
114+
if [ -n "${CONFIG_LTO_CLANG}" ]; then
115+
# Use vmlinux.o instead of performing the slow LTO
116+
# link again.
117+
objects="--whole-archive \
118+
vmlinux.o \
119+
--no-whole-archive \
120+
${@}"
121+
else
122+
objects="--whole-archive \
123+
${KBUILD_VMLINUX_OBJS} \
124+
--no-whole-archive \
125+
--start-group \
126+
${KBUILD_VMLINUX_LIBS} \
127+
--end-group \
128+
${@}"
129+
fi
113130

114131
${LD} ${KBUILD_LDFLAGS} ${LDFLAGS_vmlinux} \
115132
${strip_debug#-Wl,} \
@@ -274,7 +291,6 @@ fi;
274291
${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init need-builtin=1
275292

276293
#link vmlinux.o
277-
info LD vmlinux.o
278294
modpost_link vmlinux.o
279295
objtool_link vmlinux.o
280296

0 commit comments

Comments
 (0)