2021-2022-1 20212813《Linux内核原理与分析》第八周作业
2021/11/11 7:13:52
本文主要是介绍2021-2022-1 20212813《Linux内核原理与分析》第八周作业,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
Linux 内核如何装载和启动一个可执行程
- 一、基础知识
- 1、编译链接的过程
- 2、ELF 可执行文件格式
- 3、静态链接和动态链接
- 静态链接
- 动态链接
- 二、实验过程
- 1、跟踪分析execve 系统调用内核处理函数sys_execve
- 三、遇到的问题
一、基础知识
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,返回符号对应的地址。使用此地址可以获得库中特定函数的地址,并且调用库中的相应函数。这样就可以使用动态加载共享库里面所定义的函数了。
这篇关于2021-2022-1 20212813《Linux内核原理与分析》第八周作业的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-12-18git仓库有更新,jenkins 自动触发拉代码怎么配置的?-icode9专业技术文章分享
- 2024-12-18Jenkins webhook 方式怎么配置指定的分支?-icode9专业技术文章分享
- 2024-12-13Linux C++项目实战入门教程
- 2024-12-13Linux C++编程项目实战入门教程
- 2024-12-11Linux部署Scrapy教程:新手入门指南
- 2024-12-11怎么将在本地创建的 Maven 仓库迁移到 Linux 服务器上?-icode9专业技术文章分享
- 2024-12-10Linux常用命令
- 2024-12-06谁看谁服! Linux 创始人对于进程和线程的理解是…
- 2024-12-04操作系统教程:新手入门及初级技巧详解
- 2024-12-04操作系统入门:新手必学指南