LD manual没有解释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
答案 0 :(得分:42)
即使没有引用符号,Afaik LD也会在符号中保留符号。 (--gc截面)。
通常用于二进制启动过程中具有某些特殊含义的部分,或多或少用于标记依赖关系树的根。
(以下为Sabuncu)
依赖树:
如果您消除了未使用的代码,则需要分析代码并标记所有可访问的部分(代码+全局变量+常量)。
因此,您选择一个部分,将其标记为“已使用”并查看其引用的其他部分,然后将这些部分标记为“已使用”,并检查它们引用的内容等。
未标记为“已使用”的部分是多余的,可以删除。
由于一个部分可以引用多个其他部分(例如,一个程序调用三个不同的其他部分),如果你要绘制结果,你会得到一棵树。
<强>罗茨:强>
然而,上述原则给我们留下了一个问题:什么是总是使用的“第一”部分?树的第一个节点(根)可以这么说吗?这就是“keep()”的作用,它告诉链接器哪些部分(如果可用)是第一个要查看的部分。因此,它们总是相互关联。
通常这些是从程序加载器调用的部分,用于执行与动态链接相关的任务(可以是可选的,并且依赖于OS / fileformat),以及程序的入口点。
答案 1 :(得分:10)
说明其用法的最小Linux IA-32示例
<强> main.S 强>:
.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
<强> link.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
进行异常,那么该部分将不会放入可执行文件中。
由于我们在before
的地址中添加了4,如果keep
部分不存在,则退出状态将为2
,这将显示在下一个.after
"a"
1}}部分。
TODO:如果我们从.keep
移除.text
,那么就没有任何反应,这使得它可以分配。我不明白为什么会这样:该部分将放在/*
Direct fourier transform
*/
int DFT(int dir,int m,double *x1,double *y1)
{
long i,k;
double arg;
double cosarg,sinarg;
double *x2=NULL,*y2=NULL;
x2 = malloc(m*sizeof(double));
y2 = malloc(m*sizeof(double));
if (x2 == NULL || y2 == NULL)
return(FALSE);
for (i=0;i<m;i++) {
x2[i] = 0;
y2[i] = 0;
arg = - dir * 2.0 * 3.141592654 * (double)i / (double)m;
for (k=0;k<m;k++) {
cosarg = cos(k * arg);
sinarg = sin(k * arg);
x2[i] += (x1[k] * cosarg - y1[k] * sinarg);
y2[i] += (x1[k] * sinarg + y1[k] * cosarg);
}
}
/* Copy the data back */
if (dir == 1) {
for (i=0;i<m;i++) {
x1[i] = x2[i] / (double)m;
y1[i] = y2[i] / (double)m;
}
} else {
for (i=0;i<m;i++) {
x1[i] = x2[i];
y1[i] = y2[i];
}
}
free(x2);
free(y2);
return(TRUE);
}
段内,因为它的神奇名称将是可分配的。
答案 2 :(得分:1)
强制链接器保留某些特定部分
SECTIONS
{
....
....
*(.rodata .rodata.*)
KEEP(*(SORT(.scattered_array*)));
}