c语言中的各种变量是如何存储的(二)

来源:互联网 发布:物理网络拓扑发现算法 编辑:程序博客网 时间:2024/04/29 04:18
本次讲常量数据,常量数据一般放在.rodata段(ro代表read only)。


常量数据有哪些呢,一般有字符串常量和带const的变量;

代码一:

int main()
{
       char *str = "abcdef";
        return 0;
}

lyh@debian:~/test$ objdump -h rodata | grep rodata
rodata:     file format elf32-i386
 15 .rodata       0000000f  08048468  08048468  00000468  2**2
lyh@debian:~/test$ objdump -h rodata | grep text
 13
.text         0000016c  080482e0  080482e0  000002e0  2**4


看出字符串“abcdef”存在.rodata段.rodata的初始大小是0x00000008,加上“abcdef”的大小7刚好就是上面.rodata的大小0x0000000f了。


那么是不是所有的字符串常量都是存在.rodata段中呢?
代码二:

int main()
{
char array[] = "abcdef";
return 0;
}

lyh@debian:~/test$ gcc -g rodata.c -o rodata

lyh@debian:~/test$ objdump -h rodata | grep rodata
rodata:     file format elf32-i386
 15 .rodata       00000008  08048478  08048478  00000478  2**2


可以发现.rodata段中大小为0x00000008,也就是说字符串常量“abcdef”没有在该段里,那它在哪里呢?
lyh@debian:~/test$ objdump -h rodata | grep text
13 .text         0000017c  080482e0  080482e0  000002e0  2**4


汇编代码:
       
 char array[] = "abcdef";
 
804839a:       c7 45 f9 61 62 63 64    movl   $0x64636261,-0x7(%ebp)
 
80483a1:       66 c7 45 fd 65 66       movw   $0x6665,-0x3(%ebp)
 
80483a7:       c6 45 ff 00             movb   $0x0,-0x1(%ebp)


综合可知,该字符串常量存储在了代码段中,也就是.text段。
所以,字符串常量也可能在.text(代码段)也可能在.rodata段中。






还有一种const类型的变量也存在.rodata段中。

代码三:

const int i = 1;
int main()
{
return 0;
}

lyh@debian:~/test$ objdump -h rodata | grep rodata
rodata:     file format elf32-i386
15 .rodata       0000000c  08048458  08048458  00000458  2**2

上面的全局const类型存在.rodata中。那是不是任何const的都是这样呢?
代码四:

int main()
{

const int i = 1;
return 0;

}
 15 .rodata       00000008  08048468  08048468  00000468  2**2
  
汇编代码:
int main()
{


8048394: 55                   push   %ebp
 
8048395: 89 e5                mov    %esp,%ebp
 
8048397: 83 ec 10             sub    $0x10,%esp


const int i = 1;
 
804839a: c7 45 fc 01 00 00 00 movl   $0x1,-0x4(%ebp)

return 0;
 
80483a1: b8 00 00 00 00       mov    $0x0,%eax


}

再看const类型作参数的情况

代码五:
int fun(const int i)
{
       return i;
}
int main()
{
        fun(1);
       return 0;
}
15 .rodata       00000008  08048478  08048478  00000478  2**2
汇编代码:
int fun(const int i)
{
 8048394: 55                   push   %ebp
8048395: 89 e5                mov    %esp,%ebp
return i;
8048397: 8b 45 08             mov    0x8(%ebp),%eax
}

int main()
{
 
804839c: 55                   push   %ebp
 
804839d: 89 e5                mov    %esp,%ebp
 
804839f: 83 ec 04             sub    $0x4,%esp
fun(1);
 80483a2: c7 04 24 01 00 00 00 movl   $0x1,(%esp)
 80483a9: e8 e6 ff ff ff       call   8048394 <fun>
return 0;
80483ae: b8 00 00 00 00       mov    $0x0,%eax
}

发现 .rodata段也没变,且从fun()函数的汇编代码发现 变量i存在.text,其实参数中的const只是告诉编译器该值不可修改。
所以带const类型的全局变量存在.rodata段中,

所以带const类型的全局变量和一些字符串常数存在文件的.rodata段(程序运行时该数据存在只读Memory中,看代码七和代码八)中,他们不可以修改;带const类型的参数和一些字符串常量保存在文件的.text段中(程序运行时把这些数据存进栈中,参考下面的代码六),他们也不可以修改(如果代码中有直接修改他们的代码,则不能通过编译)


代码六:

int main()
{
        const int i = 1;
        int a;
        *(&a+1) = 2; //这里&a是一个地址,实际的操作是得到 &a+sizeof(int) 该处的地址
        printf("i=%d",i);
        return 0;
}
结果:
i=2

改代码通过先绕过编译器,在程序运行时,成功把const类型的变量i成功修改了。(因为运行时,i存储在普通的栈中而已)
然而:

代码七:

const int a;

const int b;

int main()
{
        printf("&a=%d\n", &a);
        printf("&b=%d\n", &b);
        return 0;
}
lyh@debian:~/test$ ./rodata
&a=134518260
&b=134518264

发现变量a和b的地址是连续的,那么我们想到可不可以用一下代码来试着修改a的值呢

代码八:
const int a;

const int b;

int main()
{
*(&b-1) = 1;      //即对变量a进行赋值操作
printf("a=%d",a);
}
试着编译,会发生这么个错误:
rodata.c:12: error: assignment of read-only location ‘*(&b + 0xfffffffffffffffffffffffffffffffcu)’

说明变量a、b是存放在一个only read 的特殊存储空间。


------本人菜鸟一只,如有错误,望大牛们指出^_^

原创粉丝点击