Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

prevent gcc from removing an unused variable

Tags:

c

gcc

In our source files we usually have a version string like that:

static const char srcvers[] = "VERSION/foo.c/1.01/09.04.15";

When that string isn't optimized away, it's quite useful in certain cases, as one can determine the version of each source file linked to an executable by simply calling strings a.out | grep VERSION.

Unfortunately it is optimized away by gcc (using '-O'). So my question is, is there a simple way (a compiler switch would be great) to make gcc keep that variable (its name is always the same) without switching off any other optimizations.

Edit

What, in my opinion, makes the question different from that one, is that I'm was hoping to find a solution for which I wouldn't have to touch thousands of source files.

like image 488
Ingo Leonhardt Avatar asked Apr 09 '15 17:04

Ingo Leonhardt


People also ask

How do I turn off Wunused variable?

Controlling Warning Messages You can then use -Wunused-variable to turn on that warning specifically, without enabling others. To disable that warning, replace the leading -W with -Wno- , and use it in combination with an option to enable the desired warning level.

Does compiler remove unused functions?

If either the compiler or the linker can see that there are no references to C functions or C variables, they can (and usually do) remove those unused things.


3 Answers

You can use __attribute__((used)) gcc (also works in clang) specific (I see that the question is tagged gcc) attributes for this:

This attribute, attached to a function, means that code must be emitted for the function even if it appears that the function is not referenced. This is useful, for example, when the function is referenced only in inline assembly.

From https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html

Demo:

$ cat a.c
static const char srcvers[] __attribute__((used)) = "VERSION/foo.c/1.01/09.04.15";
$ gcc -O3 -c a.c
$ strings a.o
VERSION/foo.c/1.01/09.04.15

You can use some #ifs and #defines to make this terser and also compile on compilers which don't support this extension.

like image 123
Dogbert Avatar answered Oct 03 '22 21:10

Dogbert


As I understand your question, you need to add version string to every object file without touching sources. It can be done using next way.

Create header file, for example include/version.h:

#ifndef VERSION_H
#define VERSION_H

static const char _ver[] __attribute__((used)) = "VERSION/foo.c/1.01/09.04.15";

#endif /* VERSION_H */

Then in your Makefile (or whatever your build system is) add next gcc flag:

CPPFLAGS += -include include/version.h

Of course it should be passed to gcc, e.g. like this:

%.o: %.c
    $(CC) $(CFLAGS) $(CPPFLAGS) -o $(*).o -c $(*).c

Now you can observe your _ver string compiled to every object file:

$ objdump -DS src/main.o | grep _ver

Which will show you something like that:

Disassembly of section .rodata._ver:
00000000 <_ver>:
like image 40
Sam Protsenko Avatar answered Oct 03 '22 20:10

Sam Protsenko


As it seems that all the solutions require some kind of decoration of the version string in the source, it may help to define a macro containing all the necessary syntax and then use this macro in the source or header files whenever need:

#define SRCVERSION(file, version, data) static const char _ver[] __attribute__((used)) = "VERSION/" file "/" version "/" date;

Then in your source just put

SRCVERSION("foo.c", "1.01", "09.04.15")

The macro may be in a central project header file or on the compiler's command line.

That way, at least you do not have to touch all the source files again if you want to change something about the definition.

Note how the macro definition uses string concatenation to build the final version string. Also it contains the final semicolon so you can remove everything by defining an empty macro if needed.

like image 36
Ber Avatar answered Oct 03 '22 22:10

Ber