const全局变量位于哪个段

方法:

1、设计若干个const全局变量的例子,用g++编译生成可执行文件(例如a.out)

2、用readelf -S a.out 查看elf文件各段的信息

3、用objdump -S a.out查看main函数反汇编,确定调用的地址

4、根据调用的地址和2中查单到的段信息,确定调用的地址位于哪个段

5、也可绕过3、4步,直接用readelf -s a.out查看符号表,从中得知特定符号位于哪个段



情况1:

const int aaa = 0xf0f0f0f0;
int main()
{
    return aaa;
}

结论:符号表中根本就不存在aaa这个符号。应该是在编译阶段就把aaa全部替换成为0xf0f0f0f0。在本例中是一个int常量,所以用objdump可以直接在汇编指令中看到0xf0f0f0f0体现为立即数。


情况2:

extern const int aaa;
int main()
{
    return aaa;
}

结论:extern的作用,我的理解是,告诉编译器,aaa这个符号还有可能在别的文件中用到。所以从这个层面上来说,aaa放到data段或者rodata段才能体现这一特性。既然是const,那么就是放在rodata段才对。用readelf -s a.out查看符号aaa的地址和它所在的段号,再结合readelf -S a.out的结果,验证了这一猜测。


情况3:

上面两种const全局变量都是用所谓的”常量表达式“初始化。还有一种不是用常量表达式初始化的情况:

int fun()
{
    return 0xf0f0f0f0;
}

const int aaa = fun();
int main()
{
    return aaa;
}

用readelf -x .rodata a.out 和readelf -x .data a.out查看rodata和data段,没有看到0xf0f0f0f0。再用readelf -s a.out看符号表,会看到一个_ZL3aaa的符号,起始地址是08049694,BIND属性是LOCAL,位于编号为25的段内。编号为25的段正是BSS段。再查看main函数的汇编,能看到对应语句位置引用的地址也是0849694。

所以,这种情况下的const全局变量是放在BSS段内的。


发散:

有一种方法可以修改const的值:

int * ptr = const_cast(&r);//C++标准,C语言使用:int * ptr =(int*)&r;
* ptr = 0xf1f1f1f1;//修改
但是这种方法不是通用的。能成功修改的前提是r这个const变量必须位于可读可写的段内。假如r位于rodata段,就如上文的情况2,可以编译通过,但运行的时候会报段错误,因为rodata段的属性是只读的。而情况3就能正常运行,因为bss段可读可写。




  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值