Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b67067f1 authored by Nicholas Piggin's avatar Nicholas Piggin Committed by Michal Marek
Browse files

kbuild: allow archs to select link dead code/data elimination



Introduce LD_DEAD_CODE_DATA_ELIMINATION option for architectures to
select to build with -ffunction-sections, -fdata-sections, and link
with --gc-sections. It requires some work (documented) to ensure all
unreferenced entrypoints are live, and requires toolchain and build
verification, so it is made a per-arch option for now.

On a random powerpc64le build, this yelds a significant size saving,
it boots and runs fine, but there is a lot I haven't tested as yet, so
these savings may be reduced if there are bugs in the link.

    text      data        bss        dec   filename
11169741   1180744    1923176	14273661   vmlinux
10445269   1004127    1919707	13369103   vmlinux.dce

~700K text, ~170K data, 6% removed from kernel image size.

Signed-off-by: default avatarNicholas Piggin <npiggin@gmail.com>
Signed-off-by: default avatarMichal Marek <mmarek@suse.com>
parent a5967db9
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -622,6 +622,11 @@ include arch/$(SRCARCH)/Makefile
KBUILD_CFLAGS	+= $(call cc-option,-fno-delete-null-pointer-checks,)
KBUILD_CFLAGS	+= $(call cc-disable-warning,maybe-uninitialized,)

ifdef CONFIG_LD_DEAD_CODE_DATA_ELIMINATION
KBUILD_CFLAGS	+= $(call cc-option,-ffunction-sections,)
KBUILD_CFLAGS	+= $(call cc-option,-fdata-sections,)
endif

ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
KBUILD_CFLAGS	+= -Os
else
@@ -809,6 +814,10 @@ LDFLAGS_BUILD_ID = $(patsubst -Wl$(comma)%,%,\
KBUILD_LDFLAGS_MODULE += $(LDFLAGS_BUILD_ID)
LDFLAGS_vmlinux += $(LDFLAGS_BUILD_ID)

ifdef CONFIG_LD_DEAD_CODE_DATA_ELIMINATION
LDFLAGS_vmlinux	+= $(call ld-option, --gc-sections,)
endif

ifeq ($(CONFIG_STRIP_ASM_SYMS),y)
LDFLAGS_vmlinux	+= $(call ld-option, -X,)
endif
+13 −0
Original line number Diff line number Diff line
@@ -467,6 +467,19 @@ config THIN_ARCHIVES
	  Select this if the architecture wants to use thin archives
	  instead of ld -r to create the built-in.o files.

config LD_DEAD_CODE_DATA_ELIMINATION
	bool
	help
	  Select this if the architecture wants to do dead code and
	  data elimination with the linker by compiling with
	  -ffunction-sections -fdata-sections and linking with
	  --gc-sections.

	  This requires that the arch annotates or otherwise protects
	  its external entry points from being discarded. Linker scripts
	  must also merge .text.*, .data.*, and .bss.* correctly into
	  output sections.

config HAVE_CONTEXT_TRACKING
	bool
	help
+29 −23
Original line number Diff line number Diff line
@@ -196,9 +196,14 @@
	*(.dtb.init.rodata)						\
	VMLINUX_SYMBOL(__dtb_end) = .;

/* .data section */
/*
 * .data section
 * -fdata-sections generates .data.identifier which needs to be pulled in
 * with .data, but don't want to pull in .data..stuff which has its own
 * requirements. Same for bss.
 */
#define DATA_DATA							\
	*(.data)							\
	*(.data .data.[0-9a-zA-Z_]*)					\
	*(.ref.data)							\
	*(.data..shared_aligned) /* percpu related */			\
	MEM_KEEP(init.data)						\
@@ -320,76 +325,76 @@
	/* Kernel symbol table: Normal symbols */			\
	__ksymtab         : AT(ADDR(__ksymtab) - LOAD_OFFSET) {		\
		VMLINUX_SYMBOL(__start___ksymtab) = .;			\
		*(SORT(___ksymtab+*))					\
		KEEP(*(SORT(___ksymtab+*)))				\
		VMLINUX_SYMBOL(__stop___ksymtab) = .;			\
	}								\
									\
	/* Kernel symbol table: GPL-only symbols */			\
	__ksymtab_gpl     : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) {	\
		VMLINUX_SYMBOL(__start___ksymtab_gpl) = .;		\
		*(SORT(___ksymtab_gpl+*))				\
		KEEP(*(SORT(___ksymtab_gpl+*)))				\
		VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .;		\
	}								\
									\
	/* Kernel symbol table: Normal unused symbols */		\
	__ksymtab_unused  : AT(ADDR(__ksymtab_unused) - LOAD_OFFSET) {	\
		VMLINUX_SYMBOL(__start___ksymtab_unused) = .;		\
		*(SORT(___ksymtab_unused+*))				\
		KEEP(*(SORT(___ksymtab_unused+*)))			\
		VMLINUX_SYMBOL(__stop___ksymtab_unused) = .;		\
	}								\
									\
	/* Kernel symbol table: GPL-only unused symbols */		\
	__ksymtab_unused_gpl : AT(ADDR(__ksymtab_unused_gpl) - LOAD_OFFSET) { \
		VMLINUX_SYMBOL(__start___ksymtab_unused_gpl) = .;	\
		*(SORT(___ksymtab_unused_gpl+*))			\
		KEEP(*(SORT(___ksymtab_unused_gpl+*)))			\
		VMLINUX_SYMBOL(__stop___ksymtab_unused_gpl) = .;	\
	}								\
									\
	/* Kernel symbol table: GPL-future-only symbols */		\
	__ksymtab_gpl_future : AT(ADDR(__ksymtab_gpl_future) - LOAD_OFFSET) { \
		VMLINUX_SYMBOL(__start___ksymtab_gpl_future) = .;	\
		*(SORT(___ksymtab_gpl_future+*))			\
		KEEP(*(SORT(___ksymtab_gpl_future+*)))			\
		VMLINUX_SYMBOL(__stop___ksymtab_gpl_future) = .;	\
	}								\
									\
	/* Kernel symbol table: Normal symbols */			\
	__kcrctab         : AT(ADDR(__kcrctab) - LOAD_OFFSET) {		\
		VMLINUX_SYMBOL(__start___kcrctab) = .;			\
		*(SORT(___kcrctab+*))					\
		KEEP(*(SORT(___kcrctab+*)))				\
		VMLINUX_SYMBOL(__stop___kcrctab) = .;			\
	}								\
									\
	/* Kernel symbol table: GPL-only symbols */			\
	__kcrctab_gpl     : AT(ADDR(__kcrctab_gpl) - LOAD_OFFSET) {	\
		VMLINUX_SYMBOL(__start___kcrctab_gpl) = .;		\
		*(SORT(___kcrctab_gpl+*))				\
		KEEP(*(SORT(___kcrctab_gpl+*)))				\
		VMLINUX_SYMBOL(__stop___kcrctab_gpl) = .;		\
	}								\
									\
	/* Kernel symbol table: Normal unused symbols */		\
	__kcrctab_unused  : AT(ADDR(__kcrctab_unused) - LOAD_OFFSET) {	\
		VMLINUX_SYMBOL(__start___kcrctab_unused) = .;		\
		*(SORT(___kcrctab_unused+*))				\
		KEEP(*(SORT(___kcrctab_unused+*)))			\
		VMLINUX_SYMBOL(__stop___kcrctab_unused) = .;		\
	}								\
									\
	/* Kernel symbol table: GPL-only unused symbols */		\
	__kcrctab_unused_gpl : AT(ADDR(__kcrctab_unused_gpl) - LOAD_OFFSET) { \
		VMLINUX_SYMBOL(__start___kcrctab_unused_gpl) = .;	\
		*(SORT(___kcrctab_unused_gpl+*))			\
		KEEP(*(SORT(___kcrctab_unused_gpl+*)))			\
		VMLINUX_SYMBOL(__stop___kcrctab_unused_gpl) = .;	\
	}								\
									\
	/* Kernel symbol table: GPL-future-only symbols */		\
	__kcrctab_gpl_future : AT(ADDR(__kcrctab_gpl_future) - LOAD_OFFSET) { \
		VMLINUX_SYMBOL(__start___kcrctab_gpl_future) = .;	\
		*(SORT(___kcrctab_gpl_future+*))			\
		KEEP(*(SORT(___kcrctab_gpl_future+*)))			\
		VMLINUX_SYMBOL(__stop___kcrctab_gpl_future) = .;	\
	}								\
									\
	/* Kernel symbol table: strings */				\
        __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) {	\
		*(__ksymtab_strings)					\
		KEEP(*(__ksymtab_strings))				\
	}								\
									\
	/* __*init sections */						\
@@ -424,7 +429,7 @@
#define SECURITY_INIT							\
	.security_initcall.init : AT(ADDR(.security_initcall.init) - LOAD_OFFSET) { \
		VMLINUX_SYMBOL(__security_initcall_start) = .;		\
		*(.security_initcall.init) 				\
		KEEP(*(.security_initcall.init))			\
		VMLINUX_SYMBOL(__security_initcall_end) = .;		\
	}

@@ -432,7 +437,7 @@
 * during second ld run in second ld pass when generating System.map */
#define TEXT_TEXT							\
		ALIGN_FUNCTION();					\
		*(.text.hot .text .text.fixup .text.unlikely)		\
		*(.text.hot .text .text.fixup .text.unlikely .text.*)	\
		*(.ref.text)						\
	MEM_KEEP(init.text)						\
	MEM_KEEP(exit.text)						\
@@ -527,6 +532,7 @@

/* init and exit section handling */
#define INIT_DATA							\
	KEEP(*(SORT(___kentry+*)))					\
	*(.init.data)							\
	MEM_DISCARD(init.data)						\
	KERNEL_CTORS()							\
@@ -593,7 +599,7 @@
		BSS_FIRST_SECTIONS					\
		*(.bss..page_aligned)					\
		*(.dynbss)						\
		*(.bss)							\
		*(.bss .bss.[0-9a-zA-Z_]*)				\
		*(COMMON)						\
	}

@@ -676,12 +682,12 @@

#define INIT_CALLS_LEVEL(level)						\
		VMLINUX_SYMBOL(__initcall##level##_start) = .;		\
		*(.initcall##level##.init)				\
		*(.initcall##level##s.init)				\
		KEEP(*(.initcall##level##.init))			\
		KEEP(*(.initcall##level##s.init))			\

#define INIT_CALLS							\
		VMLINUX_SYMBOL(__initcall_start) = .;			\
		*(.initcallearly.init)					\
		KEEP(*(.initcallearly.init))				\
		INIT_CALLS_LEVEL(0)					\
		INIT_CALLS_LEVEL(1)					\
		INIT_CALLS_LEVEL(2)					\
@@ -695,21 +701,21 @@

#define CON_INITCALL							\
		VMLINUX_SYMBOL(__con_initcall_start) = .;		\
		*(.con_initcall.init)					\
		KEEP(*(.con_initcall.init))				\
		VMLINUX_SYMBOL(__con_initcall_end) = .;

#define SECURITY_INITCALL						\
		VMLINUX_SYMBOL(__security_initcall_start) = .;		\
		*(.security_initcall.init)				\
		KEEP(*(.security_initcall.init))			\
		VMLINUX_SYMBOL(__security_initcall_end) = .;

#ifdef CONFIG_BLK_DEV_INITRD
#define INIT_RAM_FS							\
	. = ALIGN(4);							\
	VMLINUX_SYMBOL(__initramfs_start) = .;				\
	*(.init.ramfs)							\
	KEEP(*(.init.ramfs))						\
	. = ALIGN(8);							\
	*(.init.ramfs.info)
	KEEP(*(.init.ramfs.info))
#else
#define INIT_RAM_FS
#endif
+23 −0
Original line number Diff line number Diff line
@@ -182,6 +182,29 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
# define unreachable() do { } while (1)
#endif

/*
 * KENTRY - kernel entry point
 * This can be used to annotate symbols (functions or data) that are used
 * without their linker symbol being referenced explicitly. For example,
 * interrupt vector handlers, or functions in the kernel image that are found
 * programatically.
 *
 * Not required for symbols exported with EXPORT_SYMBOL, or initcalls. Those
 * are handled in their own way (with KEEP() in linker scripts).
 *
 * KENTRY can be avoided if the symbols in question are marked as KEEP() in the
 * linker script. For example an architecture could KEEP() its entire
 * boot/exception vector code rather than annotate each function and data.
 */
#ifndef KENTRY
# define KENTRY(sym)						\
	extern typeof(sym) sym;					\
	static const unsigned long __kentry_##sym		\
	__used							\
	__attribute__((section("___kentry" "+" #sym ), used))	\
	= (unsigned long)&sym;
#endif

#ifndef RELOC_HIDE
# define RELOC_HIDE(ptr, off)					\
  ({ unsigned long __ptr;					\
+15 −15
Original line number Diff line number Diff line
#ifndef _LINUX_EXPORT_H
#define _LINUX_EXPORT_H

/*
 * Export symbols from the kernel to modules.  Forked from module.h
 * to reduce the amount of pointless cruft we feed to gcc when only
@@ -46,7 +47,7 @@ extern struct module __this_module;
	extern __visible void *__crc_##sym __attribute__((weak));	\
	static const unsigned long __kcrctab_##sym			\
	__used								\
	__attribute__((section("___kcrctab" sec "+" #sym), unused))	\
	__attribute__((section("___kcrctab" sec "+" #sym), used))	\
	= (unsigned long) &__crc_##sym;
#else
#define __CRC_SYMBOL(sym, sec)
@@ -59,10 +60,9 @@ extern struct module __this_module;
	static const char __kstrtab_##sym[]				\
	__attribute__((section("__ksymtab_strings"), aligned(1)))	\
	= VMLINUX_SYMBOL_STR(sym);					\
	extern const struct kernel_symbol __ksymtab_##sym;	\
	__visible const struct kernel_symbol __ksymtab_##sym	\
	static const struct kernel_symbol __ksymtab_##sym		\
	__used								\
	__attribute__((section("___ksymtab" sec "+" #sym), unused))	\
	__attribute__((section("___ksymtab" sec "+" #sym), used))	\
	= { (unsigned long)&sym, __kstrtab_##sym }

#if defined(__KSYM_DEPS__)
Loading