Skip to contentSkip to conversation

Testing of function/data-sections on linux-2.6.35-rc4

PATCH Denys Vlasenko 3 participants 13 messages Jul 18, 2010 – Jul 26, 2010

Subsystems (14)
Arm (32-bit) x86 PowerPC Kbuild +10 more subsystems
lore
Share & tools
lore
#0 lore raw

Hi Tim, Tim, folks,

Update on -ffunction-sections status:

I re-tested linux-2.6.35-rc4 today.

Most of work needed for -ffunction-sections -fdata-sections is already in this kernel. This mail explains what is still missing.

In order to have a working kernel with this make invocation:

make KCFLAGS="-ffunction-sections -fdata-sections"

linux-2.6.35-rc4 needs three patches:

* modpost fix for 64k+ sections: linux-2.6.35-rc4-fs.modpost.patch This patch is in -mm, it still not reach mainline...

* fix for kernel linker stripts: linux-2.6.35-rc4-fs.fix-kernel-linker-scripts.patch It makes _all_ linker scripts -ffunction/data-sections safe via:
- *(.data)
+ *(.data .data.*)

* fix for module linker script: linux-2.6.35-rc4-fs.fix-ko-module-linker-script.patch Prevents kernel modules from having unnecessarily many
sections and thus prevents module size growth.

Then, in order to also garbage-collect the sections, I added

LDFLAGS_vmlinux += --gc-sections

in top-level Makefile.

This requires the additional patch (linux-2.6.35-rc4-fsgs.patch) which adds KEEP(section) directives to kernel linker stripts. Otherwise, linker will discard some crucial sections.

All four patches are attached.

I am sending this email from the machine which runs the kernel built with -ffunction-sections -fdata-sections --gc-sections.

Signature · 1 line
vda
scripts/mod/file2alias.c +3 -3
@@ -884,16 +884,16 @@
 	char *zeros = NULL;
 
 	/* We're looking for a section relative symbol */
-	if (!sym->st_shndx || sym->st_shndx >= info->hdr->e_shnum)
+	if (!sym->st_shndx || get_secindex(info, sym) >= info->num_sections)
 		return;
 
 	/* Handle all-NULL symbols allocated into .bss */
-	if (info->sechdrs[sym->st_shndx].sh_type & SHT_NOBITS) {
+	if (info->sechdrs[get_secindex(info, sym)].sh_type & SHT_NOBITS) {
 		zeros = calloc(1, sym->st_size);
 		symval = zeros;
 	} else {
 		symval = (void *)info->hdr
-			+ info->sechdrs[sym->st_shndx].sh_offset
+			+ info->sechdrs[get_secindex(info, sym)].sh_offset
 			+ sym->st_value;
 	}
 
scripts/mod/modpost.c +68 -26

199 lines not on this page · raw message

scripts/mod/modpost.h +43 -0

50 lines not on this page · raw message

arch/alpha/boot/bootloader.lds +4 -4
@@ -4,17 +4,17 @@
 SECTIONS
 {
   . = 0x20000000;
-  .text : { *(.text) }
+  .text : { *(.text .text.*) }
   _etext = .;
   PROVIDE (etext = .);
-  .rodata : { *(.rodata) *(.rodata.*) }
-  .data : { *(.data) CONSTRUCTORS }
+  .rodata : { *(.rodata .rodata.*) }
+  .data : { *(.data .data.*) CONSTRUCTORS }
   .got : { *(.got) }
   .sdata : { *(.sdata) }
   _edata = .;
   PROVIDE (edata = .);
   .sbss : { *(.sbss) *(.scommon) }
-  .bss : { *(.bss) *(COMMON) }
+  .bss : { *(.bss .bss.*) *(COMMON) }
   _end = . ;
   PROVIDE (end = .);
 
arch/arm/boot/bootp/bootp.lds +1 -1
@@ -15,7 +15,7 @@
   .text : {
    _stext = .;
    *(.start)
-   *(.text)
+   *(.text .text.*)
    initrd_size = initrd_end - initrd_start;
    _etext = .;
   }
arch/arm/boot/compressed/vmlinux.lds.in +2 -4
@@ -29,12 +29,10 @@
   .text : {
     _start = .;
     *(.start)
-    *(.text)
-    *(.text.*)
+    *(.text .text.*)
     *(.fixup)
     *(.gnu.warning)
-    *(.rodata)
-    *(.rodata.*)
+    *(.rodata .rodata.*)
     *(.glue_7)
     *(.glue_7t)
     *(.piggydata)
arch/arm/kernel/vmlinux.lds.S +1 -2
@@ -95,8 +95,7 @@
 			*(.fixup)
 #endif
 			*(.gnu.warning)
-			*(.rodata)
-			*(.rodata.*)
+			*(.rodata .rodata.*)
 			*(.glue_7)
 			*(.glue_7t)
 		*(.got)			/* Global offset table		*/
arch/cris/boot/compressed/decompress_v10.lds +4 -5
@@ -12,19 +12,18 @@
 	.text :
 	{
 		_stext = . ;
-		*(.text)
-		*(.rodata)
-		*(.rodata.*)
+		*(.text .text.*)
+		*(.rodata .rodata.*)
 		_etext = . ;
 	} > dram
 	.data :
 	{
-		*(.data)
+		*(.data .data.*)
 		_edata = . ;
 	} > dram
 	.bss :
 	{
-		*(.bss)
+		*(.bss .bss.*)
 		_end = ALIGN( 0x10 ) ;
 	} > dram
 }
arch/cris/boot/compressed/decompress_v32.lds +4 -5
@@ -12,19 +12,18 @@
 	.text :
 	{
 		_stext = . ;
-		*(.text)
-		*(.rodata)
-		*(.rodata.*)
+		*(.text .text.*)
+		*(.rodata .rodata.*)
 		_etext = . ;
 	} > dram
 	.data :
 	{
-		*(.data)
+		*(.data .data.*)
 		_edata = . ;
 	} > dram
 	.bss :
 	{
-		*(.bss)
+		*(.bss .bss.*)
 		_end = ALIGN( 0x10 ) ;
 	} > dram
 }
arch/cris/boot/rescue/rescue_v10.lds +2 -2
@@ -9,12 +9,12 @@
 	.text :
 	{
 		stext = . ;
-		*(.text)
+		*(.text .text.*)
 		etext = . ;
 	} > flash
 	.data :
 	{
-		*(.data)
+		*(.data .data.*)
 		edata = . ;
 	} > flash
 }
arch/cris/boot/rescue/rescue_v32.lds +4 -5
@@ -16,21 +16,20 @@
 	.text :
 	{
 		_stext = . ;
-		*(.text)
+		*(.text .text.*)
 		*(.init.text)
-		*(.rodata)
-		*(.rodata.*)
+		*(.rodata .rodata.*)
 		_etext = . ;
 	} > bootblk
 	.data :
 	{
-		*(.data)
+		*(.data .data.*)
 		_edata = . ;
 	} > bootblk
 	.bss :
 	{
 		_bss = . ;
-		*(.bss)
+		*(.bss .bss.*)
 		_end = ALIGN( 0x10 ) ;
 	} > intmem
 
arch/frv/kernel/vmlinux.lds.S +1 -1
@@ -114,7 +114,7 @@
 
   .sbss		: { *(.sbss .sbss.*) }
   .bss		: { *(.bss .bss.*) }
-  .bss..stack	: { *(.bss) }
+  .bss..stack	: { *(.bss) } /* BUG??? we already absorbed it into .bss */
 
   __bss_stop = .;
   _end = . ;
arch/h8300/boot/compressed/vmlinux.lds +2 -2
@@ -5,13 +5,13 @@
         __stext = . ;
 	__text = .;
 	       *(.text..startup)
-	       *(.text)
+	       *(.text .text.*)
         __etext = . ;
         }
 
 	.rodata :
 	{
-		*(.rodata)
+		*(.rodata .rodata.*)
 	}
         .data :
 
arch/h8300/boot/compressed/vmlinux.scr +1 -1
@@ -3,7 +3,7 @@
   .data : {
 	_input_len = .;
 	LONG(_input_data_end - _input_data) _input_data = .;
-	*(.data)
+	*(.data .data.*)
 	_input_data_end = .;
 	}
 }
arch/ia64/hp/sim/boot/bootloader.lds +4 -4
@@ -7,13 +7,13 @@
   . = 0x100000;
 
   _text = .;
-  .text : { *(__ivt_section) *(.text) }
+  .text : { *(__ivt_section) *(.text .text.*) }
   _etext = .;
 
   /* Global data */
   _data = .;
-  .rodata : { *(.rodata) *(.rodata.*) }
-  .data    : { *(.data) *(.gnu.linkonce.d*) CONSTRUCTORS }
+  .rodata : { *(.rodata .rodata.*) }
+  .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 @@
 
   __bss_start = .;
   .sbss      : { *(.sbss) *(.scommon) }
-  .bss       : { *(.bss) *(COMMON) }
+  .bss       : { *(.bss .bss.*) *(COMMON) }
   . = ALIGN(64 / 8);
   __bss_stop = .;
   _end = . ;
arch/ia64/kernel/gate.lds.S +2 -2
@@ -54,10 +54,10 @@
 	.IA_64.unwind_info	: { *(.IA_64.unwind_info*) }
 	.IA_64.unwind		: { *(.IA_64.unwind*) }	:readable	:unwind
 #ifdef HAVE_BUGGY_SEGREL
-	.text (GATE_ADDR + PAGE_SIZE) : { *(.text) *(.text.*) }	:readable
+	.text (GATE_ADDR + PAGE_SIZE) : { *(.text .text.*) }	:readable
 #else
 	. = ALIGN(PERCPU_PAGE_SIZE) + (. & (PERCPU_PAGE_SIZE - 1));
-	.text			: { *(.text) *(.text.*) }	:epc
+	.text			: { *(.text .text.*) }	:epc
 #endif
 
 	/DISCARD/		: {
arch/ia64/scripts/check-segrel.lds +2 -2
@@ -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 {
arch/m32r/boot/compressed/vmlinux.lds.S +4 -4
@@ -6,12 +6,12 @@
   . = CONFIG_MEMORY_START + 0x00400000;
 
   _text = .;
-  .text : { *(.text) } = 0
-  .rodata : { *(.rodata) *(.rodata.*) }
+  .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 @@
 
   . = ALIGN(32 / 8);
   __bss_start = .;
-  .bss : { *(.bss) *(.sbss) }
+  .bss : { *(.bss .bss.*) *(.sbss) }
   . = ALIGN(32 / 8);
   _ebss = .;
   . = ALIGN(4096);
arch/m32r/boot/compressed/vmlinux.scr +1 -1
@@ -2,7 +2,7 @@
 {
   .data : {
 	zimage_data = .;
-	*(.data)
+	*(.data .data.*)
 	zimage_data_end = .;
 	}
   zimage_len = zimage_data_end - zimage_data;
arch/m68knommu/kernel/vmlinux.lds.S +2 -2
@@ -75,7 +75,7 @@
 		*(__ex_table)
 		__stop___ex_table = .;
 
-		*(.rodata) *(.rodata.*)
+		*(.rodata .rodata.*)
 		*(__vermagic)		/* Kernel version magic */
 		*(__markers_strings)
 		*(.rodata1)
@@ -168,7 +168,7 @@
 	.bss : {
 		. = ALIGN(4);
 		_sbss = . ;
-		*(.bss)
+		*(.bss .bss.*)
 		*(COMMON)
 		. = ALIGN(4) ;
 		_ebss = . ;
arch/mips/lasat/image/romscript.normal +1 -1
@@ -11,7 +11,7 @@
 
   .data ALIGN(0x10) :
   {
-    *(.data)
+    *(.data .data.*)
   }
   _image_start = ADDR(.data);
   _image_size = SIZEOF(.data);
arch/mn10300/boot/compressed/vmlinux.lds +1 -1
@@ -3,7 +3,7 @@
   .data : {
 	input_len = .;
 	LONG(input_data_end - input_data) input_data = .;
-	*(.data)
+	*(.data .data.*)
 	input_data_end = .;
 	}
 }
arch/parisc/kernel/vmlinux.lds.S +1 -1
@@ -111,7 +111,7 @@
 		*(.data..vm0.pte)
 	}
 	.bss : {
-		*(.bss)
+		*(.bss .bss.*)
 		*(COMMON)
 	}
 	__bss_stop = .;
arch/powerpc/boot/zImage.coff.lds.S +2 -2
@@ -6,7 +6,7 @@
   _start = .;
   .text      :
   {
-    *(.text)
+    *(.text .text.*)
     *(.fixup)
   }
   _etext = .;
@@ -40,7 +40,7 @@
   .bss       :
   {
    *(.sbss)
-   *(.bss)
+   *(.bss .bss.*)
   }
   _end = . ;
 
arch/powerpc/boot/zImage.lds.S +2 -2
@@ -6,7 +6,7 @@
   _start = .;
   .text      :
   {
-    *(.text)
+    *(.text .text.*)
     *(.fixup)
   }
   _etext = .;
@@ -44,7 +44,7 @@
   .bss       :
   {
    *(.sbss)
-   *(.bss)
+   *(.bss .bss.*)
   }
   . = ALIGN(4096);
   _end = . ;
arch/powerpc/boot/zImage.ps3.lds.S +2 -2
@@ -20,7 +20,7 @@
   _start = .;
   .text      :
   {
-    *(.text)
+    *(.text .text.*)
     *(.fixup)
   }
   _etext = .;
@@ -43,7 +43,7 @@
   .bss       :
   {
    *(.sbss)
-   *(.bss)
+   *(.bss .bss.*)
   }
   . = ALIGN(4096);
   _end = . ;
arch/sh/boot/compressed/vmlinux.scr +1 -1
@@ -3,7 +3,7 @@
   .rodata..compressed : {
 	input_len = .;
 	LONG(input_data_end - input_data) input_data = .;
-	*(.data)
+	*(.data .data.*)
 	output_len = . - 4;
 	input_data_end = .;
 	}
arch/sh/kernel/vsyscall/vsyscall.lds.S +1 -1
@@ -35,7 +35,7 @@
 	 */
 	. = 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	: {
arch/x86/boot/setup.ld +2 -2
@@ -20,7 +20,7 @@
 	.initdata	: { *(.initdata) }
 	__end_init = .;
 
-	.text		: { *(.text) }
+	.text		: { *(.text .text.*) }
 	.text32		: { *(.text32) }
 
 	. = ALIGN(16);
@@ -45,7 +45,7 @@
 	.bss		:
 	{
 		__bss_start = .;
-		*(.bss)
+		*(.bss .bss.*)
 		__bss_end = .;
 	}
 	. = ALIGN(16);
arch/x86/kernel/acpi/realmode/wakeup.lds.S +1 -1
@@ -41,7 +41,7 @@
 	. = ALIGN(16);
 	.bss :	{
 		__bss_start = .;
-		*(.bss)
+		*(.bss .bss.*)
 		__bss_end = .;
 	}
 
arch/x86/kernel/vmlinux.lds.S +1 -1
@@ -306,7 +306,7 @@
 	.bss : AT(ADDR(.bss) - LOAD_OFFSET) {
 		__bss_start = .;
 		*(.bss..page_aligned)
-		*(.bss)
+		*(.bss .bss.*)
 		. = ALIGN(4);
 		__bss_stop = .;
 	}
arch/xtensa/boot/boot-elf/boot.lds.S +4 -4
@@ -10,19 +10,19 @@
 	{
 		__reloc_start = . ;
 		_text_start = . ;
-		*(.literal .text.literal .text)
+		*(.literal .text.literal .text .text.*)
 		_text_end = . ;
 	}
 
 	.rodata ALIGN(0x04):
 	{
-		*(.rodata)
+		*(.rodata .rodata.*)
 		*(.rodata1)
 	}
 
 	.data ALIGN(0x04):
 	{
-		*(.data)
+		*(.data .data.*)
 		*(.data1)
 		*(.sdata)
 		*(.sdata2)
@@ -57,7 +57,7 @@
 		*(.sbss)
 		*(.scommon)
 		*(.dynbss)
-		*(.bss)
+		*(.bss .bss.*)
 		__bss_end = .;
 	}
 	_end = .;
arch/xtensa/boot/boot-redboot/boot.ld +4 -4
@@ -8,19 +8,19 @@
 	{
 		__reloc_start = . ;
 		_text_start = . ;
-		*(.literal .text.literal .text)
+		*(.literal .text.literal .text .text.*)
 		_text_end = . ;
 	}
 
 	.rodata ALIGN(0x04):
 	{
-		*(.rodata)
+		*(.rodata .rodata.*)
 		*(.rodata1)
 	}
 
 	.data ALIGN(0x04):
 	{
-		*(.data)
+		*(.data .data.*)
 		*(.data1)
 		*(.sdata)
 		*(.sdata2)
@@ -55,7 +55,7 @@
 		*(.sbss)
 		*(.scommon)
 		*(.dynbss)
-		*(.bss)
+		*(.bss .bss.*)
 		__bss_end = .;
 	}
 	_end = .;
include/asm-generic/vmlinux.lds.h +15 -3
@@ -140,9 +140,21 @@
 #define TRACE_SYSCALLS()
 #endif
 
+/* .data.foo are generated by gcc itself with -fdata-sections,
+ * whereas double-dot sections (like .data..percpu) are generated
+ * by kernel's magic macros.
+ *
+ * arch/.../vmlinux.lds.S decides where to place various double-dot sections
+ * as needed by its arch, here DATA_DATA needs to be careful and collect
+ * only .data and .data.foo sections, skipping .data..foo
+ *
+ * Same goes for .text, .bss and .rodata. In case of .rodata, various
+ * .rodata.foo sections are generated by gcc even without -fdata-sections
+ */
+
 /* .data section */
 #define DATA_DATA							\
-	*(.data)							\
+	*(.data .data.[A-Za-z0-9_$^]*)					\
 	*(.ref.data)							\
 	DEV_KEEP(init.data)						\
 	DEV_KEEP(exit.data)						\
@@ -202,7 +214,7 @@
 	. = ALIGN((align));						\
 	.rodata           : AT(ADDR(.rodata) - LOAD_OFFSET) {		\
 		VMLINUX_SYMBOL(__start_rodata) = .;			\
-		*(.rodata) *(.rodata.*)					\
+		*(.rodata .rodata.[A-Za-z0-9_$^]*)			\
 		*(__vermagic)		/* Kernel version magic */	\
 		*(__markers_strings)	/* Markers: strings */		\
 		*(__tracepoints_strings)/* Tracepoints: strings */	\
@@ -501,7 +513,7 @@
 	.bss : AT(ADDR(.bss) - LOAD_OFFSET) {				\
 		*(.bss..page_aligned)					\
 		*(.dynbss)						\
-		*(.bss)							\
+		*(.bss .bss.[A-Za-z0-9_$^]*)				\
 		*(COMMON)						\
 	}
 
scripts/module-common.lds +23 -0
@@ -3,6 +3,29 @@
  * Archs are free to supply their own linker scripts.  ld will
  * combine them automatically.
  */
+
+/* .data.foo are generated by gcc itself with -fdata-sections,
+ * whereas double-dot sections (like .data..percpu) are generated
+ * by kernel's magic macros.
+ *
+ * Since this script does not specify what to do with double-dot sections,
+ * ld -r will coalesce all .data..foo input sections into one .data..foo
+ * output section, all .data..bar input sections into one .data..bar
+ * output section and so on. This is exactly what we want.
+ *
+ * Same goes for .text, .bss and .rodata. In case of .rodata, various
+ * .rodata.foo sections are generated by gcc even without -fdata-sections
+ */
+
 SECTIONS {
+
+	/* Coalesce sections produced by gcc -ffunction-sections */
+	.text   0 : AT(0) { *(.text .text.[A-Za-z0-9_$^]*) }
+
+	/* Coalesce sections produced by gcc -fdata-sections */
+	.rodata 0 : AT(0) { *(.rodata .rodata.[A-Za-z0-9_$^]*) }
+	.data   0 : AT(0) { *(.data .data.[A-Za-z0-9_$^]*) }
+	.bss    0 : AT(0) { *(.bss .bss.[A-Za-z0-9_$^]*) }
+
 	/DISCARD/ : { *(.discard) }
 }
Makefile +3 -1
@@ -610,6 +610,8 @@
 LDFLAGS_vmlinux	+= $(call ld-option, -X,)
 endif
 
+LDFLAGS_vmlinux += --gc-sections
+
 # Default kernel image to build when no specific target is given.
 # KBUILD_IMAGE may be overruled on the command line or
 # set in the environment
@@ -705,7 +707,7 @@
 # Rule to link vmlinux - also used during CONFIG_KALLSYMS
 # May be overridden by arch/$(ARCH)/Makefile
 quiet_cmd_vmlinux__ ?= LD      $@
-      cmd_vmlinux__ ?= $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) -o $@ \
+      cmd_vmlinux__ ?= $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) -o $@ -Map [email protected] \
       -T $(vmlinux-lds) $(vmlinux-init)                          \
       --start-group $(vmlinux-main) --end-group                  \
       $(filter-out $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o FORCE ,$^)
arch/arm/kernel/vmlinux.lds.S +1 -1
@@ -157,7 +157,7 @@
 		. = ALIGN(32);
 		__start___ex_table = .;
 #ifdef CONFIG_MMU
-		*(__ex_table)
+		KEEP(*(__ex_table))
 #endif
 		__stop___ex_table = .;
 
arch/blackfin/kernel/vmlinux.lds.S +1 -1
@@ -51,7 +51,7 @@
 
 		. = ALIGN(16);
 		___start___ex_table = .;
-		*(__ex_table)
+		KEEP(*(__ex_table))
 		___stop___ex_table = .;
 
 		__etext = .;
arch/cris/boot/rescue/rescue_v32.lds +2 -2
@@ -36,7 +36,7 @@
 	/* Get rid of stuff from EXPORT_SYMBOL(foo). */
 	/DISCARD/ :
 	{
-	        *(__ksymtab_strings)
-	        *(__ksymtab)
+		KEEP(*(__ksymtab_strings))
+		*(__ksymtab)
 	}
 }
arch/cris/kernel/vmlinux.lds.S +2 -2
@@ -72,7 +72,7 @@
 	.init.setup : { INIT_SETUP(16) }
 #ifdef CONFIG_ETRAX_ARCH_V32
 	__start___param = .;
-	__param : { *(__param) }
+	__param : { KEEP(*(__param)) }
 	__stop___param = .;
 #endif
 	.initcall.init : {
@@ -88,7 +88,7 @@
 #ifdef CONFIG_BLK_DEV_INITRD
 	.init.ramfs : {
 		__initramfs_start = .;
-		*(.init.ramfs)
+		KEEP(*(.init.ramfs))
 		__initramfs_end = .;
 	}
 #endif
arch/h8300/kernel/vmlinux.lds.S +1 -1
@@ -112,7 +112,7 @@
 	. = ALIGN(0x4) ;
 	INIT_SETUP(0x4)
 	___setup_start = .;
-		*(.init.setup)
+		KEEP(*(.init.setup))
 	. = ALIGN(0x4) ;
 	___setup_end = .;
 	INIT_CALLS
arch/m68knommu/kernel/vmlinux.lds.S +4 -4
@@ -72,7 +72,7 @@
 
 		. = ALIGN(16);          /* Exception table              */
 		__start___ex_table = .;
-		*(__ex_table)
+		KEEP(*(__ex_table))
 		__stop___ex_table = .;
 
 		*(.rodata .rodata.*)
@@ -129,16 +129,16 @@
 
 		/* Kernel symbol table: GPL-future symbols */
 		__start___kcrctab_gpl_future = .;
-		*(__kcrctab_gpl_future)
+		KEEP(*(__kcrctab_gpl_future))
 		__stop___kcrctab_gpl_future = .;
 
 		/* Kernel symbol table: strings */
-		*(__ksymtab_strings)
+		KEEP(*(__ksymtab_strings))
 
 		/* Built-in module parameters */
 		. = ALIGN(4) ;
 		__start___param = .;
-		*(__param)
+		KEEP(*(__param))
 		__stop___param = .;
 
 		. = ALIGN(4) ;
arch/microblaze/kernel/vmlinux.lds.S +1 -1
@@ -122,7 +122,7 @@
 
 	.init.ramfs ALIGN(4096) : AT(ADDR(.init.ramfs) - LOAD_OFFSET) {
 		__initramfs_start = .;
-		*(.init.ramfs)
+		KEEP(*(.init.ramfs))
 		__initramfs_end = .;
 		. = ALIGN(4);
 		LONG(0);
arch/mn10300/kernel/vmlinux.lds.S +3 -3
@@ -51,7 +51,7 @@
   . = ALIGN(PAGE_SIZE);
   .smp_locks : AT(ADDR(.smp_locks) - LOAD_OFFSET) {
   	__smp_locks = .;
-	*(.smp_locks)
+	KEEP(*(.smp_locks))
 	__smp_locks_end = .;
   }
 
@@ -62,9 +62,9 @@
   INIT_DATA_SECTION(16)
   . = ALIGN(4);
   __alt_instructions = .;
-  .altinstructions : { *(.altinstructions) }
+  .altinstructions : { KEEP(*(.altinstructions)) }
   __alt_instructions_end = .;
- .altinstr_replacement : { *(.altinstr_replacement) }
+ .altinstr_replacement : { KEEP(*(.altinstr_replacement)) }
   /* .exit.text is discard at runtime, not link time, to deal with references
      from .altinstructions and .eh_frame */
 	.exit.text : { EXIT_TEXT; }
arch/um/include/asm/common.lds.S +2 -2
@@ -76,10 +76,10 @@
   . = ALIGN(4);
   .altinstructions : {
 	__alt_instructions = .;
-	*(.altinstructions)
+	KEEP(*(.altinstructions))
 	__alt_instructions_end = .;
   }
-  .altinstr_replacement : { *(.altinstr_replacement) }
+  .altinstr_replacement : { KEEP(*(.altinstr_replacement)) }
   /* .exit.text is discard at runtime, not link time, to deal with references
      from .altinstructions and .eh_frame */
   .exit.text : { *(.exit.text) }
arch/x86/kernel/vmlinux.lds.S +12 -12
@@ -162,46 +162,46 @@
 
 	. = VSYSCALL_ADDR;
 	.vsyscall_0 : AT(VLOAD(.vsyscall_0)) {
-		*(.vsyscall_0)
+		KEEP(*(.vsyscall_0))
 	} :user
 
 	. = ALIGN(L1_CACHE_BYTES);
 	.vsyscall_fn : AT(VLOAD(.vsyscall_fn)) {
-		*(.vsyscall_fn)
+		KEEP(*(.vsyscall_fn))
 	}
 
 	. = ALIGN(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)
+		KEEP(*(.vgetcpu_mode))
 	}
 	vgetcpu_mode = VVIRT(.vgetcpu_mode);
 
 	. = ALIGN(L1_CACHE_BYTES);
 	.jiffies : AT(VLOAD(.jiffies)) {
-		*(.jiffies)
+		KEEP(*(.jiffies))
 	}
 	jiffies = VVIRT(.jiffies);
 
 	.vsyscall_3 ADDR(.vsyscall_0) + 3072: AT(VLOAD(.vsyscall_3)) {
-		*(.vsyscall_3)
+		KEEP(*(.vsyscall_3))
 	}
 
 	. = __vsyscall_0 + PAGE_SIZE;
@@ -252,12 +252,12 @@
 	. = ALIGN(8);
 	.altinstructions : AT(ADDR(.altinstructions) - LOAD_OFFSET) {
 		__alt_instructions = .;
-		*(.altinstructions)
+		KEEP(*(.altinstructions))
 		__alt_instructions_end = .;
 	}
 
 	.altinstr_replacement : AT(ADDR(.altinstr_replacement) - LOAD_OFFSET) {
-		*(.altinstr_replacement)
+		KEEP(*(.altinstr_replacement))
 	}
 
 	/*
@@ -290,7 +290,7 @@
 	. = ALIGN(PAGE_SIZE);
 	.smp_locks : AT(ADDR(.smp_locks) - LOAD_OFFSET) {
 		__smp_locks = .;
-		*(.smp_locks)
+		KEEP(*(.smp_locks))
 		. = ALIGN(PAGE_SIZE);
 		__smp_locks_end = .;
 	}
arch/x86/vdso/vdso-layout.lds.S +2 -2
@@ -34,8 +34,8 @@
 	      *(.gnu.linkonce.b.*)
 	}
 
-	.altinstructions	: { *(.altinstructions) }
-	.altinstr_replacement	: { *(.altinstr_replacement) }
+	.altinstructions	: { KEEP(*(.altinstructions)) }
+	.altinstr_replacement	: { KEEP(*(.altinstr_replacement)) }
 
 	/*
 	 * Align the actual code well away from the non-instruction data.
include/asm-generic/vmlinux.lds.h +44 -44

221 lines not on this page · raw message

#1 lore raw
Quoted 2 lines · Denys Vlasenko

I am sending this email from the machine which runs the kernel built with -ffunction-sections -fdata-sections --gc-sections.

(sorry for the previous HTML-email)

For the record, what are the metrics of this kernel vs. the standard one?

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds
--
To unsubscribe from this list: send the line "unsubscribe linux-parisc" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#2 lore raw
Quoted 7 lines · Geert Uytterhoeven
Quoted 2 lines · Denys Vlasenko

I am sending this email from the machine which runs the kernel built with -ffunction-sections -fdata-sections --gc-sections.

(sorry for the previous HTML-email)

For the record, what are the metrics of this kernel vs. the standard one?

Kernel:

text data bss dec hex filename

8299299  857324  785348 9941971  97b3d3 linux-2.6.35-rc4.obj/vmlinux
7656461  841508  783700 9281669  8da085 linux-2.6.35-rc4-fs.obj/vmlinux
7566908  832388  717844 9117140  8b1dd4 linux-2.6.35-rc4-fsgs.obj/vmlinux

The largest module in my build:
text data bss dec hex filename

 451009   54640    2224  507873   7bfe1 linux-2.6.35-rc4.obj/fs/xfs/xfs.ko
 450519   54292    2202  507013   7bc85 linux-2.6.35-rc4-fs.obj/fs/xfs/xfs.ko
 450521   54292    2202  507015   7bc87 linux-2.6.35-rc4-fsgs.obj/fs/xfs/xfs.ko
Signature · 1 line
vda
#3 lore raw
In reply to Denys Vlasenko
Quoted 4 lines

* modpost fix for 64k+ sections: linux-2.6.35-rc4-fs.modpost.patch This patch is in -mm, it still not reach mainline...

Some comments below - but noting fundamental.

Sam

scripts/mod/file2alias.c +3 -3
@@ -884,16 +884,16 @@
 	char *zeros = NULL;
 
 	/* We're looking for a section relative symbol */
-	if (!sym->st_shndx || sym->st_shndx >= info->hdr->e_shnum)
+	if (!sym->st_shndx || get_secindex(info, sym) >= info->num_sections)
 		return;
 
 	/* Handle all-NULL symbols allocated into .bss */
-	if (info->sechdrs[sym->st_shndx].sh_type & SHT_NOBITS) {
+	if (info->sechdrs[get_secindex(info, sym)].sh_type & SHT_NOBITS) {
 		zeros = calloc(1, sym->st_size);
 		symval = zeros;
 	} else {
 		symval = (void *)info->hdr
-			+ info->sechdrs[sym->st_shndx].sh_offset
+			+ info->sechdrs[get_secindex(info, sym)].sh_offset
 			+ sym->st_value;
 	}
 
scripts/mod/modpost.c +9 -1
@@ -253,7 +253,7 @@
 	return export_unknown;
 }
 
-static enum export export_from_sec(struct elf_info *elf, Elf_Section sec)
+static enum export export_from_sec(struct elf_info *elf, unsigned int sec)
 {
 	if (sec == elf->export_sec)
 		return export_plain;
@@ -373,6 +373,8 @@
 	Elf_Ehdr *hdr;
 	Elf_Shdr *sechdrs;
 	Elf_Sym  *sym;
+	const char *secstrings;
+	unsigned int symtab_idx = ~0U, symtab_shndx_idx = ~0U;
 
 	hdr = grab_file(filename, &info->size);
 	if (!hdr) {
@@ -417,8 +419,19 @@
 		return 0;
 	}
 
+	/* Fixup for more than 64k sections */
+	info->num_sections = hdr->e_shnum;
+	if (info->num_sections == 0) { /* more than 64k sections? */
+		/* note: it doesn't need shndx2secindex() */
+		info->num_sections = TO_NATIVE(sechdrs[0].sh_size);
+	}

I had to read the above twice to get it.
How about something like this:

	/* Fixup for more than 64k sections */
	if (hdr->e_shnum == 0) {
		/*
		 * There are more than 64k sections,
		 * read count from .sh_size.
		 * note: it doesn't need shndx2secindex()
		 */
		info->num_sections = TO_NATIVE(sechdrs[0].sh_size);
	}
	else {
		info->num_sections = hdr->e_shnum;
	}

+ info->secindex_strings = hdr->e_shstrndx;
+ if (info->secindex_strings == SHN_XINDEX)
+ info->secindex_strings =
+ shndx2secindex(TO_NATIVE(sechdrs[0].sh_link));

Likewise here...

	/* e_shstrndx == SHN_XINDEX if we have > 64k strings */
	if (hdr->e_shstrndx != SHN_XINDEX)
		info->secindex_strings = hdr->e_shstrndx;
	else
		info->secindex_strings = shndx2secindex(TO_NATIVE(sechdrs[0].sh_link));

/* Fix endianness in section headers */
- for (i = 0; i < hdr->e_shnum; i++) {
+ for (i = 0; i < info->num_sections; i++) {

 		sechdrs[i].sh_name      = TO_NATIVE(sechdrs[i].sh_name);
 		sechdrs[i].sh_type      = TO_NATIVE(sechdrs[i].sh_type);
 		sechdrs[i].sh_flags     = TO_NATIVE(sechdrs[i].sh_flags);

@@ -431,9 +444,8 @@
sechdrs[i].sh_entsize = TO_NATIVE(sechdrs[i].sh_entsize);
}
/* Find symbol table. */
- for (i = 1; i < hdr->e_shnum; i++) {
- const char *secstrings
- = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+ secstrings = (void *)hdr + sechdrs[info->secindex_strings].sh_offset;

Moving this assignnet out of the loop is an unrelated but welcome change.

+ for (i = 1; i < info->num_sections; i++) {
const char *secname;
int nobits = sechdrs[i].sh_type == SHT_NOBITS;

@@ -461,14 +473,26 @@
else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
info->export_gpl_future_sec = i;

- if (sechdrs[i].sh_type != SHT_SYMTAB)
- continue;
+ if (sechdrs[i].sh_type == SHT_SYMTAB) {
+ unsigned int sh_link_idx;
+ symtab_idx = i;
+ info->symtab_start = (void *)hdr +
+ sechdrs[i].sh_offset;
+ info->symtab_stop = (void *)hdr +
+ sechdrs[i].sh_offset + sechdrs[i].sh_size;
+ sh_link_idx = shndx2secindex(sechdrs[i].sh_link);
+ info->strtab = (void *)hdr +
+ sechdrs[sh_link_idx].sh_offset;
+ }

- info->symtab_start = (void *)hdr + sechdrs[i].sh_offset;
- info->symtab_stop = (void *)hdr + sechdrs[i].sh_offset
- + sechdrs[i].sh_size;
- info->strtab = (void *)hdr +
- sechdrs[sechdrs[i].sh_link].sh_offset;
+ /* 32bit section no. table? ("more than 64k sections") */
+ if (sechdrs[i].sh_type == SHT_SYMTAB_SHNDX) {
+ symtab_shndx_idx = i;
+ info->symtab_shndx_start = (void *)hdr +
+ sechdrs[i].sh_offset;
+ info->symtab_shndx_stop = (void *)hdr +
+ sechdrs[i].sh_offset + sechdrs[i].sh_size;
+ }
}
if (!info->symtab_start)
fatal("%s has no symtab?\n", filename);
@@ -480,6 +504,21 @@
sym->st_value = TO_NATIVE(sym->st_value); sym->st_size = TO_NATIVE(sym->st_size);
}
+
+ if (symtab_shndx_idx != ~0U) {
+ Elf32_Word *p;
+ if (symtab_idx !=
+ shndx2secindex(sechdrs[symtab_shndx_idx].sh_link))
+ fatal("%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n",

+			      filename,
+			      shndx2secindex(sechdrs[symtab_shndx_idx].sh_link),
+			      symtab_idx);

+ /* Fix endianness */
+ for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop;
+ p++)
+ *p = TO_NATIVE(*p);
+ }
+
return 1;
}

@@ -514,7 +553,7 @@
Elf_Sym *sym, const char *symname)
{
unsigned int crc;
- enum export export = export_from_sec(info, sym->st_shndx);
+ enum export export = export_from_sec(info, get_secindex(info, sym));

switch (sym->st_shndx) {
case SHN_COMMON:
@@ -656,19 +695,19 @@
return "(unknown)";
}

-static const char *sec_name(struct elf_info *elf, int shndx) +static const char *sec_name(struct elf_info *elf, int secindex)
{
Elf_Shdr *sechdrs = elf->sechdrs;
return (void *)elf->hdr +
- elf->sechdrs[elf->hdr->e_shstrndx].sh_offset +
- sechdrs[shndx].sh_name;
+ elf->sechdrs[elf->secindex_strings].sh_offset +
+ sechdrs[secindex].sh_name;
}

static const char *sech_name(struct elf_info *elf, Elf_Shdr *sechdr) {
return (void *)elf->hdr +
- elf->sechdrs[elf->hdr->e_shstrndx].sh_offset +
- sechdr->sh_name;
+ elf->sechdrs[elf->secindex_strings].sh_offset +
+ sechdr->sh_name;
}

/* if sym is empty or point to a string
@@ -1047,11 +1086,14 @@
Elf_Sym *near = NULL;
Elf64_Sword distance = 20;
Elf64_Sword d;
+ unsigned int relsym_secindex;

if (relsym->st_name != 0)
return relsym;
+
+ relsym_secindex = get_secindex(elf, relsym);
for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
- if (sym->st_shndx != relsym->st_shndx)
+ if (get_secindex(elf, sym) != relsym_secindex)
continue;
if (ELF_ST_TYPE(sym->st_info) == STT_SECTION)
continue;
@@ -1113,9 +1155,9 @@
for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
const char *symsec;

- if (sym->st_shndx >= SHN_LORESERVE)
+ if (is_shndx_special(sym->st_shndx))
continue;
- symsec = sec_name(elf, sym->st_shndx);
+ symsec = sec_name(elf, get_secindex(elf, sym));
if (strcmp(symsec, sec) != 0)
continue;
if (!is_valid_name(elf, sym))
@@ -1311,7 +1353,7 @@
const char *tosec;
const struct sectioncheck *mismatch;

- tosec = sec_name(elf, sym->st_shndx);
+ tosec = sec_name(elf, get_secindex(elf, sym));
mismatch = section_mismatch(fromsec, tosec);
if (mismatch) {
Elf_Sym *to;
@@ -1339,7 +1381,7 @@
Elf_Shdr *sechdr, Elf_Rela *r)
{
Elf_Shdr *sechdrs = elf->sechdrs;
- int section = sechdr->sh_info;
+ int section = shndx2secindex(sechdr->sh_info);

return (void *)elf->hdr + sechdrs[section].sh_offset +
r->r_offset - sechdrs[section].sh_addr;
@@ -1447,7 +1489,7 @@
r.r_addend = TO_NATIVE(rela->r_addend);
sym = elf->symtab_start + r_sym;
/* Skip special sections */
- if (sym->st_shndx >= SHN_LORESERVE)
+ if (is_shndx_special(sym->st_shndx))
continue;
check_section_mismatch(modname, elf, &r, sym, fromsec);
}
@@ -1505,7 +1547,7 @@
}
sym = elf->symtab_start + r_sym;
/* Skip special sections */
- if (sym->st_shndx >= SHN_LORESERVE)
+ if (is_shndx_special(sym->st_shndx))
continue;
check_section_mismatch(modname, elf, &r, sym, fromsec);
}
@@ -1530,7 +1572,7 @@
Elf_Shdr *sechdrs = elf->sechdrs;

/* Walk through all sections */
- for (i = 0; i < elf->hdr->e_shnum; i++) {
+ for (i = 0; i < elf->num_sections; i++) {
check_section(modname, elf, &elf->sechdrs[i]);
/* We want to process only relocation sections and not .init */ if (sechdrs[i].sh_type == SHT_RELA)

scripts/mod/modpost.h +43 -0

50 lines not on this page · raw message

#4 lore raw
Quoted 35 lines · Sam Ravnborg
Quoted 4 lines

* modpost fix for 64k+ sections: linux-2.6.35-rc4-fs.modpost.patch This patch is in -mm, it still not reach mainline...

Some comments below - but noting fundamental.

scripts/mod/modpost.c +6 -0
+	/* Fixup for more than 64k sections */
+	info->num_sections = hdr->e_shnum;
+	if (info->num_sections == 0) { /* more than 64k sections? */
+		/* note: it doesn't need shndx2secindex() */
+		info->num_sections = TO_NATIVE(sechdrs[0].sh_size);
+	}

I had to read the above twice to get it.
How about something like this:

	/* Fixup for more than 64k sections */
	if (hdr->e_shnum == 0) {
		/*
		 * There are more than 64k sections,
		 * read count from .sh_size.
		 * note: it doesn't need shndx2secindex()
		 */
		info->num_sections = TO_NATIVE(sechdrs[0].sh_size);
	}
	else {
		info->num_sections = hdr->e_shnum;
	}
(quoted diff) +4 -0
+	info->secindex_strings = hdr->e_shstrndx;
+	if (info->secindex_strings == SHN_XINDEX)
+		info->secindex_strings =
+		    shndx2secindex(TO_NATIVE(sechdrs[0].sh_link));
Quoted 1 line

Likewise here...

Done both.

...

Quoted 7 lines
(quoted diff) +1 -3
-	for (i = 1; i < hdr->e_shnum; i++) {
-		const char *secstrings
-			= (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+	secstrings = (void *)hdr + sechdrs[info->secindex_strings].sh_offset;

Moving this assignnet out of the loop is an unrelated but welcome change.

I take you are ok with it?

Please find updated patch below.

Signature · 303 lines
vda



--- linux-2.6.35-rc4/scripts/mod/file2alias.c
+++ linux-2.6.35-rc4-fs.modpost/scripts/mod/file2alias.c
@@ -884,16 +884,16 @@
 	char *zeros = NULL;
 
 	/* We're looking for a section relative symbol */
-	if (!sym->st_shndx || sym->st_shndx >= info->hdr->e_shnum)
+	if (!sym->st_shndx || get_secindex(info, sym) >= info->num_sections)
 		return;
 
 	/* Handle all-NULL symbols allocated into .bss */
-	if (info->sechdrs[sym->st_shndx].sh_type & SHT_NOBITS) {
+	if (info->sechdrs[get_secindex(info, sym)].sh_type & SHT_NOBITS) {
 		zeros = calloc(1, sym->st_size);
 		symval = zeros;
 	} else {
 		symval = (void *)info->hdr
-			+ info->sechdrs[sym->st_shndx].sh_offset
+			+ info->sechdrs[get_secindex(info, sym)].sh_offset
 			+ sym->st_value;
 	}
 
--- linux-2.6.35-rc4/scripts/mod/modpost.c
+++ linux-2.6.35-rc4-fs.modpost/scripts/mod/modpost.c
@@ -253,7 +253,7 @@
 	return export_unknown;
 }
 
-static enum export export_from_sec(struct elf_info *elf, Elf_Section sec)
+static enum export export_from_sec(struct elf_info *elf, unsigned int sec)
 {
 	if (sec == elf->export_sec)
 		return export_plain;
@@ -373,6 +373,8 @@
 	Elf_Ehdr *hdr;
 	Elf_Shdr *sechdrs;
 	Elf_Sym  *sym;
+	const char *secstrings;
+	unsigned int symtab_idx = ~0U, symtab_shndx_idx = ~0U;
 
 	hdr = grab_file(filename, &info->size);
 	if (!hdr) {
@@ -417,8 +419,27 @@
 		return 0;
 	}
 
+	if (hdr->e_shnum == 0) {
+		/*
+		 * There are more than 64k sections,
+		 * read count from .sh_size.
+		 * note: it doesn't need shndx2secindex()
+		 */
+		info->num_sections = TO_NATIVE(sechdrs[0].sh_size);
+	}
+	else {
+		info->num_sections = hdr->e_shnum;
+	}
+	if (hdr->e_shstrndx == SHN_XINDEX) {
+		info->secindex_strings =
+		    shndx2secindex(TO_NATIVE(sechdrs[0].sh_link));
+	}
+	else {
+		info->secindex_strings = hdr->e_shstrndx;
+	}
+
 	/* Fix endianness in section headers */
-	for (i = 0; i < hdr->e_shnum; i++) {
+	for (i = 0; i < info->num_sections; i++) {
 		sechdrs[i].sh_name      = TO_NATIVE(sechdrs[i].sh_name);
 		sechdrs[i].sh_type      = TO_NATIVE(sechdrs[i].sh_type);
 		sechdrs[i].sh_flags     = TO_NATIVE(sechdrs[i].sh_flags);
@@ -431,9 +452,8 @@
 		sechdrs[i].sh_entsize   = TO_NATIVE(sechdrs[i].sh_entsize);
 	}
 	/* Find symbol table. */
-	for (i = 1; i < hdr->e_shnum; i++) {
-		const char *secstrings
-			= (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+	secstrings = (void *)hdr + sechdrs[info->secindex_strings].sh_offset;
+	for (i = 1; i < info->num_sections; i++) {
 		const char *secname;
 		int nobits = sechdrs[i].sh_type == SHT_NOBITS;
 
@@ -461,14 +481,26 @@
 		else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
 			info->export_gpl_future_sec = i;
 
-		if (sechdrs[i].sh_type != SHT_SYMTAB)
-			continue;
+		if (sechdrs[i].sh_type == SHT_SYMTAB) {
+			unsigned int sh_link_idx;
+			symtab_idx = i;
+			info->symtab_start = (void *)hdr +
+			    sechdrs[i].sh_offset;
+			info->symtab_stop  = (void *)hdr +
+			    sechdrs[i].sh_offset + sechdrs[i].sh_size;
+			sh_link_idx = shndx2secindex(sechdrs[i].sh_link);
+			info->strtab       = (void *)hdr +
+			    sechdrs[sh_link_idx].sh_offset;
+		}
 
-		info->symtab_start = (void *)hdr + sechdrs[i].sh_offset;
-		info->symtab_stop  = (void *)hdr + sechdrs[i].sh_offset
-			                         + sechdrs[i].sh_size;
-		info->strtab       = (void *)hdr +
-			             sechdrs[sechdrs[i].sh_link].sh_offset;
+		/* 32bit section no. table? ("more than 64k sections") */
+		if (sechdrs[i].sh_type == SHT_SYMTAB_SHNDX) {
+			symtab_shndx_idx = i;
+			info->symtab_shndx_start = (void *)hdr +
+			    sechdrs[i].sh_offset;
+			info->symtab_shndx_stop  = (void *)hdr +
+			    sechdrs[i].sh_offset + sechdrs[i].sh_size;
+		}
 	}
 	if (!info->symtab_start)
 		fatal("%s has no symtab?\n", filename);
@@ -480,6 +512,21 @@
 		sym->st_value = TO_NATIVE(sym->st_value);
 		sym->st_size  = TO_NATIVE(sym->st_size);
 	}
+
+	if (symtab_shndx_idx != ~0U) {
+		Elf32_Word *p;
+		if (symtab_idx !=
+		    shndx2secindex(sechdrs[symtab_shndx_idx].sh_link))
+			fatal("%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n",
+			      filename,
+			      shndx2secindex(sechdrs[symtab_shndx_idx].sh_link),
+			      symtab_idx);
+		/* Fix endianness */
+		for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop;
+		     p++)
+			*p = TO_NATIVE(*p);
+	}
+
 	return 1;
 }
 
@@ -514,7 +561,7 @@
 			       Elf_Sym *sym, const char *symname)
 {
 	unsigned int crc;
-	enum export export = export_from_sec(info, sym->st_shndx);
+	enum export export = export_from_sec(info, get_secindex(info, sym));
 
 	switch (sym->st_shndx) {
 	case SHN_COMMON:
@@ -656,19 +703,19 @@
 		return "(unknown)";
 }
 
-static const char *sec_name(struct elf_info *elf, int shndx)
+static const char *sec_name(struct elf_info *elf, int secindex)
 {
 	Elf_Shdr *sechdrs = elf->sechdrs;
 	return (void *)elf->hdr +
-	        elf->sechdrs[elf->hdr->e_shstrndx].sh_offset +
-	        sechdrs[shndx].sh_name;
+		elf->sechdrs[elf->secindex_strings].sh_offset +
+		sechdrs[secindex].sh_name;
 }
 
 static const char *sech_name(struct elf_info *elf, Elf_Shdr *sechdr)
 {
 	return (void *)elf->hdr +
-	        elf->sechdrs[elf->hdr->e_shstrndx].sh_offset +
-	        sechdr->sh_name;
+		elf->sechdrs[elf->secindex_strings].sh_offset +
+		sechdr->sh_name;
 }
 
 /* if sym is empty or point to a string
@@ -1047,11 +1094,14 @@
 	Elf_Sym *near = NULL;
 	Elf64_Sword distance = 20;
 	Elf64_Sword d;
+	unsigned int relsym_secindex;
 
 	if (relsym->st_name != 0)
 		return relsym;
+
+	relsym_secindex = get_secindex(elf, relsym);
 	for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
-		if (sym->st_shndx != relsym->st_shndx)
+		if (get_secindex(elf, sym) != relsym_secindex)
 			continue;
 		if (ELF_ST_TYPE(sym->st_info) == STT_SECTION)
 			continue;
@@ -1113,9 +1163,9 @@
 	for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
 		const char *symsec;
 
-		if (sym->st_shndx >= SHN_LORESERVE)
+		if (is_shndx_special(sym->st_shndx))
 			continue;
-		symsec = sec_name(elf, sym->st_shndx);
+		symsec = sec_name(elf, get_secindex(elf, sym));
 		if (strcmp(symsec, sec) != 0)
 			continue;
 		if (!is_valid_name(elf, sym))
@@ -1311,7 +1361,7 @@
 	const char *tosec;
 	const struct sectioncheck *mismatch;
 
-	tosec = sec_name(elf, sym->st_shndx);
+	tosec = sec_name(elf, get_secindex(elf, sym));
 	mismatch = section_mismatch(fromsec, tosec);
 	if (mismatch) {
 		Elf_Sym *to;
@@ -1339,7 +1389,7 @@
 				    Elf_Shdr *sechdr, Elf_Rela *r)
 {
 	Elf_Shdr *sechdrs = elf->sechdrs;
-	int section = sechdr->sh_info;
+	int section = shndx2secindex(sechdr->sh_info);
 
 	return (void *)elf->hdr + sechdrs[section].sh_offset +
 		r->r_offset - sechdrs[section].sh_addr;
@@ -1447,7 +1497,7 @@
 		r.r_addend = TO_NATIVE(rela->r_addend);
 		sym = elf->symtab_start + r_sym;
 		/* Skip special sections */
-		if (sym->st_shndx >= SHN_LORESERVE)
+		if (is_shndx_special(sym->st_shndx))
 			continue;
 		check_section_mismatch(modname, elf, &r, sym, fromsec);
 	}
@@ -1505,7 +1555,7 @@
 		}
 		sym = elf->symtab_start + r_sym;
 		/* Skip special sections */
-		if (sym->st_shndx >= SHN_LORESERVE)
+		if (is_shndx_special(sym->st_shndx))
 			continue;
 		check_section_mismatch(modname, elf, &r, sym, fromsec);
 	}
@@ -1530,7 +1580,7 @@
 	Elf_Shdr *sechdrs = elf->sechdrs;
 
 	/* Walk through all sections */
-	for (i = 0; i < elf->hdr->e_shnum; i++) {
+	for (i = 0; i < elf->num_sections; i++) {
 		check_section(modname, elf, &elf->sechdrs[i]);
 		/* We want to process only relocation sections and not .init */
 		if (sechdrs[i].sh_type == SHT_RELA)
--- linux-2.6.35-rc4/scripts/mod/modpost.h
+++ linux-2.6.35-rc4-fs.modpost/scripts/mod/modpost.h
@@ -129,7 +129,50 @@
 	const char   *strtab;
 	char	     *modinfo;
 	unsigned int modinfo_len;
+
+	/* support for 32bit section numbers */
+
+	unsigned int num_sections; /* max_secindex + 1 */
+	unsigned int secindex_strings;
+	/* if Nth symbol table entry has .st_shndx = SHN_XINDEX,
+	 * take shndx from symtab_shndx_start[N] instead */
+	Elf32_Word   *symtab_shndx_start;
+	Elf32_Word   *symtab_shndx_stop;
 };
+
+static inline int is_shndx_special(unsigned int i)
+{
+	return i != SHN_XINDEX && i >= SHN_LORESERVE && i <= SHN_HIRESERVE;
+}
+
+/* shndx is in [0..SHN_LORESERVE) U (SHN_HIRESERVE, 0xfffffff], thus:
+ * shndx == 0               <=> sechdrs[0]
+ * ......
+ * shndx == SHN_LORESERVE-1 <=> sechdrs[SHN_LORESERVE-1]
+ * shndx == SHN_HIRESERVE+1 <=> sechdrs[SHN_LORESERVE]
+ * shndx == SHN_HIRESERVE+2 <=> sechdrs[SHN_LORESERVE+1]
+ * ......
+ * fyi: sym->st_shndx is uint16, SHN_LORESERVE = ff00, SHN_HIRESERVE = ffff,
+ * so basically we map  0000..feff -> 0000..feff
+ *                      ff00..ffff -> (you are a bad boy, dont do it)
+ *                     10000..xxxx -> ff00..(xxxx-0x100)
+ */
+static inline unsigned int shndx2secindex(unsigned int i)
+{
+	if (i <= SHN_HIRESERVE)
+		return i;
+	return i - (SHN_HIRESERVE + 1 - SHN_LORESERVE);
+}
+
+/* Accessor for sym->st_shndx, hides ugliness of "64k sections" */
+static inline unsigned int get_secindex(const struct elf_info *info,
+					const Elf_Sym *sym)
+{
+	if (sym->st_shndx != SHN_XINDEX)
+		return sym->st_shndx;
+	return shndx2secindex(info->symtab_shndx_start[sym -
+						       info->symtab_start]);
+}
 
 /* file2alias.c */
 extern unsigned int cross_build;
Acked-by
#5 lore raw
Quoted 46 lines · Denys Vlasenko
Quoted 35 lines · Sam Ravnborg
Quoted 4 lines

* modpost fix for 64k+ sections: linux-2.6.35-rc4-fs.modpost.patch This patch is in -mm, it still not reach mainline...

Some comments below - but noting fundamental.

scripts/mod/modpost.c +6 -0
+	/* Fixup for more than 64k sections */
+	info->num_sections = hdr->e_shnum;
+	if (info->num_sections == 0) { /* more than 64k sections? */
+		/* note: it doesn't need shndx2secindex() */
+		info->num_sections = TO_NATIVE(sechdrs[0].sh_size);
+	}

I had to read the above twice to get it.
How about something like this:

	/* Fixup for more than 64k sections */
	if (hdr->e_shnum == 0) {
		/*
		 * There are more than 64k sections,
		 * read count from .sh_size.
		 * note: it doesn't need shndx2secindex()
		 */
		info->num_sections = TO_NATIVE(sechdrs[0].sh_size);
	}
	else {
		info->num_sections = hdr->e_shnum;
	}
(quoted diff) +4 -0
+	info->secindex_strings = hdr->e_shstrndx;
+	if (info->secindex_strings == SHN_XINDEX)
+		info->secindex_strings =
+		    shndx2secindex(TO_NATIVE(sechdrs[0].sh_link));
Quoted 1 line

Likewise here...

Done both.

...

Quoted 5 lines
(quoted diff) +1 -3
-	for (i = 1; i < hdr->e_shnum; i++) {
-		const char *secstrings
-			= (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+	secstrings = (void *)hdr + sechdrs[info->secindex_strings].sh_offset;
Quoted 8 lines
Quoted 2 lines

Moving this assignnet out of the loop is an unrelated but welcome change.

I take you are ok with it?

Please find updated patch below.

If the patch get a proper changelog then it has my:

Sam

#6 lore raw
In reply to Denys Vlasenko
Quoted 5 lines

* fix for kernel linker stripts: linux-2.6.35-rc4-fs.fix-kernel-linker-scripts.patch It makes _all_ linker scripts -ffunction/data-sections safe via:
- *(.data)
+ *(.data .data.*)

This patch touches both the regular kernel linker scripts and the boot linker scripts.
I would strongly prefer a split so you touched the boot linker scripts in a separate patch.

In addition the patch handles more sections than
documented: rodata, bss, text.

The patch introduce the following syntax for input sections:

    *(.bss .bss.*)

Where the kernel linker script would have one input section per line.
Can we stick to the "layout" used in the kernel linker scripts?

The patch in addition in several places changes linker scripts that already uses the two-lines layout to a single line approach. These "fixes" should be omitted.

Why do we need *(.bss .bss.*)?
Does -fdata-sections introduce special .bss sectiosn too?

This is the kind of info the changelog should give us.

Sam

arch/arm/boot/compressed/vmlinux.lds.in +2 -4
@@ -29,12 +29,10 @@
   .text : {
     _start = .;
     *(.start)
-    *(.text)
-    *(.text.*)
+    *(.text .text.*)
     *(.fixup)
     *(.gnu.warning)
-    *(.rodata)
-    *(.rodata.*)
+    *(.rodata .rodata.*)
     *(.glue_7)
     *(.glue_7t)
     *(.piggydata)

This is one example where the patch only does layout changes.

arch/arm/kernel/vmlinux.lds.S +1 -2
@@ -95,8 +95,7 @@
 			*(.fixup)
 #endif
 			*(.gnu.warning)
-			*(.rodata)
-			*(.rodata.*)
+			*(.rodata .rodata.*)
 			*(.glue_7)
 			*(.glue_7t)
 

Likewise...

arch/frv/kernel/vmlinux.lds.S +1 -1
@@ -114,7 +114,7 @@
 
   .sbss		: { *(.sbss .sbss.*) }
   .bss		: { *(.bss .bss.*) }
-  .bss..stack	: { *(.bss) }
+  .bss..stack	: { *(.bss) } /* BUG??? we already absorbed it into .bss */
 

As the comments says the last line is redundant - remove it.

include/asm-generic/vmlinux.lds.h +14 -2
@@ -140,9 +140,21 @@
 #define TRACE_SYSCALLS()
 #endif
 
+/* .data.foo are generated by gcc itself with -fdata-sections,
+ * whereas double-dot sections (like .data..percpu) are generated
+ * by kernel's magic macros.
+ *
+ * arch/.../vmlinux.lds.S decides where to place various double-dot sections
+ * as needed by its arch, here DATA_DATA needs to be careful and collect
+ * only .data and .data.foo sections, skipping .data..foo
+ *
+ * Same goes for .text, .bss and .rodata. In case of .rodata, various
+ * .rodata.foo sections are generated by gcc even without -fdata-sections
+ */
+
 /* .data section */
 #define DATA_DATA							\
-	*(.data)							\
+	*(.data .data.[A-Za-z0-9_$^]*)					\
 	*(.ref.data)							\
 	DEV_KEEP(init.data)						\
 	DEV_KEEP(exit.data)						\
@@ -202,7 +214,7 @@
 	. = ALIGN((align));						\
 	.rodata           : AT(ADDR(.rodata) - LOAD_OFFSET) {		\
 		VMLINUX_SYMBOL(__start_rodata) = .;			\
-		*(.rodata) *(.rodata.*)					\
+		*(.rodata .rodata.[A-Za-z0-9_$^]*)			\
 

.rodata deserve same comment as .data

*(__vermagic) /* Kernel version magic */ \
*(__markers_strings) /* Markers: strings */ \
*(__tracepoints_strings)/* Tracepoints: strings */ \
@@ -501,7 +513,7 @@
.bss : AT(ADDR(.bss) - LOAD_OFFSET) { \
*(.bss..page_aligned) \
*(.dynbss) \
- *(.bss) \
+ *(.bss .bss.[A-Za-z0-9_$^]*) \
.bss deserve a comment too.

Sam

#7 lore raw
Quoted 10 lines · Sam Ravnborg
Quoted 5 lines

* fix for kernel linker stripts: linux-2.6.35-rc4-fs.fix-kernel-linker-scripts.patch It makes _all_ linker scripts -ffunction/data-sections safe via:
- *(.data)
+ *(.data .data.*)

This patch touches both the regular kernel linker scripts and the boot linker scripts.
I would strongly prefer a split so you touched the boot linker scripts in a separate patch.

No problem.

Quoted 2 lines

In addition the patch handles more sections than
documented: rodata, bss, text.

Yes, that was assumed.

Quoted 7 lines

The patch introduce the following syntax for input sections:

    *(.bss .bss.*)

Where the kernel linker script would have one input section per line.
Can we stick to the "layout" used in the kernel linker scripts?

Sure.

Quoted 3 lines

The patch in addition in several places changes linker scripts that already uses the two-lines layout to a single line approach. These "fixes" should be omitted.

Reverted.

Quoted 2 lines

Why do we need *(.bss .bss.*)?
Does -fdata-sections introduce special .bss sectiosn too?

Yes, it does.

Please take a look at attached updated patches.

Signature · 1 line
vda
arch/alpha/boot/bootloader.lds +3 -3
@@ -4,17 +4,17 @@
 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 = .);
 
arch/arm/boot/bootp/bootp.lds +1 -0
@@ -16,6 +16,7 @@
    _stext = .;
    *(.start)
    *(.text)
+   *(.text.*)
    initrd_size = initrd_end - initrd_start;
    _etext = .;
   }
arch/cris/boot/compressed/decompress_v10.lds +3 -0
@@ -13,6 +13,7 @@
 	{
 		_stext = . ;
 		*(.text)
+		*(.text.*)
 		*(.rodata)
 		*(.rodata.*)
 		_etext = . ;
@@ -20,11 +21,13 @@
 	.data :
 	{
 		*(.data)
+		*(.data.*)
 		_edata = . ;
 	} > dram
 	.bss :
 	{
 		*(.bss)
+		*(.bss.*)
 		_end = ALIGN( 0x10 ) ;
 	} > dram
 }
arch/cris/boot/compressed/decompress_v32.lds +3 -0
@@ -13,6 +13,7 @@
 	{
 		_stext = . ;
 		*(.text)
+		*(.text.*)
 		*(.rodata)
 		*(.rodata.*)
 		_etext = . ;
@@ -20,11 +21,13 @@
 	.data :
 	{
 		*(.data)
+		*(.data.*)
 		_edata = . ;
 	} > dram
 	.bss :
 	{
 		*(.bss)
+		*(.bss.*)
 		_end = ALIGN( 0x10 ) ;
 	} > dram
 }
arch/cris/boot/rescue/rescue_v10.lds +2 -0
@@ -10,11 +10,13 @@
 	{
 		stext = . ;
 		*(.text)
+		*(.text.*)
 		etext = . ;
 	} > flash
 	.data :
 	{
 		*(.data)
+		*(.data.*)
 		edata = . ;
 	} > flash
 }
arch/cris/boot/rescue/rescue_v32.lds +3 -0
@@ -17,6 +17,7 @@
 	{
 		_stext = . ;
 		*(.text)
+		*(.text.*)
 		*(.init.text)
 		*(.rodata)
 		*(.rodata.*)
@@ -25,12 +26,14 @@
 	.data :
 	{
 		*(.data)
+		*(.data.*)
 		_edata = . ;
 	} > bootblk
 	.bss :
 	{
 		_bss = . ;
 		*(.bss)
+		*(.bss.*)
 		_end = ALIGN( 0x10 ) ;
 	} > intmem
 
arch/h8300/boot/compressed/vmlinux.lds +2 -0
@@ -6,12 +6,14 @@
 	__text = .;
 	       *(.text..startup)
 	       *(.text)
+	       *(.text.*)
         __etext = . ;
         }
 
 	.rodata :
 	{
 		*(.rodata)
+		*(.rodata.*)
 	}
         .data :
 
arch/h8300/boot/compressed/vmlinux.scr +1 -0
@@ -4,6 +4,7 @@
 	_input_len = .;
 	LONG(_input_data_end - _input_data) _input_data = .;
 	*(.data)
+	*(.data.*)
 	_input_data_end = .;
 	}
 }
arch/ia64/hp/sim/boot/bootloader.lds +3 -3
@@ -7,13 +7,13 @@
   . = 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 @@
 
   __bss_start = .;
   .sbss      : { *(.sbss) *(.scommon) }
-  .bss       : { *(.bss) *(COMMON) }
+  .bss       : { *(.bss) *(.bss.*) *(COMMON) }
   . = ALIGN(64 / 8);
   __bss_stop = .;
   _end = . ;
arch/m32r/boot/compressed/vmlinux.lds.S +3 -3
@@ -6,12 +6,12 @@
   . = 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 @@
 
   . = ALIGN(32 / 8);
   __bss_start = .;
-  .bss : { *(.bss) *(.sbss) }
+  .bss : { *(.bss) *(.bss.*) *(.sbss) }
   . = ALIGN(32 / 8);
   _ebss = .;
   . = ALIGN(4096);
arch/m32r/boot/compressed/vmlinux.scr +1 -0
@@ -3,6 +3,7 @@
   .data : {
 	zimage_data = .;
 	*(.data)
+	*(.data.*)
 	zimage_data_end = .;
 	}
   zimage_len = zimage_data_end - zimage_data;
arch/mn10300/boot/compressed/vmlinux.lds +1 -0
@@ -4,6 +4,7 @@
 	input_len = .;
 	LONG(input_data_end - input_data) input_data = .;
 	*(.data)
+	*(.data.*)
 	input_data_end = .;
 	}
 }
arch/powerpc/boot/zImage.coff.lds.S +2 -0
@@ -7,6 +7,7 @@
   .text      :
   {
     *(.text)
+    *(.text.*)
     *(.fixup)
   }
   _etext = .;
@@ -41,6 +42,7 @@
   {
    *(.sbss)
    *(.bss)
+   *(.bss.*)
   }
   _end = . ;
 
arch/powerpc/boot/zImage.lds.S +2 -0
@@ -7,6 +7,7 @@
   .text      :
   {
     *(.text)
+    *(.text.*)
     *(.fixup)
   }
   _etext = .;
@@ -45,6 +46,7 @@
   {
    *(.sbss)
    *(.bss)
+   *(.bss.*)
   }
   . = ALIGN(4096);
   _end = . ;
arch/powerpc/boot/zImage.ps3.lds.S +2 -0
@@ -21,6 +21,7 @@
   .text      :
   {
     *(.text)
+    *(.text.*)
     *(.fixup)
   }
   _etext = .;
@@ -44,6 +45,7 @@
   {
    *(.sbss)
    *(.bss)
+   *(.bss.*)
   }
   . = ALIGN(4096);
   _end = . ;
arch/sh/boot/compressed/vmlinux.scr +1 -0
@@ -4,6 +4,7 @@
 	input_len = .;
 	LONG(input_data_end - input_data) input_data = .;
 	*(.data)
+	*(.data.*)
 	output_len = . - 4;
 	input_data_end = .;
 	}
arch/x86/boot/setup.ld +2 -1
@@ -20,7 +20,7 @@
 	.initdata	: { *(.initdata) }
 	__end_init = .;
 
-	.text		: { *(.text) }
+	.text		: { *(.text) *(.text.*) }
 	.text32		: { *(.text32) }
 
 	. = ALIGN(16);
@@ -46,6 +46,7 @@
 	{
 		__bss_start = .;
 		*(.bss)
+		*(.bss.*)
 		__bss_end = .;
 	}
 	. = ALIGN(16);
arch/xtensa/boot/boot-elf/boot.lds.S +4 -1
@@ -10,19 +10,21 @@
 	{
 		__reloc_start = . ;
 		_text_start = . ;
-		*(.literal .text.literal .text)
+		*(.literal .text.literal .text .text.*)
 		_text_end = . ;
 	}
 
 	.rodata ALIGN(0x04):
 	{
 		*(.rodata)
+		*(.rodata.*)
 		*(.rodata1)
 	}
 
 	.data ALIGN(0x04):
 	{
 		*(.data)
+		*(.data.*)
 		*(.data1)
 		*(.sdata)
 		*(.sdata2)
@@ -58,6 +60,7 @@
 		*(.scommon)
 		*(.dynbss)
 		*(.bss)
+		*(.bss.*)
 		__bss_end = .;
 	}
 	_end = .;
arch/xtensa/boot/boot-redboot/boot.ld +4 -1
@@ -8,19 +8,21 @@
 	{
 		__reloc_start = . ;
 		_text_start = . ;
-		*(.literal .text.literal .text)
+		*(.literal .text.literal .text .text.*)
 		_text_end = . ;
 	}
 
 	.rodata ALIGN(0x04):
 	{
 		*(.rodata)
+		*(.rodata.*)
 		*(.rodata1)
 	}
 
 	.data ALIGN(0x04):
 	{
 		*(.data)
+		*(.data.*)
 		*(.data1)
 		*(.sdata)
 		*(.sdata2)
@@ -56,6 +58,7 @@
 		*(.scommon)
 		*(.dynbss)
 		*(.bss)
+		*(.bss.*)
 		__bss_end = .;
 	}
 	_end = .;
arch/frv/kernel/vmlinux.lds.S +0 -1
@@ -114,7 +114,6 @@
 
   .sbss		: { *(.sbss .sbss.*) }
   .bss		: { *(.bss .bss.*) }
-  .bss..stack	: { *(.bss) }
 
   __bss_stop = .;
   _end = . ;
arch/ia64/scripts/check-segrel.lds +2 -2
@@ -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 {
arch/m68knommu/kernel/vmlinux.lds.S +1 -0
@@ -169,6 +169,7 @@
 		. = ALIGN(4);
 		_sbss = . ;
 		*(.bss)
+		*(.bss.*)
 		*(COMMON)
 		. = ALIGN(4) ;
 		_ebss = . ;
arch/mips/lasat/image/romscript.normal +1 -0
@@ -12,6 +12,7 @@
   .data ALIGN(0x10) :
   {
     *(.data)
+    *(.data.*)
   }
   _image_start = ADDR(.data);
   _image_size = SIZEOF(.data);
arch/parisc/kernel/vmlinux.lds.S +1 -0
@@ -112,6 +112,7 @@
 	}
 	.bss : {
 		*(.bss)
+		*(.bss.*)
 		*(COMMON)
 	}
 	__bss_stop = .;
arch/sh/kernel/vsyscall/vsyscall.lds.S +1 -1
@@ -35,7 +35,7 @@
 	 */
 	. = 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	: {
arch/x86/kernel/acpi/realmode/wakeup.lds.S +1 -0
@@ -42,6 +42,7 @@
 	.bss :	{
 		__bss_start = .;
 		*(.bss)
+		*(.bss.*)
 		__bss_end = .;
 	}
 
arch/x86/kernel/vmlinux.lds.S +1 -0
@@ -307,6 +307,7 @@
 		__bss_start = .;
 		*(.bss..page_aligned)
 		*(.bss)
+		*(.bss.*)
 		. = ALIGN(4);
 		__bss_stop = .;
 	}
include/asm-generic/vmlinux.lds.h +17 -1
@@ -140,9 +140,22 @@
 #define TRACE_SYSCALLS()
 #endif
 
+/* .data.foo are generated by gcc itself with -fdata-sections,
+ * whereas double-dot sections (like .data..percpu) are generated
+ * by kernel's magic macros.
+ *
+ * arch/.../vmlinux.lds.S decides where to place various double-dot sections
+ * as needed by its arch, here DATA_DATA needs to be careful and collect
+ * only .data and .data.foo sections, skipping .data..foo
+ *
+ * Same goes for .text, .bss and .rodata. In case of .rodata, various
+ * .rodata.foo sections are generated by gcc even without -fdata-sections
+ */
+
 /* .data section */
 #define DATA_DATA							\
 	*(.data)							\
+	*(.data.[A-Za-z0-9_$^]*)					\
 	*(.ref.data)							\
 	DEV_KEEP(init.data)						\
 	DEV_KEEP(exit.data)						\
@@ -202,7 +215,8 @@
 	. = ALIGN((align));						\
 	.rodata           : AT(ADDR(.rodata) - LOAD_OFFSET) {		\
 		VMLINUX_SYMBOL(__start_rodata) = .;			\
-		*(.rodata) *(.rodata.*)					\
+		*(.rodata)						\
+		*(.rodata.[A-Za-z0-9_$^]*)				\
 		*(__vermagic)		/* Kernel version magic */	\
 		*(__markers_strings)	/* Markers: strings */		\
 		*(__tracepoints_strings)/* Tracepoints: strings */	\
@@ -369,6 +383,7 @@
 		ALIGN_FUNCTION();					\
 		*(.text.hot)						\
 		*(.text)						\
+		*(.text.[A-Za-z0-9_$^]*)				\
 		*(.ref.text)						\
 	DEV_KEEP(init.text)						\
 	DEV_KEEP(exit.text)						\
@@ -502,6 +517,7 @@
 		*(.bss..page_aligned)					\
 		*(.dynbss)						\
 		*(.bss)							\
+		*(.bss.[A-Za-z0-9_$^]*)					\
 		*(COMMON)						\
 	}
 
Acked-by
#8 lore raw
Quoted 36 lines · Denys Vlasenko
Quoted 10 lines · Sam Ravnborg
Quoted 5 lines

* fix for kernel linker stripts: linux-2.6.35-rc4-fs.fix-kernel-linker-scripts.patch It makes _all_ linker scripts -ffunction/data-sections safe via:
- *(.data)
+ *(.data .data.*)

This patch touches both the regular kernel linker scripts and the boot linker scripts.
I would strongly prefer a split so you touched the boot linker scripts in a separate patch.

No problem.

Quoted 2 lines

In addition the patch handles more sections than
documented: rodata, bss, text.

Yes, that was assumed.

Quoted 7 lines

The patch introduce the following syntax for input sections:

    *(.bss .bss.*)

Where the kernel linker script would have one input section per line.
Can we stick to the "layout" used in the kernel linker scripts?

Sure.

Quoted 3 lines

The patch in addition in several places changes linker scripts that already uses the two-lines layout to a single line approach. These "fixes" should be omitted.

Reverted.

Quoted 8 lines
Quoted 2 lines

Why do we need *(.bss .bss.*)?
Does -fdata-sections introduce special .bss sectiosn too?

Yes, it does.

Please take a look at attached updated patches.

Looks better now - thanks.

With proper changelogs both patches has my:

Sam

Acked-by
#9 lore raw
In reply to Denys Vlasenko
Quoted 3 lines

* fix for module linker script: linux-2.6.35-rc4-fs.fix-ko-module-linker-script.patch Prevents kernel modules from having unnecessarily many
sections and thus prevents module size growth.

scripts/module-common.lds +23 -0
@@ -3,6 +3,29 @@
  * Archs are free to supply their own linker scripts.  ld will
  * combine them automatically.
  */
+
+/* .data.foo are generated by gcc itself with -fdata-sections,
+ * whereas double-dot sections (like .data..percpu) are generated
+ * by kernel's magic macros.
+ *
+ * Since this script does not specify what to do with double-dot sections,
+ * ld -r will coalesce all .data..foo input sections into one .data..foo
+ * output section, all .data..bar input sections into one .data..bar
+ * output section and so on. This is exactly what we want.
+ *
+ * Same goes for .text, .bss and .rodata. In case of .rodata, various
+ * .rodata.foo sections are generated by gcc even without -fdata-sections
+ */
+
 SECTIONS {
+
+	/* Coalesce sections produced by gcc -ffunction-sections */
+	.text   0 : AT(0) { *(.text .text.[A-Za-z0-9_$^]*) }
+
+	/* Coalesce sections produced by gcc -fdata-sections */
+	.rodata 0 : AT(0) { *(.rodata .rodata.[A-Za-z0-9_$^]*) }
+	.data   0 : AT(0) { *(.data .data.[A-Za-z0-9_$^]*) }
+	.bss    0 : AT(0) { *(.bss .bss.[A-Za-z0-9_$^]*) }
+
 	/DISCARD/ : { *(.discard) }
 }
#10 lore raw
In reply to Denys Vlasenko
Quoted 11 lines

Then, in order to also garbage-collect the sections, I added

LDFLAGS_vmlinux += --gc-sections

in top-level Makefile.

This requires the additional patch (linux-2.6.35-rc4-fsgs.patch) which adds KEEP(section) directives to kernel linker stripts. Otherwise, linker will discard some crucial sections.

Changelog does not address why you need:

     -Map [email protected]

and what effect they have.

And it is obvious that some archs should consolidate a little more from asm-generic/vmlinux.lds.h.
But that said this patch looks much better than the initial versions posted.

How do you determine which sections needs the KEEP()? Worth documenting for future when we add new sections.

Sam

Makefile +3 -1
@@ -610,6 +610,8 @@
 LDFLAGS_vmlinux	+= $(call ld-option, -X,)
 endif
 
+LDFLAGS_vmlinux += --gc-sections
+
 # Default kernel image to build when no specific target is given.
 # KBUILD_IMAGE may be overruled on the command line or
 # set in the environment
@@ -705,7 +707,7 @@
 # Rule to link vmlinux - also used during CONFIG_KALLSYMS
 # May be overridden by arch/$(ARCH)/Makefile
 quiet_cmd_vmlinux__ ?= LD      $@
-      cmd_vmlinux__ ?= $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) -o $@ \
+      cmd_vmlinux__ ?= $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) -o $@ -Map [email protected] \
       -T $(vmlinux-lds) $(vmlinux-init)                          \
       --start-group $(vmlinux-main) --end-group                  \
       $(filter-out $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o FORCE ,$^)
arch/arm/kernel/vmlinux.lds.S +1 -1
@@ -157,7 +157,7 @@
 		. = ALIGN(32);
 		__start___ex_table = .;
 #ifdef CONFIG_MMU
-		*(__ex_table)
+		KEEP(*(__ex_table))
 #endif
 		__stop___ex_table = .;
 
arch/blackfin/kernel/vmlinux.lds.S +1 -1
@@ -51,7 +51,7 @@
 
 		. = ALIGN(16);
 		___start___ex_table = .;
-		*(__ex_table)
+		KEEP(*(__ex_table))
 		___stop___ex_table = .;
 
 		__etext = .;
arch/cris/boot/rescue/rescue_v32.lds +2 -2
@@ -36,7 +36,7 @@
 	/* Get rid of stuff from EXPORT_SYMBOL(foo). */
 	/DISCARD/ :
 	{
-	        *(__ksymtab_strings)
-	        *(__ksymtab)
+		KEEP(*(__ksymtab_strings))
+		*(__ksymtab)
 	}
 }
arch/cris/kernel/vmlinux.lds.S +2 -2
@@ -72,7 +72,7 @@
 	.init.setup : { INIT_SETUP(16) }
 #ifdef CONFIG_ETRAX_ARCH_V32
 	__start___param = .;
-	__param : { *(__param) }
+	__param : { KEEP(*(__param)) }
 	__stop___param = .;
 #endif
 	.initcall.init : {
@@ -88,7 +88,7 @@
 #ifdef CONFIG_BLK_DEV_INITRD
 	.init.ramfs : {
 		__initramfs_start = .;
-		*(.init.ramfs)
+		KEEP(*(.init.ramfs))
 		__initramfs_end = .;
 	}
 #endif
arch/h8300/kernel/vmlinux.lds.S +1 -1
@@ -112,7 +112,7 @@
 	. = ALIGN(0x4) ;
 	INIT_SETUP(0x4)
 	___setup_start = .;
-		*(.init.setup)
+		KEEP(*(.init.setup))
 	. = ALIGN(0x4) ;
 	___setup_end = .;
 	INIT_CALLS
arch/m68knommu/kernel/vmlinux.lds.S +4 -4
@@ -72,7 +72,7 @@
 
 		. = ALIGN(16);          /* Exception table              */
 		__start___ex_table = .;
-		*(__ex_table)
+		KEEP(*(__ex_table))
 		__stop___ex_table = .;
 
 		*(.rodata .rodata.*)
@@ -129,16 +129,16 @@
 
 		/* Kernel symbol table: GPL-future symbols */
 		__start___kcrctab_gpl_future = .;
-		*(__kcrctab_gpl_future)
+		KEEP(*(__kcrctab_gpl_future))
 		__stop___kcrctab_gpl_future = .;
 
 		/* Kernel symbol table: strings */
-		*(__ksymtab_strings)
+		KEEP(*(__ksymtab_strings))
 
 		/* Built-in module parameters */
 		. = ALIGN(4) ;
 		__start___param = .;
-		*(__param)
+		KEEP(*(__param))
 		__stop___param = .;
 
 		. = ALIGN(4) ;
arch/microblaze/kernel/vmlinux.lds.S +1 -1
@@ -122,7 +122,7 @@
 
 	.init.ramfs ALIGN(4096) : AT(ADDR(.init.ramfs) - LOAD_OFFSET) {
 		__initramfs_start = .;
-		*(.init.ramfs)
+		KEEP(*(.init.ramfs))
 		__initramfs_end = .;
 		. = ALIGN(4);
 		LONG(0);
arch/mn10300/kernel/vmlinux.lds.S +3 -3
@@ -51,7 +51,7 @@
   . = ALIGN(PAGE_SIZE);
   .smp_locks : AT(ADDR(.smp_locks) - LOAD_OFFSET) {
   	__smp_locks = .;
-	*(.smp_locks)
+	KEEP(*(.smp_locks))
 	__smp_locks_end = .;
   }
 
@@ -62,9 +62,9 @@
   INIT_DATA_SECTION(16)
   . = ALIGN(4);
   __alt_instructions = .;
-  .altinstructions : { *(.altinstructions) }
+  .altinstructions : { KEEP(*(.altinstructions)) }
   __alt_instructions_end = .;
- .altinstr_replacement : { *(.altinstr_replacement) }
+ .altinstr_replacement : { KEEP(*(.altinstr_replacement)) }
   /* .exit.text is discard at runtime, not link time, to deal with references
      from .altinstructions and .eh_frame */
 	.exit.text : { EXIT_TEXT; }
arch/um/include/asm/common.lds.S +2 -2
@@ -76,10 +76,10 @@
   . = ALIGN(4);
   .altinstructions : {
 	__alt_instructions = .;
-	*(.altinstructions)
+	KEEP(*(.altinstructions))
 	__alt_instructions_end = .;
   }
-  .altinstr_replacement : { *(.altinstr_replacement) }
+  .altinstr_replacement : { KEEP(*(.altinstr_replacement)) }
   /* .exit.text is discard at runtime, not link time, to deal with references
      from .altinstructions and .eh_frame */
   .exit.text : { *(.exit.text) }
arch/x86/kernel/vmlinux.lds.S +12 -12
@@ -162,46 +162,46 @@
 
 	. = VSYSCALL_ADDR;
 	.vsyscall_0 : AT(VLOAD(.vsyscall_0)) {
-		*(.vsyscall_0)
+		KEEP(*(.vsyscall_0))
 	} :user
 
 	. = ALIGN(L1_CACHE_BYTES);
 	.vsyscall_fn : AT(VLOAD(.vsyscall_fn)) {
-		*(.vsyscall_fn)
+		KEEP(*(.vsyscall_fn))
 	}
 
 	. = ALIGN(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)
+		KEEP(*(.vgetcpu_mode))
 	}
 	vgetcpu_mode = VVIRT(.vgetcpu_mode);
 
 	. = ALIGN(L1_CACHE_BYTES);
 	.jiffies : AT(VLOAD(.jiffies)) {
-		*(.jiffies)
+		KEEP(*(.jiffies))
 	}
 	jiffies = VVIRT(.jiffies);
 
 	.vsyscall_3 ADDR(.vsyscall_0) + 3072: AT(VLOAD(.vsyscall_3)) {
-		*(.vsyscall_3)
+		KEEP(*(.vsyscall_3))
 	}
 
 	. = __vsyscall_0 + PAGE_SIZE;
@@ -252,12 +252,12 @@
 	. = ALIGN(8);
 	.altinstructions : AT(ADDR(.altinstructions) - LOAD_OFFSET) {
 		__alt_instructions = .;
-		*(.altinstructions)
+		KEEP(*(.altinstructions))
 		__alt_instructions_end = .;
 	}
 
 	.altinstr_replacement : AT(ADDR(.altinstr_replacement) - LOAD_OFFSET) {
-		*(.altinstr_replacement)
+		KEEP(*(.altinstr_replacement))
 	}
 
 	/*
@@ -290,7 +290,7 @@
 	. = ALIGN(PAGE_SIZE);
 	.smp_locks : AT(ADDR(.smp_locks) - LOAD_OFFSET) {
 		__smp_locks = .;
-		*(.smp_locks)
+		KEEP(*(.smp_locks))
 		. = ALIGN(PAGE_SIZE);
 		__smp_locks_end = .;
 	}
arch/x86/vdso/vdso-layout.lds.S +2 -2
@@ -34,8 +34,8 @@
 	      *(.gnu.linkonce.b.*)
 	}
 
-	.altinstructions	: { *(.altinstructions) }
-	.altinstr_replacement	: { *(.altinstr_replacement) }
+	.altinstructions	: { KEEP(*(.altinstructions)) }
+	.altinstr_replacement	: { KEEP(*(.altinstr_replacement)) }
 
 	/*
 	 * Align the actual code well away from the non-instruction data.
include/asm-generic/vmlinux.lds.h +44 -44

221 lines not on this page · raw message

#11 lore raw

Hi Sam,

Quoted 12 lines · Sam Ravnborg
Quoted 11 lines

Then, in order to also garbage-collect the sections, I added

LDFLAGS_vmlinux += --gc-sections

in top-level Makefile.

This requires the additional patch (linux-2.6.35-rc4-fsgs.patch) which adds KEEP(section) directives to kernel linker stripts. Otherwise, linker will discard some crucial sections.

Quoted 5 lines

Changelog does not address why you need:

     -Map [email protected]

and what effect they have.

I didn't plan to push the last step (--gc-sections) to mainline yet. Thus the patch has debugging stuff in it.

Quoted 6 lines

And it is obvious that some archs should consolidate a little more from asm-generic/vmlinux.lds.h.
But that said this patch looks much better than the initial versions posted.

How do you determine which sections needs the KEEP()? Worth documenting for future when we add new sections.

No problem, I will be adding comments at every KEEP() why it's needed.

Signature · 1 line
vda
#12 lore raw
Quoted 25 lines · Denys Vlasenko

Hi Sam,

Quoted 12 lines · Sam Ravnborg
Quoted 11 lines

Then, in order to also garbage-collect the sections, I added

LDFLAGS_vmlinux += --gc-sections

in top-level Makefile.

This requires the additional patch (linux-2.6.35-rc4-fsgs.patch) which adds KEEP(section) directives to kernel linker stripts. Otherwise, linker will discard some crucial sections.

Quoted 5 lines

Changelog does not address why you need:

     -Map [email protected]

and what effect they have.

I didn't plan to push the last step (--gc-sections) to mainline yet. Thus the patch has debugging stuff in it.

Quoted 8 lines
Quoted 6 lines

And it is obvious that some archs should consolidate a little more from asm-generic/vmlinux.lds.h.
But that said this patch looks much better than the initial versions posted.

How do you determine which sections needs the KEEP()? Worth documenting for future when we add new sections.

No problem, I will be adding comments at every KEEP() why it's needed.

A general comment in vmlinux.lds.h and a careful explanation in the changelog should be enough.

You should not comment each of the KEEP().

Sam