实模式汇编代码header.S——无用的bootsect
2010-12-31 20:59
239 查看
3.2 实模式汇编代码header.S
如上所述,第一和第二部分是实模式代码,这些代码来自于汇编程序arch/x86/boot/header.S和c程序arch/x86/boot/main.c。再从加载开始说,如上所述,vmlinuz保护模式的代码加载到0x100000开始的位置。而实模式的代码,因为被加载的位置不要求是固定的,也就是上面文档中看到的:
Kernel setup | The kernel real-mode code.
Kernel boot sector
它们的位置是X,其不确定性是受Boot loader,也就是grub大小的影响。
3.2.1 无用的bootsect代码
所以,我们先来看header.S的代码,第46行:46 .global bootsect_start
47 bootsect_start:
48
49 # Normalize the start address
50 ljmp $BOOTSEG, $start2
这是bootsect开始代码,也就是vmlinuz第一个512字节的源代码。
我们看到$BOOTSEG是在源代码的第28行定义的BOOTSEG=0x07C0。没错,这个ljmp的意思就是说的是跳转到07C0的偏移start2处。还记得我们BIOS一节说过,BIOS不管你是内核还是bootloader,总会一来把第一个块加载到内存然后执行0x07c0处的代码。那么如果从这里开始执行,就说明vmlinuz是被BIOS直接加载过来的,这是不允许的,因为现在linux都需要经过一个特定的bootloader,如前面大篇幅介绍的GRUB。这也就是前面说的bootsect有点特殊的地方,就是说它并没打算用来执行,是个死代码。所以万一它被作为bootsect由BIOS直接执行,那么就直接提示reboot。可以拿vmware实验一下:
dd if=/boot/vmlinuz-2.6.34.1 of=vm.img bs=512 count=1
然后用vm.img作为软盘启动。程序就会跳到$start2处:
52 start2:
53 movw %cs, %ax
54 movw %ax, %ds
55 movw %ax, %es
56 movw %ax, %ss
57 xorw %sp, %sp
58 sti
59 cld
60
61 movw $bugger_off_msg, %si
62
我们看到,start2首先将将ds,es,ss全设置为cs,其内容为0x07C0;然后将sp设置成0、开中断sti、cld清方向标志最后把下面bugger_off_msg 符号的偏移地址放在si寄存器中。继续走:
63 msg_loop:
64 lodsb
65 andb %al, %al
66 jz bs_die
67 movb $0xe, %ah
68 movw $7, %bx
69 int $0x10
70 jmp msg_loop
71
63行的msg_loop的lodsb指令把si指向的源串的内容逐步装入al中(另一个指令stosb是将al中数据装入di指向的地址中)。64行,当取完的时候,al=0,此时操作andb后方向为0,执行下句跳转语句到bs_die。当然,al不为0的时候,执行69行Video中断服务指令,其中AH = 0Eh,AL = 对应字符(8位),BL = Color (only in graphic mode)。
72 bs_die:
73 # Allow the user to press a key, then reboot
74 xorw %ax, %ax
75 int $0x16
76 int $0x19
77
78 # int 0x19 should never return. In case it does anyway,
79 # invoke the BIOS reset code...
80 ljmp $0xf000,$0xfff0
81
82 .section ".bsdata", "a"
83 bugger_off_msg:
84 .ascii "Direct booting from floppy is no longer supported./r/n"
85 .ascii "Please use a boot loader program instead./r/n"
86 .ascii "/n"
87 .ascii "Remove disk and press any key to reboot . . ./r/n"
88 .byte 0
89
90
91 # Kernel attributes; used by setup. This is part 1 of the
92 # header, from the old boot sector.
93
上面这些代码的作用就是打印消息并等待重启,就不多说了。在这里顺便说一下,grub的boot_func中的big_linux_boot里,描述了实际上grub的stage2将内核的bootsect和setup实模式代码载入到地址0x90000后。也就是说,这里就是对应Grub是0x90000的证据。由于我们setup.ld链接脚本里规定的setup.bin入口点是_start,那么grub加载vmlinuz后将跳过前512个字节,即0x200个字节的,直接跳转到地址0x90200处执行的。我们还是来关注真正的setup代码了,从偏移内核映像vmlinuz的0x0200开始。
那么grub怎么执行这条代码呢?grub会执行jmp_far(0x20, 0); 也就是跳过vmlinuz的0x200个字节,也就是跳到vmlinuz实模式代码_start执行了,因为这样就略过了前512字节的bootsect。这也就是一开始我们说bootsect.S消失了的秘密。
实际上,jmp_far就是grub中一条指令,ljmp。再看看第105行的注释,这就是ljmp跳到的位置,即_start,也就是进入“中世纪时代”。
相关文章推荐
- 实模式汇编代码header.S——准备实模式下C语言环境
- gdb:如果在没有符号表的时候让gdb强制以thumb模式反汇编ARM二进制代码
- 51汇编实现的spi代码(模式0)
- 如何在VS2010下切换代码的汇编模式
- 常用的设计模式和代码
- 编写可测试的前端代码第二部分 – 从反模式进行重构
- 单例模式及C++实现代码
- Android驱动开发之earlysuspend睡眠模式--实现代码【转】
- 设计模式----代理模式UML和实现代码
- 闲着……学学写写汇编(只贴代码)(3)
- gcc查看汇编代码
- 模板方法模式分析、结构图和基本代码
- 一段汇编代码翻译成c语言的练习
- 关于JAVA中状态设计模式的讲解示例代码
- Reactor 模式+代码讲解
- 简单工厂和工厂模式的合并对比代码
- Java代码重构的几种模式
- 代码的“门面”——模式系列谈之Façade模式
- win32汇编代码的屏幕截屏程序
- 单例模式代码