为什么全局和静态对象存放在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提取了bssdata的部分。

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>:
        ...

因此,变量 il 存储在 .data 部分中,因为它们已被初始化。变量 jk 位于 .bss 部分,因为它们没有被初始化。我能理解。

但为什么 Test 的所有对象都在 .bss 部分,即使那些已初始化的对象?我认为 t0t1t4 应该存储在 .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 构造函数对其进行初始化,以避免内存消耗加倍和构造函数调用缓慢。