I am using a very specific toolchain (SHARC DSP Processor from Analog Devices) and I would like to get a better understanding of my compiler/linker.
I have somewhere a volatile global variable:
volatile long foo;
This variable is not used and not referenced in my code but I want to preserve it in my final executable (don't ask me why, the sad truth is sad).
I usually link my project with the -e
option. It tells the linker to remove dead code from the executable. I initially thought no compilers would dare remove any global variable especially if these symbols are declared as volatile. Unfortunately it does.
Then I found a very specific pragma #pragma retain_name
which tell the linker to keep a symbol even though it is never used.
I would like to know if such situation can be found in some ISO/POSIX standards. I always though neither the compiler or the linker would make any assumptions on volatile symbols. And thus, no compilers would ever try to remove a dead volatile variable or function from the final executable.
Am I wrong?
You could make a dummy function with external linkage that uses the variable.
long
help_us_keep_foo(void)
{
return foo;
}
Unless you are performing whole-program analysis, this will prevent foo
from being eliminated. If you do perform whole-program analysis, you can use a trick like the following.
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;
}
I have been using a similar trick (inserting harmless print statements that test an exceptionally unlikely condition) in benchmarking code to make sure that the things I wanted to benchmark are not optimized away.
If the situation permits it, you could use a less “visible” trick like assigning foo = foo
but since it is volatile
, I'm not sure you can do this safely.
If one standard for C is the K&R book, there is not much to say about volatile
except that it is mentioned a few times and is said to be related to optimization.
In Appendix A.8.2 Type Specifiers, it says this:
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.
Emphasis mine and note what the last paragraph says. It could suggest that the compiler can choose to ignore the volatile
qualifier anyway.
The compilers will allow volatile variable to remain un-optimized in my experience, even if they are never used. I'm not so sure about the linkers though. The standard says very little about the linking process.
FWIW my general experience with commercial compilers for embedded targets, is that they sometimes do not comply fully with the standards. I've been using a TI compiler+linker toolchain lately, and let's just say it is really different from what I'm used to with the gcc+ld ports for ARM e.g. ...
EDIT:
No of course the K&R book is not the standard. Let's have a look at a real standard, e.g. the ISO C99 standard obtained from here, one paragraph in Section 6.7.3 Type qualifiers, 6
says:
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.
Unfortunately I don't think this helps answer the question..
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With