在 ORG 指令后设置段寄存器
Setting segment registers after ORG instruction
我目前正在关注 a tutorial on OS development,其中包括关于引导加载程序的讨论。
我的引导加载程序目前处于 16 位实模式,因此,我可以使用提供的 BIOS 中断(例如 VGA 视频中断等)。
BIOS 提供了视频中断0x10
(即视频电传输出)。视频中断有函数0x0E
,它允许我在屏幕上打印一个字符。
这是基本的引导加载程序:
org 0x7c00 ; Set program start (origin) address location at 0x7c00.
; This program is loaded by the BIOS at 0x7c00.
bits 16 ; We live in 16-bit Real Mode.
start:
jmp loader
bootmsg db "Welcome to my Operating System!", 0 ; My data string.
;-------------------------------------------------------
; Description: Print a null terminating string
;-------------------------------------------------------
print:
lodsb ; Load string byte at address DS:SI and place in AL.
; Then, increment/decrement SI as defined by the Direction Flag (DF) in FLAGS.
or al, al ; Set the zero flag - is AL zero?
jz printdone ; Check if this is the null byte
mov ah, 0eh
int 10h
jmp print
printdone:
ret
loader:
;|---------- Related to my question ----------|
xor ax, ax
mov ds, ax
mov es, ax
;|--------------------------------------------|
mov si, bootmsg
call print
cli ; Clears all interrupts.
hlt ; Halts the system.
times 510 - ($-$$) db 0 ; Make sure our bootloader is 512 bytes large.
dw 0xAA55 ; Boot signature - Byte 511 is 0xAA and Byte 512 is 0x55, indicated a bootable disk.1
如上代码所示,我突出显示了以下三行:
xor ax, ax
mov ds, ax
mov es, ax
根据原始资料,它是这样说的:
Setup segments to insure they are 0. Remember that we have ORG 0x7c00. This means all addresses are based from 0x7c00:0. Because the data segments are within the same code segment, null em.
我有点困惑。根据我的理解,org
指令告诉加载程序在地址 0x7c00
加载该程序。那我们为什么不把这个作为我们的起始地址呢?意思是,我们的两个重叠数据和代码段 不是 位于零的 基地址 处。 基地址 应该是 0x7c0。 为什么作者将基地址设置为0x0?
mov ax, 07c0h
mov dx, ax
mov es, ax
我一直在研究 org
指令和其他文档,我了解发生了什么。
根据org
指令中的NASM documentation,origin:
The function of the ORG directive is to specify the origin address which NASM will assume the program begins at when it is loaded into memory. [...] NASM's ORG does exactly what the directive says: origin. Its sole function is to specify one offset which is added to all internal address references within the section.
因此,NASM 编译器假定程序将加载到原始指令指定的地址(即 org
)。 BIOS 正是这样做的。根据 the following,一旦 BIOS 找到包含有效引导签名的有效引导扇区,引导加载程序将“加载到位于 0x0000:0x7c00 的内存中(段 0,地址 0x7c00)."
从上面的引用中,当 NASM 文档说 "internal address references," 时,它指的是对代码中使用的具体内存区域的所有引用(例如引用标签等) .例如,上面引导加载程序代码中的行:mov si, bootmsg
会将 bootmsg
解析为 0x07c00 + offset
,其中偏移量由我的字符串第一个字节的位置决定 bootmsg
(即 'W')。
使用上面的代码,如果我使用 ndisasm utility 反汇编 bin 文件,我会看到以下内容:
00000000 EB2C jmp short 0x2e
00000002 57
00000003 656C
00000005 636F6D
00000008 6520746F
0000000C 206D79
0000000F 204F70
00000012 657261
00000015 7469
00000017 6E
00000018 67205379
0000001C 7374
0000001E 656D
00000020 2100
00000022 AC lodsb
00000023 08C0 or al,al
00000025 7406 jz 0x2d
00000027 B40E mov ah,0xe
00000029 CD10 int 0x10
0000002B EBF5 jmp short 0x22
0000002D C3 ret
0000002E 31C0 xor ax,ax
00000030 8ED8 mov ds,ax
00000032 8EC0 mov es,ax
00000034 BE027C mov si,0x7c02
00000037 E8E8FF call 0x22
0000003A FA cli
0000003B F4 hlt
00000... ... ...
(我删除了从 0x00000002 到 0x00000020 的生成指令,因为那是我的 bootmsg
字符串并且代表数据,而不是代码)。
正如我们从输出程序集中看到的那样,在地址 0x00000034 处,我的 bootmsg
已被替换为 0x7c02(例如 0x7c00 + offset=0x02)。
provided some very solid insight too. It is a common misconception to think the bootloader is loaded to 0x7c0:0x0000 (segment 0x07c0, offset 0). Although one could technically use this, it has been standardized to use the segment offset of zero instead (A good practice is to enforce CS:IP at the very start of your boot sector). As Michael has mentioned, if one wants more information, look at section 4 of the following guide on segment offset addressing.
我目前正在关注 a tutorial on OS development,其中包括关于引导加载程序的讨论。
我的引导加载程序目前处于 16 位实模式,因此,我可以使用提供的 BIOS 中断(例如 VGA 视频中断等)。
BIOS 提供了视频中断0x10
(即视频电传输出)。视频中断有函数0x0E
,它允许我在屏幕上打印一个字符。
这是基本的引导加载程序:
org 0x7c00 ; Set program start (origin) address location at 0x7c00.
; This program is loaded by the BIOS at 0x7c00.
bits 16 ; We live in 16-bit Real Mode.
start:
jmp loader
bootmsg db "Welcome to my Operating System!", 0 ; My data string.
;-------------------------------------------------------
; Description: Print a null terminating string
;-------------------------------------------------------
print:
lodsb ; Load string byte at address DS:SI and place in AL.
; Then, increment/decrement SI as defined by the Direction Flag (DF) in FLAGS.
or al, al ; Set the zero flag - is AL zero?
jz printdone ; Check if this is the null byte
mov ah, 0eh
int 10h
jmp print
printdone:
ret
loader:
;|---------- Related to my question ----------|
xor ax, ax
mov ds, ax
mov es, ax
;|--------------------------------------------|
mov si, bootmsg
call print
cli ; Clears all interrupts.
hlt ; Halts the system.
times 510 - ($-$$) db 0 ; Make sure our bootloader is 512 bytes large.
dw 0xAA55 ; Boot signature - Byte 511 is 0xAA and Byte 512 is 0x55, indicated a bootable disk.1
如上代码所示,我突出显示了以下三行:
xor ax, ax
mov ds, ax
mov es, ax
根据原始资料,它是这样说的:
Setup segments to insure they are 0. Remember that we have ORG 0x7c00. This means all addresses are based from 0x7c00:0. Because the data segments are within the same code segment, null em.
我有点困惑。根据我的理解,org
指令告诉加载程序在地址 0x7c00
加载该程序。那我们为什么不把这个作为我们的起始地址呢?意思是,我们的两个重叠数据和代码段 不是 位于零的 基地址 处。 基地址 应该是 0x7c0。 为什么作者将基地址设置为0x0?
mov ax, 07c0h
mov dx, ax
mov es, ax
我一直在研究 org
指令和其他文档,我了解发生了什么。
根据org
指令中的NASM documentation,origin:
The function of the ORG directive is to specify the origin address which NASM will assume the program begins at when it is loaded into memory. [...] NASM's ORG does exactly what the directive says: origin. Its sole function is to specify one offset which is added to all internal address references within the section.
因此,NASM 编译器假定程序将加载到原始指令指定的地址(即 org
)。 BIOS 正是这样做的。根据 the following,一旦 BIOS 找到包含有效引导签名的有效引导扇区,引导加载程序将“加载到位于 0x0000:0x7c00 的内存中(段 0,地址 0x7c00)."
从上面的引用中,当 NASM 文档说 "internal address references," 时,它指的是对代码中使用的具体内存区域的所有引用(例如引用标签等) .例如,上面引导加载程序代码中的行:mov si, bootmsg
会将 bootmsg
解析为 0x07c00 + offset
,其中偏移量由我的字符串第一个字节的位置决定 bootmsg
(即 'W')。
使用上面的代码,如果我使用 ndisasm utility 反汇编 bin 文件,我会看到以下内容:
00000000 EB2C jmp short 0x2e
00000002 57
00000003 656C
00000005 636F6D
00000008 6520746F
0000000C 206D79
0000000F 204F70
00000012 657261
00000015 7469
00000017 6E
00000018 67205379
0000001C 7374
0000001E 656D
00000020 2100
00000022 AC lodsb
00000023 08C0 or al,al
00000025 7406 jz 0x2d
00000027 B40E mov ah,0xe
00000029 CD10 int 0x10
0000002B EBF5 jmp short 0x22
0000002D C3 ret
0000002E 31C0 xor ax,ax
00000030 8ED8 mov ds,ax
00000032 8EC0 mov es,ax
00000034 BE027C mov si,0x7c02
00000037 E8E8FF call 0x22
0000003A FA cli
0000003B F4 hlt
00000... ... ...
(我删除了从 0x00000002 到 0x00000020 的生成指令,因为那是我的 bootmsg
字符串并且代表数据,而不是代码)。
正如我们从输出程序集中看到的那样,在地址 0x00000034 处,我的 bootmsg
已被替换为 0x7c02(例如 0x7c00 + offset=0x02)。