汇编中“org xxxx”的用途是什么

Sea*_*ene 4 boot x86 assembly operating-system pc

最近我在学习如何编写引导扇区,这是我正在学习的完整代码:

org 07c00h
    mov ax, cs
    mov ds, ax
    mov es, ax
    call DispStr
    jmp $

DispStr:
    mov ax, BootMessage
    mov bp, ax
    mov cx, 16
    mov ax, 01301h
    mov bx, 000ch
    mov dl, 0
    int 10h
    ret

BootMessage: db "Hello, OS!"
times 510-($-$$) db 0

dw 0xaa55
Run Code Online (Sandbox Code Playgroud)

如果您知道如何启动系统,这是一个非常简单的代码。结果Hello OS!屏幕上显示一行,唯一不知道的就是第一行:org 07c00h,书上告诉我这行代码让编译器把地址定位到7c00h的地方,但是解释的很含糊,我真的不知道这里有什么用。这条线org 07c00h在这里做什么?我试图删除该行,并使用 nasm 创建一个bin文件,然后使用 bochs 来启动 bin 文件。与上一个没有什么不同:“你好 OS!” 也显示在屏幕上。我可以说第一行在这里什么都不做吗?org xxxxintheworld 有什么用?

Sas*_*asQ 5

汇编程序将源代码的每一行转换为处理器指令,并按顺序生成这些指令,一个接一个地,生成输出二进制文件。为此,他维护了一个内部计数器,该计数器从 0 开始计数任何此类指令的当前地址,并向上计数。

如果你正在组装一个普通程序,这些指令将在某个目标文件的代码部分结束,只有地址的空白槽,之后必须由链接器用正确的地址填充,所以这不是问题。

但是,当您组装一个没有任何部分、重定位和其他格式的平面二进制文件时,只有原始机器指令,那么汇编器就没有关于您的标签指示的位置以及数据地址的信息。因此,例如,当您有一条指令时mov si, someLabel,那么汇编程序只能计算该标签从二进制文件开头的 0 开始的偏移量。也就是说,它假定您的代码将位于从代码段中的偏移量 0 开始的内存中。

如果它不是真的,并且您希望内存中的机器指令从其他地址开始,例如。7C00,那么你需要告诉汇编程序你的程序的起始地址是7C00通过写org 0x7C00在你的源代码的开头。该指令告诉汇编器它应该从而7C00不是从启动它的内部地址计数器0。结果是这样一个程序中使用的所有地址都将被移位7C00。汇编器简单地将7C00每个标签添加到每个地址中。效果是如果标签是在ADDRES位于内存中,说,7C487C00 + 48),而不是只00480000 + 48),不管它从二进制图像文件的开头偏移仅 48 个字节(在偏移量加载7C00后将给出正确的地址)。

至于你的另一个问题:7C00是引导加载程序的物理地址。您可以用不同的方式将此物理地址表示为逻辑地址 (segment:offset),因为段重叠(下一个段10在前一个段之后 16 个字节(十六进制)开始)。例如,您可以使用逻辑地址0000:7C00,这是最简单的配置:您使用0从 RAM 开头开始的段,并7C00从中偏移0。或者,您可以使用逻辑地址07C0:0000,也就是7C0第一个段。还记得段开始时彼此相隔 16 个字节吗?所以,你只需乘以这个7C01016十进制),你会得到7C00 - 看?这是在你的十六进制地址中向右移动一个位置的问题!:-) 现在您只需添加偏移量,这是0这次,所以它仍然是7C00物理上的。在内存中开始的007C0中的字节7C00

当然,您也可以使用更复杂的地址,例如,0234:58C0,这意味着该段开始于2340,当您向其添加58C0偏移量时,您将7C00再次获得:-) 但这样做可能会令人困惑。这完全取决于您需要什么配置。如果您想将7C00物理地址视为段的开头,只需使用 segment07C0并且您的第一条指令将在 offset 处0,因此您不需要 putorg指令,或者您可以 put org 0then 。但是如果你需要读/写7C00地址下面的一些数据(例如,偷看 BIOS 数据或摆弄中断向量),那么使用段0和偏移量7C00这意味着您的第一条指令(二进制文件中的第 0 个字节)将位于7C00内存中的物理地址;那么您必须org 0x7C00根据上述原因添加指令。