The current x86 architecture does not yet support the HAVE_LD_DEAD_CODE_DATA_ELIMINATION feature. x86 is widely used in embedded scenarios, and enabling this feature would be beneficial for reducing the size of the kernel image. In order to make this work, we keep the necessary tables by annotating them with KEEP, also it requires further changes to linker script to KEEP some tables and wildcard compiler generated sections into the right place. Enabling CONFIG_UNWINDER_ORC or CONFIG_MITIGATION_RETPOLINE will enable the objtool's --orc and --retpoline parameters, which will alter the layout of the binary file, thereby preventing gc-sections from functioning properly. Therefore, HAVE_LD_DEAD_CODE_DATA_ELIMINATION should only be selected when they are not enabled. Enabling CONFIG_LTO_CLANG or CONFIG_X86_KERNEL_IBT will use vmlinux.o instead of performing the slow LTO link again. This can also prevent gc-sections from functioning properly. Therefore, using this optimization when CONFIG_LD_DEAD_CODE_DATA_ELIMINATION is not enabled. The size comparison of zImage is as follows: x86_def_defconfig i386_defconfig tinyconfig 10892288 10826240 607232 no dce 10748928 10719744 529408 dce 1.3% 0.98% 12.8% shrink When using smaller config file, there is a significant reduction in the size of the zImage. --- arch/x86/Kconfig | 1 + arch/x86/kernel/vmlinux.lds.S | 24 ++++++++++++------------ scripts/link-vmlinux.sh | 2 +- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index a902680b6537..92dfbc8ee4e7 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -247,6 +247,7 @@ config X86 select HAVE_FUNCTION_ERROR_INJECTION select HAVE_KRETPROBES select HAVE_RETHOOK + select HAVE_LD_DEAD_CODE_DATA_ELIMINATION if !CONFIG_UNWINDER_ORC && !CONFIG_MITIGATION_RETPOLINE select HAVE_LIVEPATCH if X86_64 select HAVE_MIXED_BREAKPOINTS_REGS select HAVE_MOD_ARCH_SPECIFIC diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S index 3509afc6a672..aeee2b9b6a6a 100644 --- a/arch/x86/kernel/vmlinux.lds.S +++ b/arch/x86/kernel/vmlinux.lds.S @@ -253,7 +253,7 @@ SECTIONS .x86_cpu_dev.init : AT(ADDR(.x86_cpu_dev.init) - LOAD_OFFSET) { __x86_cpu_dev_start = .; - *(.x86_cpu_dev.init) + KEEP(*(.x86_cpu_dev.init)) __x86_cpu_dev_end = .; } @@ -261,7 +261,7 @@ SECTIONS .x86_intel_mid_dev.init : AT(ADDR(.x86_intel_mid_dev.init) - \ LOAD_OFFSET) { __x86_intel_mid_dev_start = .; - *(.x86_intel_mid_dev.init) + KEEP(*(.x86_intel_mid_dev.init)) __x86_intel_mid_dev_end = .; } #endif @@ -275,21 +275,21 @@ SECTIONS . = ALIGN(8); .retpoline_sites : AT(ADDR(.retpoline_sites) - LOAD_OFFSET) { __retpoline_sites = .; - *(.retpoline_sites) + KEEP(*(.retpoline_sites)) __retpoline_sites_end = .; } . = ALIGN(8); .return_sites : AT(ADDR(.return_sites) - LOAD_OFFSET) { __return_sites = .; - *(.return_sites) + KEEP(*(.return_sites)) __return_sites_end = .; } . = ALIGN(8); .call_sites : AT(ADDR(.call_sites) - LOAD_OFFSET) { __call_sites = .; - *(.call_sites) + KEEP(*(.call_sites)) __call_sites_end = .; } #endif @@ -298,7 +298,7 @@ SECTIONS . = ALIGN(8); .ibt_endbr_seal : AT(ADDR(.ibt_endbr_seal) - LOAD_OFFSET) { __ibt_endbr_seal = .; - *(.ibt_endbr_seal) + KEEP(*(.ibt_endbr_seal)) __ibt_endbr_seal_end = .; } #endif @@ -307,7 +307,7 @@ SECTIONS . = ALIGN(8); .cfi_sites : AT(ADDR(.cfi_sites) - LOAD_OFFSET) { __cfi_sites = .; - *(.cfi_sites) + KEEP(*(.cfi_sites)) __cfi_sites_end = .; } #endif @@ -320,7 +320,7 @@ SECTIONS . = ALIGN(8); .altinstructions : AT(ADDR(.altinstructions) - LOAD_OFFSET) { __alt_instructions = .; - *(.altinstructions) + KEEP(*(.altinstructions)) __alt_instructions_end = .; } @@ -330,13 +330,13 @@ SECTIONS * get the address and the length of them to patch the kernel safely. */ .altinstr_replacement : AT(ADDR(.altinstr_replacement) - LOAD_OFFSET) { - *(.altinstr_replacement) + KEEP(*(.altinstr_replacement)) } . = ALIGN(8); .apicdrivers : AT(ADDR(.apicdrivers) - LOAD_OFFSET) { __apicdrivers = .; - *(.apicdrivers); + KEEP(*(.apicdrivers)); __apicdrivers_end = .; } @@ -406,7 +406,7 @@ SECTIONS .brk : AT(ADDR(.brk) - LOAD_OFFSET) { __brk_base = .; . += 64 * 1024; /* 64k alignment slop space */ - *(.bss..brk) /* areas brk users have reserved */ + KEEP(*(.bss..brk)) /* areas brk users have reserved */ __brk_limit = .; } @@ -432,7 +432,7 @@ SECTIONS . = ALIGN(HPAGE_SIZE); .init.scratch : AT(ADDR(.init.scratch) - LOAD_OFFSET) { __init_scratch_begin = .; - *(.init.scratch) + KEEP(*(.init.scratch)) . = ALIGN(HPAGE_SIZE); __init_scratch_end = .; } diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index 7862a8101747..7287b5a9f17d 100755 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -60,7 +60,7 @@ vmlinux_link() # skip output file argument shift - if is_enabled CONFIG_LTO_CLANG || is_enabled CONFIG_X86_KERNEL_IBT; then + if [ is_enabled CONFIG_LTO_CLANG || is_enabled CONFIG_X86_KERNEL_IBT ] && [ ! is_enabled CONFIG_LD_DEAD_CODE_DATA_ELIMINATION ]; then # Use vmlinux.o instead of performing the slow LTO link again. objs=vmlinux.o libs= -- 2.34.1