Linux内核如何装载和启动一个可执行程序
一、实验步骤
与上一课的实验步骤基本相同,在shell中依次运行以下命令,并编译运行
cd LinuxKernel
rm menu -rf
cd menu
mv test_exec.c test.c
make rootfs
重新回到shell窗口,cd LinuxKernel回退到LinuxKernel目录,使用下面的命令启动内核
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img
-s -S
水平分割一个新的shell窗口出来,使用下面的命令启动gdb调试
gdb
(gdb) file linux-3.18.6/vmlinux
(gdb) target remote:1234
并在系统调用sys_execve的入口处设置断点
(gdb) b sys_execve
在QEMU窗口中输入exec,系统就会停在上面设置的断点处:
同理可以设置以下断点
b load_elf_binary
b start_thread
从而追踪内核代码。
二、理解Linux系统加载可执行程序所需处理过程
理论:理解编译链接的过程和ELF可执行文件格式
我们都知道,C语言的执行都必须经过预处理、编译、汇编、链接和执行等过程。这次实验我们就通过 GDB 来跟踪分析一个 execve 系统调用内核处理函数 sys_execve,深入理解 Linux 操作系统装载链接和运行可执行程序的过程。
还是以 hello_world.c 程序为例,搞清楚可执行程序是如何生成的:
#include <stdio.h>
int main()
{
printf("hello, world!\n");
return 0;
}
1.预处理,处理代码中的宏定义和 include 文件,并做语法检查
gcc -E hello_world.c -o hello_world.i
2.编译,生成汇编代码
gcc -S hello_world.i -o hello_world.s
3.汇编,生成 ELF 格式的目标代码
gcc -c hello_world.s -o hello_world.o
4.链接,生成可执行代码
gcc hello_world.o -o hello_world
5.执行程序
./hello_world hello, world!</span>
2、静态链接和动态链接
静态连接库就是把(lib)文件中用到的函数代码直接链接进目标程序,程序运行的时候不再需要其它的库文件;动态链接就是把调用的函数所在文件模块(DLL)和调用函数在文件中的位置等信息链接进目标程序,程序运行的时候再从DLL中寻找相应函数代码,因此需要相应DLL文件的支持.
静态链接库与动态链接库都是共享代码的方式,如果采用静态链接库,则无论你愿不愿意,lib 中的指令都全部被直接包含在最终生成的 EXE 文件中了。但是若使用 DLL,该 DLL 不必被包含在最终 EXE 文件中,EXE 文件执行时可以“动态”地引用和卸载这个与 EXE 独立的 DLL 文件。静态链接库和动态链接库的另外一个区别在于静态链接库中不能再包含其他的动态链接库或者静态库,而在动态链接库中还可以再包含其他的动态或静态链接库。