例如,当我有:
const char mesg [] = "Hello World";
它直接放在.rodata
但是当我有时:
const char* mesg = "Hello World";
它直接放入.rodata.str1.4
它们之间有什么区别,为什么我们在使用指针时使用 .rodata.str1.4 ?
例如,当我有:
const char mesg [] = "Hello World";
它直接放在.rodata
但是当我有时:
const char* mesg = "Hello World";
它直接放入.rodata.str1.4
它们之间有什么区别,为什么我们在使用指针时使用 .rodata.str1.4 ?
我做了几个实验,看起来编译器将字符串放在目标文件的特殊部分中。有趣的事情发生在编译二进制文件时,字符串按预期以 .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..
[...]
根据类型、声明等,不同的编译器可能对只读数据使用不同的部分。
按照惯例,.rodata 可用于任何需要由加载程序放入内存的只读部分的内容。
所以将 const char * 放在那里就可以了。
但通常,编译器也会生成以 .rodata 为前缀的部分,以对只读数据进行分类。
它可能会被加载程序忽略,并完全视为 .rodata 部分(我认为它应该最常见),但如果需要,它可能允许在内存中进行一些特定的安排。
这就是链接描述文件经常指定 .rodata 和 .rodata* 的原因