首页
课程
问答
CTF
社区
招聘
峰会
发现
排行榜
知识库
工具下载
看雪20年
看雪商城
证书查询
登录
注册
首页
社区
课程
招聘
发现
问答
CTF
排行榜
知识库
工具下载
峰会
看雪商城
证书查询
社区
编程技术
发新帖
7
8
Linux-2.4.0内核加载、启动过程
发表于: 2026-4-4 13:27
10547
Linux-2.4.0内核加载、启动过程
jmpcall
4
2026-4-4 13:27
10547
# 1. 背景 <div>  想了解进入startup_32之前,CPU执行了哪些操作,但是找不到跳转到它的call或jmp指令:</div> <img src="upload/attach/202604/815036_85FHBGNTER549RA.png"> # 2. 主体过程 <div>  为避免介绍内容过于杂乱,本文尽量紧密围绕最主体、最关键的过程,不深究过于细节、相对独立、不影响整体理解的环节和疑问。</div> <img src="upload/attach/202604/815036_ZQEFZKS2SQDB76S.png"> ## 2.1. 加载内核 <div>  硬件设计层面会保证,CPU刚加电时处于实模式、仅开启段式内存管理,并且CS寄存器=0xffff、IP寄存器=0,从而执行0xffff0处的BIOS程序(主板出厂时烧入代码,断电不挥发),将bootsect(内核加载程序,位于主引导扇区),加载到0x7c00内存地址处并执行,bootsect先将自己移动到0x90000处,然后进一步将setup和内核文件,分别加载到0x90200和0x10000处,并执行setup(内核启动程序)。</div> <pre>   分析这块时,我产生过这些疑问:   (1) bootsect不移动自己,直接在0x7c00区域执行时,就加载setup和内核,存在什么问题?   (2) BIOS为什么不直接将bootsect加载到0x90000处?   (3) 0xffff0距离0x100000只有16个字节,容不下几条指令,所以0xffff0指向的是不是一条跳转指令,如果是,为什么不让CS:IP在加电时,直接指向要跳转的地方?    简单查了资料:(1)、(2)、(3)大致都是为了提高兼容性,让A的内部细节,对B透明。这样,a1、a2对执行条件的特殊要求,就可以由它们自己处理,不影响对外的约定。   (4) BIOS代码执行期间,是如何让CS:IP地址(比如0xffff0),指向BIOS,而又让BIOS指令访问的地址(比如0x7c00),指向内存的?    deepseek的解释是:通过设置PCI配置寄存器,可以让读操作,访问BIOS,写操作访问内存。    对于这个解释,我个人是这样理解的:举个例子,执行“movl 0xffff0, %eax”,从0xffff0地址读取内容(包括从CS:IP读取指令),会被PCI路由到BIOS,而执行”mov %eax, 0xffff0”,往0xffff0地址写入内容,会被PCI路由到内存。这样,BIOS就可以先在内存中,复制一个自己的影子,然后修改PCI配置,让地址完全路由到内存,后续使用BIOS,实际使用的都是BIOS影子。 </pre> ## 2.2. 启动内核 <div>  setup程序最主要的目标,是开启CPU的保护模式,并跳转到内核的入口startup_32处执行。</div> <pre>   这里,又有两个疑问:   (1) 内核的加载和启动,为什么要开发bootsect、setup两个程序,而不是开发一个程序统一完成?    BIOS只从MBR读取loader程序,而在同一个程序里实现加载和启动,大小会超过256字节,MBR装不下,就只装了bootsect程序,再由它间接加载并启动体积较大的setup程序。   (2) 整个过程中,怎么没见到grub?    grub可以理解为更强大的bootsect+setup,实质上已经是一个小型操作系统,有自己的内核、驱动、应用程序,除了必要的加载和启动内核功能,还支持丰富的用户交互命令。 </pre> ## 2.3. 内核执行 <div>  内核最初的入口是startup_32,它最主要的目标,是开启CPU的页式内存管理,并调用start_kernel()函数。</div> ## 2.4. CPU状态的变化 <div>  以上实际上是一个边搭桥、边过桥的过程:一边加载,一边执行;一边准备,一边逐步开启CPU保护模式和页式内存管理。</div> <img src="upload/attach/202604/815036_4EF9C5XTVRB5U5J.png"> ### 2.4.1. 实模式+仅开启段式内存管理 <div>  bootsect+setup可正常执行(过桥):</div> <div>  (1) BIOS为实模式提供了中断向量表,所以int指令可以正常执行;</div> <div>  (2) CPU按照”CS/SS << 4 + IP/SP”或”DS << 4 + 包含在指令中的偏移值”计算地址,仅依赖寄存器,不依赖内存上的管理数据,所以指令的执行和寻址也正常。</div> <div>  setup切换保护模式(搭桥):</div> <div>  setup事先构造全局段描述符表(gdt),并执行lgdt指令,设置GDTR寄存器=gdt,然后开启保护模式。</div> ### 2.4.2. 保护模式+仅开启段式内存管理 <div>  startup_32可正常执行(过桥):</div> <div>  切换到保护模式后,CPU硬件层对段寄存器的使用逻辑,会发生改变,段基址不再从中直接获取,而是从它指向的段描述符,间接获取,这在setup执行时,已经准备好了。</div> <div>  startup_32开启页式内存管理(搭桥):</div> <div>  startup_32事先构造目录表swapper_pg_dir,并准备充足的目录表项、页表项,然后设置cr3寄存器=swapper_pg_dir,最后开启页式内存管理。</div> ### 2.4.3. 保护模式+开启页式内存管理 <div>  start_kernel()可正常执行(过桥):</div> <div>  开启页式内存管理后,CPU硬件层的寻址逻辑,又会发生改变,对于i386 CPU,指令中的地址,不光要经过段式映射,还要经过页式映射,才能得到最终的物理地址,页式映射依赖的目录表和页表(包括表项),这些都由startup_32准备好了。</div> <div>  CPU的内核态和用户态切换:</div> <div>  保护模式下,CPU硬件层,开始区分ring0~ring3权限。由于内核先于用户程序执行,也就是先抢到ring0权限,它在跳转到用户程序执行之前,就有权将CPU权限改为ring3,而用户程序只能穿过门,回到内核代码的同时,才能将CPU权限重新提升到ring0,因此所有依赖ring0权限的操作,只能请求内核帮忙完成。这样,内核就利用CPU提供的硬件特性,将ring0权限掌握在自己手里,用户程序永远只能在ring3权限下执行。另外,从用户程序跳入内核代码执行,仍然是在推进这个进程的目标,并没有导致进程切换(和跳入.so动态库执行类似),只是执行进程的CPU状态改变了而已,这其实也是内核的本质。</div> # 3. 代码分析 <pre>   linux-2.4.0/arch/i386    |- boot    | |- <a href="elink@ad5K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6W2L8r3W2^5K9i4u0Q4x3X3g2T1L8$3!0@1L8r3W2F1i4K6u0W2j5$3!0E0i4K6u0r3L8r3W2F1N6i4S2Q4x3V1j5J5i4K6u0W2y4q4)9J5k6e0m8Q4x3V1k6K6L8%4g2J5j5$3g2Q4x3V1k6S2M7X3y4Z5i4K6u0r3K9e0x3^5y4W2)9J5c8X3u0G2L8%4c8Q4x3V1k6T1L8$3!0@1M7$3g2U0N6q4)9J5k6g2x3`.">bootsect.S</a> // bootsect    | |- <a href="elink@6b6K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6W2L8r3W2^5K9i4u0Q4x3X3g2T1L8$3!0@1L8r3W2F1i4K6u0W2j5$3!0E0i4K6u0r3L8r3W2F1N6i4S2Q4x3V1j5J5i4K6u0W2y4q4)9J5k6e0m8Q4x3V1k6K6L8%4g2J5j5$3g2Q4x3V1k6S2M7X3y4Z5i4K6u0r3K9e0x3^5y4W2)9J5c8X3u0G2L8%4c8Q4x3V1k6K6k6i4c8#2M7q4)9J5k6g2x3`.">setup.S</a> // setup    | |- compressed    | |- <a href="elink@b43K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6W2L8r3W2^5K9i4u0Q4x3X3g2T1L8$3!0@1L8r3W2F1i4K6u0W2j5$3!0E0i4K6u0r3L8r3W2F1N6i4S2Q4x3V1j5J5i4K6u0W2y4q4)9J5k6e0m8Q4x3V1k6K6L8%4g2J5j5$3g2Q4x3V1k6S2M7X3y4Z5i4K6u0r3K9e0x3^5y4W2)9J5c8X3u0G2L8%4c8Q4x3V1k6U0L8$3#2H3M7X3g2K6M7$3g2V1i4K6u0r3K9r3g2S2k6q4)9J5k6g2x3`.">head.S</a> // 提供解压缩功能,本文分析的是kernel/head.S    |- kernel // vmlinux    |- <a href="elink@af8K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6W2L8r3W2^5K9i4u0Q4x3X3g2T1L8$3!0@1L8r3W2F1i4K6u0W2j5$3!0E0i4K6u0r3L8r3W2F1N6i4S2Q4x3V1j5J5i4K6u0W2y4q4)9J5k6e0m8Q4x3V1k6K6L8%4g2J5j5$3g2Q4x3V1k6S2M7X3y4Z5i4K6u0r3K9e0x3^5y4W2)9J5c8X3E0W2M7X3&6W2L8q4)9J5c8X3S2W2j5h3c8Q4x3X3g2e0">head.S</a> // startup_32    |- <a href="elink@8ffK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6W2L8r3W2^5K9i4u0Q4x3X3g2T1L8$3!0@1L8r3W2F1i4K6u0W2j5$3!0E0i4K6u0r3L8r3W2F1N6i4S2Q4x3V1j5J5i4K6u0W2y4q4)9J5k6e0m8Q4x3V1k6K6L8%4g2J5j5$3g2Q4x3V1k6A6L8X3W2@1i4K6u0r3L8h3q4A6L8W2)9J5k6h3y4Q4x3U0y4x3y4e0t1H3">main.c</a> // start_kernel() </pre> ## 3.1. bootsect.S(bootsect程序) <div>  有些操作并不用关注,主要的有三个:</div> <div>  (1) 将自己从0x7c00迁移到0x90000,并跳转到新区域,继续执行一下条指令;</div> <div>  (2) 将ds、ss段寄存器,设置为0x90000;</div> <div>  (3) 加载setup和内核文件(按小内核文件加载),并执行setup程序。</div> <img src="upload/attach/202604/815036_4TF5MADTUCHBMS7.png"> ## 3.2. setup.S(setup程序) <div>  真正需要关注的也不多:</div> <div>  (1) 确保自己位于0x90200位置,如果不在,执行自迁移;</div> <div>  (2) 如果是大内核文件,将bootsect加载到0x10000的那部分,转移到0x100000;</div> <div>  (3) 设置中断向量表、全局段描述符表;</div> <div>  (4) 切换到保护模式;</div> <div>  (5) 跳转到startup_32执行。</div> <img src="upload/attach/202604/815036_A3SW8K86JRYXMKD.png"> <div>  setup迁移到0x90000区域过程:</div> <div>  暂不清楚,为什么不用考虑从高往低迁移的情况。</div> <img src="upload/attach/202604/815036_VK4ZTDF38XQE782.png"> <div>  向startup_32的跳转指令,写的比较有意思:</div> <div>  这是为了操作数,可以根据小内核/大内核的实际情况,进行动态设置,这同时也是代码中找不到startup_32被调用的一方面原因,另一方面是因为,这个时候还不能用0xC0010000或0xC0100000地址,访问到startup_32处的代码。</div> <img src="upload/attach/202604/815036_T4XJTJTDKZYQ4XG.png"> ## 3.3. head.S(内核入口:startup_32) <div>  这个文件,不是我自己分析的,因为《Linux内核源代码情况分析》10.2节,已经介绍的很清楚了。个人觉得比较有意思的就是390和391两行,给人一种极限过弯的感觉。</div> <img src="upload/attach/202604/815036_U68B3G6J6524TYM.png"> # 4. 打破神秘 <div>  (1) loader程序,为什么使用汇编编写?</div> <div>  第一,用于控制程序的体积,比如bootsect;第二,有些操作,C语言没有对应的语法成分,比如:int中断指令、将”jmpi __KERNEL_CS:code32”拆成opcode和操作数等;第三,内核还有很多其它.S文件,或嵌入到.c文件中的汇编代码,主要用于提高执行性能。</div> <div>  (2) 一堆没有生命的器材,组装一起,是怎么产生智能的?</div> <div>  个人认为,智能表面是一种感受,实质是一堆精密的物理反应。</div> <div>  扣动扳机,手枪完成一系列精密的动作,最终发射一枚子弹,这个过程远比跳水运动员,完成一次高分跳水,还要复杂,按道理已经很智能了,但是从感受上讲,它又跟按下电源,灯就亮了一样简单,并没有什么智能。</div> <div>  如果从穿孔纸带时代(甚至更早前手动插线连接电子管),开始去体会计算机,就并没有什么神秘了:手搓一个简单的工具,再用简单的工具,制造脱离手搓的工具,并进一步制造更多、更高级的工具。计算机,只是在交互方式上,做了更多的硬件设计,更贴近人类的习惯,所以显得智能。编程以及AI,也是通过物理的方式,让程序和数学公式,反过来参与进这些物理反应而已。</div>
登录后可查看完整内容
冰与火的战歌:Windows内核攻防实战高级班!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。
最后于
2026-4-4 16:00 被jmpcall编辑 ,原因:
#系统内核
上传的附件:
startup_32-who_call_it.png
(25.49kb,9次下载)
startup_32-jmp.png
(10.17kb,9次下载)
setup-move_self.png
(55.52kb,9次下载)
总体过程.png
(38.24kb,9次下载)
setup.S-注释.png
(2.27MB,9次下载)
head.S-注释.png
(1.90MB,9次下载)
CPU状态变化.png
(11.41kb,9次下载)
bootsect.S-注释.png
(1.58MB,9次下载)
收藏
・
7
点赞
・
8
打赏
分享
分享到微信
分享到QQ
分享到微博
赞赏记录
参与人
雪币
留言
时间
zhczf
感谢你的贡献,论坛因你而更加精彩!
2026-4-13 23:09
0x指纹
+1
谢谢你的细致分析,受益匪浅!
2026-4-8 16:01
马来
谢谢你的细致分析,受益匪浅!
2026-4-8 10:16
nulles
谢谢你的细致分析,受益匪浅!
2026-4-7 23:16
边缘
谢谢你的细致分析,受益匪浅!
2026-4-6 20:02
木志本柯
+5
非常支持你的观点!
2026-4-6 12:48
我的小拇指啊
你的分享对大家帮助很大,非常感谢!
2026-4-6 03:22
huangjw
+1
非常支持你的观点!
2026-4-5 14:26
查看更多
赞赏
×
1 雪花
5 雪花
10 雪花
20 雪花
50 雪花
80 雪花
100 雪花
150 雪花
200 雪花
支付方式:
微信支付
赞赏留言:
快捷留言
感谢分享~
精品文章~
原创内容~
精彩转帖~
助人为乐~
感谢分享~
最新回复
(
1
)
huangjw
雪 币:
6679
活跃值:
(11862)
能力值:
( LV2,RANK:10 )
在线值:
发帖
0
回帖
510
粉丝
2
关注
私信
huangjw
2
楼
火钳刘明
2026-4-5 14:27
0
游客
登录
|
注册
方可回帖
回帖
表情
雪币赚取及消费
高级回复
返回
jmpcall
4
45
发帖
236
回帖
300
RANK
关注
私信
他的文章
物理页面的关键流向
235
__down()
551
schedule()
991
Linux-2.4.0内核加载、启动过程
10546
KernelSnitch(侧信道泄漏内核地址部分)
2819
关于我们
联系我们
企业服务
看雪公众号
专注于PC、移动、智能设备安全研究及逆向工程的开发者社区
谁下载
×
ldljlzw
边缘
leidong
ONewTach
Fzzz
npc0vo
mb_kujsrqqv
mb_lthgjpwj
谁下载
×
ldljlzw
边缘
leidong
ONewTach
Fzzz
npc0vo
mb_kujsrqqv
mb_lthgjpwj
谁下载
×
ldljlzw
边缘
leidong
ONewTach
Fzzz
npc0vo
mb_kujsrqqv
mb_lthgjpwj
谁下载
×
ldljlzw
边缘
leidong
ONewTach
Fzzz
npc0vo
mb_kujsrqqv
mb_lthgjpwj
谁下载
×
ldljlzw
边缘
leidong
ONewTach
Fzzz
npc0vo
mb_kujsrqqv
mb_lthgjpwj
谁下载
×
ldljlzw
边缘
leidong
ONewTach
Fzzz
npc0vo
mb_kujsrqqv
mb_lthgjpwj
谁下载
×
ldljlzw
边缘
leidong
ONewTach
Fzzz
npc0vo
mb_kujsrqqv
mb_lthgjpwj
谁下载
×
ldljlzw
边缘
leidong
ONewTach
Fzzz
npc0vo
mb_kujsrqqv
mb_lthgjpwj
看原图
赞赏
×
雪币:
+
留言:
快捷留言
为你点赞!
返回
顶部