We currently have infrastructure for discardable text and data, but no such thing for strings. This is especially notable for inline strings such as ones used by printk() which are left behind resident in the memory throughout the life of the system even though code referring to them has been removed. Following a short discussion at the linux-mips list, here is a proposed implementation for discardable strings. It adds __initstr and __exitstr plus most of the usual variations, but most importantly it adds wrapper macros that may be used for inline strings that make them be put in separate sections which may then be discarded, while still preserving the usual merging property of sections containing strings. The macros are called _i() and _e(), with the other alternatives adding at most two letters each. This has been inspired by how the GNU gettext handles localised strings in a way that does not add too much clutter and the result is still reasonably well readable. Some use examples have been included in <linux/init.h>. There is one pitfall here -- GCC does not let one specify section flags explicitly and provides its own set based on the type of the variable instead. The guess, which is "aw", is not what we want here, so I had to circumvent it somehow. The solution is to provide the flags and the further necessary parameters as a part of the section "name" and then emit a newline and an assembly comment character so that what GCC produces for section flags is ignored. A newline is required for a reasonable implementation, because only the line comment character is almost universal across targets supported by binutils (except from a couple of obscure platforms we do not aim to support), while the trailing comment character varies wildly and may not even be available at all (cf. blackfin). This is what this strange __strflags macro is for. Of course for this to work all the linker scripts have to be updated accordingly. Signed-off-by: Maciej W. Rozycki <macro@xxxxxxxxxxxxxx> --- I did some proof-of-concept testing only of this change as for it to be of use, strings have to be annotated appropriately. I do not expect it to happen soon or automatically, but I rely on people for whom the size matters to make the necessary adjustments. For testing I made the obvious choice ;-) of drivers/net/defxx.c; for which I have a patch that I will send separately. The driver is nice enough to have a duplicate string that can be used to verify that merging still works and then the results of the discarding can be examined through /proc/kcore. I have built the changes for MIPS, albeit with a slightly older kernel as the current version does not build for my configuration of interest, and successfully verified at the run time. Architecture maintainers, I have made a reasonable attempt to get the linker script changes right, but for a few of the more complicated setups I may have not done everything necessary or I may have misplaced the sections in the output even. Please let me know of any adjustments necessary. Comments are welcome, whether positive or negative, but I do hope overall the feature is reasonable enough to be accepted. This patch applies to the current Linus tree. Maciej patch-2.6.23-20071012-inexitstr-5 diff -up --recursive --new-file linux-2.6.23-20071012.macro/arch/alpha/kernel/vmlinux.lds.S linux-2.6.23-20071012/arch/alpha/kernel/vmlinux.lds.S --- linux-2.6.23-20071012.macro/arch/alpha/kernel/vmlinux.lds.S 2007-09-04 04:55:16.000000000 +0000 +++ linux-2.6.23-20071012/arch/alpha/kernel/vmlinux.lds.S 2007-10-12 13:53:22.000000000 +0000 @@ -42,6 +42,7 @@ SECTIONS *(.init.text) _einittext = .; } + .init.str1 : { *(.init.str1) } .init.data : { *(.init.data) } . = ALIGN(16); @@ -107,7 +108,7 @@ SECTIONS _end = .; /* Sections to be discarded */ - /DISCARD/ : { *(.exit.text) *(.exit.data) *(.exitcall.exit) } + /DISCARD/ : { *(.exit.text) *(.exit.str1) *(.exit.data) *(.exitcall.exit) } .mdebug 0 : { *(.mdebug) } .note 0 : { *(.note) } diff -up --recursive --new-file linux-2.6.23-20071012.macro/arch/arm/kernel/vmlinux.lds.S linux-2.6.23-20071012/arch/arm/kernel/vmlinux.lds.S --- linux-2.6.23-20071012.macro/arch/arm/kernel/vmlinux.lds.S 2007-09-04 04:55:16.000000000 +0000 +++ linux-2.6.23-20071012/arch/arm/kernel/vmlinux.lds.S 2007-10-12 13:53:22.000000000 +0000 @@ -41,6 +41,7 @@ SECTIONS __tagtable_begin = .; *(.taglist.init) __tagtable_end = .; + *(.init.str1) . = ALIGN(16); __setup_start = .; *(.init.setup) @@ -78,6 +79,7 @@ SECTIONS /DISCARD/ : { /* Exit code and data */ *(.exit.text) + *(.exit.str1) *(.exit.data) *(.exitcall.exit) #ifndef CONFIG_MMU diff -up --recursive --new-file linux-2.6.23-20071012.macro/arch/blackfin/kernel/vmlinux.lds.S linux-2.6.23-20071012/arch/blackfin/kernel/vmlinux.lds.S --- linux-2.6.23-20071012.macro/arch/blackfin/kernel/vmlinux.lds.S 2007-10-12 02:56:53.000000000 +0000 +++ linux-2.6.23-20071012/arch/blackfin/kernel/vmlinux.lds.S 2007-10-12 13:53:22.000000000 +0000 @@ -94,6 +94,10 @@ SECTIONS *(.init.text) __einittext = .; } + .init.str1 : + { + *(.init.str1) + } .init.data : { . = ALIGN(16); @@ -194,6 +198,7 @@ SECTIONS /DISCARD/ : { *(.exit.text) + *(.exit.str1) *(.exit.data) *(.exitcall.exit) } diff -up --recursive --new-file linux-2.6.23-20071012.macro/arch/frv/kernel/vmlinux.lds.S linux-2.6.23-20071012/arch/frv/kernel/vmlinux.lds.S --- linux-2.6.23-20071012.macro/arch/frv/kernel/vmlinux.lds.S 2007-09-04 04:55:18.000000000 +0000 +++ linux-2.6.23-20071012/arch/frv/kernel/vmlinux.lds.S 2007-10-12 13:53:22.000000000 +0000 @@ -35,6 +35,7 @@ SECTIONS #endif } _einittext = .; + .init.str1 : { *(.init.str1) } .init.data : { *(.init.data) } . = ALIGN(8); @@ -124,6 +125,7 @@ SECTIONS __trap_fixup_tables = .; *(.trap.fixup.user .trap.fixup.kernel) + *(.exit.str1) } . = ALIGN(8); /* Exception table */ diff -up --recursive --new-file linux-2.6.23-20071012.macro/arch/h8300/kernel/vmlinux.lds.S linux-2.6.23-20071012/arch/h8300/kernel/vmlinux.lds.S --- linux-2.6.23-20071012.macro/arch/h8300/kernel/vmlinux.lds.S 2007-07-10 04:55:29.000000000 +0000 +++ linux-2.6.23-20071012/arch/h8300/kernel/vmlinux.lds.S 2007-10-12 13:53:22.000000000 +0000 @@ -112,6 +112,7 @@ SECTIONS __sinittext = .; *(.init.text) __einittext = .; + *(.init.str1) *(.init.data) . = ALIGN(0x4) ; ___setup_start = .; @@ -125,6 +126,7 @@ SECTIONS *(.con_initcall.init) ___con_initcall_end = .; *(.exit.text) + *(.exit.str1) *(.exit.data) #if defined(CONFIG_BLK_DEV_INITRD) . = ALIGN(4); diff -up --recursive --new-file linux-2.6.23-20071012.macro/arch/ia64/kernel/vmlinux.lds.S linux-2.6.23-20071012/arch/ia64/kernel/vmlinux.lds.S --- linux-2.6.23-20071012.macro/arch/ia64/kernel/vmlinux.lds.S 2007-09-04 04:55:19.000000000 +0000 +++ linux-2.6.23-20071012/arch/ia64/kernel/vmlinux.lds.S 2007-10-12 13:53:22.000000000 +0000 @@ -28,6 +28,7 @@ SECTIONS /* Sections to be discarded */ /DISCARD/ : { *(.exit.text) + *(.exit.str1) *(.exit.data) *(.exitcall.exit) *(.IA_64.unwind.exit.text) @@ -123,6 +124,9 @@ SECTIONS _einittext = .; } + .exit.str1 : AT(ADDR(.init.str1) - LOAD_OFFSET) + { *(.exit.str1) } + .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { *(.init.data) } diff -up --recursive --new-file linux-2.6.23-20071012.macro/arch/m32r/kernel/vmlinux.lds.S linux-2.6.23-20071012/arch/m32r/kernel/vmlinux.lds.S --- linux-2.6.23-20071012.macro/arch/m32r/kernel/vmlinux.lds.S 2007-09-04 04:55:19.000000000 +0000 +++ linux-2.6.23-20071012/arch/m32r/kernel/vmlinux.lds.S 2007-10-12 13:53:22.000000000 +0000 @@ -79,6 +79,7 @@ SECTIONS *(.init.text) _einittext = .; } + .init.str1 : { *(.init.str1) } .init.data : { *(.init.data) } . = ALIGN(16); __setup_start = .; @@ -101,6 +102,7 @@ SECTIONS /* .exit.text is discard at runtime, not link time, to deal with references from .altinstructions and .eh_frame */ .exit.text : { *(.exit.text) } + .exit.str1 : { *(.exit.str1) } .exit.data : { *(.exit.data) } #ifdef CONFIG_BLK_DEV_INITRD diff -up --recursive --new-file linux-2.6.23-20071012.macro/arch/m68k/kernel/vmlinux-std.lds linux-2.6.23-20071012/arch/m68k/kernel/vmlinux-std.lds --- linux-2.6.23-20071012.macro/arch/m68k/kernel/vmlinux-std.lds 2007-09-04 04:55:19.000000000 +0000 +++ linux-2.6.23-20071012/arch/m68k/kernel/vmlinux-std.lds 2007-10-12 13:53:22.000000000 +0000 @@ -48,6 +48,7 @@ SECTIONS *(.init.text) _einittext = .; } + .init.str1 : { *(.init.str1) } .init.data : { *(.init.data) } . = ALIGN(16); __setup_start = .; @@ -83,6 +84,7 @@ SECTIONS /* Sections to be discarded */ /DISCARD/ : { *(.exit.text) + *(.exit.str1) *(.exit.data) *(.exitcall.exit) } diff -up --recursive --new-file linux-2.6.23-20071012.macro/arch/m68k/kernel/vmlinux-sun3.lds linux-2.6.23-20071012/arch/m68k/kernel/vmlinux-sun3.lds --- linux-2.6.23-20071012.macro/arch/m68k/kernel/vmlinux-sun3.lds 2007-09-04 04:55:19.000000000 +0000 +++ linux-2.6.23-20071012/arch/m68k/kernel/vmlinux-sun3.lds 2007-10-12 13:53:22.000000000 +0000 @@ -41,6 +41,7 @@ __init_begin = .; *(.init.text) _einittext = .; } + .init.str1 : { *(.init.str1) } .init.data : { *(.init.data) } . = ALIGN(16); __setup_start = .; @@ -78,6 +79,7 @@ __init_begin = .; /* Sections to be discarded */ /DISCARD/ : { *(.exit.text) + *(.exit.str1) *(.exit.data) *(.exitcall.exit) } diff -up --recursive --new-file linux-2.6.23-20071012.macro/arch/m68knommu/kernel/vmlinux.lds.S linux-2.6.23-20071012/arch/m68knommu/kernel/vmlinux.lds.S --- linux-2.6.23-20071012.macro/arch/m68knommu/kernel/vmlinux.lds.S 2007-07-10 04:55:30.000000000 +0000 +++ linux-2.6.23-20071012/arch/m68knommu/kernel/vmlinux.lds.S 2007-10-12 13:53:22.000000000 +0000 @@ -145,6 +145,7 @@ SECTIONS { _sinittext = .; *(.init.text) _einittext = .; + *(.init.str1) *(.init.data) . = ALIGN(16); __setup_start = .; @@ -171,6 +172,7 @@ SECTIONS { /DISCARD/ : { *(.exit.text) + *(.exit.str1) *(.exit.data) *(.exitcall.exit) } diff -up --recursive --new-file linux-2.6.23-20071012.macro/arch/mips/kernel/vmlinux.lds.S linux-2.6.23-20071012/arch/mips/kernel/vmlinux.lds.S --- linux-2.6.23-20071012.macro/arch/mips/kernel/vmlinux.lds.S 2007-10-11 04:56:52.000000000 +0000 +++ linux-2.6.23-20071012/arch/mips/kernel/vmlinux.lds.S 2007-10-12 13:53:22.000000000 +0000 @@ -107,6 +107,9 @@ SECTIONS *(.init.text) _einittext = .; } + .init.str1 : { + *(.init.str1) + } .init.data : { *(.init.data) } @@ -136,6 +139,9 @@ SECTIONS .exit.text : { *(.exit.text) } + .exit.str1 : { + *(.exit.str1) + } .exit.data : { *(.exit.data) } diff -up --recursive --new-file linux-2.6.23-20071012.macro/arch/parisc/kernel/vmlinux.lds.S linux-2.6.23-20071012/arch/parisc/kernel/vmlinux.lds.S --- linux-2.6.23-20071012.macro/arch/parisc/kernel/vmlinux.lds.S 2007-09-04 04:55:20.000000000 +0000 +++ linux-2.6.23-20071012/arch/parisc/kernel/vmlinux.lds.S 2007-10-12 13:53:22.000000000 +0000 @@ -150,6 +150,7 @@ SECTIONS *(.init.text) _einittext = .; } + .init.str1 : { *(.init.str1) } .init.data : { *(.init.data) } . = ALIGN(16); __setup_start = .; @@ -176,6 +177,7 @@ SECTIONS /* .exit.text is discard at runtime, not link time, to deal with references from .altinstructions and .eh_frame */ .exit.text : { *(.exit.text) } + .exit.str1 : { *(.exit.str1) } .exit.data : { *(.exit.data) } #ifdef CONFIG_BLK_DEV_INITRD . = ALIGN(ASM_PAGE_SIZE); diff -up --recursive --new-file linux-2.6.23-20071012.macro/arch/powerpc/kernel/vmlinux.lds.S linux-2.6.23-20071012/arch/powerpc/kernel/vmlinux.lds.S --- linux-2.6.23-20071012.macro/arch/powerpc/kernel/vmlinux.lds.S 2007-09-04 04:55:20.000000000 +0000 +++ linux-2.6.23-20071012/arch/powerpc/kernel/vmlinux.lds.S 2007-10-12 13:53:22.000000000 +0000 @@ -23,6 +23,7 @@ SECTIONS /* Sections to be discarded. */ /DISCARD/ : { *(.exitcall.exit) + *(.exit.str1) *(.exit.data) } @@ -84,6 +85,8 @@ SECTIONS */ .exit.text : { *(.exit.text) } + .init.str1 : { *(.init.str1) } + .init.data : { *(.init.data); __vtop_table_begin = .; diff -up --recursive --new-file linux-2.6.23-20071012.macro/arch/ppc/kernel/vmlinux.lds.S linux-2.6.23-20071012/arch/ppc/kernel/vmlinux.lds.S --- linux-2.6.23-20071012.macro/arch/ppc/kernel/vmlinux.lds.S 2007-09-04 04:55:26.000000000 +0000 +++ linux-2.6.23-20071012/arch/ppc/kernel/vmlinux.lds.S 2007-10-12 13:53:22.000000000 +0000 @@ -101,6 +101,7 @@ SECTIONS /* .exit.text is discarded at runtime, not link time, to deal with references from __bug_table */ .exit.text : { *(.exit.text) } + .init.str1 : { *(.init.str1) } .init.data : { *(.init.data); __vtop_table_begin = .; @@ -162,6 +163,7 @@ SECTIONS /* Sections to be discarded. */ /DISCARD/ : { *(.exitcall.exit) + *(.exit.str1) *(.exit.data) } } diff -up --recursive --new-file linux-2.6.23-20071012.macro/arch/s390/kernel/vmlinux.lds.S linux-2.6.23-20071012/arch/s390/kernel/vmlinux.lds.S --- linux-2.6.23-20071012.macro/arch/s390/kernel/vmlinux.lds.S 2007-09-04 04:55:27.000000000 +0000 +++ linux-2.6.23-20071012/arch/s390/kernel/vmlinux.lds.S 2007-10-12 13:53:22.000000000 +0000 @@ -87,6 +87,7 @@ SECTIONS * to deal with references from __bug_table */ .exit.text : { *(.exit.text) } + .init.str1 : { *(.init.str1) } .init.data : { *(.init.data) } . = ALIGN(256); @@ -124,7 +125,7 @@ SECTIONS /* Sections to be discarded */ /DISCARD/ : { - *(.exit.data) *(.exitcall.exit) + *(.exit.str1) *(.exit.data) *(.exitcall.exit) } /* Stabs debugging sections. */ diff -up --recursive --new-file linux-2.6.23-20071012.macro/arch/sh/kernel/vmlinux.lds.S linux-2.6.23-20071012/arch/sh/kernel/vmlinux.lds.S --- linux-2.6.23-20071012.macro/arch/sh/kernel/vmlinux.lds.S 2007-09-04 04:55:28.000000000 +0000 +++ linux-2.6.23-20071012/arch/sh/kernel/vmlinux.lds.S 2007-10-12 13:53:22.000000000 +0000 @@ -74,6 +74,7 @@ SECTIONS _sinittext = .; .init.text : { *(.init.text) } _einittext = .; + .init.str1 : { *(.init.str1) } .init.data : { *(.init.data) } . = ALIGN(16); __setup_start = .; diff -up --recursive --new-file linux-2.6.23-20071012.macro/arch/sh64/kernel/vmlinux.lds.S linux-2.6.23-20071012/arch/sh64/kernel/vmlinux.lds.S --- linux-2.6.23-20071012.macro/arch/sh64/kernel/vmlinux.lds.S 2007-09-04 04:55:29.000000000 +0000 +++ linux-2.6.23-20071012/arch/sh64/kernel/vmlinux.lds.S 2007-10-12 13:53:22.000000000 +0000 @@ -105,6 +105,7 @@ SECTIONS _sinittext = .; .init.text : C_PHYS(.init.text) { *(.init.text) } _einittext = .; + .init.str1 : C_PHYS(.init.str1) { *(.init.str1) } .init.data : C_PHYS(.init.data) { *(.init.data) } . = ALIGN(L1_CACHE_BYTES); /* Better if Cache Line aligned */ __setup_start = .; @@ -141,6 +142,7 @@ SECTIONS /* Sections to be discarded */ /DISCARD/ : { *(.exit.text) + *(.exit.str1) *(.exit.data) *(.exitcall.exit) } diff -up --recursive --new-file linux-2.6.23-20071012.macro/arch/sparc/kernel/vmlinux.lds.S linux-2.6.23-20071012/arch/sparc/kernel/vmlinux.lds.S --- linux-2.6.23-20071012.macro/arch/sparc/kernel/vmlinux.lds.S 2007-09-04 04:55:29.000000000 +0000 +++ linux-2.6.23-20071012/arch/sparc/kernel/vmlinux.lds.S 2007-10-12 13:53:22.000000000 +0000 @@ -45,6 +45,7 @@ SECTIONS } _einittext = .; __init_text_end = .; + .init.str1 : { *(.init.str1) } .init.data : { *(.init.data) } . = ALIGN(16); __setup_start = .; @@ -83,7 +84,7 @@ SECTIONS } _end = . ; PROVIDE (end = .); - /DISCARD/ : { *(.exit.text) *(.exit.data) *(.exitcall.exit) } + /DISCARD/ : { *(.exit.text) *(.exit.str1) *(.exit.data) *(.exitcall.exit) } STABS_DEBUG diff -up --recursive --new-file linux-2.6.23-20071012.macro/arch/sparc64/kernel/vmlinux.lds.S linux-2.6.23-20071012/arch/sparc64/kernel/vmlinux.lds.S --- linux-2.6.23-20071012.macro/arch/sparc64/kernel/vmlinux.lds.S 2007-09-04 04:55:30.000000000 +0000 +++ linux-2.6.23-20071012/arch/sparc64/kernel/vmlinux.lds.S 2007-10-12 13:53:22.000000000 +0000 @@ -54,6 +54,7 @@ SECTIONS *(.init.text) _einittext = .; } + .init.str1 : { *(.init.str1) } .init.data : { *(.init.data) } . = ALIGN(16); __setup_start = .; @@ -106,7 +107,7 @@ SECTIONS } _end = . ; PROVIDE (end = .); - /DISCARD/ : { *(.exit.text) *(.exit.data) *(.exitcall.exit) } + /DISCARD/ : { *(.exit.text) *(.exit.str1) *(.exit.data) *(.exitcall.exit) } STABS_DEBUG diff -up --recursive --new-file linux-2.6.23-20071012.macro/arch/um/kernel/dyn.lds.S linux-2.6.23-20071012/arch/um/kernel/dyn.lds.S --- linux-2.6.23-20071012.macro/arch/um/kernel/dyn.lds.S 2007-09-04 04:55:30.000000000 +0000 +++ linux-2.6.23-20071012/arch/um/kernel/dyn.lds.S 2007-10-12 13:53:22.000000000 +0000 @@ -22,6 +22,7 @@ SECTIONS *(.init.text) _einittext = .; } + .init.str1 : { *(.init.str1) } . = ALIGN(4096); diff -up --recursive --new-file linux-2.6.23-20071012.macro/arch/um/kernel/uml.lds.S linux-2.6.23-20071012/arch/um/kernel/uml.lds.S --- linux-2.6.23-20071012.macro/arch/um/kernel/uml.lds.S 2007-09-04 04:55:30.000000000 +0000 +++ linux-2.6.23-20071012/arch/um/kernel/uml.lds.S 2007-10-12 13:53:22.000000000 +0000 @@ -33,6 +33,7 @@ SECTIONS *(.init.text) _einittext = .; } + .init.str1 : { *(.init.str1) } . = ALIGN(4096); .text : diff -up --recursive --new-file linux-2.6.23-20071012.macro/arch/v850/kernel/vmlinux.lds.S linux-2.6.23-20071012/arch/v850/kernel/vmlinux.lds.S --- linux-2.6.23-20071012.macro/arch/v850/kernel/vmlinux.lds.S 2007-07-10 04:55:50.000000000 +0000 +++ linux-2.6.23-20071012/arch/v850/kernel/vmlinux.lds.S 2007-10-12 13:53:22.000000000 +0000 @@ -99,6 +99,7 @@ *(.text.lock) \ *(.exitcall.exit) \ __real_etext = . ; /* There may be data after here. */ \ + *(.exit.str1) \ RODATA_CONTENTS \ . = ALIGN (4) ; \ *(.call_table_data) \ @@ -159,6 +160,7 @@ __sinittext = .; \ *(.init.text) /* 2.5 convention */ \ __einittext = .; \ + *(.init.str1) \ *(.init.data) \ *(.text.init) /* 2.4 convention */ \ *(.data.init) \ diff -up --recursive --new-file linux-2.6.23-20071012.macro/arch/x86/kernel/vmlinux_32.lds.S linux-2.6.23-20071012/arch/x86/kernel/vmlinux_32.lds.S --- linux-2.6.23-20071012.macro/arch/x86/kernel/vmlinux_32.lds.S 2007-10-12 02:56:54.000000000 +0000 +++ linux-2.6.23-20071012/arch/x86/kernel/vmlinux_32.lds.S 2007-10-12 13:53:22.000000000 +0000 @@ -134,6 +134,7 @@ SECTIONS *(.init.text) _einittext = .; } + .init.str1 : AT(ADDR(.init.str1) - LOAD_OFFSET) { *(.init.str1) } .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { *(.init.data) } . = ALIGN(16); .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) { @@ -170,6 +171,7 @@ SECTIONS /* .exit.text is discard 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.str1 : AT(ADDR(.exit.str1) - LOAD_OFFSET) { *(.exit.str1) } .exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) { *(.exit.data) } #if defined(CONFIG_BLK_DEV_INITRD) . = ALIGN(4096); diff -up --recursive --new-file linux-2.6.23-20071012.macro/arch/x86/kernel/vmlinux_64.lds.S linux-2.6.23-20071012/arch/x86/kernel/vmlinux_64.lds.S --- linux-2.6.23-20071012.macro/arch/x86/kernel/vmlinux_64.lds.S 2007-10-12 02:56:54.000000000 +0000 +++ linux-2.6.23-20071012/arch/x86/kernel/vmlinux_64.lds.S 2007-10-12 13:53:22.000000000 +0000 @@ -158,6 +158,7 @@ SECTIONS *(.init.text) _einittext = .; } + .init.str1 : AT(ADDR(.init.str1) - LOAD_OFFSET) { *(.init.str1) } __initdata_begin = .; .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { *(.init.data) } __initdata_end = .; @@ -188,6 +189,7 @@ SECTIONS /* .exit.text is discard 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.str1 : AT(ADDR(.exit.str1) - LOAD_OFFSET) { *(.exit.str1) } .exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) { *(.exit.data) } /* vdso blob that is mapped into user space */ diff -up --recursive --new-file linux-2.6.23-20071012.macro/arch/xtensa/kernel/vmlinux.lds.S linux-2.6.23-20071012/arch/xtensa/kernel/vmlinux.lds.S --- linux-2.6.23-20071012.macro/arch/xtensa/kernel/vmlinux.lds.S 2007-09-04 04:55:30.000000000 +0000 +++ linux-2.6.23-20071012/arch/xtensa/kernel/vmlinux.lds.S 2007-10-12 13:53:22.000000000 +0000 @@ -140,6 +140,8 @@ SECTIONS _einittext = .; } + .init.str1 : { *(.init.str1) } + .init.data : { *(.init.data) @@ -279,6 +281,7 @@ SECTIONS /DISCARD/ : { *(.exit.literal .exit.text) + *(.exit.str1) *(.exit.data) *(.exitcall.exit) } diff -up --recursive --new-file linux-2.6.23-20071012.macro/include/asm-um/common.lds.S linux-2.6.23-20071012/include/asm-um/common.lds.S --- linux-2.6.23-20071012.macro/include/asm-um/common.lds.S 2007-09-04 04:56:18.000000000 +0000 +++ linux-2.6.23-20071012/include/asm-um/common.lds.S 2007-10-12 13:53:22.000000000 +0000 @@ -98,6 +98,7 @@ /* .exit.text is discard at runtime, not link time, to deal with references from .altinstructions and .eh_frame */ .exit.text : { *(.exit.text) } + .exit.str1 : { *(.exit.str1) } .exit.data : { *(.exit.data) } .preinit_array : { diff -up --recursive --new-file linux-2.6.23-20071012.macro/include/linux/init.h linux-2.6.23-20071012/include/linux/init.h --- linux-2.6.23-20071012.macro/include/linux/init.h 2007-10-12 02:56:54.000000000 +0000 +++ linux-2.6.23-20071012/include/linux/init.h 2007-10-12 13:53:22.000000000 +0000 @@ -36,6 +36,20 @@ * section. * * Also note, that this data cannot be "const". + * + * For strings: + * Use __initstr, __exitstr like __initdata: + * + * static const char welcome[] __initstr = "Hello World!\n"; + * static const char goodbye[] __exitstr = "Farewell then.\n"; + * + * but also: + * + * pr_info(_i("%s: Thanks for selecting, will do my best\n"), dev->name); + * pr_info(_e("%s: Hope to be of use again soon\n"), dev->name); + * + * Note that strings have to be "const" and they are put in mergeable + * sections which means the linker will do nasty things to them. ;-) */ /* These are for everybody (although not all archs will actually @@ -45,6 +59,24 @@ #define __exitdata __attribute__ ((__section__(".exit.data"))) #define __exit_call __attribute_used__ __attribute__ ((__section__ (".exitcall.exit"))) +#define __initstr __attribute__((__section__(".init.str1" __strflags))) +#define __exitstr __attribute__((__section__(".exit.str1" __strflags))) + +#define _i(str) \ +({ \ + static const char __istr[] __initstr = (str); \ + __istr; \ +}) +#define _e(str) \ +({ \ + static const char __estr[] __exitstr = (str); \ + __istr; \ +}) + +/* Internal implementation detail for the above; just disregard. ;-) */ +#define __strflags ",\"aMS\",@progbits,1\n" \ + "# Useless section flags supplied by GCC follow: " + /* modpost check for section mismatches during the kernel build. * A section mismatch happens when there are references from a * code or data section to an init section (both code or data). @@ -247,46 +279,74 @@ void __init parse_early_param(void); #ifdef CONFIG_MODULES #define __init_or_module #define __initdata_or_module +#define __initstr_or_module +#define _iom(str) (str) #else #define __init_or_module __init #define __initdata_or_module __initdata +#define __initstr_or_module __initstr +#define _iom(str) _i(str) #endif /*CONFIG_MODULES*/ #ifdef CONFIG_HOTPLUG #define __devinit #define __devinitdata +#define __devinitstr +#define _di(str) (str) #define __devexit #define __devexitdata +#define __devexitstr +#define _de(str) (str) #else #define __devinit __init #define __devinitdata __initdata +#define __devinitstr __initstr +#define _di(str) _i(str) #define __devexit __exit #define __devexitdata __exitdata +#define __devexitstr __exitstr +#define _de(str) _e(str) #endif #ifdef CONFIG_HOTPLUG_CPU #define __cpuinit #define __cpuinitdata +#define __cpuinitstr +#define _ci(str) (str) #define __cpuexit #define __cpuexitdata +#define __cpuexitstr +#define _ce(str) (str) #else #define __cpuinit __init #define __cpuinitdata __initdata +#define __cpuinitstr __initstr +#define _ci(str) _i(str) #define __cpuexit __exit #define __cpuexitdata __exitdata +#define __cpuexitstr __exitstr +#define _ce(str) _e(str) #endif #if defined(CONFIG_MEMORY_HOTPLUG) || defined(CONFIG_ACPI_HOTPLUG_MEMORY) \ || defined(CONFIG_ACPI_HOTPLUG_MEMORY_MODULE) #define __meminit #define __meminitdata +#define __meminitstr +#define _mi(str) (str) #define __memexit #define __memexitdata +#define __memexitstr +#define _me(str) (str) #else #define __meminit __init #define __meminitdata __initdata +#define __meminitstr __initstr +#define _mi(str) _i(str) #define __memexit __exit #define __memexitdata __exitdata +#define __memexitstr __exitstr +#define _me(str) _e(str) #endif /* Functions marked as __devexit may be discarded at kernel link time, depending