2017-2018-1 20179209《Linux内核原理与分析》第八周作业
Linux内核如何装载和启动一个可执行程
一.实验
1.1理解编译链接的过程和ELF可执行文件格式。
1.1.1编译链接过程
能用图说明的问题,就少用文字描述:
1.1.2ELF可执行文件
ELF可执行文件中有三种主要的目标文件:
- 一个可重定位文件保存着代码和适当的数据,用来和其他的object文件一起创建一个可执行文件或者是一个共享文件。主要是.o文件。
- 一个可执行文件保存着一个用来执行的程勋;该文件指出了exec如何创建程序进程映像。
- 一个共享object文件保存着代码和合适地数据,用来被下面的两个链接器链接。第一个是链接编辑器,可以和其他的可重定位的共享object文件来创建其他的object。第二个是动态链接器,联合一个可执行文件和其他的共享object文件来创建一个进程映像。
Object文件参与程序的链接(创建一个程序)和程序的执行(运行一个程序)。一个ELF头在文件的开始,保存了路线图(road map),描述该文件的组织情况。程序头表告诉系统如何创建一个进程的内存映像。section头表包含了描述文件sections的信息。每个section在这个表中有一个入口;每个入口给出了该section的名字、大小等信息。sillysen@20179209:~/homework$ readelf -h main
c查看一个main目标文件的信息:
1.2编程使用exec*库函数加载一个可执行文件,动态链接分为可执行程序装载时动态链接和运行时动态链接,编程练习动态链接库的这两种使用方式。
1.2.1使用execlp加载上周GCC内联汇编的main程序
int main(int argc,char *argv[]){
int pid;
pid = fork();
if(pid < 0){
fprintf(stderr,"Fork failed!");
exit(-1);
}
else{
execlp("/home/sillysen/homework/11.14/main","./main","2","0","1","7","9","2","0","9",NULL);
exit(0);
}
return 0;
}
运行结果如下:
execlp函数的第一个参数是可执行程序的路径,后面的参数是这个可执行程序运行时的参数,值得注意的是命令本身也算一个参数,所以第二个参数一般就是命令本身。至于这里为什么输出两遍,而且是这样的格式,我也不太清楚,欢迎大家指正。
1.2.2编程练习动态链接库的这两种使用方式
1.2.2.1可执行程序装载时动态链接
我们测试的代码非常简单,能说明问题就行。把sharelib.c制作成动态库,然后在main函数中调用。源代码如下:
/*
main 函数
*/
#include <stdio.h>
extern int print();
int main(int argc, char *argv[]){
print();
return 0;
}
/*
sharelib
*/
int print(){
printf("This is share lib!\n");
return 0;
}
sillysen@20179209:~/homework/11.16$ gcc -fPIC -shared -o libsharelib.so sharelib.c //制作动态库libsharelib.so
sillysen@20179209:~/homework/11.16$ sudo cp libsharelib.so /usr/lib //将生成的动态库拷贝到/usr/lib目录,只有这样生成的程序才能执行
1.2.2.2可执行程序运行时动态链接
修改main函数为如下:
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int main(int argc, char *argv[]){
//print();
void * handle = dlopen("libsharelib.so",RTLD_NOW);
if(handle == NULL){
printf("Open Lib libsharelib.so Error:%s\n",dlerror);
return -1;
}
int (*func)(void);
char * error;
func = dlsym(handle,"print");
if((error = dlerror()) != NULL){
printf("print not found:%s\n",error);
return -1;
}
func();
dlclose(handle);
return 0;
}
编译命令为sillysen@20179209:~/homework/11.16$ gcc -o main main.c -ldl
,使用dl系列函数除了要在头文件中包含dlfcn.h之外,在编译链接时还得加-ldl参数。
1.3使用gdb跟踪分析一个execve系统调用内核处理函数sys_execve
根据孟老师视频中讲解的execve系统调用的整个过程,可以把其中一些重要的函数摘录出来,画出如下的一个简易的流程图(不完整的流程图,只包含老师讲解过的过程)如下:
为此我在关键位置设置断点(除了视频中讲解的三个外,又加了其他几个):
开始GDB跟踪:
分析:
- 八个断点只跟踪到了四个exec命令就执行完了。其中第一个是sys_execve,截图中没有是因为我一开始就断在了sys_execve处,第二个是do_open_exec断点,第三个是load_elf_binary,第四个是start_thread。其中do_execve这个断点没出现是因为在sys_execve函数中最后
return do_execve(getname(filename),argv,envp);
时候我没有s进去看;而load_elf_interp断点没有出现是因为这里调用的fork为静态装载可执行程序,而只有动态装载才会调用这个函数,到此还有两个断点do_execve_common和exec_binprm没有出现。为此我还特意断了一下exec_binprm中search_binary_handler函数,gdb显示没有这个符号,这里就留下一个问题,为什么会出现这样的情况?根据视频中讲解这个函数的目的是装载bprm数据结构,但gdb跟踪过程中却没有这一步。。。 - 新的可执行程序的起点根据程序的链接方式不同而不同,如果是静态链接,则起点为可执行文件里边规定的entry地址,也是main函数对应的位置;如果是动态链接,则elf_entry就是指向动态链接器的起点。
- execve返回后之所以能顺利执行是因为可执行程序在当前进程调用execve内核函数的时候已经部署就绪,返回用户态后之前的进程“苏醒”,开始执行程序。
二.第十三、十四章
2.1虚拟文件系统(VFS)
虚拟文件系统,作为内核子系统,为用户程序提供了文件和文件系统相关的接口。系统中所有文件系统不但依赖VFS共存,而且也依靠VFS系统协同工作。通过虚拟文件系统,程序可以利用标准的Uinx系统调用对不同文件系统,甚至不同介质上的文件系统进行读写操作。总而言之,linux下一切皆文件!
2.2文件系统抽象层
之所以可以使用这种通用接口对所有类型的文件系统进行操作,是因为内核在它的底层文件系统接口上建立了一个抽象层。该抽象层使Linux能够支持各种文件系统,即便是它们在功能和行为上存在很大的差别,为了支持多文件系统,VFS提供了一个通用文件系统模型,该模型囊括了任何文件系统的常用功能集和行为。Linux可以支持很多种差异很大的文件系统,从DOS系统的FAT到Windows系统的NTFS,再到各种Unix风格文件系统和Linux特有的文件系统。VFS抽象层之所以能衔接各种各样的文件系统,是因为它定义了所有文件系统都支持的、基本的、概念上的接口和数据结构。同时实际文件系统也将自身的诸如“如何打开文件”,“目录是什么”等概念在形式上与VFS的定义保持一致。因为实际文件系统的代码在同一接口和数据结构下隐藏了具体的实现细节,所以在VFS层和内核的其他部分看来,所有文件系统都是相同的。
2.3VFS中的四个主要对象类型
- 超级块对象 super_operations
- 索引节点对象 inode_operations
- 目录项对象 dentry_opreations
- 文件对象 file_operations
2.4块设备与字符设备
- 系统中能够随机访问固定大小数据片的硬件设备称作块设备,这些固定大小的数据片称作块。最常见的块设备是硬盘、软盘驱动器、蓝光光驱和闪存等。它们是以安装文件系统的方式使用的——这也是块设备一般的访问方式。
- 字符设备按照字符流的方式被有序访问,像串口和键盘就属于字符设备,。如果一个硬件设备是以字符流的方式被访问的话,那就应该将它归为字符设备;如果一个设备是随机访问的,那么它就属于块设备。
以上两种类型的设备区别在于是否随机访问数据——换句话说,就是能否在访问设备时随机地从一个位置跳转到另一位置。
2.5块设备
块设备中最小的可寻址单元是扇区。扇区大小一般是2的整数倍,最常见的是512字节。扇区的大小是设备的物理属性,扇区是所有块设备的基本单元——块设备无法对比它还小的单元进行寻址和操作,尽管许多块设备能够一次对多个扇区进行操作。
2.6缓冲区和缓冲区头
当一个块被调入内存时(也就是在读入后或等待写出时),它要存储在一个缓冲区中。每个缓冲区与一个块对应,它相当于是磁盘块在内存中的表示。由于内核在处理数据是需要一些相关的控制信息,所以每一个缓冲区都有一个对应的描述符。该描述符用buffer_head结构体表示,称作缓冲区头,在文件<linux/buffer_head.h>中定义,它包含了内核操作缓冲区所需要的全部信息。缓冲区头结构和各个域的说明:
struct buffer_head{
unsigned long b_state; //缓冲区状态标志
struct buffer_head *b_this_page; //页面中的缓冲区
struct page *b_page; //存储缓冲区的页面
sector_t b_blocknr; //起始块号
size_t b_size; //映像的大小
char *b_data; //页面内的数据指针
.
.
.
}
2017-2018-1 20179209《Linux内核原理与分析》第八周作业的更多相关文章
- 20169212《Linux内核原理与分析》第二周作业
<Linux内核原理与分析>第二周作业 这一周学习了MOOCLinux内核分析的第一讲,计算机是如何工作的?由于本科对相关知识的不熟悉,所以感觉有的知识理解起来了有一定的难度,不过多查查资 ...
- 20169210《Linux内核原理与分析》第二周作业
<Linux内核原理与分析>第二周作业 本周作业分为两部分:第一部分为观看学习视频并完成实验楼实验一:第二部分为看<Linux内核设计与实现>1.2.18章并安装配置内核. 第 ...
- 2018-2019-1 20189221 《Linux内核原理与分析》第九周作业
2018-2019-1 20189221 <Linux内核原理与分析>第九周作业 实验八 理理解进程调度时机跟踪分析进程调度与进程切换的过程 进程调度 进度调度时机: 1.中断处理过程(包 ...
- 2017-2018-1 20179215《Linux内核原理与分析》第二周作业
20179215<Linux内核原理与分析>第二周作业 这一周主要了解了计算机是如何工作的,包括现在存储程序计算机的工作模型.X86汇编指令包括几种内存地址的寻址方式和push.pop.c ...
- 2019-2020-1 20199329《Linux内核原理与分析》第九周作业
<Linux内核原理与分析>第九周作业 一.本周内容概述: 阐释linux操作系统的整体构架 理解linux系统的一般执行过程和进程调度的时机 理解linux系统的中断和进程上下文切换 二 ...
- 2019-2020-1 20199329《Linux内核原理与分析》第二周作业
<Linux内核原理与分析>第二周作业 一.上周问题总结: 未能及时整理笔记 Linux还需要多用 markdown格式不熟练 发布博客时间超过规定期限 二.本周学习内容: <庖丁解 ...
- 2019-2020-1 20209313《Linux内核原理与分析》第二周作业
2019-2020-1 20209313<Linux内核原理与分析>第二周作业 零.总结 阐明自己对"计算机是如何工作的"理解. 一.myod 步骤 复习c文件处理内容 ...
- 2018-2019-1 20189221《Linux内核原理与分析》第一周作业
Linux内核原理与分析 - 第一周作业 实验1 Linux系统简介 Linux历史 1991 年 10 月,Linus Torvalds想在自己的电脑上运行UNIX,可是 UNIX 的商业版本非常昂 ...
- 《Linux内核原理与分析》第一周作业 20189210
实验一 Linux系统简介 这一节主要学习了Linux的历史,Linux有关的重要人物以及学习Linux的方法,Linux和Windows的区别.其中学到了LInux中的应用程序大都为开源自由的软件, ...
- 2018-2019-1 20189221《Linux内核原理与分析》第二周作业
读书报告 <庖丁解牛Linux内核分析> 第 1 章 计算工作原理 1.1 存储程序计算机工作模型 1.2 x86-32汇编基础 1.3汇编一个简单的C语言程序并分析其汇编指令执行过程 因 ...
随机推荐
- 在windows上一键编译各种版本的protobuf(2017-12-05修改)
所需工具 : cmake for windows 和 git for windows 原理:protobuf 是google的一个开源项目,其源代码在github上可以下载到,并且源码都采用cm ...
- 关于ionic打包出错:ionic Unable to start the daemon process
一直试都没问题的ionic build android 今天竟然冒出了这个错误 Error:Unable to start the daemon process. This problem migh ...
- python——操作符重载(重要)
类可以重载python的操作符 旧认识:__X__的名字 是系统定义的名字:是python特殊方法专用标识. 操作符重载使我们的对象与内置的一样.__X__的名字的方法是特殊的挂钩(hook) ...
- 【BIEE】11_BIEE图形报表在谷歌浏览器64.0.3282.140中访问图例乱码解决
如上图,使用谷歌浏览器访问BIEE图形报表的时候,标题.图例等涉及到中文的地方全部乱码了!但是用IE打开是不会乱码的,这是由于:谷歌需要设置编码格式 但是55版本以后,谷歌公司为了加快浏览器的速度,提 ...
- 51单片机 | 实现SMG12864液晶显示器操作
———————————————————————————————————————————— SMG12864液晶显示器 128*64个点位,可以显示图形或8*4个汉字 - - - - - - - - - ...
- Android蓝牙
代码地址如下:http://www.demodashi.com/demo/12772.html 前言:最近,新换了一家公司,公司的软件需要通过蓝牙与硬件进行通讯,于是趁此机会将Android蓝牙详细的 ...
- [译] 通过 contentEditable 属性创建一个所见即所得的编辑器(富文本编辑器)
译者注 这只是一篇入门教程,介绍了一些基础知识,仅供参考,切不可因此觉得富文本编辑器很简单. 创建富文本编辑器是一个非常复杂的工程,需要考虑到方方面面,也有很多坑(请参考原文第一条评论). 为免误导大 ...
- 新建WORD文档打开会出现转换文件对话框3步解决办法
1.选择“纯文本”格式打开word文件. ------------------------------------------------------------------------------ ...
- matlab-非线性方程求根函数及函数曲线绘制
Matlab中提供了很多求解非线性方程(y=f(x))的函数,刚開始使用,真的很困惑.全部.这里依据matlab的help文档对这些函数做一些小小的总结 fsolve函数 用来求解非线性方程组:F(x ...
- E - Hangover(1.4.1)
Time Limit:1000MS Memory Limit:10000KB 64bit IO Format:%I64d & %I64u Submit cid=1006#sta ...