Variable Placement in C

Talk is cheap. Show me the code. – Geek

Prelude

1
int x section(".my_section");

Given the above code, combined with one customized linking script, we could place x in one absolute address, which is indeed the intention. As the program grows larger, I want to introduce another variable in the same section, so I did the most natural thing:

1
2
int x section(".my_section");
int y section(".my_section");

As I anticipated, everything works OK. That should be the end of the story, I didn’t continue working on it for almost another half year. The problem is that the application crashes when I use gcc -Os optimization. I have never shown as much interest in faster code as I did in readable code, so I didn’t pay much attention to it. (Maybe the compiler did some wrong optimization.)

Thunder storm

I have always disable optimization (-O0) after realizing optimization doesn’t work, until I was stuck in the work place, because of one thunder storm. I have nothing interesting to do but to dig it out who’s the culprit. I used one simple but effect method to narrow down the scope, binary search. Considering that there’s a few hundred object file after compiling, it’s silly to inspect them one by one. (Might have to do this, if one’s not lucky.) I build the application twice, one (alpha) for ‘-O0’, the other (beta) ‘-O3’, verifying alpha works OK and beta fails. Next, pick some object files from alpha set and replace the corresponding ones in beta. Finally, link them to obtain the final executable, and see how it works. If one’s lucky, it’s possible to narrow down the culprit efficiently. I would consider myself lucky, for it took me 15 mins.

Culprit and Solution

The reason why application fails after optimization is the order x and y is not preserved (swapped in this case). My expectation that variable placement in one section has no strict relation to how it’s mapped to memory. (Preserving the order is just one option, the default one.) Since it’s required by C standard, compilers can do anything it needs to make the code faster. Therefore, the application, which relies on x being placed at the absolute address, fails mysteriously.

I then spent almost two hours trying to find one solution for this. Unfortunately, my luck runs out, and the only thing I could find is do use one structure to preserve the ordering:

1
2
3
4
5
typedef struct mystruct_s {
int x;
int y;
} mystruct;
mystruct z section(".my_section");

Conclusion

C language doesn’t enforce variable layout within one section. Instead, the easist would be using one stucture, if one doesn’t want to fiddle with linking scrpits.