我有如下功能:
const char* get_message() {
return "This is a constant message, will NOT change forever!";
};
const char* get_message2() {
return "message2";
};
我计划在我的应用程序的任何地方使用它们,即使在不同的线程中。
我想知道这些字符串的生命周期,即在函数之外使用这些
const char*
字符串是否安全 get_message
。
我猜想硬编码的
const char*
字符串将被编译到应用程序的代码段而不是数据段中,所以也许像上面那样使用它们是安全的?
是的,这样做是安全的。你的假设是正确的。
让我们看看代码中 gdb
发生了什么我们在函数中放置断点,返回指向常量字符串的指针:
代码通过以下指令获取该字符串:
0x000055555555514a <+8>: lea 0xeb3(%rip),%rax # 0x555555556004
这条指令的作用是计算“message2”的地址。 我们在这里看到 PIC(位置无关代码)的含义。 “message2”字符串的地址不是硬编码为绝对地址,而是计算为相对地址,作为下一条指令地址 (0x555555555151 + 0xeb3) 的硬编码偏移 0xeb3 并放入寄存器 rax
(gdb) i r $rax
rax 0x555555556004 93824992239620
现在我们在 rax 中有“message2”的地址:
(gdb) x/s 0x555555556004
0x555555556004: "message2"
这意味着进程将始终获得“message2”的正确地址,无论它加载到内存中的哪个位置。
现在让我们看看地址0x555555556004在进程地址映射中的位置 是:
0x555555556000 0x555555557000 0x1000 0x2000 r--p /home/drazen/proba/main
因此该部分不可执行且不可写,只是可读(r--p)。
当我们使用 readelf 检查时,它显示它位于 ELF 文件的 .rodata 部分:
drazen@HP-ProBook-640G1:~/proba$ readelf -x .rodata main
Hex dump of section '.rodata':
0x00002000 01000200 6d657373 61676532 00 ....message2.
所以答案是,这个字符串不会被硬编码在 ELF 文件的代码段 .text 中,而是被硬编码在 rodata 中,但是,是的,当内存中存在长进程时,它就会存在。
希望有帮助!