@@ -877,6 +877,24 @@ ifeq ($(CONFIG_LD_HAS_Z_UNIQUE_SYMBOL)$(CONFIG_LIVEPATCH),yy)
KBUILD_LDFLAGS += -z unique-symbol
endif
+# Allow ASM code to generate separate sections for each function. See
+# `include/linux/linkage.h` for explanation. This flag is to enable GAS to
+# insert the name of the previous section instead of `%S` inside .pushsection
+ifdef CONFIG_HAVE_ASM_FUNCTION_SECTIONS
+ifneq ($(CONFIG_LD_DEAD_CODE_DATA_ELIMINATION)$(CONFIG_LTO_CLANG),)
+SECSUBST_AFLAGS := -Wa,--sectname-subst
+KBUILD_AFLAGS_KERNEL += $(SECSUBST_AFLAGS)
+KBUILD_CFLAGS_KERNEL += $(SECSUBST_AFLAGS)
+export SECSUBST_AFLAGS
+endif
+
+# Same for modules. LD DCE doesn't work for them, thus not checking for it
+ifneq ($(CONFIG_LTO_CLANG),)
+KBUILD_AFLAGS_MODULE += -Wa,--sectname-subst
+KBUILD_CFLAGS_MODULE += -Wa,--sectname-subst
+endif
+endif # CONFIG_HAVE_ASM_FUNCTION_SECTIONS
+
ifdef CONFIG_LD_DEAD_CODE_DATA_ELIMINATION
KBUILD_CFLAGS_KERNEL += -ffunction-sections -fdata-sections
LDFLAGS_vmlinux += --gc-sections
@@ -1322,6 +1322,12 @@ config DYNAMIC_SIGFRAME
config HAVE_ARCH_NODE_DEV_GROUP
bool
+config ARCH_SUPPORTS_ASM_FUNCTION_SECTIONS
+ bool
+ help
+ An arch should select this if it can be built and run with its
+ asm functions placed into separate sections to improve DCE and LTO.
+
source "kernel/gcov/Kconfig"
source "scripts/gcc-plugins/Kconfig"
@@ -84,6 +84,9 @@
/* Align . to a 8 byte boundary equals to maximum function alignment. */
#define ALIGN_FUNCTION() . = ALIGN(8)
+/* This is useful for collecting individual sections back into one main */
+#define SECT_WILDCARD(sect) sect sect.[0-9a-zA-Z_]*
+
/*
* LD_DEAD_CODE_DATA_ELIMINATION option enables -fdata-sections, which
* generates .data.identifier sections, which need to be pulled in with
@@ -97,12 +100,12 @@
* sections to be brought in with rodata.
*/
#if defined(CONFIG_LD_DEAD_CODE_DATA_ELIMINATION) || defined(CONFIG_LTO_CLANG)
-#define TEXT_MAIN .text .text.[0-9a-zA-Z_]*
-#define DATA_MAIN .data .data.[0-9a-zA-Z_]* .data..L* .data..compoundliteral* .data.$__unnamed_* .data.$L*
-#define SDATA_MAIN .sdata .sdata.[0-9a-zA-Z_]*
-#define RODATA_MAIN .rodata .rodata.[0-9a-zA-Z_]* .rodata..L*
-#define BSS_MAIN .bss .bss.[0-9a-zA-Z_]* .bss..compoundliteral*
-#define SBSS_MAIN .sbss .sbss.[0-9a-zA-Z_]*
+#define TEXT_MAIN SECT_WILDCARD(.text)
+#define DATA_MAIN SECT_WILDCARD(.data) .data..L* .data..compoundliteral* .data.$__unnamed_* .data.$L*
+#define SDATA_MAIN SECT_WILDCARD(.sdata)
+#define RODATA_MAIN SECT_WILDCARD(.rodata) .rodata..L*
+#define BSS_MAIN SECT_WILDCARD(.bss) .bss..compoundliteral*
+#define SBSS_MAIN SECT_WILDCARD(.sbss)
#else
#define TEXT_MAIN .text
#define DATA_MAIN .data
@@ -564,7 +567,7 @@
#define NOINSTR_TEXT \
ALIGN_FUNCTION(); \
__noinstr_text_start = .; \
- *(.noinstr.text) \
+ *(SECT_WILDCARD(.noinstr.text)) \
__noinstr_text_end = .;
/*
@@ -621,7 +624,7 @@
#define ENTRY_TEXT \
ALIGN_FUNCTION(); \
__entry_text_start = .; \
- *(.entry.text) \
+ *(SECT_WILDCARD(.entry.text)) \
__entry_text_end = .;
#define IRQENTRY_TEXT \
@@ -643,7 +646,7 @@
__static_call_text_end = .;
/* Section used for early init (in .S files) */
-#define HEAD_TEXT KEEP(*(.head.text))
+#define HEAD_TEXT KEEP(*(SECT_WILDCARD(.head.text)))
#define HEAD_TEXT_SECTION \
.head.text : AT(ADDR(.head.text) - LOAD_OFFSET) { \
@@ -73,6 +73,38 @@
#define __ALIGN_STR ".align 4,0x90"
#endif
+/*
+ * Allow ASM symbols to have their own unique sections if they are being
+ * generated by the compiler for C functions (DCE, LTO). Correlates with
+ * the presence of the `-ffunction-section` in KBUILD_CFLAGS.
+ */
+#if defined(CONFIG_HAVE_ASM_FUNCTION_SECTIONS) && \
+ ((defined(CONFIG_LD_DEAD_CODE_DATA_ELIMINATION) && !defined(MODULE)) || \
+ (defined(CONFIG_LTO_CLANG)))
+
+#define SYM_PUSH_SECTION(name) \
+ .pushsection %S.name, "ax"
+
+#define SYM_POP_SECTION() \
+ .popsection
+
+#define __ASM_PUSH_SECTION(name) \
+ ".pushsection %S." name ", \"ax\""
+
+#else /* !(CONFIG_HAVE_ASM_FUNCTION_SECTIONS && (DCE || LTO)) */
+
+#define SYM_PUSH_SECTION(name)
+#define SYM_POP_SECTION()
+#define __ASM_PUSH_SECTION(name)
+
+#endif /* !(CONFIG_HAVE_ASM_FUNCTION_SECTIONS && (DCE || LTO)) */
+
+#define ASM_PUSH_SECTION(name) \
+ __ASM_PUSH_SECTION(__stringify(name))
+
+#define ASM_POP_SECTION() \
+ __stringify(SYM_POP_SECTION())
+
#ifdef __ASSEMBLY__
/* SYM_T_FUNC -- type used by assembler to mark functions */
@@ -209,6 +241,15 @@
SYM_START(name, SYM_L_LOCAL, SYM_A_ALIGN)
#endif
+/*
+ * SYM_FUNC_START_WEAK_ALIAS -- use where there are two global names for one
+ * function, and one of them is weak
+ */
+#ifndef SYM_FUNC_START_WEAK_ALIAS
+#define SYM_FUNC_START_WEAK_ALIAS(name) \
+ SYM_START(name, SYM_L_WEAK, SYM_A_ALIGN)
+#endif
+
/*
* SYM_FUNC_START_ALIAS -- use where there are two global names for one
* function
@@ -225,12 +266,24 @@
* later.
*/
#define SYM_FUNC_START(name) \
+ SYM_PUSH_SECTION(name) ASM_NL \
+ SYM_START(name, SYM_L_GLOBAL, SYM_A_ALIGN)
+#endif
+
+/*
+ * SYM_FUNC_START_SECT -- use for global functions, will be conditionally
+ * placed into a section specified in the second argument
+ */
+#ifndef SYM_FUNC_START_SECT
+#define SYM_FUNC_START_SECT(name, sect) \
+ SYM_PUSH_SECTION(sect) ASM_NL \
SYM_START(name, SYM_L_GLOBAL, SYM_A_ALIGN)
#endif
/* SYM_FUNC_START_NOALIGN -- use for global functions, w/o alignment */
#ifndef SYM_FUNC_START_NOALIGN
#define SYM_FUNC_START_NOALIGN(name) \
+ SYM_PUSH_SECTION(name) ASM_NL \
SYM_START(name, SYM_L_GLOBAL, SYM_A_NONE)
#endif
@@ -238,24 +291,38 @@
#ifndef SYM_FUNC_START_LOCAL
/* the same as SYM_FUNC_START_LOCAL_ALIAS, see comment near SYM_FUNC_START */
#define SYM_FUNC_START_LOCAL(name) \
+ SYM_PUSH_SECTION(name) ASM_NL \
SYM_START(name, SYM_L_LOCAL, SYM_A_ALIGN)
#endif
/* SYM_FUNC_START_LOCAL_NOALIGN -- use for local functions, w/o alignment */
#ifndef SYM_FUNC_START_LOCAL_NOALIGN
#define SYM_FUNC_START_LOCAL_NOALIGN(name) \
+ SYM_PUSH_SECTION(name) ASM_NL \
+ SYM_START(name, SYM_L_LOCAL, SYM_A_NONE)
+#endif
+
+/*
+ * SYM_FUNC_START_LOCAL_NOALIGN_SECT -- use for local functions, w/o alignment,
+ * will be conditionally placed into a section specified in the second argument
+ */
+#ifndef SYM_FUNC_START_LOCAL_NOALIGN_SECT
+#define SYM_FUNC_START_LOCAL_NOALIGN_SECT(name, sect) \
+ SYM_PUSH_SECTION(sect) ASM_NL \
SYM_START(name, SYM_L_LOCAL, SYM_A_NONE)
#endif
/* SYM_FUNC_START_WEAK -- use for weak functions */
#ifndef SYM_FUNC_START_WEAK
#define SYM_FUNC_START_WEAK(name) \
+ SYM_PUSH_SECTION(name) ASM_NL \
SYM_START(name, SYM_L_WEAK, SYM_A_ALIGN)
#endif
/* SYM_FUNC_START_WEAK_NOALIGN -- use for weak functions, w/o alignment */
#ifndef SYM_FUNC_START_WEAK_NOALIGN
#define SYM_FUNC_START_WEAK_NOALIGN(name) \
+ SYM_PUSH_SECTION(name) ASM_NL \
SYM_START(name, SYM_L_WEAK, SYM_A_NONE)
#endif
@@ -272,24 +339,59 @@
#ifndef SYM_FUNC_END
/* the same as SYM_FUNC_END_ALIAS, see comment near SYM_FUNC_START */
#define SYM_FUNC_END(name) \
- SYM_END(name, SYM_T_FUNC)
+ SYM_END(name, SYM_T_FUNC) ASM_NL \
+ SYM_POP_SECTION()
#endif
/* SYM_CODE_START -- use for non-C (special) functions */
#ifndef SYM_CODE_START
#define SYM_CODE_START(name) \
+ SYM_PUSH_SECTION(name) ASM_NL \
+ SYM_START(name, SYM_L_GLOBAL, SYM_A_ALIGN)
+#endif
+
+/*
+ * SYM_CODE_START_SECT -- use for non-C (special) functions, will be
+ * conditionally placed into a section specified in the second argument
+ */
+#ifndef SYM_CODE_START_SECT
+#define SYM_CODE_START_SECT(name, sect) \
+ SYM_PUSH_SECTION(sect) ASM_NL \
SYM_START(name, SYM_L_GLOBAL, SYM_A_ALIGN)
#endif
/* SYM_CODE_START_NOALIGN -- use for non-C (special) functions, w/o alignment */
#ifndef SYM_CODE_START_NOALIGN
#define SYM_CODE_START_NOALIGN(name) \
+ SYM_PUSH_SECTION(name) ASM_NL \
+ SYM_START(name, SYM_L_GLOBAL, SYM_A_NONE)
+#endif
+
+/*
+ * SYM_CODE_START_NOALIGN_SECT -- use for non-C (special) functions,
+ * w/o alignment, will be conditionally placed into a section specified
+ * in the second argument
+ */
+#ifndef SYM_CODE_START_NOALIGN_SECT
+#define SYM_CODE_START_NOALIGN_SECT(name, sect) \
+ SYM_PUSH_SECTION(sect) ASM_NL \
SYM_START(name, SYM_L_GLOBAL, SYM_A_NONE)
#endif
/* SYM_CODE_START_LOCAL -- use for local non-C (special) functions */
#ifndef SYM_CODE_START_LOCAL
#define SYM_CODE_START_LOCAL(name) \
+ SYM_PUSH_SECTION(name) ASM_NL \
+ SYM_START(name, SYM_L_LOCAL, SYM_A_ALIGN)
+#endif
+
+/*
+ * SYM_CODE_START_LOCAL -- use for local non-C (special) functions, will
+ * be conditionally placing into a section specified in the second argument
+ */
+#ifndef SYM_CODE_START_LOCAL_SECT
+#define SYM_CODE_START_LOCAL_SECT(name, sect) \
+ SYM_PUSH_SECTION(sect) ASM_NL \
SYM_START(name, SYM_L_LOCAL, SYM_A_ALIGN)
#endif
@@ -299,13 +401,26 @@
*/
#ifndef SYM_CODE_START_LOCAL_NOALIGN
#define SYM_CODE_START_LOCAL_NOALIGN(name) \
+ SYM_PUSH_SECTION(name) ASM_NL \
+ SYM_START(name, SYM_L_LOCAL, SYM_A_NONE)
+#endif
+
+/*
+ * SYM_CODE_START_LOCAL_NOALIGN_SECT -- use for local non-C (special)
+ * functions, w/o alignment, will be conditionally placed into a section
+ * specified in the second argument
+ */
+#ifndef SYM_CODE_START_LOCAL_NOALIGN_SECT
+#define SYM_CODE_START_LOCAL_NOALIGN_SECT(name, sect) \
+ SYM_PUSH_SECTION(sect) ASM_NL \
SYM_START(name, SYM_L_LOCAL, SYM_A_NONE)
#endif
/* SYM_CODE_END -- the end of SYM_CODE_START_LOCAL, SYM_CODE_START, ... */
#ifndef SYM_CODE_END
#define SYM_CODE_END(name) \
- SYM_END(name, SYM_T_NONE)
+ SYM_END(name, SYM_T_NONE) ASM_NL \
+ SYM_POP_SECTION()
#endif
/* === data annotations === */
@@ -1386,6 +1386,16 @@ config CC_OPTIMIZE_FOR_SIZE
endchoice
+config HAVE_ASM_FUNCTION_SECTIONS
+ depends on ARCH_SUPPORTS_ASM_FUNCTION_SECTIONS
+ depends on $(cc-option,-Wa$(comma)--sectname-subst)
+ def_bool y
+ help
+ This enables asm function sections if both architecture and
+ toolchain support it. It allows creating a separate section
+ for each function written in assembly in order to improve DCE
+ and LTO (works the same way as -ffunction-sections for C code).
+
config HAVE_LD_DEAD_CODE_DATA_ELIMINATION
bool
help
@@ -960,7 +960,9 @@ static void check_section(const char *modname, struct elf_info *elf,
".kprobes.text", ".cpuidle.text", ".noinstr.text"
#define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \
".fixup", ".entry.text", ".exception.text", ".text.*", \
- ".coldtext", ".softirqentry.text"
+ ".coldtext", ".softirqentry.text", ".text.unlikely.*", \
+ ".noinstr.text.*", ".head.text.*", ".fixup.*", \
+ ".entry.text.*"
#define INIT_SECTIONS ".init.*"
#define MEM_INIT_SECTIONS ".meminit.*"
@@ -1041,7 +1043,7 @@ enum mismatch {
struct sectioncheck {
const char *fromsec[20];
const char *bad_tosec[20];
- const char *good_tosec[20];
+ const char *good_tosec[25];
enum mismatch mismatch;
const char *symbol_white_list[20];
void (*handler)(const char *modname, struct elf_info *elf,
Sometimes it can be useful to create a separate section for every function (symbol in general) to be able then to selectively merge them back into one or several others. This is how Dead Code Elimination (DCE, CONFIG_LD_DEAD_CODE_DATA_ELIMINATION) and a part of Link-Time Optimization (LTO, currently CONFIG_LTO_CLANG) work. Currently, this can only be done for C functions as the compilers are able to do this automatically when `-ffunction-sections` is specified. Add a basic infra for supporting asm function sections, which means support for putting functions written in assembly into separate sections. If any of the required build options (DCE, LTO, FG-KASLR later) is on and the target architecture claims it supports them, all asm functions and "code" will be placed into separate so-named ("current_section.function_name") sections by default. This is achieved using `--sectname-subst` GAS flag which will then substitute "%S" in a .pushsection or .section directive with the name of the current section. So, .section .entry.text # current section is .entry.text SYM_FUNC_START(foo) -> .pushsection %S.foo # now the section is .entry.text.foo do_something SYM_FUNC_END(foo) -> .popsection # back to .entry.text Now the function "foo" is placed into .entry.text.foo and can be garbage-collected if there are no consumers for it. Otherwise, the linker script will merge it back into .entry.text. Since modpost is being run on vmlinux.o, i.e. before the final linking, expand its okay-list to cover new potential sections (which will get processed afterwards). Suggested-by: Peter Zijlstra <peterz@infradead.org> # always do, then merge Suggested-by: Nicolas Pitre <nico@fluxnic.net> # --sectname-subst flag Signed-off-by: Alexander Lobakin <alexandr.lobakin@intel.com> --- Makefile | 18 +++++ arch/Kconfig | 6 ++ include/asm-generic/vmlinux.lds.h | 21 +++--- include/linux/linkage.h | 119 +++++++++++++++++++++++++++++- init/Kconfig | 10 +++ scripts/mod/modpost.c | 6 +- 6 files changed, 167 insertions(+), 13 deletions(-)