nasm 中的标签偏移量

Label offsets in nasm

我正在尝试为 x86 编写一个简单的引导加载程序,但我在理解 NASM 汇编程序时如何将标签转换为偏移量方面遇到了问题。

(这只是一个演示程序)

bits 16
org 0x7C00

start:
    mov ax, 0x07C0
    mov ds, ax
    mov si, msg
    call print
    hlt

print:
    ; print char array stored in [ds:si]
    ret

msg db 'hello!'

我用 nasm -f bin 命令组装了代码。但它没有按预期工作。我在二进制输出上使用了objdump -b binary -m i8086 -M intel -D,发现mov si, msgcall print对应的行被翻译成了:

mov    si,0x7c0d
call   0xc

所以当 NASM 将 mov si, msg 中的 msg 替换为偏移值时,它使用相对于 0x0000 的绝对偏移,但是当它转换 printcall print 偏移它使用相对于 cs 的偏移量,即 0x07C0。所以当我尝试打印字符时 [ds:si] 没有指向预期的位置。问题是为什么?如果我做错了,正确的方法是什么?

这是反汇编程序的产物:它将相对位移转换为绝对地址。
如果您将 0x7c00 作为原点传递给它,它将显示正确的值。

c:\>ndisasm -b 16 -o 7c00h a
00007C00  B8C007            mov ax,0x7c0
00007C03  8ED8              mov ds,ax
00007C05  BE0D7C            mov si,0x7c0d
00007C08  E80100            call word 0x7c0c
00007C0B  F4                hlt
00007C0C  C3                ret

ndisasm 示例

错误是您正在为 ds 使用 0x7c0,从 ds 可以看出,您的代码的原始值是零而不是 0x7c00。

比如start在原点,对于NASM就是0x7c00,一个mov si, start拼装成mov si, 0x7c00
在运行时 start 位于 线性地址 0x07c00 但指针 [ds:si] 指向 0x07c0:0x7c00 = 0x0f800 由于 ds 的方式被初始化。

您可以将 ds 初始化为零([ds:si] 将指向 0x0000:0x7c00 = 0x07c00)或将原点设置为零([ds:si] 将指向 0x07c0:0x0000 = 0x07c00)。

附带说明:您可以为 cs 和其他段使用不同的值,但这是您必须记住并注意的事情,例如,您移动代码或设置ISR.
但是,你必须初始化所有的段寄存器,包括ss:sp.
如果这是您第一次尝试使用引导加载程序,我建议您将 cs 设置为与 ds 相同。
无论如何,如果您想尝试不同的值,NASM 支持 Multi-sections 作为 bin 输出格式,这是它支持的最接近分段的格式。