大局变量和大局常量的试验
连续之前的方法,给出一个简略的C程序,其间声明的大局变量分为3种:
初始化过的大局变量
未初始化的大局变量
大局常量
#vi test5.c
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,创立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字节对齐
main+0x10: movl $4,0×8060948 ; l=4
main+0x1a: movl $5,0x806094c ; m=5
main+0x24: movl $6,0×8060950 ; 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函数回来
现在,让我们在大局变量初始化后的当地设置断点,调查一下这几个大局变量的值:
> 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的区域
用户进程所依靠的各个同享库紧接着Kernel映射在用户地址空间的高端
最终是用户进程地址空间在地址空间的低端
各同享库的代码段,存放着二进制可履行的机器指令,是由kernel把该库ELF文件的代码段map到虚存空间,特点是read/exec/share
各同享库的数据段,存放着程序履行所需的大局变量,是由kernel把ELF文件的数据段map到虚存空间,特点为read/write/private
用户代码段,存放着二进制方式的可履行的机器指令,是由kernel把ELF文件的代码段map到虚存空间,特点为read/exec
用户代码段之上是数据段,存放着程序履行所需的大局变量,是由kernel把ELF文件的数据段map到虚存空间,特点为 read/write/private
用户代码段之下是栈(stack),作为进程的暂时数据区,是由kernel把匿名内存map到虚存空间,特点为read/write/exec
用户数据段之上是堆(heap),当且仅当malloc调用时存在,是由kernel把匿名内存map到虚存空间,特点为read/write/exec
留意Stack和Heap的差异和联络:
相同点:
1. 都是来自于kernel分配的匿名内存,和磁盘上的ELF文件无关
2. 特点均为read/write/exec
不同点:
1.栈的分配在C言语层面一般是经过声明局部变量,调用函数引起的;堆的分配则是经过显式的调用(malloc)引起的
2.栈的开释在C言语层面是对用户通明的,用户不需要关怀,由C编译器发生的相应的指令代庖;堆则需显式的调用(free)来开释
3.栈空间的增加方向是从高地址到低地址;堆空间的增加方向是由低地址到高地址
4.栈存在于任何进程的地址空间;堆则在程序中没有调用malloc的状况下不存在
用户地址空间的布局跟着CPU和OS的不同,略有差异,以上都是根据X86 CPU在Solaris OS上的状况的评论。
声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/changshang/peixun/260210.html