使用 Visual Studio 2013 编译,调试 linux-0.11
强烈推荐学习 Linux 源码从 0.11 版开始入手,原因嘛,见下面推荐两本 Linux 0.11 源码分析书籍前言。《linux 内核完全注释》 http://product.china-pub.com/22033电子书下载地址:http://pan.baidu.com/s/1ntx5hKt《Linux内核设计的艺术》 http://product.china-pub.com/
·
强烈推荐学习 Linux 源码从 0.11 版开始入手,原因嘛,见下面推荐两本 Linux 0.11 源码分析书籍前言。
《linux 内核完全注释》 http://product.china-pub.com/22033
电子书下载地址:http://pan.baidu.com/s/1ntx5hKt
《Linux内核设计的艺术》 http://product.china-pub.com/3767800
为什么用 Visual Studio 2013 就不用多说了吧,绝对比任何专用的源代码阅读软件都强悍。
查看函数调用层次一类的功能,为分析源代码提供最大的方便。
而且 MASM Intel 格式的汇编代码,可比 GCC AT&T 格式的便于阅读多了。
编辑汇编代码,推荐使用 Notepad++,完美支持 MASM 语法高亮。
首先下载我修改好的 VS 版 Linux 0.11 源码,解压后打开解决方案。
右键点击 Image 项目,重新生成,按 Ctrl + F5 运行即可。
会启动调试版的 Bochs 虚拟机,加载新编译的软盘镜像运行。
虚拟硬盘内,带 gcc 1.40 编译环境,可以自己写程序测试各个系统调用功能。
阅读代码中有不明白的,直接插入 printk,重新生成运行,几秒钟的事。
关于 rm, chmod 一类命令提示 Not owner 的问题,是由于 0.11 版无 lstat 系统调用。
可以直接从 0.12 版复制新加的系统调用,补完即可,相信看过这部分代码后,大家都能做到。
#define __NR_sigsuspend 72
#define __NR_sigpending 73
#define __NR_sethostname 74
#define __NR_setrlimit 75
#define __NR_getrlimit 76
#define __NR_getrusage 77
#define __NR_gettimeofday 78
#define __NR_settimeofday 79
#define __NR_getgroups 80
#define __NR_setgroups 81
#define __NR_select 82
#define __NR_symlink 83
#define __NR_lstat 84
#define __NR_readlink 85
#define __NR_uselib 86
linux-0.12 官网下载地址:https://www.kernel.org/pub/linux/kernel/Historic/old-versions/linux-0.12.tar.gz
Bochs 的调试技巧
h 查看各命令帮助,一目了然,就不多说了,简单说下常用的。
b 断点
c 继续
s 逐语句
p 逐过程
r 寄存器
调试指定函数的方法
打开 Release 目录下 system.map 文件,搜索函数名,如:
0001:0000ca00 _main 0000da00 f main.obj
地址是取符号名后面那个,即 Rva+Base 地址。在 Bochs 控制台输入 b 0x0000da00 即可在 main 函数处中断。
和原版配置文件的区别
修改根文件系统设备号
在 bootsect.asm 以下行设置
ROOT_DEV = 0301h
修改键盘布局方案
在 keyboard.asm 以下行设置
KBD_US EQU
Linux 在 VS 下的实现
由于 PE 文件在内存中,会把 PE 头也载入,PE 头最大 4096,既 Rva 值。
也就是说,链接时,即使基地址设置成0,代码的偏移也会是 4096。
所以,直接给 system 模块载入到内存 1000h 处,原版是 0。
1000h 刚好是 pg0 的地址,所以给 pg_dir 手工定义成 0。
然后 pg0 定义在程序入口处,其它页 pg1 之类的 ORG 依次减 1000h。
由于 MASM 无 ljmp 指令,实现段间跳转使用 retf 指令,如下:
push 代码段
push 地址
retf
VS 下最大的问题是不能链接 16 位代码,LINK 没有 /TINY 参数选项。
解决的方法就是不使用绝对定位,给绝对定位改成固定内存地址,直接使用 32 位模式链接即可。
利用 ORG 固定变量地址后,定义下面这样的宏来操作变量,可读性也非常强,基本不受影响。
sread = ds:[01C0h]
head = ds:[01C2h]
track = ds:[01C4h]
关于 GCC 内嵌汇编,语法原因,用宏无法实现,基本上都改写成了内联函数的形式,效率上应该没啥差别。
对指定内存地址读写和除法取模的汇编代码,都用 C 重写了,调用又不频繁,用汇编没啥意义,重写后更易阅读。
《linux 内核完全注释》 http://product.china-pub.com/22033
电子书下载地址:http://pan.baidu.com/s/1ntx5hKt
《Linux内核设计的艺术》 http://product.china-pub.com/3767800
为什么用 Visual Studio 2013 就不用多说了吧,绝对比任何专用的源代码阅读软件都强悍。
查看函数调用层次一类的功能,为分析源代码提供最大的方便。
而且 MASM Intel 格式的汇编代码,可比 GCC AT&T 格式的便于阅读多了。
编辑汇编代码,推荐使用 Notepad++,完美支持 MASM 语法高亮。
首先下载我修改好的 VS 版 Linux 0.11 源码,解压后打开解决方案。
右键点击 Image 项目,重新生成,按 Ctrl + F5 运行即可。
会启动调试版的 Bochs 虚拟机,加载新编译的软盘镜像运行。
虚拟硬盘内,带 gcc 1.40 编译环境,可以自己写程序测试各个系统调用功能。
阅读代码中有不明白的,直接插入 printk,重新生成运行,几秒钟的事。
关于 rm, chmod 一类命令提示 Not owner 的问题,是由于 0.11 版无 lstat 系统调用。
可以直接从 0.12 版复制新加的系统调用,补完即可,相信看过这部分代码后,大家都能做到。
#define __NR_sigsuspend 72
#define __NR_sigpending 73
#define __NR_sethostname 74
#define __NR_setrlimit 75
#define __NR_getrlimit 76
#define __NR_getrusage 77
#define __NR_gettimeofday 78
#define __NR_settimeofday 79
#define __NR_getgroups 80
#define __NR_setgroups 81
#define __NR_select 82
#define __NR_symlink 83
#define __NR_lstat 84
#define __NR_readlink 85
#define __NR_uselib 86
linux-0.12 官网下载地址:https://www.kernel.org/pub/linux/kernel/Historic/old-versions/linux-0.12.tar.gz
Bochs 的调试技巧
h 查看各命令帮助,一目了然,就不多说了,简单说下常用的。
b 断点
c 继续
s 逐语句
p 逐过程
r 寄存器
调试指定函数的方法
打开 Release 目录下 system.map 文件,搜索函数名,如:
0001:0000ca00 _main 0000da00 f main.obj
地址是取符号名后面那个,即 Rva+Base 地址。在 Bochs 控制台输入 b 0x0000da00 即可在 main 函数处中断。
和原版配置文件的区别
修改根文件系统设备号
在 bootsect.asm 以下行设置
ROOT_DEV = 0301h
修改键盘布局方案
在 keyboard.asm 以下行设置
KBD_US EQU
Linux 在 VS 下的实现
由于 PE 文件在内存中,会把 PE 头也载入,PE 头最大 4096,既 Rva 值。
也就是说,链接时,即使基地址设置成0,代码的偏移也会是 4096。
所以,直接给 system 模块载入到内存 1000h 处,原版是 0。
1000h 刚好是 pg0 的地址,所以给 pg_dir 手工定义成 0。
然后 pg0 定义在程序入口处,其它页 pg1 之类的 ORG 依次减 1000h。
由于 MASM 无 ljmp 指令,实现段间跳转使用 retf 指令,如下:
push 代码段
push 地址
retf
VS 下最大的问题是不能链接 16 位代码,LINK 没有 /TINY 参数选项。
解决的方法就是不使用绝对定位,给绝对定位改成固定内存地址,直接使用 32 位模式链接即可。
利用 ORG 固定变量地址后,定义下面这样的宏来操作变量,可读性也非常强,基本不受影响。
sread = ds:[01C0h]
head = ds:[01C2h]
track = ds:[01C4h]
关于 GCC 内嵌汇编,语法原因,用宏无法实现,基本上都改写成了内联函数的形式,效率上应该没啥差别。
对指定内存地址读写和除法取模的汇编代码,都用 C 重写了,调用又不频繁,用汇编没啥意义,重写后更易阅读。
VS 版 Linux 0.11 下载地址:http://download.csdn.net/detail/norfa/7057293
运行截图:
更多推荐
已为社区贡献1条内容
所有评论(0)