计算机系统篇之链接(10):.bss、.data 和 .rodata sections 之间的区别

Author: stormQ

Created: Friday, 08. May 2020 10:20PM

Last Modified: Thursday, 05. November 2020 11:02PM



摘要

本文通过示例剖析了.bss.data.rodatasections 之间的区别。

验证过程

Section 名称 区别1:用途不同 区别2:在目标文件中占用的空间不同
.rodata 用于维护只读数据,比如:常量字符串、带 const 修饰的全局变量和静态变量等 在目标文件中占用空间
.data 用于维护初始化的且初始值非0的全局变量和静态变量(不带 const 修饰) 在目标文件中占用空间
.bss 用于维护未初始化的或初始值为0的全局变量和静态变量(不带 const 修饰) 不占用目标文件的空间

注:

区别 1 和区别 2 的验证过程:

# 查看 sum.cpp
$ cat sum.cpp 
int sum(int a, int b)
{
  static int val_1;
  static int val_2 = 0;
  static int val_3 = 1;
  static int val_4 = 0;
  static int val_5 = 2;
  const static int val_6 = 0;
  return a + b;
}
# 生成可重定位目标文件 sum.o
$ g++ -c sum.cpp -o sum.o
# 查看 sum.o 的 sections
$ readelf -S sum.o
There are 12 section headers, starting at offset 0x340:

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .text             PROGBITS         0000000000000000  00000040
       0000000000000014  0000000000000000  AX       0     0     1
  [ 2] .data             PROGBITS         0000000000000000  00000054
       0000000000000008  0000000000000000  WA       0     0     4
  [ 3] .bss              NOBITS           0000000000000000  0000005c
       000000000000000c  0000000000000000  WA       0     0     4
  [ 4] .rodata           PROGBITS         0000000000000000  0000005c
       0000000000000004  0000000000000000   A       0     0     4
  [ 5] .comment          PROGBITS         0000000000000000  00000060
       0000000000000033  0000000000000001  MS       0     0     1
  [ 6] .note.GNU-stack   PROGBITS         0000000000000000  00000093
       0000000000000000  0000000000000000           0     0     1
  [ 7] .eh_frame         PROGBITS         0000000000000000  00000098
       0000000000000038  0000000000000000   A       0     0     8
  [ 8] .rela.eh_frame    RELA             0000000000000000  000002c8
       0000000000000018  0000000000000018   I      10     7     8
  [ 9] .shstrtab         STRTAB           0000000000000000  000002e0
       000000000000005c  0000000000000000           0     0     1
  [10] .symtab           SYMTAB           0000000000000000  000000d0
       0000000000000180  0000000000000018          11    15     8
  [11] .strtab           STRTAB           0000000000000000  00000250
       0000000000000078  0000000000000000           0     0     1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), l (large)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

从上面的 sum.o 的 sections 信息,可以看出:

1).data的大小为 8(Size 列的值为 0000000000000008),在目标文件中占用 8 字节(00000054~0000005c);

2).bss的大小为 12(Size 列的值为 000000000000000c),在目标文件中占用 0 字节(.bss在目标文件中的偏移量为 0000005c,.bss下一个 section——comment在目标文件中的偏移量为 0000005c)。因此,可以得出结论:.bss不占用目标文件的空间。

3).rodata的大小为 4(Size 列的值为 0000000000000004),在目标文件中占用 4 字节(0000005c~00000060)。从而,验证了"区别2:在目标文件中占用的空间不同"

4)sum.cpp 中初始化的且初始值非0的变量(不带 const 修饰)有两个:val_3、val_5,占用 8 字节,与.data的大小一致;未初始化的或初始值为0的变量(不带 const 修饰)有三个:val_1、val_2、val_4,占用 12 字节,与.bss的大小一致;带 const 修饰的全局变量和静态变量有一个:val_6,占用 4 字节,与.rodata的大小一致。从而,验证了"区别1:用途不同"

最后,可以总结出对于 C++ 程序中一个全局变量或静态变量到底存放在.rodata.data.bss中哪一个 section 的判断规则为:首先判断全局变量或静态变量是否带 const 修饰。如果带 const 修饰, 无论初始值是否为0,都会存放到.rodatasection 中;否则,判断是否已初始化且初始值是否为0。如果已初始化且初始值非0,则存放到.datasection 中;否则,存放到.bsssection 中。


下一篇:计算机系统篇之链接(11):为什么要避免在 C 和 C++ 中使用全局变量

上一篇:计算机系统篇之链接(9):位置无关代码(下)——真正理解 PIC 函数调用的工作原理(Linux X86-64 示例)

首页