例如我有:
const char mesg [] = "Hello World";
直接放在.rodata
但是我有:
const char* mesg = "Hello World";
直接放在.rodata.str1.4
当我们使用指针时,它们与我们使用.rodata.str1.4的原因有什么区别?
答案 0 :(得分:3)
我做了几个实验,看起来编译器将字符串放在目标文件的特殊部分中。有趣的事情发生在编译二进制文件时,字符串最终会按预期在.rodata中结束。进一步的实验表明,如果在不同的对象中有相同的字符串,它们会在生成的二进制文件中统一到相同的字符串中。
所以我怀疑这样做的原因是编译器想要给链接器一些关于除“只读”之外的只读数据的信息,这样最终的链接可以做出更明智的决策。处理它,包括重复数据删除。
$ cat foo.c
const char *
fun(int i)
{
const char *foo = "foofoo foo foo foo";
const char *bar = "barbar bar bar bar";
return i ? foo : bar;
}
$ cat bar.c
#include <stdio.h>
extern const char *fun(int);
int
main(int argc, char **argv)
{
const char *foo = "foofoo foo foo foo";
printf("%s%s\n", foo, fun(1));
return 0;
}
$ cc -c -O2 foo.c
$ cc -c -O2 bar.c
$ objdump -s foo.o
[...]
Contents of section .rodata.str1.1:
0000 62617262 61722062 61722062 61722062 barbar bar bar b
0010 61720066 6f6f666f 6f20666f 6f20666f ar.foofoo foo fo
0020 6f20666f 6f00 o foo.
[...]
$ objdump -s bar.o
[...]
Contents of section .rodata.str1.1:
0000 666f6f66 6f6f2066 6f6f2066 6f6f2066 foofoo foo foo f
0010 6f6f0025 7325730a 00 oo.%s%s..
[...]
$ cc -o foobar foo.o bar.o
$ objdump -s foobar
[...]
Contents of section .rodata:
400608 01000200 00000000 00000000 00000000 ................
400618 62617262 61722062 61722062 61722062 barbar bar bar b
400628 61720066 6f6f666f 6f20666f 6f20666f ar.foofoo foo fo
400638 6f20666f 6f002573 25730a00 o foo.%s%s..
[...]
答案 1 :(得分:2)
不同的编译器可能会对只读数据使用不同的部分,具体取决于类型,声明等。
按照惯例,<。> .rodata可用于任何需要由装载程序放入内存的只读部分的内容。但通常,编译器还会生成以.rodata为前缀的部分,以对只读数据进行分类 它可能只是被加载器忽略,并且完全被视为.rodata部分(我认为它应该是最常见的情况),但如果需要,它可能允许在内存中进行某些特定的安排。
这就是链接器脚本经常指定.rodata和.rodata *
的原因