在什么情况下 C 链接器会消除未使用的可变符号?
Under which circumstances will a C Linker eliminate unused volatile symbols?
我正在使用一个非常特殊的工具链(Analog Devices 的 SHARC DSP 处理器),我想更好地了解我的 compiler/linker。
我在某处有一个不稳定的全局变量:
volatile long foo;
此变量未在我的代码中使用和引用,但我想将其保留在我的最终可执行文件中(不要问我为什么,可悲的事实是可悲的)。
我通常 link 我的项目带有 -e
选项。它告诉 linker 从可执行文件中删除死代码。我最初认为没有编译器敢于删除任何全局变量,尤其是当这些符号被声明为 volatile 时。不幸的是它确实如此。
然后我发现了一个非常具体的 pragma #pragma retain_name
,它告诉 linker 保留一个符号,即使它从未被使用过。
我想知道在某些ISO/POSIX标准中是否可以找到这种情况。我一直认为编译器或 linker 都不会对可变符号做出任何假设。因此,没有编译器会尝试从最终的可执行文件中删除无效的 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
,我不确定您是否可以安全地执行此操作。
如果说C的一个标准是K&R书,那么volatile
就没什么好说的了,只是提了几次,据说跟优化有关
在附录 A.8.2 类型说明符中,它是这样说的:
Types may also be qualified, to indicate special properties of the
objects being declared. type-qualifier:
const
volatile
Type qualifiers may appear with any type specifier. A const
object may be initialized, but not thereafter assigned to.
There are no implementation-dependent semantics for volatile objects. The const
and volatile properties are new with the ANSI standard. The purpose of
const is to announce objects that may be placed in read-only memory,
and perhaps to increase opportunities for optimization. The purpose of
volatile is to force an implementation to suppress optimization that
could otherwise occur. For example, for a machine with memory-mapped
input/output, a pointer to a device register might be declared as a
pointer to volatile, in order to prevent the compiler from removing
apparently redundant references through the pointer. Except that it
should diagnose explicit attempts to change const objects, a compiler
may ignore these qualifiers.
强调我的并注意最后一段所说的内容。它可能表明编译器可以选择忽略 volatile
限定符。
根据我的经验,编译器将允许 volatile 变量保持未优化状态,即使它们从未被使用过。
不过,我不太确定链接器。该标准很少提及链接过程。
FWIW 我对嵌入式目标的商业编译器的一般经验是,它们有时不完全符合标准。我最近一直在使用 TI 编译器+链接器工具链,我们只是说它与我过去使用的 ARM 的 gcc+ld 端口非常不同,例如...
编辑:
不,K&R 书当然不是标准。让我们来看看一个真正的标准,例如从 here 获得的 ISO C99 标准,Section 6.7.3 Type qualifiers, 6
中的一段说:
An object that has volatile-qualified type may be modified in ways unknown to the
implementation or have other unknown side effects. Therefore any expression referring
to such an object shall be evaluated strictly according to the rules of the abstract machine,
as described in 5.1.2.3. Furthermore, at every sequence point the value last stored in the
object shall agree with that prescribed by the abstract machine, except as modified by the
unknown factors mentioned previously.114) What constitutes an access to an object that
has volatile-qualified type is implementation-defined.
不幸的是,我不认为这有助于回答问题..
我正在使用一个非常特殊的工具链(Analog Devices 的 SHARC DSP 处理器),我想更好地了解我的 compiler/linker。
我在某处有一个不稳定的全局变量:
volatile long foo;
此变量未在我的代码中使用和引用,但我想将其保留在我的最终可执行文件中(不要问我为什么,可悲的事实是可悲的)。
我通常 link 我的项目带有 -e
选项。它告诉 linker 从可执行文件中删除死代码。我最初认为没有编译器敢于删除任何全局变量,尤其是当这些符号被声明为 volatile 时。不幸的是它确实如此。
然后我发现了一个非常具体的 pragma #pragma retain_name
,它告诉 linker 保留一个符号,即使它从未被使用过。
我想知道在某些ISO/POSIX标准中是否可以找到这种情况。我一直认为编译器或 linker 都不会对可变符号做出任何假设。因此,没有编译器会尝试从最终的可执行文件中删除无效的 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
,我不确定您是否可以安全地执行此操作。
如果说C的一个标准是K&R书,那么volatile
就没什么好说的了,只是提了几次,据说跟优化有关
在附录 A.8.2 类型说明符中,它是这样说的:
Types may also be qualified, to indicate special properties of the objects being declared. type-qualifier: const volatile Type qualifiers may appear with any type specifier. A const object may be initialized, but not thereafter assigned to. There are no implementation-dependent semantics for volatile objects. The const and volatile properties are new with the ANSI standard. The purpose of const is to announce objects that may be placed in read-only memory, and perhaps to increase opportunities for optimization. The purpose of volatile is to force an implementation to suppress optimization that could otherwise occur. For example, for a machine with memory-mapped input/output, a pointer to a device register might be declared as a pointer to volatile, in order to prevent the compiler from removing apparently redundant references through the pointer. Except that it should diagnose explicit attempts to change const objects, a compiler may ignore these qualifiers.
强调我的并注意最后一段所说的内容。它可能表明编译器可以选择忽略 volatile
限定符。
根据我的经验,编译器将允许 volatile 变量保持未优化状态,即使它们从未被使用过。 不过,我不太确定链接器。该标准很少提及链接过程。
FWIW 我对嵌入式目标的商业编译器的一般经验是,它们有时不完全符合标准。我最近一直在使用 TI 编译器+链接器工具链,我们只是说它与我过去使用的 ARM 的 gcc+ld 端口非常不同,例如...
编辑:
不,K&R 书当然不是标准。让我们来看看一个真正的标准,例如从 here 获得的 ISO C99 标准,Section 6.7.3 Type qualifiers, 6
中的一段说:
An object that has volatile-qualified type may be modified in ways unknown to the implementation or have other unknown side effects. Therefore any expression referring to such an object shall be evaluated strictly according to the rules of the abstract machine, as described in 5.1.2.3. Furthermore, at every sequence point the value last stored in the object shall agree with that prescribed by the abstract machine, except as modified by the unknown factors mentioned previously.114) What constitutes an access to an object that has volatile-qualified type is implementation-defined.
不幸的是,我不认为这有助于回答问题..