In the past, I worked on ELF and PE on Linux/Windows but that did not really help me much to answer his question so when I came home, I decided to first write a C code and verify the location of static/global variables. In theory, global variables that are not defined should go to 'data' section and those that are either defined to be zero should go to 'bss' section. But for those that are defined to be non-zero, I am not sure. So let me find out where they are.
So first let me show my C code.
int g_init_var1 = 3;
int g_init_var2 = 0;
int g_un_var;
int testfunc(int num)
{
int auto_var;
static int static_var_1 = 0;
static int static_var_2;
if (num == 1)
static_var_2 = num;
return 0;
}
int main(int argc, char *argv[])
{
int num;
scanf("%d", &num);
testfunc(num);
return 0;
}
I just declared two global variables and two static variables and after that I compiled the code with /FA option to produce assembly code. C:\> cl /FApe.asm pe.c
When I looked at assembly code, I found the following.
PUBLIC _g_init_var1
PUBLIC _g_init_var2
_DATA SEGMENT
COMM _g_un_var:DWORD
_DATA ENDS
_BSS SEGMENT
_g_init_var2 DD 01H DUP (?)
?static_var_1@?1??testfunc@@9@9 DD 01H DUP (?) ; `testfunc'::`2'::static_var_1
_BSS ENDS
_DATA SEGMENT
_g_init_var1 DD 03H
$SG2474 DB '%d', 00H
ORG $+1
$SG2475 DB '%d', 0aH, 00H
_DATA ENDS
_BSS SEGMENT
?static_var_2@?1??testfunc@@9@9 DD 01H DUP (?) ; `testfunc'::`2'::static_var_2
; Function compile flags: /Odtp
_BSS ENDS
As expected cl put g_un_var into 'data' segment because it is not defined. But I found it interesting to see what happens to the global variables that are defined. The global variables that are defined to be zero are actually located in 'bss' segment while the global variables that are defined to be non-zero are located in 'data' segment.For static variables, we see the same pattern. The only thing I would comment is that g_init_var1/g_init_var2 is the type of PUBLIC but g_un_var is the type of COMM. Linker will concatenate all PUBLIC segments having the same name to form a single, contiguous segment. But with COMM, it creates a communal variable which behaves like external variables and communal variables are allocated by the linker. In a nutshell, they are just like global variables but we cannot assign them initial values and the only drawback of using communal variable is that they may not appear in consecutive memory locations.
After this exercise, I try the same on linux to see if there is any difference and the following is the result of objdump.
Disassembly of section .data:
00000000006008b8 <__data_start>:
6008b8: 00 00 add %al,(%rax)
...
00000000006008bc <g_init_var1>:
6008bc: 03 00 add (%rax),%eax
...
00000000006008c0 <static_var_1.2130>:
6008c0: 01 00 add %eax,(%rax)
...
Disassembly of section .bss:
00000000006008c8 <dtor_idx.6147>:
...
00000000006008d0 <completed.6145>:
6008d0: 00 00 add %al,(%rax
...
00000000006008d4 <g_init_var2>:
6008d4: 00 00 add %al,(%rax)
...
00000000006008d8 <static_var_2.2131>:
6008d8: 00 00 add %al,(%rax)
...
00000000006008dc <g_un_var>:
6008dc: 00 00 add %al,(%rax)
...
So today's exercise helps me to visualize where the global/static variables go and let me finish my post with a couple of links that I referred to verify my theory.
- Paradigm Assembler User's guide : for communal variables
No comments:
Post a Comment