Add __initbss section
RFC 1/1 Add __initbss section
Hi,
As discussed previously, it seems a good idea to create a new init section .init.bss that store uninitialized data used only at boot time. That way, we can avoid to embed these uninitialized data in the Linux image since it's totaly useless.
As a good candidate for using this, is tlbex.c. This file allocates a couple of big arrays that don't need to be part of the init data section since they're not initialized and they're currently only used at boot time.
So this patchset does this but the result looks weird: I tried to apply this patch on top of the patchset:
---8<---
arch/mips/mm/tlbex.c +3 -4
@@ -743,11 +743,11 @@ il_bgez(u32 **p, struct reloc **r, unsigned int reg, enum label_id l)* We deliberately chose a buffer size of 128, so we won't scribble * over anything important on overflow before we panic. */ -static __initdata u32 tlb_handler[128 ]; +static __initbss u32 tlb_handler[128];/* simply assume worst case size for labels and relocs */ -static __initdata struct label labels[128 ]; -static __initdata struct reloc relocs[128 ]; +static __initbss struct label labels[128]; +static __initbss struct reloc relocs[128]; --->8---
and the kernel image is bigger after the patch is applied !
$ ls -l vmlinux* -rwxrwxr-x 1 fbuihuu fbuihuu 2503324 2007-10-11 11:41 vmlinux* -rwxrwxr-x 1 fbuihuu fbuihuu 2503264 2007-10-11 11:41 vmlinux~old*
Could anybody explain me why ? The time is missing and I probably couldn't investigate into this until this weekend.
Also not that with the current patchset applied, there are now 2 segments that need to be loaded, hopefully it won't cause any issues with any bootloaders out there that would assume that an image has only one segment...
Other question: I noticed that the exit.data section is not discarded. Could anybody give me the reason why ?
Franck
PATCH 1/2 Add .init.bss section
This patch creates a new init section called .init.bss.
This section is similar to .init.data but doesn't consume any space in the vmlinux image.
All data marked as part of this section must not be initialized, of course.
--- include/linux/init.h | 24 ++++++++++++++++-------- 1 files changed, 16 insertions(+), 8 deletions(-)
include/linux/init.h +16 -8
@@ -43,6 +43,8 @@#define __init __attribute__ ((__section__ (".init.text"))) __cold#define __initdata __attribute__ ((__section__ (".init.data")))#define __exitdata __attribute__ ((__section__(".exit.data"))) +#define __initbss __attribute__ ((__section__ (".init.bss"))) +#define __exitbss __attribute__ ((__section__ (".exit.bss")))#define __exit_call __attribute_used__ __attribute__ ((__section__ (".exitcall.exit")))/* modpost check for section mismatches during the kernel build.
@@ -257,10 +259,12 @@ void __init parse_early_param(void);#define __devexit#define __devexitdata#else -#define __devinit __init -#define __devinitdata __initdata -#define __devexit __exit -#define __devexitdata __exitdata +#define __devinit __init +#define __devinitdata __initdata +#define __devinitbss __initbss +#define __devexit __exit +#define __devexitdata __exitdata +#define __devexitbss __exitbss#endif #ifdef CONFIG_HOTPLUG_CPU
@@ -270,9 +274,11 @@ void __init parse_early_param(void);#define __cpuexitdata#else #define __cpuinit __init -#define __cpuinitdata __initdata -#define __cpuexit __exit +#define __cpuinitdata __initdata +#define __cpuinitbss __initbss +#define __cpuexit __exit#define __cpuexitdata __exitdata +#define __cpuexitbss __exitbss#endif #if defined(CONFIG_MEMORY_HOTPLUG ) || defined(CONFIG_ACPI_HOTPLUG_MEMORY ) \
@@ -283,9 +289,11 @@ void __init parse_early_param(void);#define __memexitdata#else #define __meminit __init -#define __meminitdata __initdata -#define __memexit __exit +#define __meminitdata __initdata +#define __meminitbss __meminitbss +#define __memexit __exit#define __memexitdata __exitdata +#define __memexitbss __exitbss#endif /* Functions marked as __devexit may be discarded at kernel link time, depending
Signature · 1 line
1.5.3.3
PATCH 2/2 Add .init.bss section for MIPS
In reply to Franck Bui-Huu--- arch/mips/kernel/head.S | 5 +++++ arch/mips/kernel/vmlinux.lds.S | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletions(-)
arch/mips/kernel/head.S +5 -0
@@ -183,6 +183,11 @@ NESTED(kernel_entry, 16, sp) # kernel entry point LONG_S zero, (t0) bne t0, t1, 1b + PTR_LA a0, _sinitbss + PTR_LA a1, _einitbss + PTR_SUBU a1, a0 + jal __bzero + LONG_S a0, fw_arg0 # firmware arguments LONG_S a1, fw_arg1 LONG_S a2, fw_arg2
arch/mips/kernel/vmlinux.lds.S +6 -1
@@ -100,7 +100,7 @@ SECTIONS _edata = .; /* End of data section */ /* will be freed after init */ - . = ALIGN(_PAGE_SIZE); /* Init code and data */ + . = ALIGN(_PAGE_SIZE); /* Init code, data and bss */ __init_begin = .; .init.text : { _sinittext = .;
@@ -110,6 +110,11 @@ SECTIONS .init.data : { *(.init.data) } + .init.bss (NOLOAD) : { + _sinitbss = .; + *(.init.bss) + _einitbss = .; + } . = ALIGN(16); .init.setup : { __setup_start = .;
Signature · 1 line
1.5.3.3
Quoted 2 lines · Franck Bui-Huu
Other question: I noticed that the exit.data section is not discarded. Could anybody give me the reason why ?
.exit.data and .exit.text may reference each other. __exit functions generally get compiled into .exit.text but some constructs such as jump tables for switch() constructs may be compiled into address tables which gcc unfortunately will put into .rodata, so .rodata will end up referencing function addresses in .exit.text which makes ld unhappy if .exit.text was discarded. So until this is fixed in gcc we can't discard exit code, unfortunately.
It's actually an issue which doesn't strike very often, so users who are desparate for shrinking the kernel down could try to undo patchsets:
6f0b1e5d266fb1d0da019c07b56ccc02c3a4f53a
ca7402fed2a76cd5a417ac4d375a5539dcb2b6de
and see if they can get away with it. If the final kernel link succeeds, the build would be ok.
I think gcc should probably put the jump table into a .subsection if a section was explicitly requested, at least for non-PIC code.
Ralf
Quoted 2 lines · Ralf Baechle
I think gcc should probably put the jump table into a .subsection if a section was explicitly requested, at least for non-PIC code.
Has anybody filed a bug report? The GCC maintainers may well not be
aware of the problem and some arcane ways of use exercised by Linux.
Maciej
Quoted 5 lines · Maciej W. Rozycki
Quoted 2 lines
I think gcc should probably put the jump table into a .subsection if a section was explicitly requested, at least for non-PIC code.
Has anybody filed a bug report? The GCC maintainers may well not be
aware of the problem and some arcane ways of use exercised by Linux.
Beofore applying the previously mentioned fixes I spoke to them but they were not very inclined to consider the gcc behaviour a bug.
Ralf
Quoted 2 lines · Ralf Baechle
Beofore applying the previously mentioned fixes I spoke to them but they were not very inclined to consider the gcc behaviour a bug.
This may qualify as the lack of a feature indeed. So I guess the
ultimate solution is waiting for somebody to get inclined enough to implement it. ;-)
Maciej
Quoted 5 lines · Ralf Baechle
Quoted 2 lines · Franck Bui-Huu
Other question: I noticed that the exit.data section is not discarded. Could anybody give me the reason why ?
Quoted 8 lines
.exit.data and .exit.text may reference each other.
__exitfunctions generally get compiled into .exit.text but some constructs such as jump tables forswitch()constructs may be compiled into address tables which gcc unfortunately will put into .rodata, so .rodata will end up referencing function addresses in .exit.text which makes ld unhappy if .exit.text was discarded. So until this is fixed in gcc we can't discard exit code, unfortunately.
Thanks for the details.
I actually don't see any point to move these tables in .rodata since they're part of the code...
Quoted 12 lines
It's actually an issue which doesn't strike very often, so users who are desparate for shrinking the kernel down could try to undo patchsets:
6f0b1e5d266fb1d0da019c07b56ccc02c3a4f53a
ca7402fed2a76cd5a417ac4d375a5539dcb2b6deand see if they can get away with it. If the final kernel link succeeds, the build would be ok.
I think gcc should probably put the jump table into a .subsection if a section was explicitly requested, at least for non-PIC code.
yes that would be great, and do the same for strings, data and we could get rid of all __initxxx annotations.
Franck
Quoted 9 lines · Franck Bui-Huu
Quoted 8 lines
.exit.data and .exit.text may reference each other.
__exitfunctions generally get compiled into .exit.text but some constructs such as jump tables forswitch()constructs may be compiled into address tables which gcc unfortunately will put into .rodata, so .rodata will end up referencing function addresses in .exit.text which makes ld unhappy if .exit.text was discarded. So until this is fixed in gcc we can't discard exit code, unfortunately.
Quoted 4 lines
Thanks for the details.
I actually don't see any point to move these tables in .rodata since they're part of the code...
As I recall the argumentation was they should go there because that section can be marked no-exec. Which isn't terribly useful on MIPS where only very few processors have the no-exec capability.
Anyway, I guess it takes somebody to cook a patch :-)
Ralf
Quoted 2 lines · Ralf Baechle
As I recall the argumentation was they should go there because that section can be marked no-exec.
Are these switch tables really different from ELF .plt or .got ?
Franck
Quoted 8 lines · Franck Bui-Huu
and the kernel image is bigger after the patch is applied !
$ ls -l vmlinux*(quoted diff) +0
-2-rwxrwxr-x 1 fbuihuu fbuihuu 2503324 2007-10-11 11:41 vmlinux* -rwxrwxr-x 1 fbuihuu fbuihuu 2503264 2007-10-11 11:41 vmlinux~old*Could anybody explain me why ? The time is missing and I probably couldn't investigate into this until this weekend.
I guess for a bss-type section you want to use something like:
.section .init.bss,"aw",@nobits
Quoted 4 lines
Also not that with the current patchset applied, there are now 2 segments that need to be loaded, hopefully it won't cause any issues with any bootloaders out there that would assume that an image has only one segment...
Well, there should be no need for an extra segment -- just rearrange the
order of the sections in the linker script appropriately. You should probably add __exitbss for consistency too. You can make all the three sections adjacent so that no separate initialisation is required.
Another place for optimisation are inline string literals referred to
from .init.text or .exit.text only, which is a bit more complicated to handle, but sounds interesting enough to me I shall give it a try in the next few days. I have an idea how to do it.
Maciej
Quoted 8 lines · Maciej W. Rozycki
Quoted 6 lines · Franck Bui-Huu
and the kernel image is bigger after the patch is applied !
$ ls -l vmlinux*(quoted diff) +0
-2-rwxrwxr-x 1 fbuihuu fbuihuu 2503324 2007-10-11 11:41 vmlinux* -rwxrwxr-x 1 fbuihuu fbuihuu 2503264 2007-10-11 11:41 vmlinux~old*
Quoted 7 lines
Quoted 2 lines
Could anybody explain me why ? The time is missing and I probably couldn't investigate into this until this weekend.
I guess for a bss-type section you want to use something like:
.section .init.bss,"aw",@nobits
Sorry but I'm missing your point here. This indeed should be added for assembler code but I don't see how it's related with the kernel image size difference I was seeing.
Quoted 6 lines
Well, there should be no need for an extra segment -- just rearrange the
order of the sections in the linker script appropriately. You should probably add__exitbssfor consistency too. You can make all the three sections adjacent so that no separate initialisation is required.
I'll do that.
Franck
Quoted 8 lines · Franck Bui-Huu
Quoted 4 lines
I guess for a bss-type section you want to use something like:
.section .init.bss,"aw",@nobitsSorry but I'm missing your point here. This indeed should be added for assembler code but I don't see how it's related with the kernel image size difference I was seeing.
Well, otherwise the section is marked as containing data and therefore
taking space in the image. Compare the output of readelf -S' and/or objdump -h' with and without the directive above.
What do you mean by "assembler code" in this context, BTW? Everything is
assembler code, be it handwritten or GCC-generated. Have a look at how GCC sets flags for your section, by running `gcc -S' and examining the output.
Maciej
Quoted 4 lines · Maciej W. Rozycki
Quoted 2 lines · Franck Bui-Huu
Quoted 2 lines
I guess for a bss-type section you want to use something like:
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
.section .init.bss,"aw",@nobitsSorry but I'm missing your point here. This indeed should be added for assembler code but I don't see how it's related with the kernel image size difference I was seeing.
Well, otherwise the section is marked as containing data and therefore
taking space in the image.
Well, since .init.bss is declared as follow:
.init.bss (NOLOAD) : {
...
}data should not take any space in the image...
Quoted 2 lines
What do you mean by "assembler code" in this context, BTW?
I meant to be able to put data into .init.bss section from assembly code (*.S files) like __INITDATA does for .init.data section.
Franck
Quoted 7 lines · Franck Bui-Huu
Well, since .init.bss is declared as follow:
.init.bss (NOLOAD) : { ... }data should not take any space in the image...
The above only marks it as unloadable (cf. e.g. debugging information).
It is still there.
Quoted 2 lines
I meant to be able to put data into .init.bss section from assembly code (*.S files) like
__INITDATAdoes for .init.data section.
That does not differ from what has to be done for any other language --
ultimately `gas', which is responsible for such arrangements, has to see an appropriate ".section" directive.
Maciej
Quoted 4 lines · Maciej W. Rozycki
Quoted 2 lines · Franck Bui-Huu
Well, since .init.bss is declared as follow:
Quoted 9 lines
Quoted 5 lines
.init.bss (NOLOAD) : { ... }data should not take any space in the image...
The above only marks it as unloadable (cf. e.g. debugging information).
It is still there.
So it seems there is no way from a linker script to specify that a section has the nobits type, is it ?
After spending some fun time trying several different configurations with gcc and ld, I noticed that gcc makes a section with @nobits attribute if the section name starts with .bss.*
So calling .bss.init instead of .init.bss makes gcc do the right thing. Here is a bit of tlbex.s:
.word 0 .section .bss.init,"aw",@nobits .align 2 .type tlb_handler, @object .size tlb_handler, 512 tlb_handler: .space 512 .align 2 .type labels, @object .size labels, 1024 labels: .space 1024
Another test I did is to put .init.bss (not .bss.init) section right before .bss section in order to have only one segment to load. And it makes magically ld do the right thing. I must admit that I don't understand why, and the lack of documentation doesn't help...
Unfortunately I don't know if we can rely on one of these behaviours. IOW if they're going to work with all supported versions of gcc/ld.
Anyway, I'll resubmit a new patchset for futher discussion.
Franck
Quoted 2 lines · Franck Bui-Huu
So it seems there is no way from a linker script to specify that a section has the nobits type, is it ?
Well, you cannot switch section types in a linker script at all in
general. The place to do it is always in the assembler, which is the tool which actually emits this data.
Quoted 3 lines
After spending some fun time trying several different configurations with gcc and ld, I noticed that gcc makes a section with @nobits attribute if the section name starts with .bss.*
Exactly how GCC sets section flags is mostly determined bydefault_section_type_flags() in gcc/varasm.c; some flags are set elsewhere too. This is with HEAD of GCC.
Quoted 4 lines
Another test I did is to put .init.bss (not .bss.init) section right before .bss section in order to have only one segment to load. And it makes magically ld do the right thing. I must admit that I don't understand why, and the lack of documentation doesn't help...
Hmm, isn't what `info ld' says enough? I think a look at what the SysV
ABI documents say about ELF could clarify some matters too. Also have a look at how sections are mapped to segments as after the final link it is segments that matter -- `readelf -l' will do.
Quoted 3 lines
Unfortunately I don't know if we can rely on one of these behaviours. IOW if they're going to work with all supported versions of gcc/ld.
Probably -- I guess you only need to check what GCC 3.2 did. Or you
could use a hack with __attribute__((section())) like one I did for merging strings -- unlike with SECTION_BSS I think there is no way to request (SECTION_MERGE | SECTION_STRINGS) in an implicit way anyhow.
Maciej
Quoted 9 lines · Maciej W. Rozycki
Quoted 3 lines · Franck Bui-Huu
After spending some fun time trying several different configurations with gcc and ld, I noticed that gcc makes a section with @nobits attribute if the section name starts with .bss.*
Exactly how GCC sets section flags is mostly determined by
default_section_type_flags()ingcc/varasm.c; some flags are set elsewhere too. This is with HEAD of GCC.
It seems that we can rely on this behaviour. I looked at gcc 4.1.2/3.2 sources and they made a section part of .bss if the section name starts with ".bss.".
Quoted 6 lines
Quoted 4 lines
Another test I did is to put .init.bss (not .bss.init) section right before .bss section in order to have only one segment to load. And it makes magically ld do the right thing. I must admit that I don't understand why, and the lack of documentation doesn't help...
Hmm, isn't what `info ld' says enough?
Hmm, I'm must be blind but I missed that each time I read it. Could you point out the section number please ?
OK, I think the best thing to do now is to respin the patchset and submit it linux arch mailing list.
thanks,
Franck
Quoted 4 lines · Franck Bui-Huu
Quoted 1 line
Hmm, isn't what `info ld' says enough?
Hmm, I'm must be blind but I missed that each time I read it. Could you point out the section number please ?
That's section 3.8, I would guess, but if what you are looking for is not
there, then perhaps the description could be improved.
Maciej
Quoted 9 lines · Maciej W. Rozycki
Quoted 3 lines · Franck Bui-Huu
Quoted 1 line
Hmm, isn't what `info ld' says enough?
Hmm, I'm must be blind but I missed that each time I read it. Could you point out the section number please ?
That's section 3.8, I would guess, but if what you are looking for is not
there, then perhaps the description could be improved.
After reading section 3.8 "PHDRS Command", I still fail to find something interesting.
Franck
Franck Bui-Huu wrote:
[snip]
Quoted 4 lines
Also not that with the current patchset applied, there are now 2 segments that need to be loaded, hopefully it won't cause any issues with any bootloaders out there that would assume that an image has only one segment...
This breaks at least conversion to ECOFF as used on DECstations. Srec might also be affected, I'm not sure about that.
Thiemo
Quoted 6 lines · Thiemo Seufer
Quoted 4 lines
Also not that with the current patchset applied, there are now 2 segments that need to be loaded, hopefully it won't cause any issues with any bootloaders out there that would assume that an image has only one segment...
This breaks at least conversion to ECOFF as used on DECstations.
Indeed, thanks for pointing it out -- I use ELF over MOP and keep
forgetting about people preferring TFTP, sigh. I wonder whether objcopy' might be doing a better job than elf2ecoff' these days though. It may be worth checking...
It all boils down to padding out what cannot be expressed in a less
capable format after all. That's what I did in `mopd' for ELF support too -- holes between segments are transmitted as zeroes. Though MOP clients may actually support discontiguous images as each MOP "downline load" packet has its designated memory load address included in the header (it just shows how reasonable a bootstrap protocol it is!).
Maciej
Quoted 11 lines · Maciej W. Rozycki
Quoted 6 lines
Quoted 4 lines
Also not that with the current patchset applied, there are now 2 segments that need to be loaded, hopefully it won't cause any issues with any bootloaders out there that would assume that an image has only one segment...
This breaks at least conversion to ECOFF as used on DECstations.
Indeed, thanks for pointing it out -- I use ELF over MOP and keep
forgetting about people preferring TFTP, sigh. I wonder whetherobjcopy' might be doing a better job thanelf2ecoff' these days though. It may be worth checking...
That would be quite unexpected. Binutils has severe issues when used with multiple binary formats. For the general case fixing and maintaining that would be of almost nightmarish complexity so years ago I settled for elf2ecoff and I guess that step also made binutils maintainers alot happier ;-)
Quoted 6 lines
It all boils down to padding out what cannot be expressed in a less
capable format after all. That's what I did in `mopd' for ELF support too -- holes between segments are transmitted as zeroes. Though MOP clients may actually support discontiguous images as each MOP "downline load" packet has its designated memory load address included in the header (it just shows how reasonable a bootstrap protocol it is!).
With ELF dumb more generic protocols like TFTP work great. Shows what a great format ELF is ;-)
Ralf
Quoted 5 lines · Ralf Baechle
That would be quite unexpected. Binutils has severe issues when used with multiple binary formats. For the general case fixing and maintaining that would be of almost nightmarish complexity so years ago I settled for elf2ecoff and I guess that step also made binutils maintainers alot happier ;-)
I have now recalled what the issue is -- `objcopy' is keen to copy the
file header as well as possible and that includes MIPS-III annotation which makes the firmware of R4k-based DECstations unhappy. They all expect MIPS-I binaries. It's not binutils's fault I am afraid.
Quoted 2 lines
With ELF dumb more generic protocols like TFTP work great. Shows what a great format ELF is ;-)
Yeah, sure... Until you discover your ELF parser in the firmware does
not do this and that and also crashes on yet something else (since when has CFE supported ELF64, then?). You cannot escape such bugs as one with ECOFF above for example. And if your firmware is a binary blob in a classic PROM, then you are bust.
At least an <address,size> pair is dumb enough it is hard to get it wrong
and `mopd' may be modified however you like to get what you need; the daemon itself is not interested in the gory details of the binary being sent, so it will accept about anything remotely conforming to the ELF format anyway. :-)
Maciej
Quoted 7 lines · Maciej W. Rozycki
Quoted 5 lines · Thiemo Seufer
Quoted 4 lines
Also not that with the current patchset applied, there are now 2 segments that need to be loaded, hopefully it won't cause any issues with any bootloaders out there that would assume that an image has only one segment...
Quoted 6 lines
Quoted 1 line
This breaks at least conversion to ECOFF as used on DECstations.
Indeed, thanks for pointing it out -- I use ELF over MOP and keep
forgetting about people preferring TFTP, sigh. I wonder whetherobjcopy' might be doing a better job thanelf2ecoff' these days though. It may be worth checking...
The problem seems to be that (DECstation-firmware's view of) ECOFF can only handle a single .text segment.
Quoted 3 lines
It all boils down to padding out what cannot be expressed in a less
capable format after all. That's what I did in `mopd' for ELF support too -- holes between segments are transmitted as zeroes.
AFAICS this won't work for interleaved .text / .data / .bss segments.
Thiemo
Quoted 10 lines · Thiemo Seufer
Franck Bui-Huu wrote:
[snip]Quoted 4 lines
Also not that with the current patchset applied, there are now 2 segments that need to be loaded, hopefully it won't cause any issues with any bootloaders out there that would assume that an image has only one segment...
This breaks at least conversion to ECOFF as used on DECstations. Srec might also be affected, I'm not sure about that.
Ok, so I will reorder the things to have only one segment.
Thanks.
Franck