diff -urpN linux-2.6.23-rc4.gc2/Makefile linux-2.6.23-rc4.gc3/Makefile --- linux-2.6.23-rc4.gc2/Makefile 2007-08-31 18:58:29.000000000 +0100 +++ linux-2.6.23-rc4.gc3/Makefile 2007-09-05 14:15:33.000000000 +0100 @@ -508,6 +508,11 @@ CFLAGS += $(call cc-option, -fn NOSTDINC_FLAGS += -nostdinc -isystem $(shell $(CC) -print-file-name=include) CHECKFLAGS += $(NOSTDINC_FLAGS) +ifdef CONFIG_DISCARD_UNUSED_SECTIONS +CFLAGS += $(call cc-option, -ffunction-sections -fdata-sections) +LDFLAGS_vmlinux += $(call ld-option, -gc-sections) +endif + # warn about C99 declaration after statement CFLAGS += $(call cc-option,-Wdeclaration-after-statement,) diff -urpN linux-2.6.23-rc4.gc2/arch/frv/Makefile linux-2.6.23-rc4.gc3/arch/frv/Makefile --- linux-2.6.23-rc4.gc2/arch/frv/Makefile 2007-08-31 18:31:02.000000000 +0100 +++ linux-2.6.23-rc4.gc3/arch/frv/Makefile 2007-09-05 14:15:33.000000000 +0100 @@ -52,7 +52,9 @@ endif #LDFLAGS_vmlinux := -Map linkmap.txt -ifdef CONFIG_GC_SECTIONS +# Is this needed? We do this already in kernel's top-level Makefile. +# $(LINKFLAGS) seems to be unused. +ifdef CONFIG_DISCARD_UNUSED_SECTIONS CFLAGS += -ffunction-sections -fdata-sections LINKFLAGS += --gc-sections endif diff -urpN linux-2.6.23-rc4.gc2/arch/x86_64/kernel/vmlinux.lds.S linux-2.6.23-rc4.gc3/arch/x86_64/kernel/vmlinux.lds.S --- linux-2.6.23-rc4.gc2/arch/x86_64/kernel/vmlinux.lds.S 2007-09-05 14:14:37.000000000 +0100 +++ linux-2.6.23-rc4.gc3/arch/x86_64/kernel/vmlinux.lds.S 2007-09-05 14:32:42.000000000 +0100 @@ -28,14 +28,14 @@ SECTIONS _text = .; /* Text and read-only data */ .text : AT(ADDR(.text) - LOAD_OFFSET) { /* First the code that has to be first for bootstrapping */ - *(.text_head) + KEEP(*(.text_head)) _stext = .; /* Then the rest */ TEXT_TEXT SCHED_TEXT LOCK_TEXT KPROBES_TEXT - *(.fixup) + *(.fixup) /* no need to KEEP, every .fixup is referenced by __ex_table */ *(.gnu.warning) } :text = 0x9090 /* out-of-line lock text */ @@ -44,8 +44,9 @@ SECTIONS _etext = .; /* End of text section */ . = ALIGN(16); /* Exception table */ + /* Points to potentially-faulting insns and corresponding .fixups */ __start___ex_table = .; - __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { *(__ex_table) } + __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { KEEP(*(__ex_table)) } __stop___ex_table = .; NOTES :text :note @@ -91,34 +92,34 @@ SECTIONS #define VVIRT(x) (ADDR(x) - VVIRT_OFFSET) . = VSYSCALL_ADDR; - .vsyscall_0 : AT(VSYSCALL_PHYS_ADDR) { *(.vsyscall_0) } :user + .vsyscall_0 : AT(VSYSCALL_PHYS_ADDR) { KEEP(*(.vsyscall_0)) } :user __vsyscall_0 = VSYSCALL_VIRT_ADDR; . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); - .vsyscall_fn : AT(VLOAD(.vsyscall_fn)) { *(.vsyscall_fn) } + .vsyscall_fn : AT(VLOAD(.vsyscall_fn)) { KEEP(*(.vsyscall_fn)) } . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); .vsyscall_gtod_data : AT(VLOAD(.vsyscall_gtod_data)) - { *(.vsyscall_gtod_data) } + { KEEP(*(.vsyscall_gtod_data)) } vsyscall_gtod_data = VVIRT(.vsyscall_gtod_data); .vsyscall_clock : AT(VLOAD(.vsyscall_clock)) - { *(.vsyscall_clock) } + { KEEP(*(.vsyscall_clock)) } vsyscall_clock = VVIRT(.vsyscall_clock); - .vsyscall_1 ADDR(.vsyscall_0) + 1024: AT(VLOAD(.vsyscall_1)) - { *(.vsyscall_1) } - .vsyscall_2 ADDR(.vsyscall_0) + 2048: AT(VLOAD(.vsyscall_2)) - { *(.vsyscall_2) } + .vsyscall_1 VSYSCALL_ADDR + 1024: AT(VLOAD(.vsyscall_1)) + { KEEP(*(.vsyscall_1)) } + .vsyscall_2 VSYSCALL_ADDR + 2048: AT(VLOAD(.vsyscall_2)) + { KEEP(*(.vsyscall_2)) } - .vgetcpu_mode : AT(VLOAD(.vgetcpu_mode)) { *(.vgetcpu_mode) } + .vgetcpu_mode : AT(VLOAD(.vgetcpu_mode)) { KEEP(*(.vgetcpu_mode)) } vgetcpu_mode = VVIRT(.vgetcpu_mode); . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); - .jiffies : AT(VLOAD(.jiffies)) { *(.jiffies) } + .jiffies : AT(VLOAD(.jiffies)) { KEEP(*(.jiffies)) } jiffies = VVIRT(.jiffies); - .vsyscall_3 ADDR(.vsyscall_0) + 3072: AT(VLOAD(.vsyscall_3)) - { *(.vsyscall_3) } + .vsyscall_3 VSYSCALL_ADDR + 3072: AT(VLOAD(.vsyscall_3)) + { KEEP(*(.vsyscall_3)) } . = VSYSCALL_VIRT_ADDR + 4096; @@ -141,11 +142,12 @@ SECTIONS } /* might get freed after init */ + . = ALIGN(4096); __smp_alt_begin = .; __smp_locks = .; .smp_locks : AT(ADDR(.smp_locks) - LOAD_OFFSET) { - *(.smp_locks) + KEEP(*(.smp_locks)) /* points to lock prefixes */ } __smp_locks_end = .; . = ALIGN(4096); @@ -155,15 +157,15 @@ SECTIONS __init_begin = .; .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) { _sinittext = .; - *(.init.text) + *(.init.text) /* no need to KEEP */ _einittext = .; } __initdata_begin = .; - .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { *(.init.data) } + .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { *(.init.data) } /* no need to KEEP */ __initdata_end = .; . = ALIGN(16); __setup_start = .; - .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) { *(.init.setup) } + .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) { KEEP(*(.init.setup)) } /* obsolete_checksetup() walks it */ __setup_end = .; __initcall_start = .; .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) { @@ -172,34 +174,34 @@ SECTIONS __initcall_end = .; __con_initcall_start = .; .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) { - *(.con_initcall.init) + KEEP(*(.con_initcall.init)) /* console_init() walks it */ } __con_initcall_end = .; SECURITY_INIT . = ALIGN(8); __alt_instructions = .; .altinstructions : AT(ADDR(.altinstructions) - LOAD_OFFSET) { - *(.altinstructions) + KEEP(*(.altinstructions)) /* alternative_instructions() walks it */ } __alt_instructions_end = .; .altinstr_replacement : AT(ADDR(.altinstr_replacement) - LOAD_OFFSET) { - *(.altinstr_replacement) + KEEP(*(.altinstr_replacement)) } - /* .exit.text is discard at runtime, not link time, to deal with references + /* .exit.text is discarded at runtime, not link time, to deal with references from .altinstructions and .eh_frame */ .exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) { *(.exit.text) } .exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) { *(.exit.data) } /* vdso blob that is mapped into user space */ vdso_start = . ; - .vdso : AT(ADDR(.vdso) - LOAD_OFFSET) { *(.vdso) } + .vdso : AT(ADDR(.vdso) - LOAD_OFFSET) { KEEP(*(.vdso)) } . = ALIGN(4096); vdso_end = .; #ifdef CONFIG_BLK_DEV_INITRD . = ALIGN(4096); __initramfs_start = .; - .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { *(.init.ramfs) } + .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { KEEP(*(.init.ramfs)) } __initramfs_end = .; #endif @@ -210,7 +212,7 @@ SECTIONS . = ALIGN(4096); __nosave_begin = .; - .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) { *(.data_nosave) } + .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) { *(.data_nosave) } /* not saved by suspend */ . = ALIGN(4096); __nosave_end = .; @@ -218,6 +220,7 @@ SECTIONS .bss : AT(ADDR(.bss) - LOAD_OFFSET) { *(.bss_page_aligned) *(.bss) + *(SORT_BY_ALIGNMENT(.bss.*)) } __bss_stop = .; diff -urpN linux-2.6.23-rc4.gc2/include/asm-generic/vmlinux.lds.h linux-2.6.23-rc4.gc3/include/asm-generic/vmlinux.lds.h --- linux-2.6.23-rc4.gc2/include/asm-generic/vmlinux.lds.h 2007-09-05 14:14:38.000000000 +0100 +++ linux-2.6.23-rc4.gc3/include/asm-generic/vmlinux.lds.h 2007-09-05 14:26:20.000000000 +0100 @@ -6,19 +6,26 @@ #define VMLINUX_SYMBOL(_sym_) _sym_ #endif +#ifndef CONFIG_DISCARD_UNUSED_SECTIONS +/* Don't confuse old ld with new stuff */ +#define KEEP(x) x +#define SORT_BY_ALIGNMENT(x) x +#endif + /* Align . to a 8 byte boundary equals to maximum function alignment. */ #define ALIGN_FUNCTION() . = ALIGN(8) /* .data section */ #define DATA_DATA \ *(.data) \ + *(SORT_BY_ALIGNMENT(.data.*)) \ *(.data_init_refok) #define RO_DATA(align) \ . = ALIGN((align)); \ .rodata : AT(ADDR(.rodata) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start_rodata) = .; \ - *(.rodata) *(.rodata.*) \ + *(.rodata) *(SORT_BY_ALIGNMENT(.rodata.*)) \ *(__vermagic) /* Kernel version magic */ \ } \ \ @@ -28,109 +35,110 @@ \ /* PCI quirks */ \ .pci_fixup : AT(ADDR(.pci_fixup) - LOAD_OFFSET) { \ + /* walked by pci_fixup_device() */ \ VMLINUX_SYMBOL(__start_pci_fixups_early) = .; \ - *(.pci_fixup_early) \ + KEEP(*(.pci_fixup_early)) \ VMLINUX_SYMBOL(__end_pci_fixups_early) = .; \ VMLINUX_SYMBOL(__start_pci_fixups_header) = .; \ - *(.pci_fixup_header) \ + KEEP(*(.pci_fixup_header)) \ VMLINUX_SYMBOL(__end_pci_fixups_header) = .; \ VMLINUX_SYMBOL(__start_pci_fixups_final) = .; \ - *(.pci_fixup_final) \ + KEEP(*(.pci_fixup_final)) \ VMLINUX_SYMBOL(__end_pci_fixups_final) = .; \ VMLINUX_SYMBOL(__start_pci_fixups_enable) = .; \ - *(.pci_fixup_enable) \ + KEEP(*(.pci_fixup_enable)) \ VMLINUX_SYMBOL(__end_pci_fixups_enable) = .; \ VMLINUX_SYMBOL(__start_pci_fixups_resume) = .; \ - *(.pci_fixup_resume) \ + KEEP(*(.pci_fixup_resume)) \ VMLINUX_SYMBOL(__end_pci_fixups_resume) = .; \ } \ \ /* RapidIO route ops */ \ .rio_route : AT(ADDR(.rio_route) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start_rio_route_ops) = .; \ - *(.rio_route_ops) \ + KEEP(*(.rio_route_ops)) \ VMLINUX_SYMBOL(__end_rio_route_ops) = .; \ } \ \ /* Kernel symbol table: Normal symbols */ \ __ksymtab : AT(ADDR(__ksymtab) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start___ksymtab) = .; \ - *(__ksymtab) \ + KEEP(*(__ksymtab)) \ VMLINUX_SYMBOL(__stop___ksymtab) = .; \ } \ \ /* Kernel symbol table: GPL-only symbols */ \ __ksymtab_gpl : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start___ksymtab_gpl) = .; \ - *(__ksymtab_gpl) \ + KEEP(*(__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) = .; \ - *(__ksymtab_unused) \ + KEEP(*(__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) = .; \ - *(__ksymtab_unused_gpl) \ + KEEP(*(__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) = .; \ - *(__ksymtab_gpl_future) \ + KEEP(*(__ksymtab_gpl_future)) \ VMLINUX_SYMBOL(__stop___ksymtab_gpl_future) = .; \ } \ \ /* Kernel symbol table: Normal symbols */ \ __kcrctab : AT(ADDR(__kcrctab) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start___kcrctab) = .; \ - *(__kcrctab) \ + KEEP(*(__kcrctab)) \ VMLINUX_SYMBOL(__stop___kcrctab) = .; \ } \ \ /* Kernel symbol table: GPL-only symbols */ \ __kcrctab_gpl : AT(ADDR(__kcrctab_gpl) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start___kcrctab_gpl) = .; \ - *(__kcrctab_gpl) \ + KEEP(*(__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) = .; \ - *(__kcrctab_unused) \ + KEEP(*(__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) = .; \ - *(__kcrctab_unused_gpl) \ + KEEP(*(__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) = .; \ - *(__kcrctab_gpl_future) \ + KEEP(*(__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)) \ } \ \ /* Built-in module parameters. */ \ __param : AT(ADDR(__param) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start___param) = .; \ - *(__param) \ + KEEP(*(__param)) \ VMLINUX_SYMBOL(__stop___param) = .; \ VMLINUX_SYMBOL(__end_rodata) = .; \ } \ @@ -144,7 +152,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) = .; \ } @@ -153,6 +161,7 @@ #define TEXT_TEXT \ ALIGN_FUNCTION(); \ *(.text) \ + *(SORT_BY_ALIGNMENT(.text.*)) \ *(.text_init_refok) /* sched.text is aling to function alignment to secure we have same @@ -231,23 +240,23 @@ } #define INITCALLS \ - *(.initcall0.init) \ - *(.initcall0s.init) \ - *(.initcall1.init) \ - *(.initcall1s.init) \ - *(.initcall2.init) \ - *(.initcall2s.init) \ - *(.initcall3.init) \ - *(.initcall3s.init) \ - *(.initcall4.init) \ - *(.initcall4s.init) \ - *(.initcall5.init) \ - *(.initcall5s.init) \ - *(.initcallrootfs.init) \ - *(.initcall6.init) \ - *(.initcall6s.init) \ - *(.initcall7.init) \ - *(.initcall7s.init) + KEEP(*(.initcall0.init)) /* do_initcalls() walks them */ \ + KEEP(*(.initcall0s.init)) \ + KEEP(*(.initcall1.init)) \ + KEEP(*(.initcall1s.init)) \ + KEEP(*(.initcall2.init)) \ + KEEP(*(.initcall2s.init)) \ + KEEP(*(.initcall3.init)) \ + KEEP(*(.initcall3s.init)) \ + KEEP(*(.initcall4.init)) \ + KEEP(*(.initcall4s.init)) \ + KEEP(*(.initcall5.init)) \ + KEEP(*(.initcall5s.init)) \ + KEEP(*(.initcallrootfs.init)) \ + KEEP(*(.initcall6.init)) \ + KEEP(*(.initcall6s.init)) \ + KEEP(*(.initcall7.init)) \ + KEEP(*(.initcall7s.init)) #define PERCPU(align) \ . = ALIGN(align); \ diff -urpN linux-2.6.23-rc4.gc2/init/Kconfig linux-2.6.23-rc4.gc3/init/Kconfig --- linux-2.6.23-rc4.gc2/init/Kconfig 2007-08-31 18:31:05.000000000 +0100 +++ linux-2.6.23-rc4.gc3/init/Kconfig 2007-09-05 14:15:33.000000000 +0100 @@ -347,6 +347,20 @@ config CC_OPTIMIZE_FOR_SIZE If unsure, say N. +config DISCARD_UNUSED_SECTIONS + bool "Discard unused code/data sections (DANGEROUS)" + default n + depends on EXPERIMENTAL + help + Enabling this option will pass --ffunction-sections -fdata-sections + to gcc and --gc-sections to ld, resulting in a smaller kernel. + + WARNING: --gc-sections support is very new and considered highly + experimental for now. You need at least binutils 2.18, + and even then surprises are likely. + + If unsure, say N. + config SYSCTL bool