2021-2022-1 20212813《Linux内核原理与分析》第八周作业
作者:互联网
Linux 内核如何装载和启动一个可执行程
一、基础知识
1、编译链接的过程
程序从源代码到可执行文件需要经过以下步骤:
预处理、编译、汇编、链接,如下图所示,每一步产生不同的文件。
各步骤的任务如下:
- 预处理:删除所有注释;删除所有的“#define”,展开所有的宏定义;处理所有的条件预编译指令;添加行号和文件名标识等
- 编译:编译时,gcc首先检查代码的规范性、是否有语法错误等,以确定代码实际要做的工作。在检查无误后,gcc把代码翻译成汇编语言
- 汇编:指把汇编语言代码翻译成目标机器指令的过程,形成的.o格式文件已经是ELF格式文件
- 链接:将各种代码和数据部分收集起来并组合成为一个单个文件,这个文件可以被加载到内存中并执行
以下两张图分别展示的是汇编和链接之后的文件节区信息表,能够发现链接之后的大部分节Addr有了地址值,并且多了很多内容。
2、ELF 可执行文件格式
ELF(Excutable and Linking Format)是一个文件格式的标准。如下图所示,通过readelf -h test
查看可执行文件hello的头部,头部里面注明了目标文件类型ELF32,入口点地址为0x8048730,即可执行文件加载到内存中开始执行的第一行代码地址。可执行文件的格式和进程的地址空间有一个映射的关系,当程序要加载到内存中运行时,将ELF文件的代码段和数据段加载到进程的地址空间。
ELF文件的三种类型:
- 可重定位文件:保存着代码和适当的数据,用来和其他的object文件一起创建一个可执行文件或者是一个共享文件。主要是.o文件;
- 可执行文件:保存着一个用来执行的程序;
- 共享目标文件:共享库是指可以被可执行文件或其他库文件使用的目标文件
3、静态链接和动态链接
静态链接
静态链接是在生成可执行文件时进行的。在目标模块中记录符号地址,而在可执行文件中改写为指令直接使用的数字地址。
动态链接
在装入或运行时进行链接。通常被链接的共享代码称为动态链接库(DLL, Dynamic-Link Library)或共享库(shared library)。动态链接分为可执行程序装载时动态链接和运行时动态链接:
- 装载时动态链接
编写以下文件example.c和example.h生成共享库:
#include <stdio.h>
#include "example.h"
int fun_zzx()
{
printf("This is a shared libary\n");
return 0;
}
#ifndef _EXAMPLE_H_
#define _EXAMPLE_H_
#define SUCCESS 0
#define FAILURE (-1)
int fun_zzx();
#endif
测试文件test.c:
#include <stdio.h>
int main()
{
fun_zzx();
return 0;
}
测试结果如下图所示:
- 运行时动态链接
修改example.c文件为:
#include <stdio.h>
#include "example.h"
int fun_zzx()
{
printf("This is a Dynamical Loading libary!\n");
return SUCCESS;
}
新的测试文件test.c代码如下:
#include <stdio.h>
#include <dlfcn.h>
#include "example.h"
int main()
{
printf("This is a Main program!\n");
/* Use Dynamical Loading Lib */
void * handle = dlopen("libexample.so",RTLD_NOW);
if(handle == NULL)
{
printf("Open Lib libexample.so Error:%s\n",dlerror());
return FAILURE;
}
int (*func)(void);
char * error;
func = dlsym(handle,"fun_zzx");
if((error = dlerror()) != NULL)
{
printf("fun_zzx not found:%s\n",error);
return FAILURE;
}
printf("Calling fun_zzx() function of libexample.so!\n");
func();
dlclose(handle);
return SUCCESS;
return 0;
}
测试结果如下图所示:
二、实验过程
1、跟踪分析execve 系统调用内核处理函数sys_execve
execve系统调用的整个过程的简单流程图如下:
按照之前调试MenuOS的方法,启动gdb在sys_execve、load_elf_binary和start_thread处设置断点,然后运行OS:
在MenuOS中执行exec命令,跟踪结果如下:
追踪到start_thread,用po new_ip
,得到的是0x8048730,通过readelf –h hello
可以看到hello这个可执行程序它的入口点地址也是0x8048730。
之后在执行hello程序的过程中,对寄存器的值进行修改以更新的执行环境:
三、遇到的问题
如果要调用动态加载共享库,就要使用定义在dlfcn.h中的dlopen。给出文件名libexample.so和标志RTLD_NOW打开动态链接库,返回handle句柄。dlsym函数与上面的dlopen函数配合使用,根据操作句柄(由dlopen打开动态链接后返回的指针)handle与符号(要求获取的函数或全局变量的名称)fun_zzx,返回符号对应的地址。使用此地址可以获得库中特定函数的地址,并且调用库中的相应函数。这样就可以使用动态加载共享库里面所定义的函数了。
标签:可执行文件,文件,include,zzx,2022,Linux,fun,20212813,链接 来源: https://blog.csdn.net/zzx751775692/article/details/121241117