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

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

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

volatile long foo; 

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

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

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

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

我错了吗?

如果C的一个标准是K&R书籍,那么除了提到几次并且据说与优化相关之外,没有太多关于volatile说法。

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

类型也可以是限定的,以指示声明的对象的特殊属性。 type-qualifier:const volatile类型限定符可以与任何类型说明符一起出现。 可以初始化const对象,但之后不将其分配给。 volatile对象没有依赖于实现的语义。 const和volatile属性是ANSI标准的新特性。 const的目的是宣布可能放在只读存储器中的对象,并且可能增加优化的机会。 volatile 的目的 是强制实现抑制否则可能发生的优化。 例如,对于具有内存映射输入/输出的机器,可以将指向设备寄存器的指针声明为指向volatile的指针,以防止编译器通过指针移除明显冗余的引用。 除了它应该诊断显式尝试更改const对象之外,编译器可能会忽略这些限定符。

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

编译器将允许volatile变量在我的经验中保持未优化,即使它们从未使用过。 我对接头不太确定。 该标准对链接过程几乎没有说明。

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

编辑:

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

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

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

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

 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 ,我不确定你能安全地做到这一点。