[PATCH 3/3] build system: section garbage collection - main part

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Saturday 24 November 2007 15:14, Denys Vlasenko wrote:
> 3.gc
>     The meat of the patchset is here.
>     Introduce config option DISCARD_UNUSED_SECTIONS.
>     If it is selected:
>     Pass -ffunction-sections -fdata-sections to gcc and
>     --gc-sections --print-gc-sections to ld.
>     Use arch/$(SRCARCH)/kernel/modules.lds.S linker script for linking *.ko
>     files.
>     Generate linker map files for vmlinux and modules.
>     Add *(.text.*), *(.data.*) wildcards to linker scripts to accomodate
>     new kinds of sections generated by gcc.
>     Add KEEP(<sections>) directives to sections which must not be
>     discarded. Fix arch/frv/Makefile to use DISCARD_UNUSED_SECTIONS instead
>     of what seems to be a vestigial custom solution.

Signed-off-by: Denys Vlasenko <[email protected]>
-- 
vda
diff -urpN linux-2.6.gc2/Makefile linux-2.6.gc3/Makefile
--- linux-2.6.gc2/Makefile	2007-11-23 18:55:08.000000000 -0800
+++ linux-2.6.gc3/Makefile	2007-11-24 14:46:38.000000000 -0800
@@ -526,6 +526,11 @@ KBUILD_CFLAGS         += $(call cc-optio
 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 += --gc-sections --print-gc-sections -Map vmlinux.map
+endif
+
 # warn about C99 declaration after statement
 KBUILD_CFLAGS += $(call cc-option,-Wdeclaration-after-statement,)
 
@@ -924,6 +929,7 @@ prepare: prepare0
 # done in arch/$(ARCH)/kernel/Makefile
 
 export CPPFLAGS_vmlinux.lds += -P -C -U$(ARCH)
+export CPPFLAGS_modules.lds += -P -C -U$(ARCH)
 
 # The asm symlink changes when $(ARCH) changes.
 # Detect this and ask user to run make mrproper
diff -urpN linux-2.6.gc2/arch/alpha/boot/bootloader.lds linux-2.6.gc3/arch/alpha/boot/bootloader.lds
--- linux-2.6.gc2/arch/alpha/boot/bootloader.lds	2007-11-23 18:55:08.000000000 -0800
+++ linux-2.6.gc3/arch/alpha/boot/bootloader.lds	2007-11-23 21:22:59.000000000 -0800
@@ -4,17 +4,17 @@ printk = srm_printk;
 SECTIONS
 {
   . = 0x20000000;
-  .text : { *(.text) }
+  .text : { *(.text) *(.text.*) }
   _etext = .;
   PROVIDE (etext = .);
   .rodata : { *(.rodata) *(.rodata.*) }
-  .data : { *(.data) CONSTRUCTORS }
+  .data : { *(.data) *(.data.*) CONSTRUCTORS }
   .got : { *(.got) }
   .sdata : { *(.sdata) }
   _edata = .;
   PROVIDE (edata = .);
   .sbss : { *(.sbss) *(.scommon) }
-  .bss : { *(.bss) *(COMMON) }
+  .bss : { *(.bss) *(.bss.*) *(COMMON) }
   _end = . ;
   PROVIDE (end = .);
 
diff -urpN linux-2.6.gc2/arch/alpha/kernel/vmlinux.lds.S linux-2.6.gc3/arch/alpha/kernel/vmlinux.lds.S
--- linux-2.6.gc2/arch/alpha/kernel/vmlinux.lds.S	2007-11-23 20:55:55.000000000 -0800
+++ linux-2.6.gc3/arch/alpha/kernel/vmlinux.lds.S	2007-11-23 21:30:54.000000000 -0800
@@ -129,6 +129,7 @@ SECTIONS
 	}
 	.bss : {
 		*(.bss)
+		*(.bss.*)
 		*(COMMON)
 	}
 	__bss_stop = .;
diff -urpN linux-2.6.gc2/arch/arm/boot/bootp/bootp.lds linux-2.6.gc3/arch/arm/boot/bootp/bootp.lds
--- linux-2.6.gc2/arch/arm/boot/bootp/bootp.lds	2007-11-23 18:55:08.000000000 -0800
+++ linux-2.6.gc3/arch/arm/boot/bootp/bootp.lds	2007-11-23 21:23:15.000000000 -0800
@@ -15,7 +15,7 @@ SECTIONS
   .text : {
    _stext = .;
    *(.start)
-   *(.text)
+   *(.text .text.*)
    initrd_size = initrd_end - initrd_start;
    _etext = .;
   }
diff -urpN linux-2.6.gc2/arch/arm/boot/compressed/vmlinux.lds.in linux-2.6.gc3/arch/arm/boot/compressed/vmlinux.lds.in
--- linux-2.6.gc2/arch/arm/boot/compressed/vmlinux.lds.in	2007-11-23 18:55:08.000000000 -0800
+++ linux-2.6.gc3/arch/arm/boot/compressed/vmlinux.lds.in	2007-11-23 21:24:25.000000000 -0800
@@ -35,12 +35,12 @@ SECTIONS
   .got			: { *(.got) }
   _got_end = .;
   .got.plt		: { *(.got.plt) }
-  .data			: { *(.data) }
+  .data			: { *(.data) *(.data.*) }
   _edata = .;
 
   . = BSS_START;
   __bss_start = .;
-  .bss			: { *(.bss) }
+  .bss			: { *(.bss) *(.bss.*) }
   _end = .;
 
   .stack (NOLOAD)	: { *(.stack) }
diff -urpN linux-2.6.gc2/arch/arm/kernel/vmlinux.lds.S linux-2.6.gc3/arch/arm/kernel/vmlinux.lds.S
--- linux-2.6.gc2/arch/arm/kernel/vmlinux.lds.S	2007-11-23 20:55:54.000000000 -0800
+++ linux-2.6.gc3/arch/arm/kernel/vmlinux.lds.S	2007-11-23 21:31:04.000000000 -0800
@@ -169,6 +169,7 @@ SECTIONS
 	.bss : {
 		__bss_start = .;	/* BSS				*/
 		*(.bss)
+		*(.bss.*)
 		*(COMMON)
 		_end = .;
 	}
diff -urpN linux-2.6.gc2/arch/avr32/kernel/vmlinux.lds.S linux-2.6.gc3/arch/avr32/kernel/vmlinux.lds.S
--- linux-2.6.gc2/arch/avr32/kernel/vmlinux.lds.S	2007-11-23 20:55:53.000000000 -0800
+++ linux-2.6.gc3/arch/avr32/kernel/vmlinux.lds.S	2007-11-23 21:31:12.000000000 -0800
@@ -124,6 +124,7 @@ SECTIONS
 	.bss    	: AT(ADDR(.bss) - LOAD_OFFSET) {
 		__bss_start = .;
 		*(.bss)
+		*(.bss.*)
 		*(COMMON)
 		. = ALIGN(8);
 		__bss_stop = .;
diff -urpN linux-2.6.gc2/arch/cris/arch-v10/vmlinux.lds.S linux-2.6.gc3/arch/cris/arch-v10/vmlinux.lds.S
--- linux-2.6.gc2/arch/cris/arch-v10/vmlinux.lds.S	2007-11-23 20:55:56.000000000 -0800
+++ linux-2.6.gc3/arch/cris/arch-v10/vmlinux.lds.S	2007-11-23 21:31:19.000000000 -0800
@@ -104,6 +104,7 @@ SECTIONS
 	.bss : {
 		*(COMMON)
 		*(.bss)
+		*(.bss.*)
 	}
 
 	. =  ALIGN (0x20);
diff -urpN linux-2.6.gc2/arch/cris/arch-v32/vmlinux.lds.S linux-2.6.gc3/arch/cris/arch-v32/vmlinux.lds.S
--- linux-2.6.gc2/arch/cris/arch-v32/vmlinux.lds.S	2007-11-23 20:55:56.000000000 -0800
+++ linux-2.6.gc3/arch/cris/arch-v32/vmlinux.lds.S	2007-11-23 21:31:26.000000000 -0800
@@ -116,6 +116,7 @@ SECTIONS
 	.bss : {
 		*(COMMON)
 		*(.bss)
+		*(.bss.*)
 	}
 
 	. =  ALIGN (0x20);
diff -urpN linux-2.6.gc2/arch/frv/Makefile linux-2.6.gc3/arch/frv/Makefile
--- linux-2.6.gc2/arch/frv/Makefile	2007-11-23 18:55:09.000000000 -0800
+++ linux-2.6.gc3/arch/frv/Makefile	2007-11-23 21:50:49.000000000 -0800
@@ -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.
+# Also $(LINKFLAGS) seems to be unused.
+ifdef CONFIG_DISCARD_UNUSED_SECTIONS
 KBUILD_CFLAGS	+= -ffunction-sections -fdata-sections
 LINKFLAGS	+= --gc-sections
 endif
diff -urpN linux-2.6.gc2/arch/h8300/boot/compressed/vmlinux.lds linux-2.6.gc3/arch/h8300/boot/compressed/vmlinux.lds
--- linux-2.6.gc2/arch/h8300/boot/compressed/vmlinux.lds	2007-11-23 20:55:45.000000000 -0800
+++ linux-2.6.gc3/arch/h8300/boot/compressed/vmlinux.lds	2007-11-23 21:25:10.000000000 -0800
@@ -5,13 +5,13 @@ SECTIONS
         __stext = . ;
 	__text = .;
 	       *(.startup.text)
-	       *(.text)
+	       *(.text) *(.text.*)
         __etext = . ;
         }
 
 	.rodata :
 	{
-		*(.rodata)
+		*(.rodata) *(.rodata.*)
 	}
         .data :
 
diff -urpN linux-2.6.gc2/arch/ia64/hp/sim/boot/bootloader.lds linux-2.6.gc3/arch/ia64/hp/sim/boot/bootloader.lds
--- linux-2.6.gc2/arch/ia64/hp/sim/boot/bootloader.lds	2007-11-23 18:55:09.000000000 -0800
+++ linux-2.6.gc3/arch/ia64/hp/sim/boot/bootloader.lds	2007-11-23 21:25:44.000000000 -0800
@@ -7,13 +7,13 @@ SECTIONS
   . = 0x100000;
 
   _text = .;
-  .text : { *(__ivt_section) *(.text) }
+  .text : { *(__ivt_section) *(.text) *(.text.*) }
   _etext = .;
 
   /* Global data */
   _data = .;
   .rodata : { *(.rodata) *(.rodata.*) }
-  .data    : { *(.data) *(.gnu.linkonce.d*) CONSTRUCTORS }
+  .data    : { *(.data) *(.data.*) *(.gnu.linkonce.d*) CONSTRUCTORS }
   __gp = ALIGN (8) + 0x200000;
   .got           : { *(.got.plt) *(.got) }
   /* We want the small data sections together, so single-instruction offsets
@@ -24,7 +24,7 @@ SECTIONS
 
   _bss = .;
   .sbss      : { *(.sbss) *(.scommon) }
-  .bss       : { *(.bss) *(COMMON) }
+  .bss       : { *(.bss) *(.bss.*) *(COMMON) }
   . = ALIGN(64 / 8);
   _end = . ;
 
diff -urpN linux-2.6.gc2/arch/ia64/kernel/vmlinux.lds.S linux-2.6.gc3/arch/ia64/kernel/vmlinux.lds.S
--- linux-2.6.gc2/arch/ia64/kernel/vmlinux.lds.S	2007-11-23 20:55:59.000000000 -0800
+++ linux-2.6.gc3/arch/ia64/kernel/vmlinux.lds.S	2007-11-23 21:31:52.000000000 -0800
@@ -244,7 +244,7 @@ SECTIONS
   .sbss : AT(ADDR(.sbss) - LOAD_OFFSET)
 	{ *(.sbss) *(.scommon) }
   .bss : AT(ADDR(.bss) - LOAD_OFFSET)
-	{ *(.bss) *(COMMON) }
+	{ *(.bss) *(.bss.*) *(COMMON) }
 
   _end = .;
 
diff -urpN linux-2.6.gc2/arch/ia64/scripts/check-segrel.lds linux-2.6.gc3/arch/ia64/scripts/check-segrel.lds
--- linux-2.6.gc2/arch/ia64/scripts/check-segrel.lds	2007-11-23 18:55:09.000000000 -0800
+++ linux-2.6.gc3/arch/ia64/scripts/check-segrel.lds	2007-11-23 21:28:43.000000000 -0800
@@ -1,9 +1,9 @@
 SECTIONS {
 	. = SIZEOF_HEADERS;
-	.rodata : { *(.rodata) } :ro
+	.rodata : { *(.rodata) *(.rodata.*) } :ro
 	.note : { *(.note*) }
 	. = 0xa0000;
-	.data : { *(.data) } :dat
+	.data : { *(.data) *(.data.*) } :dat
 	/DISCARD/ : { *(*) }
 }
 PHDRS {
diff -urpN linux-2.6.gc2/arch/m32r/boot/compressed/vmlinux.lds.S linux-2.6.gc3/arch/m32r/boot/compressed/vmlinux.lds.S
--- linux-2.6.gc2/arch/m32r/boot/compressed/vmlinux.lds.S	2007-11-23 18:55:09.000000000 -0800
+++ linux-2.6.gc3/arch/m32r/boot/compressed/vmlinux.lds.S	2007-11-23 21:27:15.000000000 -0800
@@ -6,12 +6,12 @@ SECTIONS
   . = CONFIG_MEMORY_START + 0x00400000;
 
   _text = .;
-  .text : { *(.text) } = 0
+  .text : { *(.text) *(.text.*) } = 0
   .rodata : { *(.rodata) *(.rodata.*) }
   _etext = .;
 
   . = ALIGN(32 / 8);
-  .data : { *(.data) }
+  .data : { *(.data) *(.data.*) }
   . = ALIGN(32 / 8);
   _got = .;
   .got  : { *(.got) _egot = .; *(.got.*) }
@@ -19,7 +19,7 @@ SECTIONS
 
   . = ALIGN(32 / 8);
   __bss_start = .;
-  .bss : { *(.bss) *(.sbss) }
+  .bss : { *(.bss) *(.bss.*) *(.sbss) }
   . = ALIGN(32 / 8);
   _ebss = .;
   . = ALIGN(4096);
diff -urpN linux-2.6.gc2/arch/m32r/kernel/vmlinux.lds.S linux-2.6.gc3/arch/m32r/kernel/vmlinux.lds.S
--- linux-2.6.gc2/arch/m32r/kernel/vmlinux.lds.S	2007-11-23 20:55:57.000000000 -0800
+++ linux-2.6.gc3/arch/m32r/kernel/vmlinux.lds.S	2007-11-23 21:32:02.000000000 -0800
@@ -116,7 +116,7 @@ SECTIONS
   /* freed after init ends here */
 
   __bss_start = .;		/* BSS */
-  .bss : { *(.bss) }
+  .bss : { *(.bss) *(.bss.*) }
   . = ALIGN(4);
   __bss_stop = .;
 
diff -urpN linux-2.6.gc2/arch/m68k/kernel/vmlinux-std.lds linux-2.6.gc3/arch/m68k/kernel/vmlinux-std.lds
--- linux-2.6.gc2/arch/m68k/kernel/vmlinux-std.lds	2007-11-23 20:55:53.000000000 -0800
+++ linux-2.6.gc3/arch/m68k/kernel/vmlinux-std.lds	2007-11-23 21:32:16.000000000 -0800
@@ -33,7 +33,7 @@ SECTIONS
 	CONSTRUCTORS
 	}
 
-  .bss : { *(.bss) }		/* BSS */
+  .bss : { *(.bss) *(.bss.*) }		/* BSS */
 
   . = ALIGN(16);
   .cacheline_aligned.data : { *(.cacheline_aligned.data) } :data
diff -urpN linux-2.6.gc2/arch/m68k/kernel/vmlinux-sun3.lds linux-2.6.gc3/arch/m68k/kernel/vmlinux-sun3.lds
--- linux-2.6.gc2/arch/m68k/kernel/vmlinux-sun3.lds	2007-11-23 20:55:53.000000000 -0800
+++ linux-2.6.gc3/arch/m68k/kernel/vmlinux-sun3.lds	2007-11-23 21:32:10.000000000 -0800
@@ -71,7 +71,7 @@ __init_begin = .;
 	.init.task.data : { *(.init_task.data) }
 
 
-  .bss : { *(.bss) }		/* BSS */
+  .bss : { *(.bss) *(.bss.*) }		/* BSS */
 
   _end = . ;
 
diff -urpN linux-2.6.gc2/arch/m68knommu/kernel/vmlinux.lds.S linux-2.6.gc3/arch/m68knommu/kernel/vmlinux.lds.S
--- linux-2.6.gc2/arch/m68knommu/kernel/vmlinux.lds.S	2007-11-23 20:55:53.000000000 -0800
+++ linux-2.6.gc3/arch/m68knommu/kernel/vmlinux.lds.S	2007-11-23 21:32:23.000000000 -0800
@@ -179,6 +179,7 @@ SECTIONS {
 		. = ALIGN(4);
 		_sbss = . ;
 		*(.bss)
+		*(.bss.*)
 		*(COMMON)
 		. = ALIGN(4) ;
 		_ebss = . ;
diff -urpN linux-2.6.gc2/arch/mips/kernel/vmlinux.lds.S linux-2.6.gc3/arch/mips/kernel/vmlinux.lds.S
--- linux-2.6.gc2/arch/mips/kernel/vmlinux.lds.S	2007-11-23 20:55:54.000000000 -0800
+++ linux-2.6.gc3/arch/mips/kernel/vmlinux.lds.S	2007-11-23 21:32:30.000000000 -0800
@@ -169,6 +169,7 @@ SECTIONS
 	}
 	.bss : {
 		*(.bss)
+		*(.bss.*)
 		*(COMMON)
 	}
 	__bss_stop = .;
diff -urpN linux-2.6.gc2/arch/parisc/kernel/vmlinux.lds.S linux-2.6.gc3/arch/parisc/kernel/vmlinux.lds.S
--- linux-2.6.gc2/arch/parisc/kernel/vmlinux.lds.S	2007-11-23 20:56:00.000000000 -0800
+++ linux-2.6.gc3/arch/parisc/kernel/vmlinux.lds.S	2007-11-23 21:32:37.000000000 -0800
@@ -141,6 +141,7 @@ SECTIONS
 	}
 	.bss : {
 		*(.bss)
+		*(.bss.*)
 		*(COMMON)
 	}
 	__bss_stop = .;
diff -urpN linux-2.6.gc2/arch/powerpc/boot/zImage.coff.lds.S linux-2.6.gc3/arch/powerpc/boot/zImage.coff.lds.S
--- linux-2.6.gc2/arch/powerpc/boot/zImage.coff.lds.S	2007-11-23 18:55:09.000000000 -0800
+++ linux-2.6.gc3/arch/powerpc/boot/zImage.coff.lds.S	2007-11-23 21:22:04.000000000 -0800
@@ -7,7 +7,7 @@ SECTIONS
   _start = .;
   .text      :
   {
-    *(.text)
+    *(.text .text.*)
     *(.fixup)
   }
   _etext = .;
@@ -41,7 +41,7 @@ SECTIONS
   .bss       :
   {
    *(.sbss)
-   *(.bss)
+   *(.bss .bss.*)
   }
   _end = . ;
 
diff -urpN linux-2.6.gc2/arch/powerpc/boot/zImage.lds.S linux-2.6.gc3/arch/powerpc/boot/zImage.lds.S
--- linux-2.6.gc2/arch/powerpc/boot/zImage.lds.S	2007-11-23 18:55:09.000000000 -0800
+++ linux-2.6.gc3/arch/powerpc/boot/zImage.lds.S	2007-11-23 21:32:48.000000000 -0800
@@ -8,6 +8,7 @@ SECTIONS
   .text      :
   {
     *(.text)
+    *(.text.*)
     *(.fixup)
   }
   _etext = .;
@@ -46,6 +47,7 @@ SECTIONS
   {
    *(.sbss)
    *(.bss)
+   *(.bss.*)
   }
   . = ALIGN(4096);
   _end = . ;
diff -urpN linux-2.6.gc2/arch/powerpc/boot/zImage.ps3.lds.S linux-2.6.gc3/arch/powerpc/boot/zImage.ps3.lds.S
--- linux-2.6.gc2/arch/powerpc/boot/zImage.ps3.lds.S	2007-11-23 18:55:09.000000000 -0800
+++ linux-2.6.gc3/arch/powerpc/boot/zImage.ps3.lds.S	2007-11-23 21:26:51.000000000 -0800
@@ -21,6 +21,7 @@ SECTIONS
   .text      :
   {
     *(.text)
+    *(.text.*)
     *(.fixup)
   }
   _etext = .;
@@ -44,6 +45,7 @@ SECTIONS
   {
    *(.sbss)
    *(.bss)
+   *(.bss.*)
   }
   . = ALIGN(4096);
   _end = . ;
diff -urpN linux-2.6.gc2/arch/powerpc/kernel/vmlinux.lds.S linux-2.6.gc3/arch/powerpc/kernel/vmlinux.lds.S
--- linux-2.6.gc2/arch/powerpc/kernel/vmlinux.lds.S	2007-11-23 20:55:55.000000000 -0800
+++ linux-2.6.gc3/arch/powerpc/kernel/vmlinux.lds.S	2007-11-23 21:32:54.000000000 -0800
@@ -37,7 +37,7 @@ SECTIONS
 		ALIGN_FUNCTION();
 		*(.head.text)
 		_text = .;
-		*(.text .fixup .init.refok.text .exit.text.refok)
+		*(.text *(.text.*) .fixup .init.refok.text .exit.text.refok)
 		SCHED_TEXT
 		LOCK_TEXT
 		KPROBES_TEXT
@@ -240,6 +240,7 @@ SECTIONS
 		*(.sbss) *(.scommon)
 		*(.dynbss)
 		*(.bss)
+		*(.bss.*)
 		*(COMMON)
 		__bss_stop = .;
 	}
diff -urpN linux-2.6.gc2/arch/ppc/kernel/vmlinux.lds.S linux-2.6.gc3/arch/ppc/kernel/vmlinux.lds.S
--- linux-2.6.gc2/arch/ppc/kernel/vmlinux.lds.S	2007-11-23 20:55:54.000000000 -0800
+++ linux-2.6.gc3/arch/ppc/kernel/vmlinux.lds.S	2007-11-23 21:33:01.000000000 -0800
@@ -154,6 +154,7 @@ SECTIONS
    *(.sbss) *(.scommon)
    *(.dynbss)
    *(.bss)
+   *(.bss.*)
    *(COMMON)
   }
   __bss_stop = .;
diff -urpN linux-2.6.gc2/arch/s390/kernel/vmlinux.lds.S linux-2.6.gc3/arch/s390/kernel/vmlinux.lds.S
--- linux-2.6.gc2/arch/s390/kernel/vmlinux.lds.S	2007-11-23 20:55:57.000000000 -0800
+++ linux-2.6.gc3/arch/s390/kernel/vmlinux.lds.S	2007-11-23 21:33:07.000000000 -0800
@@ -142,6 +142,7 @@ SECTIONS
 	.bss : {
 		__bss_start = .;
 		*(.bss)
+		*(.bss.*)
 		. = ALIGN(2);
 		__bss_stop = .;
 	}
diff -urpN linux-2.6.gc2/arch/sh/kernel/vmlinux.lds.S linux-2.6.gc3/arch/sh/kernel/vmlinux.lds.S
--- linux-2.6.gc2/arch/sh/kernel/vmlinux.lds.S	2007-11-23 22:00:09.000000000 -0800
+++ linux-2.6.gc3/arch/sh/kernel/vmlinux.lds.S	2007-11-23 21:33:16.000000000 -0800
@@ -115,8 +115,17 @@ SECTIONS
 	.bss : {
 		__init_end = .;
 		__bss_start = .;		/* BSS */
+
+		/* Why such strage name - .bss.k.page_aligned?
+		 * .bss.page_aligned may clash with a section produced by gcc -fdata_sections.
+		 * .bss_page_aligned, .page_aligned_bss will not work because
+		 * we must use .bss.xxx section names for zero-initialized sections
+		 * we want to combine into bss, otherwise gcc does not set
+		 * 'nobits' flag for the section, and it cannot be merged into bss.
+		 */
 		*(.bss.k.page_aligned)
 		*(.bss)
+		*(.bss.*)
 		*(COMMON)
 		. = ALIGN(4);
 		_ebss = .;			/* uClinux MTD sucks */
diff -urpN linux-2.6.gc2/arch/sh/kernel/vsyscall/vsyscall.lds.S linux-2.6.gc3/arch/sh/kernel/vsyscall/vsyscall.lds.S
--- linux-2.6.gc2/arch/sh/kernel/vsyscall/vsyscall.lds.S	2007-11-23 18:55:10.000000000 -0800
+++ linux-2.6.gc3/arch/sh/kernel/vsyscall/vsyscall.lds.S	2007-11-23 21:21:33.000000000 -0800
@@ -35,7 +35,7 @@ SECTIONS
 	 */
 	. = 0x400;
 
-	.text		: { *(.text) } 			:text	=0x90909090
+	.text		: { *(.text .text.*) }		:text	=0x90909090
 	.note		: { *(.note.*) }		:text	:note
 	.eh_frame_hdr	: { *(.eh_frame_hdr ) }		:text	:eh_frame_hdr
 	.eh_frame	: {
diff -urpN linux-2.6.gc2/arch/sh64/boot/compressed/vmlinux.lds.S linux-2.6.gc3/arch/sh64/boot/compressed/vmlinux.lds.S
--- linux-2.6.gc2/arch/sh64/boot/compressed/vmlinux.lds.S	2007-11-23 18:55:10.000000000 -0800
+++ linux-2.6.gc3/arch/sh64/boot/compressed/vmlinux.lds.S	2007-11-23 21:30:14.000000000 -0800
@@ -32,7 +32,7 @@ SECTIONS
 	*(.gnu.warning)
 	} = NOP
   . = ALIGN(4);
-  .rodata : { *(.rodata) }
+  .rodata : { *(.rodata) *(.rodata.*) }
 
   /* There is no 'real' reason for eight byte alignment, four would work
    * as well, but gdb downloads much (*4) faster with this.
@@ -47,6 +47,7 @@ SECTIONS
 	{
 	_data = .;
 	*(.data)
+	*(.data.*)
 	}
   _data_image = LOADADDR(.data);/* Address of data section in ROM */
 
@@ -58,6 +59,7 @@ SECTIONS
   __bss_start = .;		/* BSS */
   .bss : {
 	*(.bss)
+	*(.bss.*)
 	}
   . = ALIGN(4);
   _end = . ;
diff -urpN linux-2.6.gc2/arch/sh64/kernel/vmlinux.lds.S linux-2.6.gc3/arch/sh64/kernel/vmlinux.lds.S
--- linux-2.6.gc2/arch/sh64/kernel/vmlinux.lds.S	2007-11-23 20:55:55.000000000 -0800
+++ linux-2.6.gc3/arch/sh64/kernel/vmlinux.lds.S	2007-11-23 21:33:26.000000000 -0800
@@ -124,6 +124,7 @@ SECTIONS
   __bss_start = .;		/* BSS */
   .bss : C_PHYS(.bss) {
 	*(.bss)
+	*(.bss.*)
 	}
   . = ALIGN(8);
   _end = . ;
diff -urpN linux-2.6.gc2/arch/sparc/kernel/vmlinux.lds.S linux-2.6.gc3/arch/sparc/kernel/vmlinux.lds.S
--- linux-2.6.gc2/arch/sparc/kernel/vmlinux.lds.S	2007-11-23 20:55:53.000000000 -0800
+++ linux-2.6.gc3/arch/sparc/kernel/vmlinux.lds.S	2007-11-23 21:34:37.000000000 -0800
@@ -97,6 +97,7 @@ SECTIONS
 	.bss : {
 		*(.dynbss)
 		*(.bss)
+		*(.bss.*)
 		*(COMMON)
 	}
 	_end = . ;
diff -urpN linux-2.6.gc2/arch/sparc64/kernel/vmlinux.lds.S linux-2.6.gc3/arch/sparc64/kernel/vmlinux.lds.S
--- linux-2.6.gc2/arch/sparc64/kernel/vmlinux.lds.S	2007-11-23 20:55:53.000000000 -0800
+++ linux-2.6.gc3/arch/sparc64/kernel/vmlinux.lds.S	2007-11-23 21:34:31.000000000 -0800
@@ -131,6 +131,7 @@ SECTIONS
 	.bss : {
 		*(.dynbss)
 		*(.bss)
+		*(.bss.*)
 		*(COMMON)
 	}
 	_end = . ;
diff -urpN linux-2.6.gc2/arch/um/kernel/uml.lds.S linux-2.6.gc3/arch/um/kernel/uml.lds.S
--- linux-2.6.gc2/arch/um/kernel/uml.lds.S	2007-11-23 20:55:54.000000000 -0800
+++ linux-2.6.gc3/arch/um/kernel/uml.lds.S	2007-11-23 21:34:25.000000000 -0800
@@ -91,6 +91,7 @@ SECTIONS
   {
    *(.dynbss)
    *(.bss)
+   *(.bss.*)
    *(COMMON)
   }
   _end = .;
diff -urpN linux-2.6.gc2/arch/v850/kernel/vmlinux.lds.S linux-2.6.gc3/arch/v850/kernel/vmlinux.lds.S
--- linux-2.6.gc2/arch/v850/kernel/vmlinux.lds.S	2007-11-23 20:55:56.000000000 -0800
+++ linux-2.6.gc3/arch/v850/kernel/vmlinux.lds.S	2007-11-23 21:34:18.000000000 -0800
@@ -127,6 +127,7 @@
 #define BSS_CONTENTS							      \
 		__sbss = . ;						      \
 			*(.bss)						      \
+			*(.bss.*)					      \
 			*(COMMON)					      \
 		. = ALIGN (4) ;						      \
 		__init_stack_end = . ;					      \
diff -urpN linux-2.6.gc2/arch/x86/kernel/Makefile_32 linux-2.6.gc3/arch/x86/kernel/Makefile_32
--- linux-2.6.gc2/arch/x86/kernel/Makefile_32	2007-11-23 22:16:54.000000000 -0800
+++ linux-2.6.gc3/arch/x86/kernel/Makefile_32	2007-11-23 22:16:43.000000000 -0800
@@ -2,8 +2,9 @@
 # Makefile for the linux kernel.
 #
 
-extra-y := head_32.o init_task.o vmlinux.lds
+extra-y := head_32.o init_task.o vmlinux.lds modules.lds
 CPPFLAGS_vmlinux.lds += -Ui386
+CPPFLAGS_modules.lds += -Ui386
 
 obj-y	:= process_32.o signal_32.o entry_32.o traps_32.o irq_32.o \
 		ptrace_32.o time_32.o ioport_32.o ldt_32.o setup_32.o i8259_32.o sys_i386_32.o \
diff -urpN linux-2.6.gc2/arch/x86/kernel/Makefile_64 linux-2.6.gc3/arch/x86/kernel/Makefile_64
--- linux-2.6.gc2/arch/x86/kernel/Makefile_64	2007-11-23 22:17:07.000000000 -0800
+++ linux-2.6.gc3/arch/x86/kernel/Makefile_64	2007-11-23 22:16:43.000000000 -0800
@@ -2,8 +2,10 @@
 # Makefile for the linux kernel.
 #
 
-extra-y 	:= head_64.o head64.o init_task.o vmlinux.lds
+extra-y 	:= head_64.o head64.o init_task.o vmlinux.lds modules.lds
 CPPFLAGS_vmlinux.lds += -Ux86_64
+CPPFLAGS_modules.lds += -Ux86_64
+
 EXTRA_AFLAGS	:= -traditional
 
 obj-y	:= process_64.o signal_64.o entry_64.o traps_64.o irq_64.o \
diff -urpN linux-2.6.gc2/arch/x86/kernel/modules.lds.S linux-2.6.gc3/arch/x86/kernel/modules.lds.S
--- linux-2.6.gc2/arch/x86/kernel/modules.lds.S	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.gc3/arch/x86/kernel/modules.lds.S	2007-11-23 22:16:04.000000000 -0800
@@ -0,0 +1,128 @@
+#ifdef CONFIG_X86_32
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+#else
+OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
+OUTPUT_ARCH(i386:x86-64)
+#endif
+
+/*
+This linker script is used if CONFIG_DISCARD_UNUSED_SECTIONS=y.
+We are trying to minimize number of sections in .ko file
+by coalescing .text.x, rodata.x, .data.x and bss.x input
+sections into one output section each.
+
+Kernel module loader (kernel/module.c) needs to see the following sections:
+
+.init*
+.exit*
+.gnu.linkonce.this_module
+.percpu.data
+.modinfo
+__ksymtab_gpl_future
+__ksymtab_gpl
+__ksymtab_unused_gpl
+__ksymtab_unused
+__ksymtab
+__kcrctab_gpl_future
+__kcrctab_gpl
+__kcrctab_unused_gpl
+__kcrctab_unused
+__kcrctab
+__param
+__ex_table
+__obsparm
+__versions
+.debug (?!)
+$ARCH_UNWIND_SECTION_NAME (none for x86 yet)
+
+They must not be coalesced into sections with other names.
+
+*/
+
+SECTIONS
+{
+  /* ro, code */
+
+  /* .fixup and .altinstr_replacement work just fine
+   * without dedicated sections */
+  .text				: {
+				    *(SORT_BY_ALIGNMENT(.text*))
+				/* __ex_table points here */
+				    *(SORT_BY_ALIGNMENT(.fixup*))
+				/* .altinstructions points here */
+				    *(SORT_BY_ALIGNMENT(.altinstr_replacement*))
+				}
+  /* only if CONFIG_MODULE_UNLOAD */
+  .exit.text			: { *(SORT_BY_ALIGNMENT(.exit.text)) }
+  /* end CONFIG_MODULE_UNLOAD */
+
+  /* ro, data */
+
+  .rodata			: { *(SORT_BY_ALIGNMENT(.rodata*)) }
+  /* Kernel searches through this table when it needs to handle an exception */
+  __ex_table			: { *(__ex_table*) }
+  /* These two tables are not currently handled by in-kernel module loader,
+   * but likely will be in future kernels */
+  .altinstructions		: { *(.altinstructions*) }
+  .smp_locks			: { *(.smp_locks*) }
+  /* Used by depmod in order to generate modules.dep, modules.symbols */
+  __ksymtab_strings		: { *(SORT_BY_ALIGNMENT(__ksymtab_strings)) }
+  /* EXPORT_SYMBOLs exported in this module */
+  __ksymtab_gpl_future		: { *(__ksymtab_gpl_future) }
+  __ksymtab_gpl			: { *(__ksymtab_gpl) }
+  __ksymtab_unused_gpl		: { *(__ksymtab_unused_gpl) }
+  __ksymtab_unused		: { *(__ksymtab_unused) }
+  __ksymtab			: { *(__ksymtab) }
+  /* only if CONFIG_MODVERSIONS */
+  __kcrctab_gpl_future		: { *(__kcrctab_gpl_future) }
+  __kcrctab_gpl			: { *(__kcrctab_gpl) }
+  __kcrctab_unused_gpl		: { *(__kcrctab_unused_gpl) }
+  __kcrctab_unused		: { *(__kcrctab_unused) }
+  __kcrctab			: { *(__kcrctab) }
+  /* from *.mod.c: const struct modversion_info ____versions[] */
+  __versions			: { *(__versions) }
+  /* end CONFIG_MODVERSIONS */
+  __param			: { *(.__param) }
+  __obsparm			: { *(.__obsparm) }
+  /* from *.mod.c: const char __module_depends[] "depends=mod1,mod2" */
+  .modinfo			: { *(SORT_BY_ALIGNMENT(.modinfo)) }
+  /* ld segfaults if we give it --build-id and then discard this section */
+  .note.gnu.build-id		: { *(.note.gnu.build-id) }
+
+  /* rw, data */
+
+  .data				: {
+				    *(SORT_BY_ALIGNMENT(.cacheline_aligned.data))
+				    *(SORT_BY_ALIGNMENT(.data*))
+				    *(SORT_BY_ALIGNMENT(.read_mostly.data))
+				}
+  /* from *.mod.c: struct module __this_module */
+  .gnu.linkonce.this_module	: { *(.gnu.linkonce.this_module) }
+
+  /* only if CONFIG_SMP */
+  .percpu.data			: { *(SORT_BY_ALIGNMENT(.percpu.data)) }
+  /* end CONFIG_SMP */
+
+  /* only if CONFIG_MODULE_UNLOAD */
+  .exit.data			: { *(SORT_BY_ALIGNMENT(.exit.data)) }
+  /* end CONFIG_MODULE_UNLOAD */
+
+  /* rw, data initialized to 0 */
+
+  .bss				: { *(SORT_BY_ALIGNMENT(.bss*)) }
+
+  /* init code/data. discarded at the end of sys_init_module() */
+
+  .init.text			: { *(SORT_BY_ALIGNMENT(.init.text)) }
+  .init.data			: { *(SORT_BY_ALIGNMENT(.init.data)) }
+
+  /* Be bold and resist the temptation to pull junk "by default" */
+
+  /DISCARD/			: { *(*) }
+
+  /* If you are going to revive these, please add comment why it is needed */
+  /* .debug			: { *(.debug) } */
+  /* .comment			: { *(.comment) } */
+  /* .note.GNU-stack		: { *(.note.GNU-stack) } */
+}
diff -urpN linux-2.6.gc2/arch/x86/kernel/vmlinux_32.lds.S linux-2.6.gc3/arch/x86/kernel/vmlinux_32.lds.S
--- linux-2.6.gc2/arch/x86/kernel/vmlinux_32.lds.S	2007-11-23 22:00:09.000000000 -0800
+++ linux-2.6.gc3/arch/x86/kernel/vmlinux_32.lds.S	2007-11-23 21:48:58.000000000 -0800
@@ -2,14 +2,7 @@
  * Written by Martin Mares <[email protected]>;
  *
  * Don't define absolute symbols until and unless you know that symbol
- * value is should remain constant even if kernel image is relocated
- * at run time. Absolute symbols are not relocated. If symbol value should
- * change if kernel is relocated, make the symbol section relative and
- * put it inside the section definition.
- */
-
-/* Don't define absolute symbols until and unless you know that symbol
- * value is should remain constant even if kernel image is relocated
+ * value should remain constant even if kernel image is relocated
  * at run time. Absolute symbols are not relocated. If symbol value should
  * change if kernel is relocated, make the symbol section relative and
  * put it inside the section definition.
@@ -39,7 +32,7 @@ SECTIONS
 
   .head.text : AT(ADDR(.head.text) - LOAD_OFFSET) {
   	_text = .;			/* Text and read-only data */
-	*(.head.text)
+	KEEP(*(.head.text))
   } :text = 0x9090
 
   /* read-only */
@@ -48,16 +41,17 @@ SECTIONS
 	SCHED_TEXT
 	LOCK_TEXT
 	KPROBES_TEXT
-	*(.fixup)
+	*(.fixup) /* no need to KEEP, every .fixup is referenced by __ex_table */
 	*(.gnu.warning)
   	_etext = .;			/* End of text section */
   } :text = 0x9090
 
   . = ALIGN(16);		/* Exception table */
   __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) {
-  	__start___ex_table = .;
-	 *(__ex_table)
-  	__stop___ex_table = .;
+	/* Points to potentially-faulting insns and corresponding .fixups */
+	__start___ex_table = .;
+	KEEP(*(__ex_table))
+	__stop___ex_table = .;
   }
 
   NOTES :text :note
@@ -67,7 +61,7 @@ SECTIONS
   . = ALIGN(4);
   .tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) {
   	__tracedata_start = .;
-	*(.tracedata)
+	KEEP(*(.tracedata)) /* really need to KEEP? */
   	__tracedata_end = .;
   }
 
@@ -83,7 +77,7 @@ SECTIONS
   . = ALIGN(4096);
   .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) {
   	__nosave_begin = .;
-	*(.nosave.data)
+	*(.nosave.data) /* not saved by suspend */
   	. = ALIGN(4096);
   	__nosave_end = .;
   }
@@ -115,7 +109,7 @@ SECTIONS
   . = ALIGN(4096);
   .smp_locks : AT(ADDR(.smp_locks) - LOAD_OFFSET) {
   	__smp_locks = .;
-	*(.smp_locks)
+	KEEP(*(.smp_locks)) /* points to lock prefixes */
 	__smp_locks_end = .;
   }
   /* will be freed after init
@@ -134,11 +128,11 @@ SECTIONS
 	*(.init.text)
 	_einittext = .;
   }
-  .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { *(.init.data) }
+  .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { *(.init.data) } /* no need to KEEP */
   . = ALIGN(16);
   .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) {
   	__setup_start = .;
-	*(.init.setup)
+	KEEP(*(.init.setup)) /* obsolete_checksetup() walks it */
   	__setup_end = .;
    }
   .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) {
@@ -148,26 +142,26 @@ SECTIONS
   }
   .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) {
   	__con_initcall_start = .;
-	*(.con_initcall.init)
+	KEEP(*(.con_initcall.init)) /* console_init() walks it */
   	__con_initcall_end = .;
   }
   SECURITY_INIT
   . = ALIGN(4);
   .altinstructions : AT(ADDR(.altinstructions) - LOAD_OFFSET) {
   	__alt_instructions = .;
-	*(.altinstructions)
+	KEEP(*(.altinstructions)) /* alternative_instructions() walks it */
 	__alt_instructions_end = .;
   }
   .altinstr_replacement : AT(ADDR(.altinstr_replacement) - LOAD_OFFSET) {
-	*(.altinstr_replacement)
+	KEEP(*(.altinstr_replacement))
   }
   . = ALIGN(4);
   .parainstructions : AT(ADDR(.parainstructions) - LOAD_OFFSET) {
   	__parainstructions = .;
-	*(.parainstructions)
+	KEEP(*(.parainstructions)) /* really need to KEEP? */
   	__parainstructions_end = .;
   }
-  /* .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) }
@@ -175,7 +169,7 @@ SECTIONS
   . = ALIGN(4096);
   .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) {
 	__initramfs_start = .;
-	*(.init.ramfs)
+	KEEP(*(.init.ramfs))
 	__initramfs_end = .;
   }
 #endif
@@ -192,8 +186,17 @@ SECTIONS
   .bss : AT(ADDR(.bss) - LOAD_OFFSET) {
 	__init_end = .;
 	__bss_start = .;		/* BSS */
+
+	/* Why such strage name - .bss.k.page_aligned?
+	 * .bss.page_aligned may clash with a section produced by gcc -fdata_sections.
+	 * .bss_page_aligned, .page_aligned_bss will not work because
+	 * we must use .bss.xxx section names for zero-initialized sections
+	 * we want to combine into bss, otherwise gcc does not set
+	 * 'nobits' flag for the section, and it cannot be merged into bss.
+	 */
 	*(.bss.k.page_aligned)
 	*(.bss)
+	*(SORT_BY_ALIGNMENT(.bss.*))
 	. = ALIGN(4);
 	__bss_stop = .;
   	_end = . ;
diff -urpN linux-2.6.gc2/arch/x86/kernel/vmlinux_64.lds.S linux-2.6.gc3/arch/x86/kernel/vmlinux_64.lds.S
--- linux-2.6.gc2/arch/x86/kernel/vmlinux_64.lds.S	2007-11-23 22:00:09.000000000 -0800
+++ linux-2.6.gc3/arch/x86/kernel/vmlinux_64.lds.S	2007-11-23 21:49:45.000000000 -0800
@@ -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 */
-	*(.head.text)
+	KEEP(*(.head.text))
 	_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 */
@@ -45,7 +45,8 @@ SECTIONS
 
   . = ALIGN(16);		/* Exception table */
   __start___ex_table = .;
-  __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { *(__ex_table) }
+  /* Points to potentially-faulting insns and corresponding .fixups */
+  __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { KEEP(*(__ex_table)) }
   __stop___ex_table = .;
 
   NOTES :text :note
@@ -57,7 +58,7 @@ SECTIONS
   . = ALIGN(4);
   .tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) {
   	__tracedata_start = .;
-	*(.tracedata)
+	KEEP(*(.tracedata)) /* really need to KEEP? */
   	__tracedata_end = .;
   }
 
@@ -91,24 +92,24 @@ 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) }
+		{ KEEP(*(.vsyscall_1)) }
   .vsyscall_2 ADDR(.vsyscall_0) + 2048: AT(VLOAD(.vsyscall_2))
-		{ *(.vsyscall_2) }
+		{ KEEP(*(.vsyscall_2)) }
 
   .vgetcpu_mode : AT(VLOAD(.vgetcpu_mode)) { *(.vgetcpu_mode) }
   vgetcpu_mode = VVIRT(.vgetcpu_mode);
@@ -118,7 +119,7 @@ SECTIONS
   jiffies = VVIRT(.jiffies);
 
   .vsyscall_3 ADDR(.vsyscall_0) + 3072: AT(VLOAD(.vsyscall_3))
-		{ *(.vsyscall_3) }
+		{ KEEP(*(.vsyscall_3)) }
 
   . = VSYSCALL_VIRT_ADDR + 4096;
 
@@ -145,7 +146,7 @@ SECTIONS
   __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);
@@ -159,11 +160,11 @@ SECTIONS
 	_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,18 +173,18 @@ 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
      from .altinstructions and .eh_frame */
@@ -192,14 +193,14 @@ SECTIONS
 
 /* 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,14 +211,23 @@ SECTIONS
 
   . = ALIGN(4096);
   __nosave_begin = .;
-  .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) { *(.nosave.data) }
+  .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) { *(.nosave.data) } /* not saved by suspend */
   . = ALIGN(4096);
   __nosave_end = .;
 
   __bss_start = .;		/* BSS */
   .bss : AT(ADDR(.bss) - LOAD_OFFSET) {
+
+	/* Why such strage name - .bss.k.page_aligned?
+	 * .bss.page_aligned may clash with a section produced by gcc -fdata_sections.
+	 * .bss_page_aligned, .page_aligned_bss will not work because
+	 * we must use .bss.xxx section names for zero-initialized sections
+	 * we want to combine into bss, otherwise gcc does not set
+	 * 'nobits' flag for the section, and it cannot be merged into bss.
+	 */
 	*(.bss.k.page_aligned)
 	*(.bss)
+	*(SORT_BY_ALIGNMENT(.bss.*))
 	}
   __bss_stop = .;
 
diff -urpN linux-2.6.gc2/arch/x86/kernel/vsyscall_32.lds.S linux-2.6.gc3/arch/x86/kernel/vsyscall_32.lds.S
--- linux-2.6.gc2/arch/x86/kernel/vsyscall_32.lds.S	2007-11-23 18:55:10.000000000 -0800
+++ linux-2.6.gc3/arch/x86/kernel/vsyscall_32.lds.S	2007-11-23 22:05:37.000000000 -0800
@@ -23,10 +23,10 @@ SECTIONS
      is insufficient, ld -shared will barf.  Just increase it here.  */
   . = VDSO_PRELINK_asm + 0x400;
 
-  .text           : { *(.text) }		:text =0x90909090
+  .text           : { *(.text .text.*) }	:text =0x90909090
   .note		  : { *(.note.*) }		:text :note
   .eh_frame_hdr   : { *(.eh_frame_hdr) }	:text :eh_frame_hdr
-  .eh_frame       : { KEEP (*(.eh_frame)) }	:text
+  .eh_frame       : { KEEP(*(.eh_frame)) }	:text
   .dynamic        : { *(.dynamic) }		:text :dynamic
   .useless        : {
   	*(.got.plt) *(.got)
diff -urpN linux-2.6.gc2/arch/xtensa/kernel/vmlinux.lds.S linux-2.6.gc3/arch/xtensa/kernel/vmlinux.lds.S
--- linux-2.6.gc2/arch/xtensa/kernel/vmlinux.lds.S	2007-11-23 22:00:09.000000000 -0800
+++ linux-2.6.gc3/arch/xtensa/kernel/vmlinux.lds.S	2007-11-23 21:33:37.000000000 -0800
@@ -255,7 +255,15 @@ SECTIONS
 
   /* BSS section */
   _bss_start = .;
-  .bss : { *(.bss.k.page_aligned) *(.bss) }
+
+  /* Why such strage name - .bss.k.page_aligned?
+   * .bss.page_aligned may clash with a section produced by gcc -fdata_sections.
+   * .bss_page_aligned, .page_aligned_bss will not work because
+   * we must use .bss.xxx section names for zero-initialized sections
+   * we want to combine into bss, otherwise gcc does not set
+   * 'nobits' flag for the section, and it cannot be merged into bss.
+   */
+  .bss : { *(.bss.k.page_aligned) *(.bss) *(.bss.*) }
   _bss_end = .;
 
   _end = .;
diff -urpN linux-2.6.gc2/include/asm-generic/vmlinux.lds.h linux-2.6.gc3/include/asm-generic/vmlinux.lds.h
--- linux-2.6.gc2/include/asm-generic/vmlinux.lds.h	2007-11-23 20:55:54.000000000 -0800
+++ linux-2.6.gc3/include/asm-generic/vmlinux.lds.h	2007-11-23 21:15:24.000000000 -0800
@@ -6,12 +6,19 @@
 #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.*))					\
 	*(.init.refok.data)						\
 	. = ALIGN(8);							\
 	VMLINUX_SYMBOL(__start___markers) = .;				\
@@ -22,7 +29,7 @@
 	. = ALIGN((align));						\
 	.rodata           : AT(ADDR(.rodata) - LOAD_OFFSET) {		\
 		VMLINUX_SYMBOL(__start_rodata) = .;			\
-		*(.rodata) *(.rodata.*)					\
+		*(.rodata) *(SORT_BY_ALIGNMENT(.rodata.*))		\
 		*(__vermagic)		/* Kernel version magic */	\
 		*(__markers_strings)	/* Markers: strings */		\
 	}								\
@@ -33,109 +40,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) = .;			\
 	}								\
@@ -149,7 +157,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) = .;		\
 	}
 
@@ -158,6 +166,7 @@
 #define TEXT_TEXT							\
 		ALIGN_FUNCTION();					\
 		*(.text)						\
+		*(SORT_BY_ALIGNMENT(.text.*))				\
 		*(.init.refok.text)					\
 		*(.exit.text.refok)
 
@@ -166,6 +175,7 @@
 #define SCHED_TEXT							\
 		ALIGN_FUNCTION();					\
 		VMLINUX_SYMBOL(__sched_text_start) = .;			\
+		/* No need to KEEP */					\
 		*(.sched.text)						\
 		VMLINUX_SYMBOL(__sched_text_end) = .;
 
@@ -174,12 +184,14 @@
 #define LOCK_TEXT							\
 		ALIGN_FUNCTION();					\
 		VMLINUX_SYMBOL(__lock_text_start) = .;			\
+		/* No need to KEEP */					\
 		*(.spinlock.text)					\
 		VMLINUX_SYMBOL(__lock_text_end) = .;
 
 #define KPROBES_TEXT							\
 		ALIGN_FUNCTION();					\
 		VMLINUX_SYMBOL(__kprobes_text_start) = .;		\
+		/* No need to KEEP */					\
 		*(.kprobes.text)					\
 		VMLINUX_SYMBOL(__kprobes_text_end) = .;
 
@@ -225,35 +237,37 @@
 	. = ALIGN(8);							\
 	__bug_table : AT(ADDR(__bug_table) - LOAD_OFFSET) {		\
 		__start___bug_table = .;				\
-		*(__bug_table)						\
+		/* Support for BUG() */					\
+		KEEP(*(__bug_table))					\
 		__stop___bug_table = .;					\
 	}
 
 #define NOTES								\
 	.notes : AT(ADDR(.notes) - LOAD_OFFSET) {			\
 		VMLINUX_SYMBOL(__start_notes) = .;			\
-		*(.note.*)						\
+		/* For /sys/kernel/notes */				\
+		KEEP(*(.note.*))					\
 		VMLINUX_SYMBOL(__stop_notes) = .;			\
 	}
 
 #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.gc2/init/Kconfig linux-2.6.gc3/init/Kconfig
--- linux-2.6.gc2/init/Kconfig	2007-11-23 18:55:26.000000000 -0800
+++ linux-2.6.gc3/init/Kconfig	2007-11-23 22:22:31.000000000 -0800
@@ -425,6 +425,23 @@ 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.
+
+	  This option also requires architecture-specific changes.
+	  Currently working architectures: x86
+
+	  If unsure, say N.
+
 config SYSCTL
 	bool
 
diff -urpN linux-2.6.gc2/scripts/Makefile.modpost linux-2.6.gc3/scripts/Makefile.modpost
--- linux-2.6.gc2/scripts/Makefile.modpost	2007-11-23 18:55:26.000000000 -0800
+++ linux-2.6.gc3/scripts/Makefile.modpost	2007-11-24 14:46:38.000000000 -0800
@@ -97,9 +97,15 @@ $(modules:.ko=.mod.o): %.mod.o: %.mod.c 
 targets += $(modules:.ko=.mod.o)
 
 # Step 6), final link of the modules
+ifdef CONFIG_DISCARD_UNUSED_SECTIONS
+quiet_cmd_ld_ko_o = LD [M]  $@
+      cmd_ld_ko_o = $(LD) -r -T arch/$(SRCARCH)/kernel/modules.lds $(LDFLAGS) $(LDFLAGS_MODULE) -o $@ -Map [email protected] \
+			  $(filter-out FORCE,$^)
+else
 quiet_cmd_ld_ko_o = LD [M]  $@
       cmd_ld_ko_o = $(LD) -r $(LDFLAGS) $(LDFLAGS_MODULE) -o $@		\
 			  $(filter-out FORCE,$^)
+endif
 
 $(modules): %.ko :%.o %.mod.o FORCE
 	$(call if_changed,ld_ko_o)

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux