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 xxxx
intheworld 有什么用?
汇编程序将源代码的每一行转换为处理器指令,并按顺序生成这些指令,一个接一个地,生成输出二进制文件。为此,他维护了一个内部计数器,该计数器从 0 开始计数任何此类指令的当前地址,并向上计数。
如果你正在组装一个普通程序,这些指令将在某个目标文件的代码部分结束,只有地址的空白槽,之后必须由链接器用正确的地址填充,所以这不是问题。
但是,当您组装一个没有任何部分、重定位和其他格式的平面二进制文件时,只有原始机器指令,那么汇编器就没有关于您的标签指示的位置以及数据地址的信息。因此,例如,当您有一条指令时mov si, someLabel
,那么汇编程序只能计算该标签从二进制文件开头的 0 开始的偏移量。也就是说,它假定您的代码将位于从代码段中的偏移量 0 开始的内存中。
如果它不是真的,并且您希望内存中的机器指令从其他地址开始,例如。7C00
,那么你需要告诉汇编程序你的程序的起始地址是7C00
通过写org 0x7C00
在你的源代码的开头。该指令告诉汇编器它应该从而7C00
不是从启动它的内部地址计数器0
。结果是这样一个程序中使用的所有地址都将被移位7C00
。汇编器简单地将7C00
每个标签添加到每个地址中。效果是如果标签是在ADDRES位于内存中,说,7C48
(7C00 + 48
),而不是只0048
(0000 + 48
),不管它从二进制图像文件的开头偏移仅 48 个字节(在偏移量加载7C00
后将给出正确的地址)。
至于你的另一个问题:7C00
是引导加载程序的物理地址。您可以用不同的方式将此物理地址表示为逻辑地址 (segment:offset),因为段重叠(下一个段10
在前一个段之后 16 个字节(十六进制)开始)。例如,您可以使用逻辑地址0000:7C00
,这是最简单的配置:您使用0
从 RAM 开头开始的段,并7C00
从中偏移0
。或者,您可以使用逻辑地址07C0:0000
,也就是7C0
第一个段。还记得段开始时彼此相隔 16 个字节吗?所以,你只需乘以这个7C0
由10
(16
十进制),你会得到7C00
- 看?这是在你的十六进制地址中向右移动一个位置的问题!:-) 现在您只需添加偏移量,这是0
这次,所以它仍然是7C00
物理上的。在内存中开始的0
段07C0
中的字节7C00
。
当然,您也可以使用更复杂的地址,例如,0234:58C0
,这意味着该段开始于2340
,当您向其添加58C0
偏移量时,您将7C00
再次获得:-) 但这样做可能会令人困惑。这完全取决于您需要什么配置。如果您想将7C00
物理地址视为段的开头,只需使用 segment07C0
并且您的第一条指令将在 offset 处0
,因此您不需要 putorg
指令,或者您可以 put org 0
then 。但是如果你需要读/写7C00
地址下面的一些数据(例如,偷看 BIOS 数据或摆弄中断向量),那么使用段0
和偏移量7C00
这意味着您的第一条指令(二进制文件中的第 0 个字节)将位于7C00
内存中的物理地址;那么您必须org 0x7C00
根据上述原因添加指令。
归档时间: |
|
查看次数: |
3464 次 |
最近记录: |