NASM的resb以二进制输出格式做什么?

What does NASM's resb do in binary output format?

我看到一段 NASM 使用 resb 的代码。但是,此代码在实模式操作系统中运行,输出格式为平面二进制。 NASM 这样做并没有报错,但在剖析输出文件后,我仍然找不到实际发生的事情。

bits 16
org 0x8000

start:
    mov ax, msg
    call os_input_string
    mov si, msg
    call os_print_string
    ret

section .bss
msg: resb 256

以下是我想到的几种可能性:

由于.bss 部分从来没有任何初始化数据(设置为nobits),因此不需要将其写入文件。当使用平面二进制格式时,NASM 只会为变量计算一个合适的指针,仅此而已。

通过反汇编代码,您可以很容易地看到发生了什么。我编译了这段代码:

bits 16
org 0x8000

start:
    mov ax, msg
    ret

section .bss
msg: resb 256

当运行通过ndisasm生成的二进制文件:

00000000  B80480            mov ax,0x8004
00000003  C3                ret

所以你可以清楚地看到NASM写了四个字节的代码,并确定.bss段可以放在后面,从位置0x8004开始。所以二进制文件中没有分配任何内容,只有指针是根据 .bss 中所需的分配计算的。

这当然是说明书上写的。 resb reserves uninitialized storage in the .bss section. Furthermore, bin files have limited section support,特别是:

Sections may be designated progbits or nobits. Default is progbits (except .bss, which defaults to nobits, of course). The .bss section will be placed after the last progbits section, unless start=, vstart=, follows=, or vfollows= has been specified.

因此,“resb 只是在二进制 的末尾分配一些未使用的 space” 基本上就是这样。不确定为什么在剖析输出文件时看不到这一点。

NASM 生成二进制 -f bin 时,它遵循一些关于节的基本规则。 NASM manual 表示:

7.1.3 Multisection Support for the bin Format

[snip]

  • The .bss section will be placed after the last progbits section, unless start=, vstart=, follows=, or vfollows= has been specified.

progbits 是一个标志,表示一个部分将实际出现在文件中(.text.data 部分的默认设置)。 .bss 默认为 nobits 这意味着该部分中保留的数据不会实际出现在文件中,但是 nobits 标记部分中的任何标签地址将解析(默认)为刚刚过去的最后 progbits.text.data 等)部分的内存。二进制文件中的BSS区域未初始化为零。它将是内存中的任何内容,因此请考虑该区域包含垃圾。如果您需要一个二进制程序来将该区域初始化为零,您将不得不在程序开始执行后自行完成。

您的问题中有迹象表明您正在创建引导加载程序的第二阶段。我将提供一个代码示例,它将 BSS 区域初始化为零。此代码假定第二阶段加载于 0x0000:0x8000 :

bits 16
org 0x8000

section .text
start:
    ; Initialize the entire BSS area to zero
    ; Assume we are the second stage of a bootloader at 0x0000:0x8000
    mov cx, _bss_end-_bss_start    ; Length of region in CX
    xor ax, ax                     ; AX=0 (also used for rep stos)
    mov es, ax
    mov ds, ax                     ; DS=ES=0x0000
    mov di, _bss_start             ; Offset of BSS region 
    rep stosb                      ; Set CX bytes of data at ES:[DI] to AL(0)

    mov ax, msg
    mov si, msg2

    ; Put second stage in halt state indefinitely.
    cli
.endloop:
    hlt
    jmp .endloop

section .bss
_bss_start:      ; Label for start of BSS
msg: resb 256
msg2: resb 10
_bss_end:        ; Label at end of BSS

虽然 BSS 的内存不是磁盘上二进制文件的一部分,但该区域中的数据标签解析为实际偏移量。你可以标记BSS区域的开始和结束,在这种情况下我使用_bss_start_bss_end。这些标签用于确定 BSS 区域的范围,以便在我们的代码开始执行时将其初始化为零。