可执行程序工作原理、

1、ELF(Executable and Linkable Format)可执行和可链接文件,其包含了以下三类:

  1. 可重定位文件(Relocatable File):保存着代码和适当的数据,用来和其它的目标文件一起来创建一个可执行文件、静态库文件或者是一个共享目标文件(主要是.o文件)
  2. 可执行文件(Executable File):保存着一个用来执行的程序,一般由多个可重定位文件结合生成,是完成了所有重定位工作和符号解析(除了运行时解析的共享库符号)的文件。
  3. 共享目标文件(Shared Object File):保存着代码和合适的数据,用来被两个链接器链接。第一个是链接编辑器(静态链接),可以和其它的可重定位和共享目标文件来创建其它的object。第二个是动态链接器,联合一个可执行文件和其它的共享目标文件来创建一个进程映象。

2、ELF文件格式:

ELF文件的主体是各种节,以及描述这些节属性的信息(Program header table和 Section header table),以及ELF文件的整体性信息(ELF header),如下图。

3、程序编译

程序从源代码到可执行文件的步骤:预处理、编译、汇编、衔接--以hello.c为例。

预处理: gcc -E hello.c -o hello.i  -m32
编译:gcc -S hello.i -o hello.s -m32
汇编:gcc -c hello.s -o hello.o -m32
默认衔接(动态库):gcc hello.o -o hello -m32
衔接静态库:gcc hello.o -o hello.static -m32 -static

最后得到的hello和hello-static文件就是可执行文件。可执行文件中的内容包括有编译后的机器指令代码、数据还包括了链接时所须要的一些信息,比如符号表、调试信息、字符串等。

其文件格式,如下图。

4、静态衔接和动态衔接

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

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

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

5、动态衔接

动态衔接分为以下两种;

  1. 可执行程序装载时动态衔接

    2.运行时动态衔接。

装载时动态衔接意味着在程序一开始启动的时候其所调用的库需要在一开始就提供,而运行时动态衔接只有程序运行到相关语句才会访问dllibexample。

6、fork和execve区别与联系

对于fork():

1、子进程复制父进程的所有进程内存到其内存地址空间中。父、子进程的

“数据段”,“堆栈段”和“代码段”完全相同,即子进程中的每一个字节都

和父进程一样。

2、子进程的当前工作目录、umask掩码值和父进程相同,fork()之前父进程

打开的文件描述符,在子进程中同样打开,并且都指向相同的文件表项。

3、子进程拥有自己的进程ID。

对于exec():

1、进程调用exec()后,将在同一块进程内存里用一个新程序来代替调用

exec()的那个进程,新程序代替当前进程映像,当前进程的“数据段”,

“堆栈段”和“代码段”背新程序改写。

2、新程序会保持调用exec()进程的ID不变。

3、调用exec()之前打开打开的描述字继续打开(好像有什么参数可以令打开

的描述字在新程序中关闭)

实验1:

编程使用exec* 库函数加载一个可执行文件,动态链接分为可执行程序装载时动态链接和运行时动态链接,编程练习动态链接库的这两种使用方式。

1、实验楼上说要从某个网站上下载下面两个源码:

shlibexample.h (1.3 KB) - Interface of Shared Lib Example

shlibexample.c (1.2 KB) - Implement of Shared Lib Example

但是后来查到是网易云付费课的附件,为了两个代码没必要花这么多钱,再说书上已经有源码了,可以自己写一遍,但是书上的代码有一个大坑,直接影响了我后面做实验的进度,之后来我会说明。

shlibexample.h
#ifndef _SH_LTB_EXAMPLE_H_
#define _SH_LTB_EXAMPLE_H_
#define SUCCESS 0
#define FAILURE (-1)
#ifdef __cplusplus
extern "C" {
#endif
int SharedLibApi();
#ifdef __cplusplus
}
#endif
#endif dllibexample.h
#ifndef _DL_LTB_EXAMPLE_H_
#define _DL_LTB_EXAMPLE_H_
#ifdef _cplusplus
extern "C"{
#endif
int DynamicalLoadingLibApi();
#ifdef _cplusplus
}
#endif
#endif shlibexample.c
#include <stdio.h>
#include "shlibexample.h"
int SharedLibApi()
{
printf("This is a shared libary!\n");
return SUCCESS;
} dllibexample.c
#include <stdio.h>
#include "dllibexample.h"
#define SUCCESS 0
#define FAILURE(-1)
int DynamicalLoadingLibApi()
{
printf(“This is a Dynamical Loading library”!\n”);
return SUCCESS;
}

2、编译成libshlibexample.so文件

$ gcc -shared shlibexample.c -o libshlibexample.so -m32
$ gcc -shared dllibexample.c -o libdllibexample.so -m32

错误到这里就显现出来了,为什么会报错我在网上查了很多答案,什么需要更新gcc啊,什么C文件头名字冲突啊,反正各种答案,耗费了很久时间就是依旧会报错,于是我重新打了好几遍代码,直到发现有一个贼细小的地方,书上很容易误导。

**注意看!这分明看着是就是LIB对吧,我在vim编辑器中敲的时候也和书上的样子差不多,然而我仔细看了一下I的上横和下横还是有点长短不一的,这货该不会是T吧!!,结果事实验证了我的判断,这货就是T,LTB。终于找到原因了 **

3、mian函数中分别以共享库和动态加载共享库的方式使用libshlibexample.so文件和libdllibexample.so文件

main.c
#include <stdio.h>
#include "shlibexample.h"
#include <dlfcn.h> int main()
{
printf("This is a Main program!\n");
/* Use Shared Lib */
printf("Calling SharedLibApi() function of libshlibexample.so!\n");
SharedLibApi(); //直接调用共享库
/* Use Dynamical Loading Lib */
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;
}

4、动态衔接运行测试

因为shilibexample在衔接时就需要提供路径,对应的头文件shilibexample.h也需要在编译器能找到位置。使用参数-L表明文件路径,-l表示库文件名。

dllibexample只有在程序运行到相关语句才会访问,在编译时不需要任何的相关信息,使用-ldl指明其所需要的共享库dlopen,同时修改LD_LIBRARY_PATH确保dllibexample.so可以查到。

gcc main.c -o main -L./ -l shlibexample -ldl -m32
export LD_LIBRARY_PATH=$PWD
./main

实验2:

使用gdb跟踪分析一个execve系统调用内核处理函数sys_execve ,验证您对Linux系统加载可执行程序所需处理过程的理解。

实验二就只能在实验楼环境做了,毕竟本地虚拟机没有配好的环境。

1、首先从github上下载包含test_exec.c文件的文件夹,进行编译。

ls
cd ~/LinuxKernel
rm menu -rf
git clone https://github.com/mengning/menu.git
cd menu
mv test_exec.c test.c
make rootfs

2、在qemu界面使用help和exec命令查看是否编译成功。

3、随后重新启动qemu。

4、加载内核和端口。

5、设置三个断点。

6、调试运行程序。

2019-2020-1 20199314 《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. vimrc配置文件

    目录 vimrc配置文件 参考 主要功能 使用方法 配置文件 文件下载 vimrc配置文件

  2. Python 命令行参数解析工具 argparse

    为什么需要argparse 开门见山,举一个简易计算器代码的例子,其中sys.argv用来读取脚本执行时后面传入的参数. def calculator(x, y, operation): if &qu ...

  3. logback颜色

    官网日志连接:https://logback.qos.ch/manual/layouts.html#coloring 举例 logging.pattern.console=%red(%d{yyyy-M ...

  4. SpringBootSecurity学习(23)前后端分离版之OAuth2.0 其它模式

    密码模式 前面介绍了授权码模式和刷新令牌两种获取最新令牌的方法,下面来看一下其它模式.首先看密码模式,我们默认配置的三种模式中其实就包含密码模式的支持: 因此我们启动项目,直接使用密码模式即可,访问地 ...

  5. 【Java基础】Java开发过程中的常用工具类库

    目录 Java开发过程中的常用工具类库 1. Apache Commons类库 2. Guava类库 3. Spring中的常用工具类 4. 其他工具 参考 Java开发过程中的常用工具类库 1. A ...

  6. AVL树、红黑树以及B树介绍

    简介 首先,说一下在数据结构中为什么要引入树这种结构,在我们上篇文章中介绍的数组与链表中,可以发现,数组适合查询这种静态操作(O(1)),不合适删除与插入这种动态操作(O(n)),而链表则是适合删除与 ...

  7. Java求和的整体思路

    一.    设计思想: 设计这个程序我们需要考虑到参数的输入,并且可以输入多个参数,以及为用户考虑到各种的边界问题.首先第一步我们应该给出输入参数的语句,让用户可以输入.第二步我们应对其进行参数个数的 ...

  8. LeetCode_844-Backspace String Compare

    输入两个字符串S和T,字符串只包含小写字母和”#“,#表示为退格键,判断操作完退格键剩下字符串是否相等例子:S = “ab#c", T = "ad # c” 返回true,剩下的字 ...

  9. django rest framework1

    内容回顾: 1.开发模式 - 普通开发方式(前后端放在一起写) - 前后端分离 2.后端开发 为前端提供URL(API/接口的开发) 注:永远返回HttpResponse 3.Django FBV.C ...

  10. [JZOJ5456]【NOIP2017提高A组冲刺11.6】奇怪的队列

    Description nodgd的粉丝太多了,每天都会有很多人排队要签名.今天有