我有以下链接描述文件:
.data&.bss放在ram中,然后一.heap节填充剩余的内存。
现在,我想添加一个.noinit始终放在内存末尾的节。因此,它会被引导加载程序等忽略。
我仍然希望我的.heap部分占据.bss和之间的所有可用空间.noinit,但是为此,我需要知道.noinit部分的大小。
天真的方法失败了:
/* .bss section which is used for uninitialized data */
.bss (NOLOAD) :
{
. = ALIGN(4);
_sbss = . ;
_szero = .;
*(.bss .bss.*)
*(COMMON)
. = ALIGN(4);
_ebss = . ;
_ezero = .;
} > ram
/* heap section */
.heap (NOLOAD) :
{
. = ALIGN(4);
_sheap = . ;
. = ORIGIN(ram) + LENGTH(ram) - SIZEOF(.noinit);
_eheap = . ;
} > ram
/*
* collect all uninitialized sections that go into RAM
*/
.noinit (NOLOAD) :
{
. = ALIGN(4);
__noinit_start = .;
*(.noinit)
__noinit_end = .;
} > ram
Run Code Online (Sandbox Code Playgroud)
这里SIZEOF(.noinit)始终是0,因为部分的发言后确定。
但是实际上我想要的是SIZEOF(*(.noinit))-但是这是一个语法错误。
那么,如何获得输入部分的大小而不先将其放入输出部分呢?
小智 3
不完全是正经的,但是在深入研究GNU ld 的源代码之后,看起来您可以在定义节后指定节的地址。
以下链接器脚本应该为您提供所需的行为:
MEMORY {
ram (rwx) : ORIGIN = 0x10000, LENGTH = 0x0002000
}
SECTIONS {
.bss (NOLOAD) : {
. = ALIGN(4);
_sbss = . ;
_szero = .;
*(.bss .bss.*)
*(COMMON)
/* Note: Just for example - padding .bss by 0x100 bytes so its not empty */
. = 0x100;
. = ALIGN(4);
_ebss = . ;
_ezero = .;
} > ram
/* create .noinit section */
.noinit (NOLOAD): {
. = ALIGN(4);
__noinit_start = .;
/* Note: Just for example - padding .noinit by 0x100 bytes so its not empty */
. = 0x100;
*(.noinit)
__noinit_end = .;
} > ram
/* place .heap after .bss */
.heap _ebss (NOLOAD) : {
. = ALIGN(4);
_sheap = . ;
. = ABSOLUTE(ORIGIN(ram) + LENGTH(ram) - SIZEOF(.noinit));
_eheap = . ;
} > ram
/* update .noinit to be placed at end of heap */
.noinit _eheap (NOLOAD) : { } > ram
}
Run Code Online (Sandbox Code Playgroud)
与上述脚本链接的空二进制文件的输出显示了节和符号的正确位置:
echo | gcc -x c++ - -nostartfiles -T linkerScript.ld -Xlinker --orphan-handling=discard -fuse-ld=bfd && objdump -th a.out
a.out: file format elf64-x86-64
Sections:
Idx Name Size VMA LMA File off Algn
0 .bss 00000100 0000000000010000 0000000000010000 00001000 2**0
ALLOC
1 .noinit 00000100 0000000000011f00 0000000000011f00 00001000 2**0
ALLOC
2 .heap 00001e00 0000000000010100 0000000000010100 00001000 2**0
ALLOC
SYMBOL TABLE:
0000000000010000 l d .bss 0000000000000000 .bss
0000000000011f00 l d .noinit 0000000000000000 .noinit
0000000000010100 l d .heap 0000000000000000 .heap
0000000000010100 g .heap 0000000000000000 _sheap
0000000000010000 g .bss 0000000000000000 _sbss
0000000000010000 g .bss 0000000000000000 _szero
0000000000010100 g .bss 0000000000000000 _ebss
0000000000010100 g .bss 0000000000000000 _ezero
0000000000011f00 g .noinit 0000000000000000 __noinit_start
0000000000012000 g .noinit 0000000000000000 __noinit_end
0000000000011f00 g .heap 0000000000000000 _eheap
Run Code Online (Sandbox Code Playgroud)
注意:我找不到任何有关此行为的文档,因此我不能保证此技巧将在 ld 的未来修订版中起作用。
注意:此技巧不适用于黄金链接器。