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, msg
和call print
对应的行被翻译成了:
mov si,0x7c0d
call 0xc
所以当 NASM 将 mov si, msg
中的 msg
替换为偏移值时,它使用相对于 0x0000
的绝对偏移,但是当它转换 print
时call 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
输出格式,这是它支持的最接近分段的格式。
我正在尝试为 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, msg
和call print
对应的行被翻译成了:
mov si,0x7c0d
call 0xc
所以当 NASM 将 mov si, msg
中的 msg
替换为偏移值时,它使用相对于 0x0000
的绝对偏移,但是当它转换 print
时call 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
输出格式,这是它支持的最接近分段的格式。