从0x7c00到0x90000
前两行代码就是设置代码段寄存器为0x07c0,接着往下看
1 2 3 4 5 6 7 8 9 10
| _start: mov ax,#0x07c0 mov ds,ax mov ax,#0x9000 mov es,ax mov cx,#256 sub si,si sub di,di rep movw
ASM
|
同前两行代码一样,接下来三行是将es寄存器设置为0x9000,cx寄存器设置为256
关于sub指令很简单,sub a,b
表示a=a-b所以下面两行就是将si寄存器和di寄存器清空。现在寄存器的值为:
1 2 3 4 5
| ds=0x07c0 es=0x9000 cx=256 si=0 di=0
SHELL
|
CPU 寄存器如图所示:
寄存器状态
有了这些寄存器的值就可以执行下面的指令了:
rep
代表重负执行下一条指令,movw
表示拷贝一个字(两个字节即16位)
movw
指令会从数据段:源变址
拷贝一个字到附加段:目的变址
,rep
指令会使下一条指令重复执行cx
(计数寄存器)次
所以这两条指令就是从0x7c00拷贝512字节到0x90000,也就是把启动区从0x7c00移动到了0x90000
跳转到go
现在我们已经把启动区拷贝到0x90000了,需要跳转到对应的位置继续执行:
1 2
| jmpi go,0x9000 go: mov ax,cs
ASM
|
jmpi
指令就跳转指令,因为前面的指令都执行过了,所以直接跳转到下一条指令对应的位置(0x9000:go),即0x90000+go
为什么是0x90000
我们知道因为历史原因,启动区会被BIOS拷贝到0x7c00,那么为什么自己还要拷贝到0x90000呢?这是因为THE LINUX/I386 BOOT PROTOCOL规定的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| | | 0A0000 +------------------------+ | Reserved for BIOS | Do not use. Reserved for BIOS EBDA. 09A000 +------------------------+ | Command line | | Stack/heap | For use by the kernel real-mode code. 098000 +------------------------+ | Kernel setup | The kernel real-mode code. 090200 +------------------------+ | Kernel boot sector | The kernel legacy boot sector. 090000 +------------------------+ | Protected-mode kernel | The bulk of the kernel image. 010000 +------------------------+ | Boot loader | <- Boot sector entry point 0000:7C00 001000 +------------------------+ | Reserved for MBR/BIOS | 000800 +------------------------+ | Typically used by MBR | 000600 +------------------------+ | BIOS use only | 000000 +------------------------+
COQ
|
总结
这部分代码只做了一件事:把启动区(MBR)从硬盘中先拷贝到0x7c00,再拷贝到0x90000.