您的位置:首页 > 运维架构 > Linux

“Linux内核分析”实验报告(七)Linux 操作系统如何装载链接并执行程序

2016-04-10 00:00 591 查看
摘要: Linux内核如何装载和启动一个可执行程序

窦猛汉+ 《Linux 内核分析》 MOOC 课程实验 分析 Linux 操作系统如何装载链接并执行程序

1.实验目的

我们知道从一个.c  .h文件到可执行文件
须经历预处理、编译、汇编、链接、执行程序等过程。然而具体怎么预处理、编译、汇编、链接、执行程序,其之间的关系我们并不明了,通过老师的视频有了一些了解,今天就通过
gdb
来跟踪分析一个
execve
系统调用内核处理函数
sys_execve
,分析
Linux
装载链接和运行可执行程序的过程。

2.实验过程

hello.c


.c
程序

1).预处理,处理代码中的宏定义和
include
文件,并做语法检查

2).编译,生成汇编代码

3).汇编,生成
ELF
格式的目标代码

4).链接,生成可执行代码

5).执行程序



预处理、编译、汇编、链接、执行程序之间的关系



1.静态链接于动态链接:

静态链接方法:静态链接的时候,载入代码就会把程序会用到的动态代码或动态代码的地址确定下来静态库的链接可以使用静态链接,动态链接库也可以使用这种方法链接导入库

动态链接方法:使用这种方式的程序并不在一开始就完成动态链接,而是直到真正调用动态库代码时,载入程序才计算(被调用的那部分)动态代码的逻辑地址,然后等到某个时候,程序又需要调用另外某块动态代码时,载入程序又去计算这部分代码的逻辑地址,所以,这种方式使程序初始化时间较短,但运行期间的性能比不上静态链接的程序。
2.静态库于动态库的特点

静态库:代码的装载速度快,执行速度也快,因为编译时它只会把你所需要的那部分链接进去,应用程序相对较大。但是如果没有多个应用程序的话,会被装载多次,浪费内存。

动态库:

共享:多个应用程序可以使用同一个动态库,启动多个应用程序的时候,只需要将动态库加载到内存一次就好。开发模块好:要求设计者对功能划分的比较好。

3.认识动态链接库

动态链接库是相对静态链接库而言的。所谓的静态链接库只把要调用的函数或过程链接到可执行文件中,成为可执行文件的一部分。换句话说,函数和过 程的代码就在程序的可执行文件中,该文件包含了运行时所需的全部代码。当多个程序都调用相同函数时,内存中就会存在这个函数的多个拷贝,这样就浪费了宝贵 的内存资源,而动态链接所调用的函数代码并没有被拷贝到应用程序的可执行文件中去,而是仅仅在其中加入了所调用函数的描述信息(往往是一些重定位信息)。 仅当应用程序被装入内存开始运行时,在系统的管理下,才在应用程序与相应的动态库之间建立链接关系。当要执行所调用的动态链接库中的函数时,根据链接产生 的重定位信息,系统下转去执行状态链接库中相应的函数代码。一般情况下,如果一个应用程序使用了动态链接库,系统保证内存只有动态库的一份复制品。

动态链接库的两种链接方法:

1)装载时动态链接(Load-time Dynamic Linking):这种方法的前提是在编译之前已经明确知道要调用的动态库的哪些函数,编译时在目标文件中只保留必要的链接信息,而不含动态库函数代码; 当程序执行时,调用函数的时候利用链接信息加载动态库函数代码并在内存中将其链接入调用程序的执行空间中(全部函数加载进内存),其主要目的是便于代码共 享。(动态加载程序,处在加载阶段,主要为了共享代码,共享代码内存)

2)运行时动态链接(Run-time Dynamic Linking):这种方式是指在编译之前并不知道将会调用哪些动态库函数,完全是在运行过程中根据需要决定应调用哪个函数,将其加载到内存中(只加载调 用的函数进内存);并标识内存地址,其他程序也可以使用该程序,并获得动态库函数的入口地址。(动态库在内存中只存在一份,处在运行阶段)

ELF文件:
在计算机科学中,是一种用于二进制文件、可执行文件、目标代码、共享库和核心转储的标准文件格式。

ELF文件由4部分组成,分别是ELF头(ELF header)、程序头表(Program header table)、节(Section)和节头表(Section header table)。实际上,一个文件中不一定包含全部内容,而且他们的位置也未必如同所示这样安排,只有ELF头的位置是固定的,其余各部分的位置、大小等信息由ELF头中的各项值来决定。



使用gdb跟踪sys_execve内核函数的处理过程:





3.实验总结

exec的执行流程为:sys_execve -> do_execve -> do_execve_common -> exec_binprm -> search_binary_handler -> load_binary ->load_elf_binary -> start_thread。我们调用execve的可执行程序时,当执行到exceve时,系统调用exceve陷入内核,创建一个新的用户态堆栈,把命令行参数的内容 和环境变量传递给系统调用内核处理函数的,然后内核处理函数会通过start_thread把这些拷贝到用户新的可执行程序的执行上下文环境.在exceve返回用户态的时候,就变成了被exceve加载的可执行程序。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c/c++ linux内核