全局變量和全局常量的實驗延續(xù)之前的方式,給出一個簡單的C程序,其中聲明的全局變量分為3種:
初始化過的全局變量
未初始化的全局變量
全局常量
#vi test5.c
本文引用地址:http://cafeforensic.com/article/201611/320805.htm int i=1;
int j=2;
int k=3;
int l,m;
int n;
const int o=7;
const int p=8;
const int q=9;
int main()
{
l=4;
m=5;
n=6;
return i+j+k+l+m+n+o+p+q;
}
# gcc test5.c -o test5
# mdb test5
Loading modules: [ libc.so.1 ]
> main::dis
main: pushl %ebp ; main至main+1,創(chuàng)建Stack Frame
main+1: movl %esp,%ebp
main+3: subl $8,%esp
main+6: andl $0xf0,%esp
main+9: movl $0,%eax
main+0xe: subl %eax,%esp ; main+3至main+0xe,為局部變量預留棧空間,并保證棧16字節(jié)對齊
main+0x10: movl $4,0x8060948 ; l=4
main+0x1a: movl $5,0x806094c ; m=5
main+0x24: movl $6,0x8060950 ; n=6
main+0x2e: movl 0x8060908,%eax
main+0x33: addl 0x8060904,%eax
main+0x39: addl 0x806090c,%eax
main+0x3f: addl 0x8060948,%eax
main+0x45: addl 0x806094c,%eax
main+0x4b: addl 0x8060950,%eax
main+0x51: addl 0x8050808,%eax
main+0x57: addl 0x805080c,%eax
main+0x5d: addl 0x8050810,%eax ; main+0x2e至main+0x5d,i+j+k+l+m+n+o+p+q
main+0x63: leave ; 撤銷Stack Frame
main+0x64: ret ; main函數(shù)返回
現(xiàn)在,讓我們在全局變量初始化后的地方設置斷點,觀察一下這幾個全局變量的值:
> main+0x2e:b ; 設置斷點
> :r ; 運行程序
mdb: stop at main+0x2e
mdb: target stopped at:
main+0x2e: movl 0x8060908,%eax
> 0x8060904,03/nap ; 察看全局變量 i,j,k的值
test5`i:
test5`i:
test5`i: 1
test5`j: 2
test5`k: 3
> 0x8060948,03/nap ; 察看全局變量l,m,n的值
test5`l:
test5`l:
test5`l: 4
test5`m: 5
test5`n: 6
> 0x8050808,03/nap ; 察看全局變量o,p,q的值
o:
o:
o: 7
p: 8
q: 9
>
概念:進程地址空間 Process Address Space
+----------------------+ ----> 0xFFFFFFFF (4GB)
| |
| Kernel Space |
| |
+----------------------+ ----> _kernel_base (0xE0000000)
| |
| Other Library |
: :
: :
| |
+----------------------+
| data section |
| Lib C Library |
| text section |
: :
: :
+----------------------+
| |
| |
: :
: grow up :
: :
| User Heap |
| |
+----------------------+
| bss |
| |
| User Data |
| |
+----------------------+
| |
| User Text |
| |
| |
+----------------------+ ----> 0x08050000
| |
| User Stack |
| |
: grow down :
: :
: :
| |
| |
+----------------------+ ----> 0
圖 3-1 Solaris在IA32上的進程地址空間
如圖3-1所示,Solaris在IA32上的進程地址空間和Linux是相似的,在用戶進程的4GB地址空間內:
Kernel總是映射到用戶地址空間的最高端,從宏定義_kernel_base至0xFFFFFFFF的區(qū)域
用戶進程所依賴的各個共享庫緊接著Kernel映射在用戶地址空間的高端
最后是用戶進程地址空間在地址空間的低端
各共享庫的代碼段,存放著二進制可執(zhí)行的機器指令,是由kernel把該庫ELF文件的代碼段map到虛存空間,屬性是read/exec/share
各共享庫的數(shù)據(jù)段,存放著程序執(zhí)行所需的全局變量,是由kernel把ELF文件的數(shù)據(jù)段map到虛存空間,屬性為read/write/private
用戶代碼段,存放著二進制形式的可執(zhí)行的機器指令,是由kernel把ELF文件的代碼段map到虛存空間,屬性為read/exec
用戶代碼段之上是數(shù)據(jù)段,存放著程序執(zhí)行所需的全局變量,是由kernel把ELF文件的數(shù)據(jù)段map到虛存空間,屬性為 read/write/private
用戶代碼段之下是棧(stack),作為進程的臨時數(shù)據(jù)區(qū),是由kernel把匿名內存map到虛存空間,屬性為read/write/exec
用戶數(shù)據(jù)段之上是堆(heap),當且僅當malloc調用時存在,是由kernel把匿名內存map到虛存空間,屬性為read/write/exec
注意Stack和Heap的區(qū)別和聯(lián)系:
相同點:
1. 都是來自于kernel分配的匿名內存,和磁盤上的ELF文件無關
2. 屬性均為read/write/exec
不同點:
1.棧的分配在C語言層面一般是通過聲明局部變量,調用函數(shù)引起的;堆的分配則是通過顯式的調用(malloc)引起的
2.棧的釋放在C語言層面是對用戶透明的,用戶不需要關心,由C編譯器產(chǎn)生的相應的指令代勞;堆則需顯式的調用(free)來釋放
3.??臻g的增長方向是從高地址到低地址;堆空間的增長方向是由低地址到高地址
4.棧存在于任何進程的地址空間;堆則在程序中沒有調用malloc的情況下不存在
用戶地址空間的布局隨著CPU和OS的不同,略有差異,以上都是基于X86 CPU在Solaris OS上的情況的討論。
評論