全局變數什麼時候在內存中申請空間呢?

一個進程不是分為代碼段數據段等等嗎?如果我定義一個全局變數什麼時候在內存中開闢空間呢?是程序運行的時候嗎?


如果是未初始化的全局變數,它一般在.bss段,.bss段在目標文件中是不佔空間的,只有大小信息,在載入程序時,為.bss段分配空間;如果是有初始值的全局變數,那麼一般是在.data段中,該段的內容在目標文件中存在,載入程序的時候,載入器分配.data段的空間,並把目標文件中的.data段內容複製到內存中。所以,不管初始化與否,都是在載入程序時,為全局變數分配好了空間。


已初始化的全局變數和局部靜態變數保存在 .data 段,在文件中存在;未初始化的全局變數和局部靜態變數保存在 .bss 段,因未初始化數據都是 x00 ,保存它們無意義,所以將其放於 .bss,記錄大小,為變數預留位置,在文件中不佔空間,載入程序時再分配。

?&> /tmp cat src.c
#include &

int a = 233;
int b;

int main() {
b = 1024;
printf("%d
", b);
return 0;
}
?&> /tmp gcc src.c
?&> /tmp objdump -s -j .data a.out

a.out: 文件格式 elf64-x86-64

Contents of section .data:
201000 00000000 00000000 08102000 00000000 .......... .....
201010 e9000000

?&> /tmp python -c print 0xe9
233
?&> /tmp objdump -x -j .bss a.out
...snip...
節:
Idx Name Size VMA LMA File off Algn
23 .bss 0000000c 0000000000201014 0000000000201014 00001014 2**2
ALLOC
...snip...
?&> /tmp gdb ./a.out
Reading symbols from ./a.out...(no debugging symbols found)...done.
gdb-peda$ start
[----------------------------------registers-----------------------------------]
RAX: 0x5555555546a0 (&: push rbp)
RBX: 0x0
RCX: 0x0
RDX: 0x7fffffffddc8 --&> 0x7fffffffe130 ("CLUTTER_IM_MODULE=xim")
RSI: 0x7fffffffddb8 --&> 0x7fffffffe125 ("/tmp/a.out")
RDI: 0x1
RBP: 0x7fffffffdcd0 --&> 0x5555555546d0 (&<__libc_csu_init&>: push r15)
RSP: 0x7fffffffdcd0 --&> 0x5555555546d0 (&<__libc_csu_init&>: push r15)
RIP: 0x5555555546a4 (&: mov DWORD PTR [rip+0x20096a],0x400 # 0x555555755018 &)
R8 : 0x555555554740 (&<__libc_csu_fini&>: repz ret)
R9 : 0x7ffff7de8bd0 (&<_dl_fini&>: push rbp)
R10: 0x4
R11: 0x1
R12: 0x555555554570 (&<_start&>: xor ebp,ebp)
R13: 0x7fffffffddb0 --&> 0x1
R14: 0x0
R15: 0x0
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x55555555469b &: jmp 0x5555555545e0 &
0x5555555546a0 &: push rbp
0x5555555546a1 &: mov rbp,rsp
=&> 0x5555555546a4 &: mov DWORD PTR [rip+0x20096a],0x400 # 0x555555755018 &
0x5555555546ae &: mov eax,DWORD PTR [rip+0x200964] # 0x555555755018 &
0x5555555546b4 &: mov esi,eax
0x5555555546b6 &: lea rdi,[rip+0x97] # 0x555555554754
0x5555555546bd &: mov eax,0x0
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffdcd0 --&> 0x5555555546d0 (&<__libc_csu_init&>: push r15)
0008| 0x7fffffffdcd8 --&> 0x7ffff7a313f1 (&<__libc_start_main+241&>: mov edi,eax)
0016| 0x7fffffffdce0 --&> 0x40000
0024| 0x7fffffffdce8 --&> 0x7fffffffddb8 --&> 0x7fffffffe125 ("/tmp/a.out")
0032| 0x7fffffffdcf0 --&> 0x1f7b9a888
0040| 0x7fffffffdcf8 --&> 0x5555555546a0 (&: push rbp)
0048| 0x7fffffffdd00 --&> 0x0
0056| 0x7fffffffdd08 --&> 0x231dccb2ba367dde
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value

Temporary breakpoint 1, 0x00005555555546a4 in main ()
gdb-peda$ p/d 0x400
$1 = 1024
gdb-peda$ xinfo 0x555555755018
0x555555755018 --&> 0x0
Virtual memory mapping:
Start : 0x0000555555755000
End : 0x0000555555756000
Offset: 0x18
Perm : rw-p
Name : /tmp/a.out
gdb-peda$ x/xw 0x555555755018
0x555555755018 &: 0x00000000
gdb-peda$ n
[----------------------------------registers-----------------------------------]
RAX: 0x5555555546a0 (&: push rbp)
RBX: 0x0
RCX: 0x0
RDX: 0x7fffffffddc8 --&> 0x7fffffffe130 ("CLUTTER_IM_MODULE=xim")
RSI: 0x7fffffffddb8 --&> 0x7fffffffe125 ("/tmp/a.out")
RDI: 0x1
RBP: 0x7fffffffdcd0 --&> 0x5555555546d0 (&<__libc_csu_init&>: push r15)
RSP: 0x7fffffffdcd0 --&> 0x5555555546d0 (&<__libc_csu_init&>: push r15)
RIP: 0x5555555546ae (&: mov eax,DWORD PTR [rip+0x200964] # 0x555555755018 &)
R8 : 0x555555554740 (&<__libc_csu_fini&>: repz ret)
R9 : 0x7ffff7de8bd0 (&<_dl_fini&>: push rbp)
R10: 0x4
R11: 0x1
R12: 0x555555554570 (&<_start&>: xor ebp,ebp)
R13: 0x7fffffffddb0 --&> 0x1
R14: 0x0
R15: 0x0
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x5555555546a0 &: push rbp
0x5555555546a1 &: mov rbp,rsp
0x5555555546a4 &: mov DWORD PTR [rip+0x20096a],0x400 # 0x555555755018 &
=&> 0x5555555546ae &: mov eax,DWORD PTR [rip+0x200964] # 0x555555755018 &
0x5555555546b4 &: mov esi,eax
0x5555555546b6 &: lea rdi,[rip+0x97] # 0x555555554754
0x5555555546bd &: mov eax,0x0
0x5555555546c2 &: call 0x555555554560
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffdcd0 --&> 0x5555555546d0 (&<__libc_csu_init&>: push r15)
0008| 0x7fffffffdcd8 --&> 0x7ffff7a313f1 (&<__libc_start_main+241&>: mov edi,eax)
0016| 0x7fffffffdce0 --&> 0x40000
0024| 0x7fffffffdce8 --&> 0x7fffffffddb8 --&> 0x7fffffffe125 ("/tmp/a.out")
0032| 0x7fffffffdcf0 --&> 0x1f7b9a888
0040| 0x7fffffffdcf8 --&> 0x5555555546a0 (&: push rbp)
0048| 0x7fffffffdd00 --&> 0x0
0056| 0x7fffffffdd08 --&> 0x231dccb2ba367dde
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x00005555555546ae in main ()
gdb-peda$ x/xw 0x555555755018
0x555555755018 &: 0x00000400

推薦閱讀:《程序員的自我修養》


執行main函數之前


事實上全局變數早就被欽定在了數據段的某一個位置(這是不需要單獨申請空間的)

#include &
int hello = 0xABCDEF;

int main()
{
printf("hello = %p
", hello);
printf("hello = %d
", hello);
return 0;
}

(Littler-Endian 位元組序)

hello 被輸出地址

00401442 |. A1 04904000 mov eax, dword ptr [0x409004]
00401447 |. 894424 04 mov dword ptr [esp+0x4], eax
0040144B |. C70424 71A040&>mov dword ptr [esp], 0040A071
00401452 |. E8 696B0000 call &

00401442 將 0x409004 的數據「移動」到 EAX 寄存器(右上角的 EAX 寄存器已經發生改變)

00401447 將 EAX 寄存器的數據移動(推入)到棧(0xABCDEF)

0040144B 將 0x40A071 的數據移動(推入)到棧(hello = %d

00401452 調用 printf 函數完成輸出 「hello = 11259375」

Hello World!


去看linker and loader


推薦閱讀:

linux CFS調度演算法的疑問?
如何理解Linux一切皆是文件?這當中又有哪些值得後人借鑒的思想?
為什麼微內核系統在PC不如宏內核普及?
platform driver 是作為一個怎樣的概念出現的?
如何製造一個內核態的軟鎖死?

TAG:Linux | C編程語言 | Linux內核 |