为什么对象 (ELF) 文件中的 .bss 部分没有内容?
Why is there no content for the .bss section in an object (ELF) file?
这个问题让我很困惑。据我所知, .bss 部分用于保存已初始化但尚未使用的数据。但是我不明白这里的'content'是什么意思,为什么这里没有内容?
感谢您的帮助!
BSS(按符号开始的块)部分没有内容,因为它会浪费存储空间。 BSS 的内容全为零,在调用 main
之前由启动代码清除。将 BSS 视为 run-length 压缩字节块。要解压缩该块,您只需要知道值 (0) 和长度,它存储在 BSS 的 ELF 条目中。
你对"data that [is] initialized but not used yet"的看法有点不对。考虑到 ELF 文件中的 所有 部分都是 "not used yet"。文本段可能会或可能不会被使用(它可能包含 dead/unreachable 代码)。数据段可能会或可能根本不会被使用(您可以定义代码从未使用过的对象)。
快速反应是:好吧,没有内容可以填充 .bss
,因此将任何数据放在与该部分相关的可执行文件中是没有意义的。仅存储变量的位置,但属于另一个 ELF 部分。
.bss
部分是您的程序包含所有未初始化变量的位置(默认情况下全部初始化为零)链接器只需要知道该区域的实际大小和实际变量位置,而不是值,因为它的内容是显而易见的,独立于放在那里的变量的性质或分布。
加载程序时,内核通常会为程序的不可修改文本(.text
部分)分配一个 read-only 段,并将已初始化的 const
变量(.rodata
部分)所以如果你试图修改那里的东西,你会得到一个例外。然后是初始化数据部分,其中包含程序的所有初始化变量(.data
部分)和未初始化变量(.bss
部分)
的初始值
数据段(看我怎么叫a section和load segment)多了space,.data
和.bss
段的总和,来装所有的变量(两者都包含在内,所以这就是它使用其长度的原因)但是 .data
部分的内容必须从文件中填充,而 .bss
部分的内容则不需要,因为在允许用户进程访问分配的段之前,所有这些都由操作系统清零。对于小型系统而言,情况并非如此,操作系统不会用零填充数据......但是在那里,编译器会添加一些代码以将所有 .bss
段置零,因此同样,无需复制任何来自可执行文件的数据。
这种行为的历史(和主要)原因是内核分配的页面必须与您的程序一起加载,出于安全原因被清除为零(因此您不能幸运地获得一个充满其他用户的页面' 密码,或其他敏感信息),所以没有理由再次用零填充它,也没有理由在那里复制任何东西,没有理由在可执行文件上放置任何东西。内核维护的页面通常仅在将要提供给用户时才清零,但会保留(因为它们是为此目的而设计的)信息,直到它们被覆盖。
这个问题让我很困惑。据我所知, .bss 部分用于保存已初始化但尚未使用的数据。但是我不明白这里的'content'是什么意思,为什么这里没有内容?
感谢您的帮助!
BSS(按符号开始的块)部分没有内容,因为它会浪费存储空间。 BSS 的内容全为零,在调用 main
之前由启动代码清除。将 BSS 视为 run-length 压缩字节块。要解压缩该块,您只需要知道值 (0) 和长度,它存储在 BSS 的 ELF 条目中。
你对"data that [is] initialized but not used yet"的看法有点不对。考虑到 ELF 文件中的 所有 部分都是 "not used yet"。文本段可能会或可能不会被使用(它可能包含 dead/unreachable 代码)。数据段可能会或可能根本不会被使用(您可以定义代码从未使用过的对象)。
快速反应是:好吧,没有内容可以填充 .bss
,因此将任何数据放在与该部分相关的可执行文件中是没有意义的。仅存储变量的位置,但属于另一个 ELF 部分。
.bss
部分是您的程序包含所有未初始化变量的位置(默认情况下全部初始化为零)链接器只需要知道该区域的实际大小和实际变量位置,而不是值,因为它的内容是显而易见的,独立于放在那里的变量的性质或分布。
加载程序时,内核通常会为程序的不可修改文本(.text
部分)分配一个 read-only 段,并将已初始化的 const
变量(.rodata
部分)所以如果你试图修改那里的东西,你会得到一个例外。然后是初始化数据部分,其中包含程序的所有初始化变量(.data
部分)和未初始化变量(.bss
部分)
数据段(看我怎么叫a section和load segment)多了space,.data
和.bss
段的总和,来装所有的变量(两者都包含在内,所以这就是它使用其长度的原因)但是 .data
部分的内容必须从文件中填充,而 .bss
部分的内容则不需要,因为在允许用户进程访问分配的段之前,所有这些都由操作系统清零。对于小型系统而言,情况并非如此,操作系统不会用零填充数据......但是在那里,编译器会添加一些代码以将所有 .bss
段置零,因此同样,无需复制任何来自可执行文件的数据。
这种行为的历史(和主要)原因是内核分配的页面必须与您的程序一起加载,出于安全原因被清除为零(因此您不能幸运地获得一个充满其他用户的页面' 密码,或其他敏感信息),所以没有理由再次用零填充它,也没有理由在那里复制任何东西,没有理由在可执行文件上放置任何东西。内核维护的页面通常仅在将要提供给用户时才清零,但会保留(因为它们是为此目的而设计的)信息,直到它们被覆盖。