I want to learn about elf files, but when I think of global variables, global static variables and scope static variables, I have some confusion. For example:
int a = 2;
int b;
static int c = 4;
static int d;
void fun(){
static int e = 6;
static int f;
}
int main(void){
fun();
}
Who can tell which segment each variable belongs to? in my opinion,
b
, d
and f
belong to the .bss
segment and a
,c
and e
belong to the data segment, but I don't know the difference between global static variables and global variables in elf file.
Global variables are stored in the data segment of memory. Local variables are stored in a stack in memory.
Code segments are stored in flash memory. The stack is located in RAM. Global variables are stored in flash or RAM, depending on whether they are writable.
A data segment is a portion of the virtual address space of a program, which contains the global variables and static variables that are initialized by the programmer.
All allocation made by malloc(), calloc() or realloc() are stored on the heap, while all local variables are stored on the stack. All global and static variables are stored in the data segment, while constants are stored in the code segment.
You can use objdump -t
to view the symbol table:
$ objdump -t foo | grep -P ' \b(a|b|c|d|e|f)\b'
0000000000601034 l O .data 0000000000000004 c
0000000000601040 l O .bss 0000000000000004 d
0000000000601044 l O .bss 0000000000000004 f.1710
0000000000601038 l O .data 0000000000000004 e.1709
0000000000601048 g O .bss 0000000000000004 b
0000000000601030 g O .data 0000000000000004 a
You are right that b
, d
, and f
are .bss
while a
, c
, and e
are .data
. Whether the symbol is static or not is recorded in a separate flag of the symbol table—that’s the l
or g
flag in the second column.
The elf(5) man page says that these are recorded using the STB_LOCAL
and STB_GLOBAL
values for the st_info
member of the symbol table. /usr/include/elf.h
says that STB_GLOBAL
is 1, while STB_LOCAL
is 0. There is a macro ST_BIND
to retrieve the binding bits of the st_info
field.
There are tons of other flags for objdump
—see the man page. objdump
works with all architectures, but there is also an elfdump
tool that does a bit better job of showing elf-specific stuff. objdump
and the underlying BFD
library can do a bad job of showing some file-format-specific data.
In general, the data segment of the executable contains initialized global/static variables and the BSS segment contains uninitialized global/static variables.
When the loader loads your program into memory, the unitialized global/static variables are automatically zero-filled.
In C, static variables (initialized or not) inside a function just mean the variables have local/function scope (sometimes referred to as internal static), but they still live in the Data/BSS segments depending on whether or not they are initialized.
So regardless of how many times fun() gets called, the static variables are initilized only once when the program is loaded.
Variables defined as static and outside any functions still live in either the data or bss segments, but have file scope only.
When your code is compiled, there is an import and export list that is part of each object file and is used by the linkage editor. Your static variables will not be in the export list and therefore inaccessable to other object files.
By excluding the static keyword, your global variables are placed in the export list and can be referred to by other object modules and the linkage editor will be able to find the symbols when creating the executable.
For a pictoral view:
+--------- TEXT ---------+ Low memory
| main() |
| fun() |
+--------- DATA ---------+
| int a (global scope) |
| int c (file scope) |
| int e (function scope) |
+---------- BSS ---------+
| int b (global scope) |
| int d (file scope) |
| int f (function scope) |
+------------------------+
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