【问题标题】:Why does aligning a .bss variable cause a massive increase in binary size?为什么对齐 .bss 变量会导致二进制大小大幅增加?
【发布时间】:2016-07-30 02:59:15
【问题描述】:

这会分配一些 BSS 变量:

.lcomm page_table_l2, 4096
.lcomm page_table_l3, 4096
.lcomm page_table_l4, 4096

我正在构建的二进制文件最终为 4792 字节,因此您可以看到没有直接包含 BSS 变量(或者二进制文件将 >12 KiB)。

但是,这三个需要 4 KiB 对齐,所以我将部分更改为:

.section .bss
.align 4096
.lcomm page_table_l2, 4096
.lcomm page_table_l3, 4096
.lcomm page_table_l4, 4096

...二进制文件增长到 8760!鉴于 BSS 应该只是 ELF 二进制文件中的一个注释,对链接器说,嘿,分配 n 个字节的归零存储,为什么对齐 BSS 变量会导致二进制?

您也可以在 C 中看到这一点:

char x[4096] __attribute__ ((aligned (8192))) = {0};

如果您改变对齐方式,输出对象文件的大小也会随之变化。 (尽管在我最初的示例中,我正在查看最终二进制文件的大小。)

请注意,此输出二进制文件是操作系统内核;我正在关注教程here。我正在使用以下链接器脚本:

ENTRY(start)

SECTIONS {
    . = 1M;

    .boot ALIGN(8) : AT(ADDR(.boot))
    {
        /* ensure that the multiboot header is at the beginning */
        KEEP( *(.multiboot_header) )
    }

    .text :
    {
        *(.text)
    }
}

根据objdump,看起来整个程序在精灵本身中对齐了4 KiB,这有点奇怪。

没有.align

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .boot         00000018  0000000000100000  0000000000100000  00000078  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA

.align:

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .boot         00000018  0000000000100000  0000000000100000  00001000  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA

注意File off,或文件中节的偏移量。为什么会改变?

【问题讨论】:

  • 你用什么命令构建? gcc -nostdlib?制作一个普通的 ELF 二进制文件?另外,我不知道多重引导内核有 text/data/bss 段;这很漂亮。您正在学习的教程使用的是 NASM,因此不难想象 gas 的工作方式略有不同。对齐 BSS 中的内容。无论如何,将其设为minimal reproducible example 只需要多几行命令和注释,说明哪个代码块放在哪个文件名中,对吧?这很有趣,让我想尝试一下,但还不足以猜测你到底做了什么:P
  • @MichaelPetch:是的,我同意很明显这是一个 ELF 二进制文件。我只是不太了解制作多重引导内核映像,不知道您为此做的任何特别的事情是否相关,或者您在创建.o 或普通 Linux 可执行文件时是否期望相同的行为。我并不怀疑 GRUB 的多重引导加载程序会将 BSS 归零,我只是说直到我刚刚读到它才知道它受支持。 :P

标签: assembly linker elf memory-alignment


【解决方案1】:

我对此进行了一些测试(只是这段代码和一个 _start 进行 exit_group 系统调用),使用 gcc -cgcc -nostdlib 构建。

似乎.o 的大小随着.S 中使用的最大对齐方式缩放。 ELF 文件中有零字节。 (以 hexdump 为例)。

但是,链接的二进制文件似乎没有任何额外的填充。所以链接后就不是问题了,只是为了构建过程中临时文件的空间消耗。


使用.space 将零字节组装到.bss 中得到的结果与使用.lcomm 在.bss 中分配空间而不切换到它时得到的结果相同。

.section .bss
    .balign 4096                # .balign or .p2align are preferable, to avoid ambiguity between power-of-2 or exponent

page_table_l2:  .space 4096
.balign 1024
page_table_l3:  .space 4096
page_table_l4:  .space 4096
foo:     .space 17
    .balign 4096              # This doesn't make the .o any bigger if a .align 4096 is already present
bar:    .space 1

#   .lcomm page_table_l2, 4096
#   .lcomm page_table_l3, 4096
#   .lcomm page_table_l4, 4096


    .text
.global _start
_start:
    xor %edi, %edi

    mov $231, %eax  #  exit_group(0)
    syscall

# the .o is big
$ gcc -c align-bss.S  && ll align-bss.o && objdump -haf align-bss.o
-rw-rw-r-- 1 peter peter 4.8K Jul 30 11:05 align-bss.o
...
Idx Name          Size      VMA               LMA               File off  Algn
...
  2 .bss          00004001  0000000000000000  0000000000000000  00001000  2**12

# the binary doesn't care
$ gcc -nostdlib align-bss.S -o align-bss  && ll align-bss && objdump -haf align-bss
-rwxrwxr-x 1 peter peter 1.2K Jul 30 11:08 align-bss
  ...
Idx Name          Size      VMA               LMA               File off  Algn
 ...
  2 .bss          00004008  0000000000601000  0000000000601000  00001000  2**12

注释了.balign 指令后,.o 为 872B,链接的静态二进制文件仍为 1.2k(未剥离)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-02
    • 1970-01-01
    • 2016-10-23
    • 2013-02-05
    • 2021-05-27
    相关资源
    最近更新 更多