2020-2021-1 20209314《Linux内核原理与分析》第四周作业

实验相关:

尝试在自己的Ubuntu中来搭建实验所需要的环境。

1.下载内核源码

首先是下载内核源码(Linux-3.18.6)解压并编译,代码过程如下:

mkdir LinuxKernel
cd LinuxKernel
wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.18.6.tar.xz
xz -d linux-3.18.6.tar.xz
tar -xvf linux-3.18.6.tar
cd linux-3.18.6
make i386_defcongig
make


在编译过程中遇到书中提到的相似的错误,提示不存在compiler-gcc9.h这一文件,查阅相关资料,是Ubuntu环境版本与gcc编译器版本不匹配的原因,进入到include/linux环境下,发现其中最高的版本为compiler-gcc5.h,解决这个问题的方法有两种,一是在网络上下载compiler-gcc9.h放入相应文件夹中,二是将compiler-gcc5.h复制重命名为compiler-gcc9.h后放入该文件夹中。实践中采用方法二解决该问题,成功编译。

2.制作根文件系统

代码如下:

mkdir rootfs
git clone https://github.com/mengning/menu.git
cd menu
gcc -pthread -o init linktable.c menu.c test.c -m32 -static
cd ../rootfs
cp ../menu/init ./
find . | cpio -o -Hnewc |gzip -9 > ../rootfs.img

其中执行

gcc -pthread -o init linktable.c menu.c test.c -m32 -static

时出现以下错误

查阅后主要是gcc缺少32位的环境,使用命令

apt-get install gcc-multilib

安装multilib后解决问题,成功编译。

3.启动不带调试信息的Linux内核和MennuOS

自己环境中没有安装qemu,使用

sudo apt-get install qemu 

安装qemu后,依然提示无法找到qemu,返回usr/bin目录中查找,发现只存在qemu-system-i386

通过Google后找到解决方法,可以建立一条软链接:

sudo ln -s /usr/bin/qemu-system-i386 /usr/bin/qemu

问题解决。

输入

qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img

启动成功

接下来是对内核进行跟踪调试,重新配置编译Linux内核,代码如下:

make menuconfig
make

重新配置编译Linux内核

4.跟踪调试Linux内核的启动过程(使用gdb跟踪)

(1)启动内核:

qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -S -s

注:

  • -s:在1234端口上创建了一个gdb-server,可用于之后设置断点跟踪内核;
  • -S:使CPU初始化之前冻结起来。

(2)启动gdb输入如下指令加载内核,建立连接

file linux-3.18.6/vmlinux  //在gdb界面中target remote之前加载符号表
target remote:1234  //用1234这个端口进行连接

(3)gdb中输入如下指令在start_kernel处设置断点

break start_kernel //可在target remote之前,也可在之后


查看star_kernel函数:

(4)gdb中输入如下指令在rest_init()处设置断点

break rest_init

查看rest_init()函数:

(5)分析

正如其名,strat_kernel是一切的起点,用于完成硬件系统的初始化工作,为C代码的运行设置环境。其中,比较重要的init_task是手工创建的PCB,是进程描述符,0号进程,即最终的idle进程。 通过rest_init()新建kernel_init和kthreadd内核线程。init_task()通过调用cpu_idle()转为idle进程,运行在内核空间;init_task()创建的kernel_init()(1号内核线程)通过调用do_execve可转为init用 户态1号进程,这是内核启动的第一个用户态进程;init_task()创建的kthreadd()(2号内核线程)始终运行在内核,负责所有内核线程的调度和管理。进程创建过程图如下图所示:

sequenceDiagram participant idle进程,无限循环运行的内核态 participant init_task(0号进程)决定了系统所有进程、线程的基因 participant init用户进程,看所有其他用户进程的祖先进程 participant kernel_init()1号内核线程 participant kthreadd()2号内核线程,始终运行在内核空间,是所有内核态其他守护线程的父线程 init_task(0号进程)决定了系统所有进程、线程的基因->>idle进程,无限循环运行的内核态: 转为 init_task(0号进程)决定了系统所有进程、线程的基因->>kernel_init()1号内核线程: 演变 init_task(0号进程)决定了系统所有进程、线程的基因->>kthreadd()2号内核线程,始终运行在内核空间,是所有内核态其他守护线程的父线程: 创建 kernel_init()1号内核线程->>init用户进程,看所有其他用户进程的祖先进程: 转为

5.尚未解决的问题(目前已解决)

在自己的Ubuntu环境中使用gdb中会出现以下错误:

查阅资料说是编译时没有正确设置-g选项,这个-g选项不能直接放在编译命令中,要在makefile的开头定义CFLAGS 变量:CFLAGS = -g ,这样list命令才能列出源代码。时间原因我在实验楼环境下完成了这部分的实验,这几天忙完后再来看这个错误怎么解决。
6.后续补充

尝试在

gcc -pthread -o init linktable.c menu.c test.c -m32 -static

中加入-g显示编译信息后成功通过,问题解决,猜测问题出在重新配置编译Linux内核中。重新检查后发现不知道什么原因导致compile the kernel with debug info未被选上,导致无法显示编译信息,再次选上后问题解决。

原文地址:https://www.cnblogs.com/mazhuhong/p/13882105.html