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
以下是我想到的几种可能性:
resb
只是在二进制 末尾分配了一些未使用的space
- 它根本不起作用,而且东西爆炸了。
由于.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 区域的范围,以便在我们的代码开始执行时将其初始化为零。
我看到一段 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
以下是我想到的几种可能性:
resb
只是在二进制 末尾分配了一些未使用的space
- 它根本不起作用,而且东西爆炸了。
由于.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 区域的范围,以便在我们的代码开始执行时将其初始化为零。