本次讲常量数据,常量数据一般放在.rodata段(ro代表read only)。
常量数据有哪些呢,一般有字符串常量和带const的变量;
{
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段中。
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()
{
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 int i = 1;
int a;
*(&a+1) = 2; //这里&a是一个地址,实际的操作是得到 &a+sizeof(int) 该处的地址
printf("i=%d",i);
return 0;
}
结果:
i=2
{
printf("&a=%d\n", &a);
printf("&b=%d\n", &b);
return 0;
}
lyh@debian:~/test$ ./rodata
&a=134518260
&b=134518264
发现变量a和b的地址是连续的,那么我们想到可不可以用一下代码来试着修改a的值呢
int main()
{
*(&b-1) = 1; //即对变量a进行赋值操作
printf("a=%d",a);
}
试着编译,会发生这么个错误:
rodata.c:12: error: assignment of read-only location ‘*(&b + 0xfffffffffffffffffffffffffffffffcu)’
常量数据有哪些呢,一般有字符串常量和带const的变量;
代码一:
{
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段中。
代码三:
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段中(程序运行时把这些数据存进栈中,参考下面的代码六),他们也不可以修改(如果代码中有直接修改他们的代码,则不能通过编译)
代码六:
{
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 b;
{
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;
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 的特殊存储空间。
------本人菜鸟一只,如有错误,望大牛们指出^_^