为什么全局和静态对象存放在bss的section中
Why are global and static objects stored in the section of bss
我正在研究二进制文件的各个部分。我使用了下面的 C++ 代码:
// test.cpp
struct Test {
int i;
Test(int ii) : i(ii) {}
Test() {}
};
Test t0{5};
Test t1 = Test(5);
Test t2;
static Test t3;
static Test t4{5};
int i = 1;
int j;
static int k;
static int l = 1;
int main() {
return 0;
}
我用命令 g++ test.cpp
编译了这段代码并得到了一个名为 a.out
.
的二进制文件
然后,我使用命令objdump
提取了bss
和data
的部分。
objdump -dj .data a.out
的输出:
a.out: file format elf64-x86-64
Disassembly of section .data:
0000000000201000 <__data_start>:
...
0000000000201008 <__dso_handle>:
201008: 08 10 20 00 00 00 00 00 .. .....
0000000000201010 <i>:
201010: 01 00 00 00 ....
0000000000201014 <_ZL1l>:
201014: 01 00 00 00 ....
objdump -dj .bss a.out
的输出:
a.out: file format elf64-x86-64
Disassembly of section .bss:
0000000000201018 <__bss_start>:
201018: 00 00 add %al,(%rax)
...
000000000020101c <t0>:
20101c: 00 00 00 00 ....
0000000000201020 <t1>:
201020: 00 00 00 00 ....
0000000000201024 <t2>:
201024: 00 00 00 00 ....
0000000000201028 <j>:
201028: 00 00 00 00 ....
000000000020102c <_ZStL8__ioinit>:
20102c: 00 00 00 00 ....
0000000000201030 <_ZL2t3>:
201030: 00 00 00 00 ....
0000000000201034 <_ZL2t4>:
201034: 00 00 00 00 ....
0000000000201038 <_ZL1k>:
...
因此,变量 i
和 l
存储在 .data
部分中,因为它们已被初始化。变量 j
和 k
位于 .bss
部分,因为它们没有被初始化。我能理解。
但为什么 Test
的所有对象都在 .bss
部分,即使那些已初始化的对象?我认为 t0
、t1
和 t4
应该存储在 .data
部分,但显然我错了。
.data
仅用于用文字数据初始化的变量。
Test
对象使用构造方法初始化。所以内存分配在bss
,然后在启动时调用构造函数填充内容。
扩展已接受的答案:有多种方法可以改变这种行为。已经在很多地方讨论过,例如:
Guaranteeing static (constant) initialization of static objects
这是我的测试:
struct Test1 {
int a;
};
struct Test2 {
Test2(const int pa) : a(pa) {}
int a;
};
struct Test3 {
constexpr Test3(const int pa) : a(pa) {}
Test3(double d) : a((int)d) {}
int a;
};
struct Test4 {
int a {0x12345604};
};
Test1 s_test1 { 0x12345601 };//Object is placed directly in .data. No constructor executed.
Test2 s_test2 { 0x12345602 };//Object is placed .bss, initialization value is in .rodata and constructor is executed during initialization
Test3 s_test3_1 { 0x12345603 };//Object is placed directly in .data. No constructor executed.
Test3 s_test3_2 { 0.0 };//Object is placed .bss, init data is in .rodata and constructor is executed during initialization
Test4 s_test4;//Object is placed directly in .data. No constructor executed.
(我用g++ (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0和arm-none-eabi-g++ (15:6.3.1+svn253039-1build1)验证6.3.1 20170620)
因此,如果您有一个非常大的静态对象,请确保通过 constexpr 构造函数对其进行初始化,以避免内存消耗加倍和构造函数调用缓慢。
我正在研究二进制文件的各个部分。我使用了下面的 C++ 代码:
// test.cpp
struct Test {
int i;
Test(int ii) : i(ii) {}
Test() {}
};
Test t0{5};
Test t1 = Test(5);
Test t2;
static Test t3;
static Test t4{5};
int i = 1;
int j;
static int k;
static int l = 1;
int main() {
return 0;
}
我用命令 g++ test.cpp
编译了这段代码并得到了一个名为 a.out
.
然后,我使用命令objdump
提取了bss
和data
的部分。
objdump -dj .data a.out
的输出:
a.out: file format elf64-x86-64
Disassembly of section .data:
0000000000201000 <__data_start>:
...
0000000000201008 <__dso_handle>:
201008: 08 10 20 00 00 00 00 00 .. .....
0000000000201010 <i>:
201010: 01 00 00 00 ....
0000000000201014 <_ZL1l>:
201014: 01 00 00 00 ....
objdump -dj .bss a.out
的输出:
a.out: file format elf64-x86-64
Disassembly of section .bss:
0000000000201018 <__bss_start>:
201018: 00 00 add %al,(%rax)
...
000000000020101c <t0>:
20101c: 00 00 00 00 ....
0000000000201020 <t1>:
201020: 00 00 00 00 ....
0000000000201024 <t2>:
201024: 00 00 00 00 ....
0000000000201028 <j>:
201028: 00 00 00 00 ....
000000000020102c <_ZStL8__ioinit>:
20102c: 00 00 00 00 ....
0000000000201030 <_ZL2t3>:
201030: 00 00 00 00 ....
0000000000201034 <_ZL2t4>:
201034: 00 00 00 00 ....
0000000000201038 <_ZL1k>:
...
因此,变量 i
和 l
存储在 .data
部分中,因为它们已被初始化。变量 j
和 k
位于 .bss
部分,因为它们没有被初始化。我能理解。
但为什么 Test
的所有对象都在 .bss
部分,即使那些已初始化的对象?我认为 t0
、t1
和 t4
应该存储在 .data
部分,但显然我错了。
.data
仅用于用文字数据初始化的变量。
Test
对象使用构造方法初始化。所以内存分配在bss
,然后在启动时调用构造函数填充内容。
扩展已接受的答案:有多种方法可以改变这种行为。已经在很多地方讨论过,例如: Guaranteeing static (constant) initialization of static objects
这是我的测试:
struct Test1 {
int a;
};
struct Test2 {
Test2(const int pa) : a(pa) {}
int a;
};
struct Test3 {
constexpr Test3(const int pa) : a(pa) {}
Test3(double d) : a((int)d) {}
int a;
};
struct Test4 {
int a {0x12345604};
};
Test1 s_test1 { 0x12345601 };//Object is placed directly in .data. No constructor executed.
Test2 s_test2 { 0x12345602 };//Object is placed .bss, initialization value is in .rodata and constructor is executed during initialization
Test3 s_test3_1 { 0x12345603 };//Object is placed directly in .data. No constructor executed.
Test3 s_test3_2 { 0.0 };//Object is placed .bss, init data is in .rodata and constructor is executed during initialization
Test4 s_test4;//Object is placed directly in .data. No constructor executed.
(我用g++ (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0和arm-none-eabi-g++ (15:6.3.1+svn253039-1build1)验证6.3.1 20170620)
因此,如果您有一个非常大的静态对象,请确保通过 constexpr 构造函数对其进行初始化,以避免内存消耗加倍和构造函数调用缓慢。