如何通过汇编得出一个结论,即某个位在内存中的特定位置?

问题描述

因此,我正在使用在网上找到的PDF构建一个小型操作系统。到目前为止,我在该项目上取得了不错的进展,但是pdf已经达到了一个概念,并不能很好地解释它。

为读者提供了四个示例,将字符串存储在寄存器中以进行打印。 第四个例子是令人困惑的地方。使用下面的图3.6,我们发现字符串与位“ 1e”处的偏移量相距30个字节。

现在,我了解了为什么我们位于0x7cXX,因为它是引导扇区的偏移量。我不明白的是,我们怎么知道它的最后2位是1e。

我认为答案是:好吧,我们将偏移量0x0e存储到ah寄存器中,对吗? 中断命令是0x10,这是ah的低位。事实是,这并不能真正解释为什么对图3.6中的程序的二进制版本进行如此大范围的更改,而我是凭直觉而不是任何明显的逻辑得出的。

为什么我们知道字符串变量位于0x7c1e?

mov ah,0x0e ; int 10/ ah = 0eh -> scrolling teletype BIOS routine

mov al,[0x7c1e ]
int 0 x10 ; Does this print an X?
jmp $ ; Jump forever.

the_secret :
db "X "

; Padding and magic BIOS number.
times 510 -( $ - $$ ) db 0
dw 0 xaa55

图3.6

```00 7 c 8a 07 cd 10 a0 1e 7c cd 10 e9 fd ff 58 00
```00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
```*
```00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa

解决方法

使用标签是执行此操作的正确方法,如注释中所建议。您还必须告诉汇编程序您的原点(org)发出正确的地址。此外,您应该初始化数据段(ds)寄存器,因为您的内存加载隐式使用了它。

我假设您正在使用NASM,因为times指令是NASMism。要修复您的代码并使用标签,您应该像这样:

org 7C00h

xor ax,ax ; set ax to zero (well-known zeroing idiom)
mov ds,ax ; set ds base to zero
mov ah,0x0E ; int 10/ ah = 0eh -> scrolling teletype BIOS routine
mov al,byte [the_secret]
int 0x10 ; This prints an 'X'
jmp $ ; Jump forever.

the_secret:
db "X "

; Padding and magic BIOS number.
times 510 - ($ - $$) db 0
dw 0xAA55

将其组合为NASM的完整源会导致从地址7C0Dh的字节加载。回到您的问题:我们怎么知道最后两个半字节(8位,2个十六进制数字)是任何特定值?

我们可以计算前面指令的大小,在这种情况下,这6条指令中的每条指令的大小为2个字节,但要载入al的字节为3个字节。那就是2 * 5 + 3 = 13 = 0Dh。但是,只要更改前面的代码,就必须重新计算地址。

这正是我们使用汇编程序的任务,而不仅仅是为所有内容输入数字值。输入的数字将是指令的机器代码字节,以及参考的相对或绝对地址。使用助记符指令,汇编器可以确定要发出的机器代码。使用标签,汇编器可以将引用计算为数字地址。

只有非常有限的汇编器不允许使用符号引用。如果您发现自己使用的是86-DOS调试器之一,则可能会将您限制为显式数字地址。但是,您不应将它们用于非常规组装。

最后,使用标签让汇编器完成工作。