C链接器在哪种情况下会消除未使用的易失符号?

时间:2015-01-28 20:19:00

标签: c linker

我正在使用非常具体的工具链(ADI公司的SHARC DSP处理器),我想更好地了解我的编译器/链接器。

我有一个易变的全局变量:

 volatile long foo;

这个变量没有被使用,也没有在我的代码中引用,但是我想把它保存在我的最终可执行文件中(不要问我为什么,这个可悲的事实很难过)。

我通常使用-e选项链接我的项目。它告诉链接器从可执行文件中删除死代码。我最初认为没有编译器敢于删除任何全局变量,特别是如果这些符号被声明为volatile。不幸的是。

然后我找到了一个非常具体的编译指示#pragma retain_name,告诉链接器保留一个符号,即使它从未使用过。

我想知道在某些ISO / POSIX标准中是否可以找到这种情况。我总是认为编译器或链接器都不会对易失性符号做出任何假设。因此,没有编译器会尝试从最终的可执行文件中删除死的volatile变量或函数。

我错了吗?

2 个答案:

答案 0 :(得分:4)

您可以使用使用变量的外部链接创建虚拟函数。

long
help_us_keep_foo(void)
{
  return foo;
}

除非您正在执行整个程序分析,否则将阻止foo被删除。如果您执行执行整个程序分析,您可以使用如下所示的技巧。

int
main(int argc, char * * argv)
{
  if (getenv("PRINT_THE_VALUE_OF_FOO_AT_PROGRAM_STARTUP"))
    printf("Your hovercraft is full of eels, and foo is %ld\n", foo);
  /* Do whatever your program has to do... */
  return 0;
}

我在基准测试代码中使用了类似的技巧(插入无害的打印语句来测试极不可能的条件),以确保我想要基准测试的东西没有被优化掉。

如果情况允许,您可以使用较少的“可见”技巧,例如分配foo = foo,但由于它是volatile,我不确定您是否可以安全地执行此操作。

答案 1 :(得分:2)

如果C的一个标准是K& R书,那么关于volatile没什么好说的,只是提到了几次,据说与优化有关。

在附录A.8.2类型说明符中,它说:

  

类型也可以是合格的,以表示特殊属性   被宣布的对象。类型限定符:   常量   挥发物   类型限定符可能与任何类型说明符一起出现。一个常数   对象可能已初始化,但此后未分配给。   volatile对象没有与实现相关的语义。常数   和volatile属性是ANSI标准的新特性。的目的   const是宣告可能放在只读内存中的对象,   也许是为了增加优化的机会。 的目的    volatile是强制实现来抑制优化   否则可能会发生。例如,对于具有内存映射的计算机   输入/输出,指向设备寄存器的指针可能被声明为a   指向volatile的指针,以防止编译器被删除   显然是通过指针的冗余引用。 除此之外   应该诊断显式尝试更改const对象,编译器   可能会忽略这些限定符。

强调我的并注意最后一段所说的内容。它可能表明编译器可以选择忽略volatile限定符。

编译器将允许volatile变量在我的经验中保持未优化,即使它们从未使用过。 我对链接器不太确定。该标准对链接过程的描述很少。

FWIW我对嵌入式目标的商业编译器的一般经验是,他们有时不完全符合标准。我最近一直在使用TI编译器+链接器工具链,让我们说它与我以前用于ARM的gcc + ld端口的情况完全不同,例如...

修改

当然,K& R书不是标准。让我们看一下真正的标准,例如:从here获得的ISO C99标准,Section 6.7.3 Type qualifiers, 6中的一个段落说:

  

具有volatile限定类型的对象可能会以未知的方式进行修改   实施或有其他未知的副作用。因此任何表达都是指   对这样的对象应严格按照抽象机的规则进行评估,   如5.1.2.3中所述。此外,在每个序列点上最后存储的值   对象应与抽象机器规定的内容一致,除非经过修改   前面提到的未知因素.114)什么构成对对象的访问   volatile的限定类型是实现定义的

不幸的是,我不认为这有助于回答这个问题。