深入理解计算机系统-hello的一生

计算机系统

大作业

题     目  程序人生-Hello’s P2P 

专       业    计算机科学与技术   

学     号    2021113538          

班     级    2103101             

学       生     张纬如          

指 导 教 师     刘宏伟             

计算机科学与技术学院

2022年5月

摘  要

本文结合《深入理解计算机系统》一书和对该对应课程的学习,对一个程序Hello的一生,各个阶段,预处理、编译、汇编、链接,进程管理,和存储等等方面进行了系统分析,经历了P2P的丰富过程:From Program to Process,从程序的结构和执行以及在系统上运行程序两大方面,从程序员的视角,对程序的一生以及计算机系统进行探讨和讲述。

关键词:计算机系统;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 Hello简介

P2P:From Program to Process

理解:当我们在各种IDE或者文本编辑器中完成了基于c语言语法的hello源程序代码,hello.c,我们需要一个过程,将program变成process,首先是从源文件到可执行目标文件的生成:

源文件经过预处理、编译、汇编、链接后就生成了可执行目标文件。

然后是对目标文件的运行:

在bash(shell)中,输入./hello,对可执行目标文件进行运行,载入内存,由OS进行管理,为它fork建立子进程,并用execve进行替换,然后进行执行,由CPU、ISA和对应二进制的指令确定程序的具体执行过程,涉及流水、进程切换、管理、异常等等。

O2O:Zero to Zero

理解:是hello可执行目标文件从执行到最后被回收的整体过程。在bash(shell)中运行后,bash给该程序建立了对应的子进程,然后是虚拟内存的相关管理和设计。运行完成后,bash回收子进程,内核删除相关数据,释放内存资源。就是完整的从无到无。

1.2 环境与工具

硬件:

X64 CPU;3.20GHz;16.0G RAM;512GHD Disk

软件:

Windows10 64位;Vmware; Ubuntu 64位

1.3 中间结果

中间结果文件:

hello.c hello.i hello.s hello.o hello. elf.txt hello_elf.txt

1.4 本章小结

本章介绍了hello程序对应的P2P和O2O内容,对其进行了大体上的描述,也介绍了本文所使用的工具环境,并列出了中间结果文件及其相应的作用。

第2章 预处理

2.1 预处理的概念与作用

概念:C语言的预处理器在源代码编译之前对其进行一些文本性质的操作。

作用:它的主要任务包括删除注释、插入被#include指令包含的文件内容、定义和替换由#define指令定义的符号,同时确定代码的部分内容是否应该根据一些条件编译指令进行编译。

2.2在Ubuntu下预处理的命令

命令:gcc -E hello.c -o hello.i

-E 只进行预处理生成预处理文件

2.3 Hello的预处理结果解析

源文件:

编译后:可以看到文件从23行填充为3060行,并且在末尾我们找到了和源文件相同的代码部分,注释已经被删除,并将#include均进行了展开

通过两者的比较,我们可以发现:预处理程序对以#开头的12个命令进行了处理:如#include、#ifdef、#ifndef等等;并将头文件包含的文件进行了插入,删除了注释。

2.4 本章小结

本章介绍了hello预处理的详细过程,根据规定的预处理命令,修改源程序,进行插入,注释删除等文本操作,从源程序的文本文件,得到预处理后的文本文件。

第3章 编译

3.1 编译的概念与作用

概念:将人所理解的c语言文本文件,变成容易被机器理解的汇编语言文本文件。

作用:让hello.i变成hello.s,为后来的汇编成机器码的二进制文件作准备

注意:这儿的编译是指从 .i 到 .s 即预处理后的文件到生成汇编语言程序

3.2 在Ubuntu下编译的命令

命令:gcc -S hello.i -o hello.s

-S只进行编译

3.3 Hello的编译结果解析

我们将对汇编程序文件的数据类型和操作都进行逐步解析。

3.3.1整型常量:

(还有0和9同理,不过因为i<9,在汇编程序中以和8比较的形式替代)

汇编代码:该处作为立即数,进行比较操作,然后设置条件码,进行条件跳转

3.3.2字符串常量:

汇编代码:printf中有一个字符串,这个字符串保存在.LC0处

3.3.3局部变量:

汇编代码:该i作为循环变量保存在内存中-4(%rbp)处

3.3.3指针、数组:

汇编代码:argv是一个指针数组,每一个元素为八个byte,内存中-32(%rbp)处为数组起始地址,加3*8后为argv[3]

3.3.4函数参数

内容同3.3.3,调用atoi函数,参数为argv[3],该数从内存中被取出后,放入了%rdi,%rdi为其参数

3.3.5比较操作

同3.3.1,进行了argc与4的比较,然后进行条件跳转

3.3.6算术操作

汇编代码:该处的循环变量加一操作,后设置条件码,进行比较

3.3.7函数操作调用和返回

汇编代码:由于sleep、getcchar函数均没有在该文件中定义,所以存在文件中的ret只有main函数的返回,将返回值传递回系统进行处理。Call后面存在的getchar@PLT之后在链接过程中会重定位为相应函数的地址。

3.4 本章小结

本章总结了由预处理文件到汇编语言文件的转换,具体分析了编译器对各个类型和各个操作的处理,及其对应的汇编语言代码。将人所理解的代码转换为机器容易理解的代码。

第4章 汇编

4.1 汇编的概念与作用

概念:将汇编程序文件变为可重定位目标文件。

作用:将文本文件转为二进制文件,从机器容易理解的程度提高至,能够真正被机器所理解执行的程度,是真正的机器语言,以二进制文件的形式保存。

注意:这儿的汇编是指从 .s 到 .o 即编译后的文件到生成机器语言二进制程序的过程。

4.2 在Ubuntu下汇编的命令

命令:gcc -c hello.s -o hello.o

-c 只生成可重定位目标文件

4.3 可重定位目标elf格式

   通过readelf进行对格式文件的获取

4.3.1 ELF头和节头部表

分析:首先是16字节的序列,描述了生成该文件的系统的字大小和字节序,然后是elf头部表的大小,目标文件类型可重定位文件,节头部表的偏移和其条目大小和数量

4.3.1 节

在ELF头和节头部表之间都是各个节的内容

.text .rodata .data .bss .symtab等等节

.rel.text(.rela.text):重定位节,包含了.text中需要进行重定位的信息,其中描述的信息需要在生成可执行文件时,进行对.text的修改,如call后的地址等等。

重定位条目:常见有两种类型:

R_X86_64_32:绝对寻址,直接使用32位的绝对地址作引用进行替换。

R_X86_64_PC32:PC相对寻址,将要使用的地址和运行的指令下一条指令地址的值作差,用差值进行替换。

4.4 Hello.o的结果解析

4.4.1 分支跳转:

跳转语句后,hello.s使用的是段名称,而反汇编的代码中则是PC相对寻址或者绝对寻址,其对应的地址

4.4.2 函数调用:

Call后,hello.s使用的是函数名称,而反汇编代码后则是PC相对寻址或者绝对寻址,其对应的地址。

4.4.3 操作数的表示

常数,hello.s使用的是十进制数,而反汇编使用十六进制表示。

4.5 本章小结

本章对汇编结果进行了分析,经过汇编过程,汇编语言转化位机器语言,比较hello.s文件和hello.o反汇编形式我们很清楚的看出了其中的不同之处,可以看出重定位节对后面链接过程的铺垫作用。

5章 链接

5.1 链接的概念与作用

概念:链接是将各种代码和数据片段收集并组合成为一个单一文件的过程,这个文件可以被加载到内存并执行。链接可以执行于编译时,也就是在源代码被编译成机器代码时;也可以执行于加载时,也就是在程序被加载器加载到内存并执行时;甚至于运行时,也就是由应用程序来执行。

作用:把可重定位目标文件和命令行参数作为输入,产生一个可以加载运行的可执行目标文件。

注意:这儿的链接是指从 hello.o 到hello生成过程。

5.2 在Ubuntu下链接的命令

命令:

5.3 可执行目标文件hello的格式

5.3.1 ElF头

同4.3.1

5.3.2头节部表

描述了30个节,比可重定位目标文件多出了很多节:

.dynamic .rela.dyn等等

5.4 hello的虚拟地址空间

   

5.5 链接的重定位过程分析

5.5.1代码起始位置

Hello从0x401000开始,而hello.o则是从0x0开始

5.5.2函数的引入,如下:

将各个可重定位目标文件进行合并、链接,形成一个可执行文件。

5.6 hello的执行流程

-init

puts@plt

printf@plt

getchar@plt

atoi@plt

exit@plt

sleep@plt

_start

main

5.7 Hello的动态链接分析

PlT:PLT是一个条目数组,每个条目是16个字节的代码,PLT[0]是一个特殊条目。跳转到动态链接器中,每个条目负责一个函数

GOT:GOT同样是一个条目数组,每个条目8个字节,和PLT联合使用,GOT的前两个条目,提供解析函数地址时会使用的信息,第三个是动态链接器在ld-linux.so模块的入口点。其余条目对应于一个被调用函数,在运行时解析。

5.8 本章小结

       本章主要研究了链接的内容,重点研究了链接后的hello与hello.o之间的区别,通过链接,将可重定位文件转化为了可执行文件。

6章 hello进程管理

6.1 进程的概念与作用

概念:一个执行中程序的实例,系统的每个程序都运行在某个进程的上下文。而上下文是由程序正确运行所需要的状态组成,包括内存力的程序的代码、数据、栈、寄存器内容、pc、环境变量等等状态。

作用:通过进程,使得我们的程序好像是当前唯一运行的程序,独占处理器和内存,也独占虚拟空间。

6.2 简述壳Shell-bash的作用与处理流程

作用:是用户和系统之间的桥梁,提供给用户与内核进行交互的窗口,并可以使用shell提供的命令进行操作。

处理流程:用户在命令行进行输入,shell接收并解析,对内置命令直接执行,非内置,检查是不是可执行文件,是就在子进程中执行;

1)读取命令,解析为对应参数;

2)判断内置,是就立即执行;

3)不是内置,检查是不是可执行文件,是fork子进程,execve加载并运行程序;

4)判断前后台,前台则等待,后台则进入下次循环。

6.3 Hello的fork进程创建过程

输入./hello后,bash(shell)发现不是内置命令,尝试用子进程运行该可执行目标文件。

当bash调用fork生成子进程时,子进程保存了父进程几乎所有信息、状态。两者不同在pid。

6.4 Hello的execve过程

execve函数在当前进程的上下文中加载并执行一个新的程序,直接替换之前的程序内容在头部表的引导下,加载器将可执行文件加载到对应的代码段和数据段,然后跳转到程序入口,启动函数,初始化环境,调用main函数,处理返回值,返回内核

6.5 Hello的进程执行

操作系统内核使用上下文切换的异常控制流来实现多进程并发执行。上下文是一个进程运行所需要的状态。

执行过程中,上下文切换,是由内核决定的,什么时候抢占当前进程,开始另一进程,称之为调度:

1)进程将控制交给内核;从用户模式进入内核模式

2)保存当前进程上下文;内核模式

3)恢复重启进程的上下文;内核模式

4)将控制传递给重启进程,完成上下文切换;从内核模式进入用户模式

Hello程序和系统其他进程通过内核进行调度,切换上下文,在各自的时间片内,由内核决定一个进程运行足够长的时间或是有异常、信号等进行上下文切换,暂停当前进程,重启其他进程。

6.6 hello的异常与信号处理

异常种类:中断、陷阱、故障、终止

1)中断:唯一的异步进行,来自外部IO设备的信号,中断信号到达后,当前指令执行完后,内核调度处理程序进行处理,然后执行被中断的程序的下一条指令;

2)陷阱:同步,由执行指令产生的结果,有意的异常,通过它系统调用来从用户模式进入内核模式;

3)故障:同步,由错误引起,可能返回到原进程的原指令处,或下一条指令处,也可能无法修正故障,导致程序直接终止。

4)终止:同步,由不可恢复的错误引起,通常是机器硬件错误,直接将控制返回给abort例程,终止引起终止的程序。

6.6.1不停乱按,包括回车

在未能完成该进程时,由于是前台任务,乱按不会产生影响,在完成后,之前的乱按会以回车为分界进行缓存为多个命令,进行解析,发现不是内置命令和可执行文件,就输出提示,跳过。

6.6.2 Ctrl Z

输入后会发送SIGTSTP信号给前台进程组的每个进程,将前台挂起

ps:可以看到正在执行的进程包括暂停的进程,所对应的名称和PID编号

jobs:可以看到唯一一个job hello被暂停了

pstree:通过pstree可以清晰看到父进程和子进程之间的关系

fg:将后台第一个作业变为前台,输入fg后,发现hello是第一个,所以使得hello程序又开始在前台运行。

kill:kill后通过ps查看,发现对应的进程被终止回收。

6.6.3 Ctrl C

发送了一个SIGINT信号给前台进程组的所有进程,终止前台的程序,通过ps我们发现hello对应的进程已经被回收。

6.7本章小结

本章介绍了进程的概念和作用,shell的概念和操作,如何fork子进程,execve加载进程,以及内核调度上下文切换,完成多任务多进程的并发,并且对异常和信号进行了研究和探索。

结论

Hello的经历异常丰富,从program到process经历了许许多多,最后在计算机系统整体配合下,完美落幕。

首先hello在系统中由hello.c经历了预处理成为,又经过编译成为,再是汇编,链接为,最后为可执行程序。

后来,为了运行,再内核的调度下,它得以在进程中加载,在异常控制流,上下文切换中,hello得以占据所有资源空间和cpu、内存的假象。而后在虚拟内存和IO部分的配合下,使得hello能够成功运行。

创新和尝试:

查阅资料后,我尝试使用了动态链接中的运行时链接的方式,使用dlopen、dlsym、dlcose等函数,对动态链接过程进行了探索,更深刻的理解了链接的过程,和不同的方式。

附件

hello.c hello.i hello.s hello.o hello. elf.txt hello_elf.txt

hello.c:源程序文件,文本文件。

hello.i:经过预处理后的文件,文本文件,展示预处理的过程和操作。

hello.s:汇编文件,文本文件,展示源文件对应汇编语言。

hello.o:可重定位目标文件,二进制文件,机器语言,为下一步链接成可执行文件做准备。

hello. elf.txt:hello.o的ELF文本内容

hello_elf.txt:hello的ELF文本内容

参考文献

[1]  深入理解计算机系统 第三版

[2]  CSDN

[3]  Github

[4]  bilibili

[5] 学习通http://www.bdgxy.com/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值