57

LD 手册没有解释该命令KEEP的作用。下面是来自第三方链接器脚本的片段,该脚本具有KEEP. 该KEEP命令在做ld什么?

SECTIONS
{  
    .text :
    {
        . = ALIGN(4);
        _text = .;
        PROVIDE(stext = .);
        KEEP(*(.isr_vector))
        KEEP(*(.init))
        *(.text .text.*)        
        *(.rodata .rodata.*)        
        *(.gnu.linkonce.t.*)
        *(.glue_7)
        *(.glue_7t)
        *(.gcc_except_table)
        *(.gnu.linkonce.r.*)
        . = ALIGN(4);
        _etext = .;
        _sidata = _etext;
        PROVIDE(etext = .);   
            _fini = . ;
                *(.fini)

    } >flash
4

3 回答 3

55

即使未引用符号,Afaik LD 也会将符号保留在该部分中。(--gc 部分)。

通常用于在二进制启动过程中有一些特殊含义的部分,或多或少地标记依赖树的根。


(对于下面的 Sabuncu)

依赖树

如果消除未使用的代码,则分析代码并标记所有可到达的部分(代码+全局变量+常量)。

因此,您选择一个部分,将其标记为“已使用”并查看它引用的其他(未使用)部分,然后将这些部分标记为“已使用”,并检查它们引用的内容等。

未标记为“已使用”的部分是多余的,可以删除。

由于一个部分可以引用多个其他部分(例如,一个过程调用三个不同的其他部分),如果您要绘制结果,您将得到一棵树。

根源:

然而,上述原则给我们留下了一个问题:始终使用的“第一”部分是什么?可以这么说树的第一个节点(根)?这就是“keep()”所做的,它告诉链接器哪些部分(如果可用)是第一个要查看的部分。因此,这些总是相互关联的。

通常,这些是从程序加载器调用的部分,以执行与动态链接相关的任务(可以是可选的,并且取决于操作系统/文件格式)和程序的入口点。

于 2012-03-22T20:42:48.633 回答
19

说明其用法的最小 Linux IA-32 示例

电源

.section .text
.global _start
_start:
    /* Dummy access so that after will be referenced and kept. */
    mov after, %eax
    /*mov keep, %eax*/

    /* Exit system call. */
    mov $1, %eax

    /* Take the exit status 4 bytes after before. */
    mov $4, %ebx
    mov before(%ebx), %ebx

    int $0x80

.section .before
    before: .long 0
/* TODO why is the `"a"` required? */
.section .keep, "a"
    keep: .long 1
.section .after
    after: .long 2

链接.ld

ENTRY(_start)
SECTIONS
{
    . = 0x400000;
    .text :
    {
        *(.text)
        *(.before)
        KEEP(*(.keep));
        *(.keep)
        *(.after)
    }
}

编译并运行:

as --32 -o main.o main.S
ld --gc-sections -m elf_i386 -o main.out -T link.ld main.o
./main.out
echo $?

输出:

1

如果我们注释掉该KEEP行,输出是:

2

如果我们:

  • 添加一个假人mov keep, %eax
  • 消除--gc-sections

输出回到1.

在 Ubuntu 14.04、Binutils 2.25 上测试。

解释

没有对符号的引用keep,因此也没有引用它的包含部分.keep

因此,如果启用了垃圾收集并且我们不使用KEEP产生异常,则该部分将不会放入可执行文件中。

由于我们将 4 的地址添加到before,如果该keep部分不存在,则退出状态将为2,这将出现在下一个.after部分中。

TODO:如果我们删除"a"from .keep,什么都不会发生,这使它可以分配。我不明白为什么会这样:该部分将放在.text段内,因为它的神奇名称将是可分配的。

于 2015-10-08T10:44:42.743 回答
2

强制链接器保留某些特定部分

SECTIONS 
{
....
....

*(.rodata .rodata.*)

KEEP(*(SORT(.scattered_array*)));
}
于 2019-02-20T04:08:00.217 回答