如何获取输入节的大小(以便将其放置在内存末尾)

86

我有以下连接脚本:

.data.bss 被放置在 RAM 中,然后一个 .heap 段填充了剩余的内存。

现在我想添加一个 .noinit 段,它总是被放置在内存的末尾。这样 bootloaders 等程序会忽略它。

我仍然希望我的 .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

这里SIZEOF(.noinit)总是0,因为该语句之后才定义该节。

但实际上我想要的是SIZEOF(*(.noinit)) - 但这是一个语法错误。

那么,如何在不先将其放入输出节中的情况下获取输入节的大小呢?


6
在此处查看一些有趣的答案/评论:https://dev59.com/4mMl5IYBdhLWcg3wJUEC - Kcvin
4
这里的答案可以满足您的需求:https://dev59.com/4mMl5IYBdhLWcg3wJUEC#55126837 - Arusekk
1个回答

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
}


一个使用上述脚本链接的空二进制文件的输出显示了节和符号的正确放置位置。
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

注意:我无法找到任何关于这种行为的文档,因此不能保证这个技巧在ld的未来版本中仍然有效。

注意:这个技巧对于gold链接器不起作用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接