我正在尝试为x86编写一个简单的bootloader,我在理解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用msg
替换mov si, msg
中的0x0000
时,它会使用相对于print
的绝对偏移量,但是当它将call print
转换为cs
时offset它使用相对于0x07C0
的偏移量[ds:si]
。因此,当我尝试打印字符{{1}}时,未指向预期的位置。问题是为什么?如果我做错了,这样做的正确方法是什么?
答案 0 :(得分:3)
这是反汇编程序的人工制品:它将相对位移转换为绝对地址。
如果您将0x7c00作为原点传递它将显示正确的值。
for (int j = 0; j < 9; j++)
{
outcome = 1;
for (int i = 0; i < 9; i++)
outcome *= list[i];
outcome = outcome / list[j];
Console.WriteLine(outcome);
}
ndisasm例子
错误是你使用0x7c0作为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
,这个值是代码的来源,如ds
所示,是零而不是0x7c00。
例如,ds
位于原点,NASM为0x7c00,start
汇编为mov si, start
。
在运行时mov si, 0x7c00
位于线性地址 0x07c00,但由于start
已初始化的方式,指针[ds:si]
指向0x07c0:0x7c00 = 0x0f800。
您可以使用零初始化ds
(ds
将指向0x0000:0x7c00 = 0x07c00)或将原点设置为零([ds:si]
将指向0x07c0:0x0000 = 0x07c00) 。
作为旁注:您可以使用[ds:si]
和其他细分受众群的不同值做得很好,但这是您必须记住的事项,并且在您移动代码或设置ISR
但是,您必须初始化所有段寄存器,包括cs
如果这是您第一次尝试使用引导加载程序,我建议ss:sp
与cs
相同。
无论如何,如果你想尝试不同的值,NASM支持ds
输出格式的Multi-sections,这是它支持的最接近分割的东西。