曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 5442|回复: 1
打印 上一主题 下一主题

傀儡引导扇区代码分析

[复制链接]

4917

主题

5879

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34382
跳转到指定楼层
楼主
发表于 2011-7-6 20:17:29 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
在早期的 2.6 内核的 arch/i386/boot/ 目录下还可以看到 bootsect.S 这个文件,该文件可以生成傀儡引导扇区,现在之所以称之为”傀儡引导扇区“ 是因为该引导扇区不再具有引导功能。在还用它进行引导时,该扇区占据了内核镜像 bzImage 的前 512 字节,现在这段代码仅实现了向 BIOS 中断向屏幕输出以下提示信息的功能:


正常情况下,系统不会执行该文件所生成的代码,也就是该模块不会被 BIOS 加载到段地址 0x7c00 。系统只能借助其它引导程序进行引导,如 LILO, GRUB;这些引导程序首先会将 bootsect 装载到地址 0x9000:0000 中,然后向已经复制到内存中的 bootsect 区域设置相关的参数,最终由内核识别和利用这些参数。

下面,将 bootsect.S 进行编译链接,然后把生成的二进制文件装载在一个软盘镜像文件里,并用 bochs 来调试观察其执行过程。

1. 将 bootsect.S 和 include/asm-i386/boot.h 复制到某个目录下,然后修改 bootsect.S 的 #include <asm/boot.h> 这行代码为 #include "boot.h"

2. 编写一个链接脚本文件,内容如下:
[Plain Text] 纯文本查看 复制代码
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386)

ENTRY(_start)
        SECTIONS
{
        . = 0;
        .boottext        : { *(.boottext) }
        .bootdata        : { *(.bootdata) }
}


3. 编译链接
[beyes@beyes bootsect]$ gcc -nostdinc -c -o bootsect.o bootsect.S
[beyes@beyes bootsect]$ ld -m elf_i386 -T boot.ld bootsect.o -o bootsect.elf
[beyes@beyes bootsect]$ objcopy -O binary bootsect.elf bootsect.bin  //使用 objcopy 提取 bootsect.elf 文件中的二进制代码,并保存到 bootsect.bin 中

4. 制作软盘镜像文件
[beyes@beyes bootsect]$ dd if=/dev/zero of=floppy.img bs=1024 count=1440
1440+0 records in
1440+0 records out
1474560 bytes (1.5 MB) copied, 0.00818535 s, 180 MB/s
[root@beyes bootsect]# losetup /dev/loop1 floppy.img
[root@beyes bootsect]# cat bootsect.bin > /dev/loop1
[root@beyes bootsect]# losetup -d /dev/loop1
简单一点,也可以直接这么制作:
[root@beyes bootsect]# dd if=bootsect.bin of=floppy2.img bs=1024 count=1440
0+1 records in
0+1 records out
512 bytes (512 B) copied, 3.5257e-05 s, 14.5 MB/s

5. 配置适用于 bochs 的 bxrc 配置文件(此步骤略)。

6. 使用 bochs 加载软盘镜像并调试:
在 0x7c00 处下断点,然后按下 c 并回车来到 bootsect.S 的 jmpl $BOOTSEC, $start2 这里,接下来便可以用 s 或 n 等命令对代码进行跟踪调试。

下面对 bootsect.S 代码进行注释
[Plain Text] 纯文本查看 复制代码
.code16
.text

code16 是伪指令,告诉 gas 要生成 16位 目标代码;text 也是伪指令,告诉 gas 下面生成的代码放到指令段中,也就是上面的 ld 链接文件中的 boottext 。
[Plain Text] 纯文本查看 复制代码
.global _start
 _start:

_start 是引导扇区入口地址,在这里被 .global 声明为全局变量,连接时可以被外部模块引用。
[Plain Text] 纯文本查看 复制代码
 jmpl    $BOOTSEG, $start2

jmpl 是长跳转指令,它不但改变指令指针寄存器 IP,还改变 CS 段寄存器。在上面的指令中,CS 会被赋值为 $BOOTSEG 所代表的地址,IP 为 start2 。

[Plain Text] 纯文本查看 复制代码
start2:
movw    %cs, %ax
movw    %ax, %ds
movw    %ax, %es
movw    %ax, %ss
movw    $0x7c00, %sp
sti
cld

%cs=%ds=%es=%es=0x7c0
sti 指令使能响应中断
cld 指令使能 %si, %di 寄存器的自动增 1 模式(如下面使用的 lodsb 指令加载字符串时,%si 和 %di 指令能自动指向下一个字符)。
movw    $bugger_off_msg, %si
将 bugger_off_msg 标号的地址放到 %si 中。

[Plain Text] 纯文本查看 复制代码
msg_loop:
lodsb
andb    %al, %al
jz      die
movb    $0xe, %ah
movw    $7, %bx
int     $0x10
jmp     msg_loop

这段代码不断的从 bugger_off_msg 这里读取字符,然后利用 0x10 号中断将这些字符逐个输出。其中,在使用 0x10 号中断时,ah 中存入 0xe 表示使用 ”电传打字机“ 模式,该模式在打印一个字符后,光标会自动移到下一个输出位置。
andb    %al, %al 语句测试是不是读到了字符串的末位,如果是的话,程序就跳到 die 那里。

在 die 标号下看到几行语句:
[Plain Text] 纯文本查看 复制代码
xorw    %ax, %ax
int     $0x16
int     $0x19
ljmp    $0xf000,$0xfff0

其中第 0x16 号中断,在使用该中断之前,清零 %ax ,表示读取键盘输入,一旦键盘有输入,程序才能继续往下走,否则停留在 int $0x16 这里。中断 0x19 号用来重启系统。

[Plain Text] 纯文本查看 复制代码
.org 497
setup_sects:    .byte SETUPSECTS
root_flags:     .word ROOT_RDONLY
syssize:        .word SYSSIZE
swap_dev:       .word SWAP_DEV
ram_size:       .word RAMDISK
vid_mode:       .word SVGA_MODE
root_dev:       .word ROOT_DEV
boot_flag:      .word 0xAA55

.org 伪指令告诉编译器从偏移到 497 这里用 0 填充。最后的 0xAA55 是可引导扇区标记。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2024-4-29 23:05 , Processed in 0.074667 second(s), 22 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表