为什么静态成员指针在 ELF 部分为零?
Why Static Member Pointer Is Zero In ELF Section?
编译以下代码,并检索 .ippalgo 部分,我注意到 name
字段为零,而其他字段符合预期。
$ g++ a.cpp
$ objdump -s -j .ippalgo a.out
a.out: file format elf64-x86-64
Contents of section .ippalgo:
601040 00000000 00000000 02000000 01000000 ................
^^^^^^^^^^^^^^^^^
$ ./a.out
sizeof(char*): 8, sizeof(int): 4
name: 0x400648
name: abcdef
但是在直接使用 "abcdef"
字符串更改 1. 行后,我似乎得到了正确的地址。
$ objdump -s -j .ippalgo a.out
a.out: file format elf64-x86-64
Contents of section .ippalgo:
601040 08064000 00000000 02000000 01000000 ..@.............
^^^^^^^^^^^^^^^^^
$ ./a.out
sizeof(char*): 8, sizeof(int): 4
name: 0x400608
name: abcdef
在任何一种情况下,main 中的最后一个打印都得到了正确的消息 abcdef
。我的问题是为什么我在第一种情况下得到零,如果有问题如何解决?
#include <cstdio>
struct DataInfo {
const char* name;
int id;
int type;
};
class Proxy {
public:
const static char *name;
const static int type;
const static int id;
};
const char* Proxy::name = "abcdef";
const int Proxy::id = 1;
const int Proxy::type = 2;
__attribute__((used, section(".ippalgo")))
DataInfo ProxyInfo = {
Proxy::name, // 1. ok when set "abcdef" directly
Proxy::type,
Proxy::id
};
int main()
{
printf("sizeof(char*): %lu, sizeof(int): %lu\n",
sizeof(char*), sizeof(int));
printf("name: %p\n", Proxy::name);
printf("name: %s\n", ProxyInfo.name);
}
TL;DR Proxy::name
不是 const
。
静态数据的初始化分为常量(包括zero-initialization)和动态初始化两个阶段
在某些条件下,两者可以合并,最终的初始化程序放在二进制文件中,而不是在 main()
之前生成代码来初始化它。
您的编译器在一种情况下选择使用常量初始化,在另一种情况下选择使用动态初始化。这是完全合法的,编译器不需要在二进制文件的任何特定结构中放置常量。
在您的情况下,Proxy::name
不是 const
,而 Proxy::id
和 Proxy::type
可能会影响编译器的选择。它甚至不是 compile-time 常量。也许编译器可以证明没有其他初始化代码写入 Proxy::name
,但这是 non-trivial,因为 class Proxy
具有外部链接。因此,即使是 as-if 规则的不断传播和应用也会让您在这里失败。
constexpr
在说服编译器使用常量初始化方面会更好。但是你至少需要声明 Proxy::name
为 const
.
编译以下代码,并检索 .ippalgo 部分,我注意到 name
字段为零,而其他字段符合预期。
$ g++ a.cpp
$ objdump -s -j .ippalgo a.out
a.out: file format elf64-x86-64
Contents of section .ippalgo:
601040 00000000 00000000 02000000 01000000 ................
^^^^^^^^^^^^^^^^^
$ ./a.out
sizeof(char*): 8, sizeof(int): 4
name: 0x400648
name: abcdef
但是在直接使用 "abcdef"
字符串更改 1. 行后,我似乎得到了正确的地址。
$ objdump -s -j .ippalgo a.out
a.out: file format elf64-x86-64
Contents of section .ippalgo:
601040 08064000 00000000 02000000 01000000 ..@.............
^^^^^^^^^^^^^^^^^
$ ./a.out
sizeof(char*): 8, sizeof(int): 4
name: 0x400608
name: abcdef
在任何一种情况下,main 中的最后一个打印都得到了正确的消息 abcdef
。我的问题是为什么我在第一种情况下得到零,如果有问题如何解决?
#include <cstdio>
struct DataInfo {
const char* name;
int id;
int type;
};
class Proxy {
public:
const static char *name;
const static int type;
const static int id;
};
const char* Proxy::name = "abcdef";
const int Proxy::id = 1;
const int Proxy::type = 2;
__attribute__((used, section(".ippalgo")))
DataInfo ProxyInfo = {
Proxy::name, // 1. ok when set "abcdef" directly
Proxy::type,
Proxy::id
};
int main()
{
printf("sizeof(char*): %lu, sizeof(int): %lu\n",
sizeof(char*), sizeof(int));
printf("name: %p\n", Proxy::name);
printf("name: %s\n", ProxyInfo.name);
}
TL;DR Proxy::name
不是 const
。
静态数据的初始化分为常量(包括zero-initialization)和动态初始化两个阶段
在某些条件下,两者可以合并,最终的初始化程序放在二进制文件中,而不是在 main()
之前生成代码来初始化它。
您的编译器在一种情况下选择使用常量初始化,在另一种情况下选择使用动态初始化。这是完全合法的,编译器不需要在二进制文件的任何特定结构中放置常量。
在您的情况下,Proxy::name
不是 const
,而 Proxy::id
和 Proxy::type
可能会影响编译器的选择。它甚至不是 compile-time 常量。也许编译器可以证明没有其他初始化代码写入 Proxy::name
,但这是 non-trivial,因为 class Proxy
具有外部链接。因此,即使是 as-if 规则的不断传播和应用也会让您在这里失败。
constexpr
在说服编译器使用常量初始化方面会更好。但是你至少需要声明 Proxy::name
为 const
.