Assembly nasm中的标签偏移
我试图为x86编写一个简单的引导加载程序,但在理解NASM在组装程序时如何将标签转换为偏移量时遇到了一个问题 (这只是一个示范项目) 我使用Assembly nasm中的标签偏移,assembly,x86,nasm,x86-16,Assembly,X86,Nasm,X86 16,我试图为x86编写一个简单的引导加载程序,但在理解NASM在组装程序时如何将标签转换为偏移量时遇到了一个问题 (这只是一个示范项目) 我使用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时,它使用相对于0x00
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
时,它使用相对于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
NDISAM示例
错误在于您正在为ds
使用0x7c0,从ds
中可以看出,使用该值,代码的原点为零,而不是0x7c0
例如,start
位于原点,对于0x7c00的NASM和mov si,start
组合为mov si,0x7c00
运行时,start
位于线性地址0x07c00,但由于初始化了ds
的方式,指针[ds:si]
指向0x07c0:0x7c00=0x0f800
您可以使用零初始化ds
([ds:si]
将指向0x0000:0x7c00=0x07c00)或将原点设置为零([ds:si]
将指向0x07c0:0x0000=0x07c00)
作为旁注:对于cs
和其他段,您可以使用不同的值,但这是您必须记住并注意的事情,例如,当您移动代码或设置ISR时。
但是,必须初始化所有段寄存器,包括ss:sp
如果这是您第一次使用引导加载程序,我建议您使用与ds相同的cs
无论如何,如果您想尝试不同的值,NASM支持bin
输出格式,这是它支持的最接近分段的东西 该调用
在机器代码中具有相对imm16偏移量+0x0001
,因此它正好指向hlt
之后,并且将工作。顺便说一句,使用farjmp 0000:7C00+
启动引导加载程序代码是一种很好的做法,以确保cs:ip
对此进行“规范化”,因为一些BioSe会以不同的变体启动引导加载程序,如07C0:0000
,因此,通过cs
进行的所有绝对偏移量和寻址在这样的BIOS中都是错误的。问题是我没有完全理解org
指令的作用。因此,源代码和段寄存器之间的不一致…。@Kia.celever很高兴知道问题现在已经解决:)出于好奇,我可以问一下您对ORG指令的错误解释是什么吗?我有时会教这些东西,这会帮助我了解一些常见的陷阱。我不知道org指令中的值实际上应该是相对于当前段的“偏移量”。我认为这是程序将要驻留的绝对(20位宽)物理地址。谢谢@Kia.celever的输入。
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