Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When is a variable placed in `.rdata` section and not in `.text` section?

Tags:

c

gcc

linker

I am trying to understand the implications of .rdata section vs .text section. I am trying a simple program as below

int main()
{
    const int a = 10;
    printf("%d\n", a);
    return 0;
}

When I build and dump the map file through gcc -o a.out sample.c -Wl,Map,test.map and search for sample.o, I find the following allocations

.text          0x0040138c       0x34 sample.o
.data          0x00402000        0x0 sample.o
.rdata         0x00403064        0x8 sample.o
.eh_frame      0x00404060       0x38 sample.o
.bss           0x00405020        0x0 sample.o

Now, if I modify my program slightly to make a a global variable as

const int a = 10;
int main()
{
     printf("%d\n", a);
     return 0;
}

By repeating the same step as above, I observe that the allocations are as below

.text          0x0040138c       0x2c sample.o
.data          0x00402000        0x0 sample.o
.rdata         0x00403064        0xc sample.o
.eh_frame      0x00404060       0x38 sample.o
.bss           0x00405020        0x0 sample.o

Wherein it clearly shows a is allocated into .rdata section as

.rdata         0x00403064        0xc sample.o
               0x00403064            a

From these experiments, I understand the global const are alocated into .rdata section, whereas the .text section size has come down. Hence, I presume that a was allocated into .text section in the first example.

My questions are:

  1. Is scope of a const variable considered while determining it's place in .rdata or .text?

  2. From my experiment, I observe that the variable required 8 bytes when it was allocated into .text section as compared to 4 bytes in .rdata section. What is the reason for this difference?

  3. If there are too many local const variables, then the size of corresponding .text section will increase significantly. What is the recommended programming practice in this scenario?

Many thanks in advance.

like image 429
Ganesh Avatar asked Apr 15 '13 22:04

Ganesh


2 Answers

In the first case, the variable is declared as a local variable. It has "automatic" storage duration, which means that it goes away at the end of the enclosing scope. It cannot occupy any piece of memory permanently because of its storage duration (this is true regardless of const). Thus, it is usually stored on the stack, or in a register.

In the second case, the variable is declared as a global variable. It has static storage duration, so it persists for the lifetime of the program. This can be stored in many places, such as .data, .bss, .text, or .rdata (or .rodata).

.data is generally used for writable static data with some predefined (nonzero) content, e.g. a global int foo = 42;. .bss is used for writable static data initialized to zero (or not initialized). rdata is used for constant static data like strings and const variables. Of course, these uses are all "in general" and may vary from compiler to compiler.

So why did .text get bigger in the first case? It is because the compiler had to generate some extra instructions to load 10 on the stack or into a register.

like image 161
nneonneo Avatar answered Nov 11 '22 09:11

nneonneo


This behavior will differ from target to target. In the first example where you think a ends up in the .text section it is the 10 that (probably) ends up in the text section and is loaded into a that is on the stack. Some architectures that have for example pc-relative addressing will place such constants somewhere between the code. Other architectures will encode the 10 as immediate addressing mode which also results in slightly bigger code size.

In the second example a is made a global variable and will be located in the .data section which is also what you observed.

So let's answer your questions with the above in mind.

  1. const in C does not mean it is a constant (uuh??), it means the programmer promises not to write it. Compilers will warn if you do it or if you run in danger of doing it, but will still compile. Thus the difference between your cases is really that a is a local variable in the first example and a global variable in the second example. Hmm, I just tried blatantly writing a const int and it really gives an error, not just a warning. It is however possible to pass such a const by reference to a function that will change it. Cross unit things may even go undetected by the compiler.

  2. If it is located in the .data section it is the size of the object, 4 bytes in your case. If the 10 is located in the code, either in a constant table or as an immediate addressing mode, then it really depends on the architecture how big it will become and what the effect is on the surrounding code.

  3. If you have many constants in your code and the architecture supports pc-relative addressing (like the ARM), then it will probably locate all those constants somewhere close to the code where they are used, but all together so one jump will suffice to jump over it, or none if there is a natural branch where the constant table can hide. Thus the constants take about as much space as they need and not (much) more. If they would all be implemented as immediate addressing then the compiler may still decide to make a table out of it if there are more efficient ways to get the constants that way.

like image 34
Bryan Olivier Avatar answered Nov 11 '22 08:11

Bryan Olivier