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:
Is scope of a const
variable considered while determining it's place in .rdata
or .text
?
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?
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.
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.
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.
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.
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.
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.
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