可执行程序工作原理

《庖丁解牛》第七章书本知识总结

  1. “目标文件”是指编译器生成的文件,“目标”指的是目标平台,例如x86或x64,它决定了编译器使用的机器指令集。目标文件一般也叫做ABI(应用程序二进制接口),目标文件和目标平台是二进制兼容的。二进制兼容是指该目标文件已经是适应某一种CPU体系结构上的二进制指令。
  2. ELF即可执行的和可链接的格式,是一个目标文件格式的标准,用于存储Linux程序。
  3. ELF文件的类型

经查资料,应该分类为4类:

  1. 可重定位文件(Relocatable File):保存着代码和适当的数据,用来和其它的目标文件一起来创建一个可执行文件、静态库文件或者是一个共享目标文件(主要是.o文件)
  2. 可执行文件(Executable File):保存着一个用来执行的程序,一般由多个可重定位文件结合生成,是完成了所有重定位工作和符号解析(除了运行时解析的共享库符号)的文件。
  3. 共享目标文件(Shared Object File):保存着代码和合适的数据,用来被两个链接器链接。第一个是链接编辑器(静态链接),可以和其它的可重定位和共享目标文件来创建其它的object。第二个是动态链接器,联合一个可执行文件和其它的共享目标文件来创建一个进程映象。
  4. 核心转储文件(Core Dump File):保存核心转储信息。
  1. ELF文件的主体是各种节,还有描述这些节属性的信息(Program header table和Section header table),以及ELF文件的整体描述信息(ELF header)。

  2. ELF Header会给出很多关于本ELF文件的属性信息,例如e_type体现了ELF文件类型,e_type值1、2、3、4分别代表可重定位文件、可执行文件、共享目标文件和核心转储文件。
  3. c代码的预处理、编译、汇编、链接(ESc、iso)

    gcc -E hello.c -o hello.i //预处理

    gcc -S hello.i -o hello.s //编译

    gcc -c hello.s -o hello.o //汇编

    gcc hello.o -o hello //链接

  4. readelf命令

    -a 等价于 -h -l -S -s -r -d -V -A -I

    -h 显示elf文件开始的文件头信息

    -S 显示节头信息

    -l 显示段头Program Header

    -s 显示符号表段中的项(如果有)

    -r 显示可重定位段的信息

    -H 显示readelf所支持的命令行选项
  5. 静态链接与动态链接

静态链接:在编译链接时直接将需要的执行代码复制到最终可执行文件中,优点是代码的装载速度快,执行速度也比较快,对外部环境依赖度低。缺点是如果多个应用程序使用同一库函数,会被装载多次,浪费内存。

动态链接:编译时不直接复制可执行代码,而是通过记录一系列符号和参数,在程序运行或加载时将这些信息传递给操作系统。操作系统负责将需要的动态库加载到内存中,在程序运行到指定的代码时,去共享执行内存中已经加载的动态库去执行代码,最终达到运行时链接的目的。优点是多个程序可以共享同一段代码,而不需要在磁盘上存储多个复制。缺点是在运行时加载可能会影响程序的前期执行性能,而且对使用的库依赖性较高。(分为装载时动态链接和运行时动态链接)

再使用gcc hello.o -o hello.static -static进行静态链接,发现得到的可执行程序文件大小大概是动态链接的100倍。

  1. 装载时动态链接

    使用命令gcc -shared shlibexample.c -o libshlibexample.so -m32编译装载时链接动态库libshlibexample.so

    shlibexample.h:



    shlibexample.c:

  2. 运行时动态链接

    使用命令gcc -shared dllibexample.c -o libdllibexample.so -m32编译运行时链接动态库libdllibexample.so

    dllibexample.h



    dllibexample.c

  3. 动态链接运行测试

    使用命令gcc main.c -o main -L./ -l shlibexample -ldl -m32编译测试main函数
#include <stdio.h>
#include "shlibexample.h"
#include <dlfcn.h> int main()
{
printf("This is a Main program!\n"); //sh
printf("Calling ShardLibApi() function of libshlibexample.so!\n");
SharedLibApi(); //dl
void * handle = dlopen ("libdllibexample.so",RTLD_NOW);
if(handle == NULL)
{
printf("Open Lib libdllibexample.so Error:%s\n",dlerror());
return FAILURE;
}
int (*func)(void);
char * error;
func = dlsym(handle,"DynamicalLoadingLibApi");
if((error = dlerror()) != NULL)
{
printf("DynamicalLoadingLibApi not found:%s\n",error);
return FAILURE;
}
printf("Calling DynamicalLoadingLibApi() function of libdllibexample.so!\n");
func();
dlclose(handle);
return SUCCESS;
}

在运行前,使用命令export LD_LIBRARY_PATH=$PWD将当前目录加入库文件搜索目录。

实验:使用cgdb跟踪分析execve系统调用内核处理函数sys_execve

  1. make rootfs,发现没有包含sys_wait.h,qemu命令也不适用于本机器,先添加sys_wait.h

  2. 修改Makefile

  3. 看到exec命令的运行结果

  4. 冻结,准备调试

  5. 设置断点(先设置到sys_execve,再设置其他两个)

  6. 单步走并进入函数,发现sys_execve调用了do_execve

  7. 继续运行到load_elf_binary

  8. 继续执行到start_thread

  9. 使用po new_ip查看new_ip所指向的地址,new_ip是返回到用户态的第一条指令的地址

  10. 查看hello文件的elf头部



    发现定义的入口地址与new_ip所指向的地址是一致的。
  11. 继续单步执行

总结

装载时动态链接中,模块非常明确调用某个导出函数,使得它们就像本地函数一样。这需要链接时链接那些函数所在DLL的导入库,导入库向系统提供了载入DLL时所需的信息及DLL函数定位。 但是在装载时装载过多的库又会影响程序的启动速度。

运行时动态链接中,不需要包含头文件,但需要在代码中进行读取、装载、关闭等一系列行为,比较繁琐而且增加了代码行数,出现错误的可能性也增加了。

参考资料

《庖丁解牛Linux》

ELF文件格式解析

ELF文件结构详解

2018-2019-1 20189215 《Linux内核原理与分析》第八周作业的更多相关文章

  1. 2019-2020-1 20199329《Linux内核原理与分析》第九周作业

    <Linux内核原理与分析>第九周作业 一.本周内容概述: 阐释linux操作系统的整体构架 理解linux系统的一般执行过程和进程调度的时机 理解linux系统的中断和进程上下文切换 二 ...

  2. 2019-2020-1 20199329《Linux内核原理与分析》第二周作业

    <Linux内核原理与分析>第二周作业 一.上周问题总结: 未能及时整理笔记 Linux还需要多用 markdown格式不熟练 发布博客时间超过规定期限 二.本周学习内容: <庖丁解 ...

  3. 20169212《Linux内核原理与分析》第二周作业

    <Linux内核原理与分析>第二周作业 这一周学习了MOOCLinux内核分析的第一讲,计算机是如何工作的?由于本科对相关知识的不熟悉,所以感觉有的知识理解起来了有一定的难度,不过多查查资 ...

  4. 20169210《Linux内核原理与分析》第二周作业

    <Linux内核原理与分析>第二周作业 本周作业分为两部分:第一部分为观看学习视频并完成实验楼实验一:第二部分为看<Linux内核设计与实现>1.2.18章并安装配置内核. 第 ...

  5. 2018-2019-1 20189221 《Linux内核原理与分析》第九周作业

    2018-2019-1 20189221 <Linux内核原理与分析>第九周作业 实验八 理理解进程调度时机跟踪分析进程调度与进程切换的过程 进程调度 进度调度时机: 1.中断处理过程(包 ...

  6. 2017-2018-1 20179215《Linux内核原理与分析》第二周作业

    20179215<Linux内核原理与分析>第二周作业 这一周主要了解了计算机是如何工作的,包括现在存储程序计算机的工作模型.X86汇编指令包括几种内存地址的寻址方式和push.pop.c ...

  7. 2019-2020-1 20209313《Linux内核原理与分析》第二周作业

    2019-2020-1 20209313<Linux内核原理与分析>第二周作业 零.总结 阐明自己对"计算机是如何工作的"理解. 一.myod 步骤 复习c文件处理内容 ...

  8. 2018-2019-1 20189221《Linux内核原理与分析》第一周作业

    Linux内核原理与分析 - 第一周作业 实验1 Linux系统简介 Linux历史 1991 年 10 月,Linus Torvalds想在自己的电脑上运行UNIX,可是 UNIX 的商业版本非常昂 ...

  9. 《Linux内核原理与分析》第一周作业 20189210

    实验一 Linux系统简介 这一节主要学习了Linux的历史,Linux有关的重要人物以及学习Linux的方法,Linux和Windows的区别.其中学到了LInux中的应用程序大都为开源自由的软件, ...

  10. 2018-2019-1 20189221《Linux内核原理与分析》第二周作业

    读书报告 <庖丁解牛Linux内核分析> 第 1 章 计算工作原理 1.1 存储程序计算机工作模型 1.2 x86-32汇编基础 1.3汇编一个简单的C语言程序并分析其汇编指令执行过程 因 ...

随机推荐

  1. 在fedora 18中将普通用户设置为sudo权限

    将一般的用户加入sudo组is not in the sudoers file. This incident will be reported 解决方法 在一般用户下执行sudo命令提示xxx is ...

  2. Delphi数据类型转换

    [转]Delphi数据类型转换 DateTimeToFileDate        将DELPHI的日期格式转换为DOS的日期格式 DateTimeToStr              将日期时间格式 ...

  3. 存储总量达20T的MySQL实例,如何完成迁移?

    版权声明:本文由王亮原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/122 来源:腾云阁 https://www.qclou ...

  4. mysql如何查询当前周的第一天的日期?

    转自:http://blog.csdn.net/zzhongcy/article/details/43016685 select date_sub(curdate(),INTERVAL WEEKDAY ...

  5. java实现创建临时文件然后在程序退出时自动删除文件(转)

    这篇文章主要介绍了java实现创建临时文件然后在程序退出时自动删除文件,从个人项目中提取出来的,小伙伴们可以直接拿走使用. 通过java的File类创建临时文件,然后在程序退出时自动删除临时文件.下面 ...

  6. 170503、centos6.5安装mysql5.6.30

    准备:虚拟机地址:192.168.0.110 安装目录/usr/local/ 首先卸载已经安装的mysql使用命令查看rpm -qa | grep mysql卸载使用 rpm -e xxx 或者 yu ...

  7. ubuntu下安装运行colmap

    从源码安装 colmap可以在主流的系统windows,mac,linux安装 从github上获取colmap的最新源码 git clone https://github.com/colmap/co ...

  8. ArcGIS API for JavaScript开发笔记(一)——ArcGIS for Javascript API 3.14本地部署

    堪称史上最详细的< ArcGIS forJavascript API 3.14本地部署>文档,有图有真相~~~ ---------环境:Windows server 2012R2,IIS ...

  9. Python自动发布Image service的实现

    使用Python自动发布地图服务已经在上一篇博客中讲到,使用Python创建.sd服务定义文件,实现脚本自动发布ArcGIS服务,下面是利用Python自动发布Image service的实现. -- ...

  10. 利用Qt开发跨平台APP(二)(iOS,使用Qt5.9,很详细,有截图)

    本文将手把手教你如何使用Qt编译出iOS应用程序. Qt是一个优秀的跨平台开发工具.我们利用Qt可以很方便地将一次编写的应用,多次编译到不同平台上,如Windows.Linux.MAC.Android ...