Search code examples
coptimizationconstants

Force GCC to always load a const (i.e. read-only) even with optimizations enabled


Let's say I have a const global variable that is, therefore, read-only and will be placed in the .rodata section. I'm compiling the code with -O3 optimizations. This will make the compiler (i.e., GCC) generate different code when reading the variable, depending on the value of the variable itself. For example, if the variable is defined as zero or a small enough value that fits the ISA instructions immediate field, it will use a single instruction. If it is large, it might use several instructions. I'd like for the generated code to be the same independently of the value. I tried declaring it as volatile const, and this seems to work as it always generates load instructions to read the value, but GCC seems to ignore the const field and place it in the .data section. Also, I tried declaring __attribute__((section(".rodata")) volatile. This resulted in the warning " Warning: setting incorrect section attributes for .rodata".

So that I don't fall into an "XY problem" issue, I'd also say my main goal is for this code to generate a final binary that is as much as possible the same (i.e., sections at the same addresses with the same sizes), independently of the value of these const variables, which comes from macros generated at compile time. Also, I'd like these const values to be in the read-only data section such they are marked as RO in the page tables and can't be corrupted at runtime.

Any suggestions on how to achieve my goal?


Solution

  • Unless you have enabled link-time optimizations, the compiler usually can do these optimization only if you defined the variable in the same .c file (translation unit).

    Therefore you could define the variables in a different translation unit, e.g. const.c:

    const int x = 42;
    

    then elsewhere use

    extern const int x;
    

    then, unless you use link-time optimizations, the compiler just has to issue proper reads in other translation units because it wouldn't know otherwise.


    You can use the X-macros to do these in one place, so that you can use something like

    DEFINE_CONST_VAR(int, x, 42);
    

    in an #include just once for each variable.