我正在学习一些简单的 x86 引导加载程序代码,并且在理解汇编程序(在我的例子中为 nasm)如何计算标签的偏移量方面遇到一些困难。
据我了解,像下面的
letter
这样的数据标签表示数据段中后续字节的偏移量。 据我了解,在像 mov al, [letter]
这样的指令中,标签被隐式解释为 ds:letter
。 这意味着汇编器需要知道数据段内label
的偏移量才能引用正确的地址。
我不明白的是汇编器如何计算这个偏移量。 要计算出偏移量,需要知道数据段的起始位置。 但它不知道这一点,因为它在组装阶段不知道
ds
的值。 那么偏移量是如何计算的呢?
[org 0x7c00]
bits 16
; initialise data segment register
mov ax, 0
mov ds, ax
; print letter
mov al, [letter]
mov ah, 0x0e
int 0x10
end:
jmp $
; data label
letter:
db 'A'
times 510 - ($ - $$) db 0
db 0x55, 0xaa
此代码按预期打印字母 A。 但我注意到,如果我将
ds
更改为其他值(例如 10),它不会打印任何内容。 很明显,汇编器正在独立于 ds
的值计算偏移量(因此不能保证 ds:letter
会到达正确的地址)——我只是不知道它是如何计算的。
在用户 ecm 和 rcgldr 的帮助下,我已经找到了困惑的根源,因此我将在下面总结我的问题的答案,以防其他人有同样的困惑。
我的错误是认为段寄存器定义了段开始的位置,因此汇编器在计算偏移量之前需要知道段寄存器的值。
这在技术上并不准确。 当我们编写程序时,我们需要对我们希望段开始的位置以及程序的字节相对于这些段的开头应该驻留在哪里有一些计划。 也就是说,在程序中分配段寄存器和偏移量之前,我们应该已经知道段和程序布局。
因此,我们分配的偏移量并不依赖于我们分配给段寄存器的值,而是,我们分配的偏移量和我们给段寄存器的值都取决于我们已经制定的段布局计划拟定的。 我们需要为这两个值提供正确的值,以便实施我们的计划并允许处理器到达我们想要的地址。 我们分配给段寄存器以获取正确的段起始地址,并使用
org
和 section
等各种指令分配偏移量以获取正确的段内字节的位置。