diff --git a/arch/Kconfig b/arch/Kconfig index 4572791825b6..0b4e93b91568 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -497,7 +497,7 @@ config LTO_NONE config LTO_CLANG bool "Use clang Link Time Optimization (LTO) (EXPERIMENTAL)" depends on ARCH_SUPPORTS_LTO_CLANG - depends on !FTRACE_MCOUNT_RECORD + depends on !FTRACE_MCOUNT_RECORD || HAVE_C_RECORDMCOUNT depends on CC_IS_CLANG && LD_IS_LLD select LTO help diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 65cbde21a9f4..f12e43993d66 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -492,6 +492,7 @@ ALIGN_FUNCTION(); \ *(.text.hot TEXT_MAIN .text.fixup .text.unlikely) \ *(.text..refcount) \ + *(.text..ftrace) \ *(.ref.text) \ MEM_KEEP(init.text*) \ MEM_KEEP(exit.text*) \ diff --git a/include/linux/compiler-clang.h b/include/linux/compiler-clang.h index d756f2318efe..64eb811a11e4 100644 --- a/include/linux/compiler-clang.h +++ b/include/linux/compiler-clang.h @@ -43,3 +43,10 @@ #define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0])) #define __assume_aligned(a, ...) \ __attribute__((__assume_aligned__(a, ## __VA_ARGS__))) + +#ifdef CONFIG_LTO_CLANG +#ifdef CONFIG_FTRACE_MCOUNT_RECORD +#define __norecordmcount \ + __attribute__((__section__(".text..ftrace"))) +#endif +#endif diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h index db192becfec4..4f498e3cc760 100644 --- a/include/linux/compiler_types.h +++ b/include/linux/compiler_types.h @@ -248,6 +248,10 @@ struct ftrace_likely_data { # define __gnu_inline #endif +#ifndef __norecordmcount +#define __norecordmcount +#endif + /* * Force always-inline if the user requests it so via the .config. * GCC does not warn about unused static inline functions for diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 1688782f3dfb..8edbec4ec3fe 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -5500,9 +5500,9 @@ static int ftrace_cmp_ips(const void *a, const void *b) return 0; } -static int ftrace_process_locs(struct module *mod, - unsigned long *start, - unsigned long *end) +static int __norecordmcount ftrace_process_locs(struct module *mod, + unsigned long *start, + unsigned long *end) { struct ftrace_page *start_pg; struct ftrace_page *pg; diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 30b9860ece7b..585ea170818f 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -223,6 +223,12 @@ ifdef BUILD_C_RECORDMCOUNT ifeq ("$(origin RECORDMCOUNT_WARN)", "command line") RECORDMCOUNT_FLAGS = -w endif + +ifdef CONFIG_LTO_CLANG +# With LTO, we postpone running recordmcount until after the LTO link step, so +# let's export the parameters for the link script. +export RECORDMCOUNT_FLAGS +else # Due to recursion, we must skip empty.o. # The empty.o file is created in the make process in order to determine # the target endianness and word size. It is made before all other C @@ -231,22 +237,28 @@ sub_cmd_record_mcount = \ if [ $(@) != "scripts/mod/empty.o" ]; then \ $(objtree)/scripts/recordmcount $(RECORDMCOUNT_FLAGS) "$(@)"; \ fi; +endif + recordmcount_source := $(srctree)/scripts/recordmcount.c \ $(srctree)/scripts/recordmcount.h -else +else # !BUILD_C_RECORDMCOUNT sub_cmd_record_mcount = set -e ; perl $(srctree)/scripts/recordmcount.pl "$(ARCH)" \ "$(if $(CONFIG_CPU_BIG_ENDIAN),big,little)" \ "$(if $(CONFIG_64BIT),64,32)" \ "$(OBJDUMP)" "$(OBJCOPY)" "$(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS)" \ "$(LD) $(KBUILD_LDFLAGS)" "$(NM)" "$(RM)" "$(MV)" \ "$(if $(part-of-module),1,0)" "$(@)"; + recordmcount_source := $(srctree)/scripts/recordmcount.pl endif # BUILD_C_RECORDMCOUNT + +ifndef CONFIG_LTO_CLANG cmd_record_mcount = \ if [ "$(findstring $(CC_FLAGS_FTRACE),$(_c_flags))" = \ "$(CC_FLAGS_FTRACE)" ]; then \ $(sub_cmd_record_mcount) \ fi; +endif # CONFIG_LTO_CLANG endif # CC_USING_RECORD_MCOUNT endif # CONFIG_FTRACE_MCOUNT_RECORD diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost index dc2d4be47ac8..1771a311ad66 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -143,6 +143,10 @@ ifdef CONFIG_LTO_CLANG echo -T $(@:.ko=.o.symversions)) \ -o $@ --whole-archive \ $(filter-out FORCE,$(^:$(modpost-ext).o=.o)) + + ifdef CONFIG_FTRACE_MCOUNT_RECORD + cmd_ld_ko_o += ; $(objtree)/scripts/recordmcount $(RECORDMCOUNT_FLAGS) $@ + endif else cmd_ld_ko_o = \ $(LD) -r $(KBUILD_LDFLAGS) \ diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index a64e3fd412ab..b6473a89bd4b 100755 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -116,6 +116,19 @@ modpost_link() ${LD} ${KBUILD_LDFLAGS} -r -o ${1} $(modversions) ${objects} } +# If CONFIG_LTO_CLANG is selected, we postpone running recordmcount until +# we have compiled LLVM IR to an object file. +recordmcount() +{ + if [ -z "${CONFIG_LTO_CLANG}" ]; then + return + fi + + if [ -n "${CONFIG_FTRACE_MCOUNT_RECORD}" ]; then + scripts/recordmcount ${RECORDMCOUNT_FLAGS} $* + fi +} + # Link of vmlinux # ${1} - optional extra .o files # ${2} - output file @@ -270,6 +283,11 @@ modpost_link vmlinux.o # modpost vmlinux.o to check for section mismatches ${MAKE} -f "${srctree}/scripts/Makefile.modpost" vmlinux.o +if [ -n "${CONFIG_LTO_CLANG}" ]; then + # Call recordmcount if needed + recordmcount vmlinux.o +fi + kallsymso="" kallsyms_vmlinux="" if [ -n "${CONFIG_KALLSYMS}" ]; then diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c index 895c40e8679f..7a9ad239da57 100644 --- a/scripts/recordmcount.c +++ b/scripts/recordmcount.c @@ -406,7 +406,8 @@ is_mcounted_section_name(char const *const txtname) strcmp(".softirqentry.text", txtname) == 0 || strcmp(".kprobes.text", txtname) == 0 || strcmp(".cpuidle.text", txtname) == 0 || - strcmp(".text.unlikely", txtname) == 0; + (strncmp(".text.", txtname, 6) == 0 && + strcmp(".text..ftrace", txtname) != 0); } /* 32 bit and 64 bit are very similar */