C++基本类型-变量在可执行文件中的存放位置及初始化时机
C++基本类型-变量在可执行文件中的存放位置及初始化时机
环境如下
如下代码
使用objdump -D -C反汇编-D会输出所有段,-C可以输出变量名
rodata 只读数据段
只读数据段中存放了
全局字符串常量char *f="123456"的值
局部字符串常量char *k="abcdef"的值
全局变量const int d=3
全局变量static const int e=4
main函数中的局部static const int j=8
由此可知,全局const变量,字符串常量的值,static const修饰的变量,会存放在rodata,而const修饰的局部变量并不存放在rodata段,而是存放在栈中,存放在只读数据段的变量在编译期就要确定其值
data 可读写数据段
可读写数据段中存放了
全局已初始化变量int b=1;
全局已初始化变量static int c=2;
全局已初始化变量char *f=0x08048640;0x08048640是rodata段中存放"123456"的起始地址
main函数中局部static int h=6;
由此可知全局已初始化变量,static 修饰的已初始化变量会存放在data段,存放在可读写数据段的变量,其值在编译期已经完成了初始化,同时还可以看出可执行文件中的多字节是以小端模式存放的
bss 未初始化变量段
bss段的变量在可执行文件中并不占用存储空间,只记录总体大小
bss段存放了
全局未初始化变量int a;
main函数中的局部未初始化变量static int m,已初始化的局部变量static int n=0;
由此可知全局/局部static未初始化或全局/局部static初始化为0的变量会存放在bss
text 代码段
我们只看main函数
可执行文件中并没有stack段,栈是对一块内存该怎样使用的一种约束,栈上的局部变量只有代码运行后才会被初始化,栈是由编译器生成的代码在管理,栈是一块连续的虚拟内存,在我的虚拟机中一个线程的栈默认最大是8M
代码段存放的是我们编写的代码产生的cpu指令,编译器通过构造栈桢来实现C++中的函数调用,栈桢是栈中的一个连续片段由ebp标识的栈底和esp标识的栈顶来确定,一个线程中的每一个函数调用都会在此线程的栈上生成一个栈桢用来保存局部变量,调用参数,寄存器的值及返回地址,最近一个被调用的函数的栈桢位于线程栈的最顶部,栈桢上的局部变量通过,基址寄存器ebp和变量的相对偏移量来确定,函数返回后栈桢回退,但栈的大小不会变小,栈会随着函数调用链的深入一直增长直至达到ulimit -s的值然后线程崩掉,栈桢是栈上的一个动态的函数调用过程
如下代码
反汇编代码如下
第三条指令sub $0x100018,%esp为函数调用分配1M的栈桢
每次fun函数调用编译器都会为其分配1M的栈桢空间
默认线程栈大小为8M
查看线程函数调用栈
当函数递归调用达到第8层时,由于栈大小超过了线程栈的上限8M,操作系统发送了signal 11(sigsegv)信号给此进程,进程崩掉
main函数的栈上存放了
main函数中的局部变量int g=5
main函数中的局部变量const int i=7
main函数中的局部变量char *k=0x8048647,0x8048647是字符串常量的值"abcdef"在rodata段的起始地址
存放在栈中的变量只有程序运行到这行代码时才会被初始化
总结一下:
函数中的局部变量,const修饰的局部变量会存放在栈中
全局已初始化变量及static修饰的已初始化变量会存放在data段
全局未初始化/初始化为0及static修饰的未初始化/初始化为0的变量会存放在bss段
const修饰的全局变量,字符串常量的值,static const 修饰的变量会存放在rodata段
位于data及rodata段的变量在编译期已完成初始化
位于stack中的变量在程序运行时被初始化
在可执行文件的反汇编代码中并未找到初始化bss段的变量的代码,bss段的初始化只需要分配一块可容纳所有未初始化变量的内存并初始化为0即可
开启优化后编译器并不会为const修饰的变量分配存储空间,对于const变量的使用在编译期编译器会直接进行值替换,并不会通过地址间接的去内存中访问该变量,在对const变量进行取址时,编译器才会为const变量分存内存,因此在取得const变量的地址后,通过指针去修改一个const变量的值,虽然可以修改成功,但通过指针取得的值与直接使用变量得到的值是不同的值,前者来自内存,后者是一个字面值,在汇编代码中作为立即数出现