哈工大计算机系统大作业

系列文章目录

计算机系统

大作业

题 目 程序人生-Hello’s P2P
专 业 英才学院
学   号 7203610522
班   级 20wj102
学 生 李昀积    
指 导 教 师 刘宏伟

计算机科学与技术学院
2022年5月

摘 要

本文介绍了hello程序从程序编写到回收的整个过程,介绍了预处理、编译、汇编、链接生成可执行文件的全过程。

目 录

第1章 概述 - 4 -
1.1 HELLO简介 - 4 -
1.2 环境与工具 - 4 -
1.3 中间结果 - 4 -
1.4 本章小结 - 4 -
第2章 预处理 - 5 -
2.1 预处理的概念与作用 - 5 -
2.2在UBUNTU下预处理的命令 - 5 -
2.3 HELLO的预处理结果解析 - 5 -
2.4 本章小结 - 5 -
第3章 编译 - 6 -
3.1 编译的概念与作用 - 6 -
3.2 在UBUNTU下编译的命令 - 6 -
3.3 HELLO的编译结果解析 - 6 -
3.4 本章小结 - 6 -
第4章 汇编 - 7 -
4.1 汇编的概念与作用 - 7 -
4.2 在UBUNTU下汇编的命令 - 7 -
4.3 可重定位目标ELF格式 - 7 -
4.4 HELLO.O的结果解析 - 7 -
4.5 本章小结 - 7 -
第5章 链接 - 8 -
5.1 链接的概念与作用 - 8 -
5.2 在UBUNTU下链接的命令 - 8 -
5.3 可执行目标文件HELLO的格式 - 8 -
5.4 HELLO的虚拟地址空间 - 8 -
5.5 链接的重定位过程分析 - 8 -
5.6 HELLO的执行流程 - 8 -
5.7 HELLO的动态链接分析 - 8 -
5.8 本章小结 - 9 -
第6章 HELLO进程管理 - 10 -
6.1 进程的概念与作用 - 10 -
6.2 简述壳SHELL-BASH的作用与处理流程 - 10 -
6.3 HELLO的FORK进程创建过程 - 10 -
6.4 HELLO的EXECVE过程 - 10 -
6.5 HELLO的进程执行 - 10 -
6.6 HELLO的异常与信号处理 - 10 -
6.7本章小结 - 10 -
第7章 HELLO的存储管理 - 11 -
7.1 HELLO的存储器地址空间 - 11 -
7.2 INTEL逻辑地址到线性地址的变换-段式管理 - 11 -
7.3 HELLO的线性地址到物理地址的变换-页式管理 - 11 -
7.4 TLB与四级页表支持下的VA到PA的变换 - 11 -
7.5 三级CACHE支持下的物理内存访问 - 11 -
7.6 HELLO进程FORK时的内存映射 - 11 -
7.7 HELLO进程EXECVE时的内存映射 - 11 -
7.8 缺页故障与缺页中断处理 - 11 -
7.9动态存储分配管理 - 11 -
7.10本章小结 - 12 -
第8章 HELLO的IO管理 - 13 -
8.1 LINUX的IO设备管理方法 - 13 -
8.2 简述UNIX IO接口及其函数 - 13 -
8.3 PRINTF的实现分析 - 13 -
8.4 GETCHAR的实现分析 - 13 -
8.5本章小结 - 13 -
结论 - 14 -
附件 - 15 -
参考文献 - 16 -

1.第1章 概述

1.1 Hello简介
Hello源程序经过预处理器得到hello.i文件,然后经过编译器得到hello.s,再经过hello.o,然后经过汇编器得到hello.o,最后由链接器生成可执行文件hello。在shell中,fork产生一个子进程,就完成了从program到process
Shell对子进程进行execve,映射虚拟内存,然后加载并运行代码,运行结束后,父进程回收程序,内核删除相关数据。
1.2 环境与工具
硬件:X64 CPU 处理器:AMD Ryzen 7Mobile 4800H
软件:windows 10, virtualbox,Ubuntu20.04,codeblocks
开发工具:gcc,edb,等等
1.3 中间结果
hello.c Hello源程序
hello.i 预处理生成文件
hello.s 汇编程序
hello.o 可重定位目标程序
hello.elf Hello.o的ELF格式可执行文件
hello 链接器生成的可执行目标文件
hello.asm Hello.o的反汇编文件
hello1.elf Hello的ELF格式可执行文件
1.4 本章小结
对hello的P2P,O2O过程进行了简述,介绍了环境和开发工具

2.第2章 预处理

2.1 预处理的概念与作用
概念:程序设计领域中,预处理一般是指在程序源代码被翻译为目标代码的过程中,生成二进制代码之前的过程。
作用:
1.将源文件中以“include”格式包含的文件复制到编译的源文件中;
2.用实际值替换用“#define”定义的字符串;
3.根据“#if”后面的条件决定需要编译的代码。
2.2在Ubuntu下预处理的命令
gcc hello.c >hello.i
2.3 Hello的预处理结果解析
经过预处理生成了hello.i文件,打开文件可以看到,在文件前多了许多的内容,主要是对源文件中的宏进行了展开
2.4 本章小结
介绍了预处理的概念和作用,对hello文件进行了预处理,并对hello.i文件进行了解析。

(第2章0.5分)

3.第3章 编译

3.1 编译的概念与作用
概念:编译是利用编译程序从预处理文本文件.i产生汇编程序.s的过程。
作用: 把高级语言翻译成计算机的二进制语言,主要是进行词法分析和语法分析。
3.2 在Ubuntu下编译的命令
gcc -S -no-pie -fno-PIC hello.i -o hello.s
3.3 Hello的编译结果解析
3.3.1汇编文件指令
在这里插入图片描述
.file:声明源文件
.text:代码节
.section:指示把代码划分成若干个段(Section)
.rodata:只读代码段
.align:数据或者指令的地址对其方式
.string:声明一个字符串(.LC0,.LC1)
.global:声明全局变量(main)
.type:声明一个符号是数据类型还是函数类型

3.3.2 数据
1字符串 将字符串存在只读数据段中
在这里插入图片描述

2 局部变量
main函数声明了一个局部变量,存在-4(%rbp)中
3立即数
在这里插入图片描述

4数组
在这里插入图片描述

3.3.3 算术操作
i++,通过addl实现
3.3.4 赋值
i=0,通过movl实现
3.3.5关系操作
argc!=4和i<8
在这里插入图片描述
在这里插入图片描述
3.3.6 控制转移
jmp .L3
jle .L4
3.3.7 函数操作
1函数调用
在这里插入图片描述

2参数传递
有exit,printf,atoi,sleep,getchar函数
3函数返回 ret

3.4 本章小结
介绍了编译的作用和概念,对hello.i进行了编译,然后对编译的结果进行了分析

3.第4章 汇编

4.1 汇编的概念与作用
汇编就是将汇编语言转化为机器可直接识别执行的代码文件的过程,汇编器将.s文件翻译成机器语言指令,把这些指令打包成可重定位目标程序的格式,并将结果保存在.o 目标文件中。
4.2 在Ubuntu下汇编的命令
gcc -c -no-pie -fno-PIC hello.s -o hello.o
4.3 可重定位目标elf格式
readelf -a hello.o > elf.txt
首先是elf的文件头
在这里插入图片描述

节头部表
在这里插入图片描述

符号表
在这里插入图片描述

重定位节
在这里插入图片描述

4.4 Hello.o的结果解析
在这里插入图片描述
在这里插入图片描述

不同之处主要与几个方面
1分支跳转上的不同
.s文件是通过段名称进行跳转。而反汇编是通过地址进行跳转
2函数调用的不同
.s文件直接使用函数名称,而反汇编则在call后就是下一条指令
3访问全局变量
.s文件中是.LC0(%rip),而反汇编代码中是反汇编代码中为0x0(%rip),汇编代码直接访问了.rodata的数据,在反汇编中因为访问时需要重定位,所以初始化为0。
4.5 本章小结
对汇编的概念和功能进行了介绍,将hello.s进行汇编生成了hello.o,用readelf读取了相关信息,然后比较了hello.s与hello.o反汇编文件的区别。
(第4章1分)

5.第5章 链接

5.1 链接的概念与作用
链接是将各种代码和数据片段收集并组合成一个单一文件的过程,这个文件可被加载到内存并执行。链接使得分离编译成为可能。
5.2 在Ubuntu下链接的命令
ld -o hello -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/crti.o hello.o /usr/lib/x86_64-linux-gnu/libc.so /usr/lib/x86_64-linux-gnu/crtn.o
5.3 可执行目标文件hello的格式
在这里插入图片描述

文件头
在这里插入图片描述

节头部表
在这里插入图片描述

符号表

在这里插入图片描述

5.4 hello的虚拟地址空间
Hello的虚拟地址起始于0x400000, 结束于0x400ff0。
根据节头部表,可以在edb中找到各个节。

5.5链接的重定位过程分析
进行比较分析可知,hello反汇编的代码已有确定的虚拟地址,已经完成了重定位,而hello.o的反汇编中虚拟地址为0,未完成重定位。

5.6 hello的执行流程
ld-2.31.so!_dl_start
ld-2.31.so!_dl_init
Hello!_start
libc-2.31.so!__libc_start_main
Hello!main
Hello!printf@plt
hello!atoi@plt
Hello!sleep@plt
hello!getchar@plt
libc-2.31.so!exit
5.7 Hello的动态链接分析
在进行动态链接前,首先要进行静态链接,生成部分链接的可执行目标文件hello。动态链接采用了延迟加载的策略,即在调用函数时才进行符号的映射。使用偏移量表GOT+过程链接表PLT实现函数的动态链接。GOT中存放函数目标地址,为每个全局函数创建一个副本函数,并将对函数的调用转换成对副本函数调用。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

5.8 本章小结
本章介绍了链接的概念与作用,分析了生成的hello 文件的结构以及与hello.o文件的异同, 介绍了ELF格式和各个节的含义。

6.第6章 hello进程管理

6.1 进程的概念与作用
概念:进程是操作系统对一个正在运行的程序的一种抽象,是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
作用:进程作为一个执行中程序的实例,系统中每个程序都运行在某个进程的上下文中,上下文是由程序正确运行所需的状态组成的。这个状态包括存放在内存中的程序的代码和数据,它的栈、通用目的寄存器的内容、程序计数器、环境变量以及打开文件描述符的集合。
6.2 简述壳Shell-bash的作用与处理流程
shell是命令行界面的解析器,能够为用户提供操作界面,提供内核服务。shell能执行一系列的读、求操作,然后终止。读操作读取来自用户的一个命令行。求值操作解析命令并代表用户运行程序。
处理流程:读取用户输入
解析用户输入
如果该命令是内置的 shell 命令则会立即解释该命令
如果不是内置命令,则调用fork创建新子进程,再调用execve执行指定程序。
6.3 Hello的fork进程创建过程
输入命令,首先shell对我们输入的命令进行解析,因为输入的命令不是一个内置的shell命令,所以shell会调用fork()创建一个子进程。
在这里插入图片描述

6.4 Hello的execve过程
在执行fork得到子进程后随即使用解析后的命令行参数调用execve,execve调用启动加载器来执行hello程序。加载器删除子进程现有的虚拟内存段,并创建新的代码、数据、堆和栈段。代码和数据段被初始化为hello的代码和数据。堆和栈被置空。然后加载器将PC指向hello程序的起始位置,即从下条指令开始执行hello程序。
6.5 Hello的进程执行
逻辑控制流:一系列程序计数器PC的值的序列叫做逻辑控制流,这些值唯一地对应于包含在程序的可执行目标文件中的指令,或是包含在运行时动态链接到程序的共享对象中的指令。
时间片:一个进程执行它的控制流的一部分的每一时间段叫做时间片。
上下文信息:上下文就是内核重新启动一个被抢占的进程所需要的状态,它由 通用寄存器、浮点寄存器、程序计数器、用户栈、状态寄存器、内核栈和各种内核数据结构等对象的值构成
hello程序执行了sleep系统调用,会引发陷阱异常,进入内核模式,使程序休眠一段时间,将控制转给其他进程。当sleep结束后,发送信号给内核,进入内核状态处理异常, 之后hello又调用getchar 函数,进入内核模式,内核中的陷阱处理程序请求来自键盘缓冲区的数据传输,并执行上下文切换,并把控制转移给其他进程。
6.6 hello的异常与信号处理
异常可以分为四类:中断、陷阱、故障、 终止。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

6.7本章小结
本章简述了进程、shell的概念与作用,分析了hello程序使用fork创建子进程的过程以及使用execve加载并运行用户程序的过程,展示hello程序执行的具体过程,以及异常信号的处理机制。

结论

1、编写代码:用高级语言写.c文件
2、预处理:从.c生成.i文件,将.c中调用的外部库展开合并到.i中
3、编译:由.i生成.s汇编文件
4、汇编。汇编器把汇编码转换为机器码,生成了 hello.o 可重定位目标文件。
5、链接。静态链接,把外部函数的代码添加到可执行文件中;动态链接,设置过程链接表PLT 和全局偏移量表 GOT,只在运行时动态引用相关代码。最后生成了 hello可执行文件。
6.创建子进程:在shell中运行hello程序时,会调用fork()函数创建子进程。这就是Hello的P2P过程。
7.加载程序:exceve函数加载运行hello程序。
8.执行指令:CPU为hello分配时间片,使hello独享,顺序执行逻辑控制流。
9.动态申请内存:printf会调用malloc向动态内存分配器申请堆中的内存。
10.结束:shell父进程回收子进程,内核删除为这个进程创建的所有数据结构。

附件

hello.i 预处理后的文件
hello.s 编译后的汇编文件
hello.o 汇编后的可重定位目标文件
hello 链接后的可执行目标文件
hello.elf hello的elf文件
helloo.elf hello.o的elf文件
helloobjdump.txt hello的反汇编代码文件
hellooobjdump.txt hello.o的反汇编代码文件

参考文献

[1] Randal E.Bryant David R.O’Hallaron. 深入理解计算机系统(第三版). 机械工业出版社,2016.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值