linux 容易分析

linux 简单分析
    为了提高自己,不知不觉踏上了linux源码分析之路了!
    我选择linux源码版本是linux 0.11,为什么选择它?因为它代码量少且资料多。

    针对它的分析是建立于网上资料之上(快捷、效果好)。

    项目如图:

  该项目是网上某某已经编译好了,并且对它进行了分析。笔者只是学习他的皮毛。

  首先进入项目的是bootsect:这个程序是linuxkernel的第一个程序,包括了linux自己的bootstrap程序,但是在 说明这个程序前,必须先说明一般IBMPC开机时的动作(此处的开机是指"打开PC的电源" )。它是第一个被读入内存中并执行的程序,现在,我们可以开始来看看到底它做了什么。 

第一步 :bootsect将它"自己"从被ROMBIOS载入的绝对地址0x7C00处搬到0x90000处, 然后利用一个jmpi(jumpindirectly)的指令,跳到新位置的jmpi的下一行去执行…

表示将跳到CS为0x9000,IP为offset"go"的位置(CS:IP=0x9000:offsetgo),其中I NITSEC=0x9000定义于程序开头的部份,而go这个label则恰好是下一行指令所在的位置。

第二步:接着,将其它segmentregisters包括DS,ES,SS都指向0x9000这个位置,与CS看齐 。

第叁步:接着利用BIOS中断服务int13h的第0号功能,重置磁盘控制器,使得刚才的设定发挥功能。

 第四步:完成重置磁盘控制器之后,bootsect就从磁盘上读入紧邻着bootsect的setup程序, 也就是以后将会介绍的setup.S,此读入动作是利用BIOS中断服务int13h的第2号功能。

第五步:再来,就要读入真正linux的kernel了,也就是你可以在linux的根目录下看到的"v mlinuz"。

第六步:接下来做的事是检查root device,之后就仿照一开始的方法,利用indirect jump跳到刚刚已读入的setup部份。

 ;//bootsec.s文件说明如下:磁盘的引导块程序,驻留在磁盘的第一扇区。
;//在PC机加电rom bios自检之后,引导扇区由bios加载到内存0x7c00处,然后将自己移动到内存0x90000处。
;//该程序的主要作用是首先将setup模块从磁盘加载到内存中,紧接着bootsect的后面位置(0x90200),然后利用bios中断0x13中断去磁盘参数表中当前引导盘的参数,
;//然后在屏幕上显示"Loading system..."字符串。再者将system模块从磁盘上加载到内存0x10000开始的地方。随后确定根文件系统的设备号,如果没有指定,
;//则根据所保存的引导盘的每类型和种类,并保存设备号与boot_dev,最后长跳转到 setup程序开始处0x90200执行setup程序。

.model tiny
.386p
;// SYSSIZE是要加载的节数(16字节为1节)。3000h共为30000h字节=192kB
;// 对当前的版本空间已足够了。
SYSSIZE = 3000h ;// 指编译连接后system模块的大小。
;// 这里给出了一个最大默认值。

SETUPLEN = 4 ;// setup程序的扇区数(setup-sectors)值
BOOTSEG = 07c0h ;// bootsect的原始地址(是段地址,以下同)
INITSEG = 9000h ;// 将bootsect移到这里
SETUPSEG = 9020h ;// setup程序从这里开始
SYSSEG = 1000h ;// system模块加载到10000(64kB)处.
ENDSEG = SYSSEG + SYSSIZE ;// 停止加载的段地址

;// DEF_ROOT_DEV: 000h - 根文件系统设备使用与引导时同样的软驱设备.
;// 301 - 根文件系统设备在第一个硬盘的第一个分区上,等等
ROOT_DEV = 301h;//指定根文件系统设备是第1个硬盘的第1个分区。这是Linux老式的硬盘命名
;//方式,具体值的含义如下:
;//设备号 = 主设备号*256 + 次设备号
;// (也即 dev_no = (major<<8 + minor)
;//(主设备号:1-内存,2-磁盘,3-硬盘,4-ttyx,5-tty,6-并行口,7-非命名管道)
;//300 - /dev/hd0 - 代表整个第1个硬盘
;//301 - /dev/hd1 - 第1个盘的第1个分区
;//... ...
;//304 - /dev/hd4 - 第1个盘的第4个分区
;//305 - /dev/hd5 - 代表整个第2个硬盘
;//306 - /dev/hd6 - 第2个盘的第1个分区
;//... ...
;//309 - /dev/hd9 - 第1个盘的第4个分区

;/* ************************************************************************
; boot被bios-启动子程序加载至7c00h(31k)处,并将自己移动到了
; 地址90000h(576k)处,并跳转至那里。
; 它然后使用BIOS中断将'setup'直接加载到自己的后面(90200h)(576.5k),
; 并将system加载到地址10000h处。
;
; 注意:目前的内核系统最大长度限制为(8*65536)(512kB)字节,即使是在
; 将来这也应该没有问题的。我想让它保持简单明了。这样512k的最大内核长度应该
; 足够了,尤其是这里没有象minix中一样包含缓冲区高速缓冲。
;
; 加载程序已经做的够简单了,所以持续的读出错将导致死循环。只能手工重启。
; 只要可能,通过一次取取所有的扇区,加载过程可以做的很快的。
;************************************************************************ */
code segment ;// 程序从_main标号开始执行。
assume cs:code
start: ;// 以下10行作用是将自身(bootsect)从目前段位置07c0h(31k)
;// 移动到9000h(576k)处,共256字(512字节),然后跳转到
;// 移动后代码的 go 标号处,也即本程序的下一语句处。
mov ax,BYTE PTR BOOTSEG ;// 将ds段寄存器置为7C0h
mov ds,ax
mov ax,BYTE PTR INITSEG ;// 将es段寄存器置为9000h
mov es,ax
mov cx,256 ;// 移动计数值 = 256字 = 512 字节
sub si,si ;// 源地址 ds:si = 07C0h:0000h
sub di,di ;// 目的地址 es:di = 9000h:0000h
rep movsw ;// 重复执行,直到cx = 0;移动1个字
; jmp INITSEG:[go] ;// 间接跳转。这里INITSEG指出跳转到的段地址。
db 0eah ;// 间接跳转指令码
dw go
dw INITSEG
go: mov ax,cs ;// 将ds、es和ss都置成移动后代码所在的段处(9000h)。
mov ds,ax ;// 由于程序中有堆栈操作(push,pop,call),因此必须设置堆栈。
mov es,ax
;// put stack at 9ff00. 将堆栈指针sp指向9ff00h(即9000h:0ff00h)处
mov ss,ax
mov sp,0FF00h ;/* 由于代码段移动过了,所以要重新设置堆栈段的位置。
; sp只要指向远大于512偏移(即地址90200h)处
; 都可以。因为从90200h地址开始处还要放置setup程序,
; 而此时setup程序大约为4个扇区,因此sp要指向大
; 于(200h + 200h*4 + 堆栈大小)

linux 容易分析

相关文章:

你感兴趣的文章:

标签云: