计算机系统
大作业
题 目 程序人生-Hello’s P2P
专 业 计算机科学与技术
学 号 2021110752
班 级 2103102
学 生 盛葛
指 导 教 师 刘宏伟
计算机科学与技术学院
2022年5月
本篇论文注重于介绍了一个源程序(.c文件)如何在电脑中从人可以读懂的高级语言和汇编语言,一步一步转化成计算机能“看懂”的01机器码,以及可执行文件在电脑中运行的过程,即进程创建到进程回收的整个过程。
本文以源文件hello.c为例,介绍了这个(.c)文件的“一生”。
关键词:预处理;编译;汇编;链接;进程管理;...
目 录
第1章 概述
1.1 Hello简介
根据Hello的自白,利用计算机系统的术语,简述Hello的P2P,020的整个过程。
- P2P(From Program To Process)的过程:
一个(.c)文件的P2P流程包括:
- 首先(.c)文件经过cpp预处理为(.i)文件;
- 再经过ccl(编译器)编译为(.s)文件;
- 接着经过as(汇编器)汇编,成为(.o)文件;
- 最后链接(ld)成二进制可执行目标文件,即(hello)。
- 020(From Zero-0 to Zero-0)的过程:
From 0 to 0是指本来内存中并不存在hello,而可执行文件hello执行后,shell为hello创建子进程,到此就是“from 0 to 1”的部分,而“from 1 to 0”是指在hello执行完毕后将会被回收,再次回到“0”。
1.2 环境与工具
列出你为编写本论文,折腾Hello的整个过程中,使用的软硬件环境,以及开发与调试工具。
硬件环境:AMD Ryzen 7 5800H CPU;
软件环境:Windows11, Ubuntu20.04;
开发与调试工具:Vissual Studio 2022, Codeblocks;
gcc, edb等。
1.3 中间结果
列出你为编写本论文,生成的中间结果文件的名字,文件的作用等。
产生的中间结果文件包括hello.i, hello.s, hello.o 以及最后的可执行目标文件hello。
作用:hello.i --> hello.c经预处理后产生的文件;
hello.s --> hello.i 经过编译后的产物,将高级语言转换为汇编语言;
hello.o --> hello.s 经过汇编后的产物,即将汇编语言翻译为机器语言;
hello --> 最后经过链接产生的二进制可执行目标文件。
1.4 本章小结
本章注重描述了一个源文件(即hello.c文件)转变成一个可执行文件(即hello)的过程,以及其中间产生的其他文件,也可以说是一个可执行文件的“出生”过程。
第2章 预处理
2.1 预处理的概念与作用
预处理的概念:
预处理是指预处理器(cpp)在编译之前根据以“#”开头的命令对原始的源文件进行修改的过程。其中预处理的命令包括“#define, #include, #ifdef, #else, #error”等。通常情况下,源文件(即.c文件)预处理后生成另一个C程序,通常以“.i”为后缀。
预处理的作用:
预处理的常见命令主要有三个,即“#include, #define, #if”,也代表了预处理的三个主要作用:
- 首先预处理过程中可以将源文件中以”include”格式包含的文件复制到编译的源文件中,也就是我们经常使用的“#include<stdio.h>”之类的命令;
- 用实际值替换用“#define”定义的字符串,比如“#define max 9”等;
- 根据“#if”后面的条件决定需要编译的代码,也就是条件编码。
2.2在Ubuntu下预处理的命令
在Linux下输入指令“gcc -E -o hello.i hello.c”即可完成对hello.c的预处理,并生成相应的hello.i文件,截图如下:
图2.1 hello.i的生成
2.3 Hello的预处理结果解析
通过打开生成的hello.i文件可以发现,原来的hello.c文件被扩展为一个3105行的一个大文件,具体截图如下:
图2.2 hello.i文件内容
通过其与hello.c文件的对比可以发现,预处理的内容就是将原hello.c文件开头的几个“#include”拆分开来,将include的所有头文件的内容引入进来,这也就是hello.i文件与hello.c文件“体量”差距那么大的原因。
2.4 本章小结
本章注重于深入了解一个hello.c程序“P2P”过程中预处理部分的相关内容,介绍了预处理部分的概念以及其在整个“P2P”过程中的作用。另外,还了解了如何在Linux下单独执行预处理的指令。
第3章 编译
3.1 编译的概念与作用
编译的概念:
编译是指编译器(cpp)将文本文件hello.i翻译成文本文件hello.s,即汇编语言程序的过程。
编译的作用:
将高级语言翻译成汇编语言,以便进一步翻译为机器语言。
3.2 在Ubuntu下编译的命令
在Linux下输入指令“gcc -S hello.i -o hello.s”即可完成对hello.i的编译,
并生成相应的hello.s文件,截图如下:
图3.1 hello.s的生成
3.3 Hello的编译结果解析
3.3.1 hello.s文件的结构
将文本文件hello.s打开后可以看到该文件的结构如下:
图3.2 hello.s的内容
主要包括“.file(源文件名),.text(代码段),.section/.rodata(只读变量),.align(对齐方式),.string(字符格式串),.global(全局变量),.type(函数类型,函数变量)”。
3.3.2 出现的各种数据类型
(1)字符串
在这个源文件中存在两个字符串,即:
“用法: Hello 学号 姓名 秒数!\n”和“Hello %s %s\n",argv[1],argv[2]”
在汇编语言中,这两个字符串被翻译为:
- 变量:
变量分为全局变量和局部变量,在汇编语言中,局部变量被保存在堆栈中,而全局变量则被保存在.data节内;
3.3.3 控制转移
(1)if语句:
源文件中的if语句如下:
对应的汇编语言如下:
- for循环语句:
源文件的for语句如下:
对应的汇编语言如下:
3.3.4 关系操作
源文件中将argc与4进行比较,即:
而在汇编语言中则翻译为:
其他的关系比较语句类似,用cmpl来代替。
3.3.5 算术操作
在循环语句中,每一次循环,循环变量i都要加1,也就是在高级语言中经常出现的i++,而在汇编语言中,这样的算术操作被翻译为:
3.3.6 函数操作
汇编语言中对函数的调用用call+函数名来表示。
例如hello.c中的exit(0),在汇编语言中的表述为:
3.4 本章小结
本章注重于介绍了编译的概念和过程,并且介绍了编译器处理各个数据类型的方法和操作。对编译的结果进行解析更加深刻地揭示了C语言的数据与操作,让我们对编译这一过程有了更深入的认识。
第4章 汇编
4.1 汇编的概念与作用
汇编的概念:
汇编是指汇编器(as)将hello.s翻译成机器语言指令,把这些指令打包成可重定位目标程序,并将结果保存在hello.o中的过程。
汇编的作用:
汇编的作用在于将人能理解的汇编语言翻译成计算机能理解的机器语言。
4.2 在Ubuntu下汇编的命令
命令为:gcc hello.s -c -o hello.o,截图如下:
图4.1 hello.o的生成
4.3 可重定位目标elf格式
(1)ELF节(输入readelf -h hello.o命令)
图4.2 ELF节
以上就是hello.o的ELF头的基本信息
- 节头表(输入readelf -S hello.o命令)
图4.3 节头表信息
由图可以看出,节头表包括“名称,类型,地址,偏移量,大小,全体大小,旗标,链接,信息,对齐”几个部分,一共有13个节头,其各自具体均在上图中可以得到。
- 符号表(输入readelf -s hello.o命令)
图4.4 符号表信息
上图就是符号表的相关信息,包括每个符号的“Num, Value, Size, Type, Bind, Vis, Ndx, Name”信息。
4.4 Hello.o的结果解析
输入命令“objdump -d -r hello.o”,得到hello.o的反汇编,截图如下:
图4.5 反汇编
再输入指令“objdump -d -r hello.o > hello.asm”,将反汇编文件存入文本文件hello.asm中,截图如下:
图4.6 储存反汇编文件
将生成的hello.asm与hello.s对比可以看出它们之间的区别如下:
- 原hello.s中存在很多的标志,例如“.L1, .L2”等,而反汇编后的hello.asm中不存在类似的标志,取而代之的是具体的地址信息;
- hello.asm中call语句后的是相对地址,例如语句如下
它的callq后面跟随的是函数相对于main函数的相对地址,而在hello.s中的对应语句如下
它的call后面跟随的是具体的函数名,而不是其地址。
(3)和第二条类似,原hello.s中的跳转指令,也就是分支转移语句,je后面跟随的是函数的名称,而hello.asm中跳转语句后面跟随的是其对于main函数的相对地址。
4.5 本章小结
本章着重于对汇编的过程和原理进行更加深刻的了解,其中包括重定位,以及因为重定位而带来的hello.s与hello.asm之间的区别,这也让我们更加深刻地理解了汇编在hello.c文件“P2P”过程中发挥的作用。
第5章 链接
5.1 链接的概念与作用
链接的概念:
链接就是指将各种代码和数据片段手机并组合成单一文件,该文件可以加载到内存中并执行的过程。
链接的作用:
链接的作用在于它可以将多个源程序结合起来,也可以将一个大的程序分解成一个个C程序分开编译,修改时也不必改掉整个程序,只更改其中的几个源程序即可。因此可以有效提高编写效率。
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.1 链接过程
5.3 可执行目标文件hello的格式
输入命令“readelf -a hello > hello_2.elf”,将hello的ELF保存到文件hello_2.elf中,这样就能得到hello文件的各段基本信息。
- ELF头:
图5.2 ELF头信息
- 节头表:
图5.3 节头表信息
- 符号表:
图5.4 符号表信息
- 程序头:
图5.5 程序头信息
5.4 hello的虚拟地址空间
首先使用edb加载hello,截图如下:
图5.6 Data Dump
在hello的ELF文件中(也就是hello_2.elf)可以得到可执行文件hello的各段的相应地址,将其分别与edb上进行对应即可,具体如下:
5.5 链接的重定位过程分析
输入命令“objdump -d -r hello”可得:
图5.8 hello的反汇编
hello与hello.o的不同:
- hello文件比hello.o文件多出来很多函数的汇编语言,例如“printf, getchar, exit, sleep”等,这说明了在链接中将hello程序中需要用到的,比如“printf, getchar”等共享库中的函数包含了进来;
- 与hello.o相比多出来了几个新的节,比如“.plt, .init”;
- 关于地址的函数,比如je, call等所跟随的地址类型的参数也因为重定位而不同。在链接过程中,链接器解析了重定位条目,call指令后面跟随的函数名被链接器修改为目标地址与下一条指令的地址之差,并指向相应的代码段,进而完成了重定位。
5.6 hello的执行流程
使用edb执行hello,说明从加载hello到_start,到call main,以及程序终止的所有过程。请列出其调用与跳转的各个子程序名或程序地址。
其用edb执行如下:
图5.9 edb执行hello
经edb调试可得,hello的执行流程为:dl_init,.plt,puts@plt,printf@plt,getchar@plt,atoi@plt,exit@plt,sleep@plt,start,_dl_relocate_static_pie,main,__libc_csu_init,__libc_csu_fini,_fini。
5.7 Hello的动态链接分析
分析hello程序的动态链接项目,通过edb调试,分析在dl_init前后,这些项目的内容变化。要截图标识说明。
5.8 本章小结
本章注重介绍了链接的基本原理,以及链接所带来的重定位等的变化。并且,连接后的hello程序与hello.o的elf的异同更加深刻地了解了链接的基本工作原理,以及它的作用。
第6章 hello进程管理
6.1 进程的概念与作用
进程的概念:
进程是一个执行中程序的实例;
进程的作用:
一个程序在系统上运行时,操作系统会提供一种程序在独占这个系统,包括处理器,主存,I/O设备的假象。处理器看上去在不间断地一条一条执行程序中的指令,也就像是在处理一条条进程。
6.2 简述壳Shell-bash的作用与处理流程
Shell-bash的作用:
Shell 是一个用C语言编写的交互型应用程序,代表用户运行其他程序。Shell 应用程序提供了一个界面,用户可以通过这个界面进行系统的基本操作,访问操作系统内核的服务。
Shell-bash的处理流程:
- 终端进程读取用户由键盘输入的命令行;
- 分析命令行字符串获取命令行参数,并构造传递给execve的argv向量;
- 检查首个命令行参数是否是一个内置的shell命令(如果不是则调用fork 创建新进程/子进程);
- 在子进程中,用步骤2获取的参数,调用execve执行指定程序;
- 如果用户没要求后台运行,shell使用waitpid或wait等待作业终止后返回;
- 若用户要求后台运行,则shell返回。
6.3 Hello的fork进程创建过程
fork进程创建流程如下:
首先给新进程分配一个标识符,在内核中分配一个PCB,将其挂在PCB表上,然后复制它的父进程的环境并为其分配资源,再复制父进程地址空间里的内容,将进程置成就绪状态,最后将其放入就绪队列,等待CPU调度。
6.4 Hello的execve过程
execve流程如下:
execve函数的功能是加载并运行可执行目标文件,且带参数列表argc和环境变量列表envp。如果出现错误,execve会返回到调用程序。在程序头部表的引导下,加载器将可执行文件的片复制到代码段和数据段,之后,加载器跳转到程序的入口,之后初始化环境,调用main函数,并处理main函数返回值,最后返回给内核。
6.5 Hello的进程执行
(1)进程调度的过程:
在执行过程中,内核可以决定抢占当前进程,并重新开始一个先前被抢占的进程,这个决策称为调度。调度的过程是由调度器完成的,当内核调度新的进程运行后,它就会抢占当前进程,并使用上下文切换机制来将控制转移到新的进程。
- 用户态与核心态转换:
核心态拥有最高的访问权限,处理器以一个寄存器当做模式位来描述当前进程的特权。进程只有在发生异常,比如故障、中断或陷入系统调用时才会得到内核访问权限,其他情况下始终处于用户权限之中。
6.6 hello的异常与信号处理
异常的类型:
- 中断(异步):总是返回到下一条指令;
- 陷阱(同步):总是返回到下一条指令;
- 故障(同步):可能不返回,也可能回到当前指令;
- 终止(同步):不返回。
hello执行过程中会出现哪几类异常,会产生哪些信号,又怎么处理的。
- 乱按回车:无影响
图6.1 乱按回车结果
- Ctrl-Z:将当前进程暂时挂起
图6.2 Ctrl-Z结果
- Ctrl-C:停止进程
图6.2 Ctrl-C结果
- Ctrl-Z + pstree:将进程结果进行树状展示
图6.3 Ctrl-Z + pstree结果
- Ctrl-Z + ps:查看挂起的进程
图6.3 Ctrl-Z + ps结果
- Ctrl-Z + jobs:展示当前进程组中的进程
图6.3 Ctrl-Z + jobs结果
- Ctrl-Z + fg:继续进行暂停后的进程
图6.3 Ctrl-Z +fg结果
6.7本章小结
本章注重于讲解进程的相关知识,以及Shell的基本概念和常用的shell指令操作。除此之外,还涉及到各种程序运行过程中可能遇到的异常,还有各种功能的信号等。
结论
hello所经历的过程:
- 预处理
源文件(即.c文件)预处理后生成另一个C程序,以“.i”为后缀,即(.i)文件;期间完成对“#”开头指令的处理;
- 编译
编译器(cpp)将文本文件hello.i翻译成文本文件hello.s,即汇编语言程序;
- 汇编
汇编器(as)将hello.s翻译成机器语言指令,把这些指令打包成可重定位目标程序,并将结果保存在hello.o中;
- 链接
将各种代码和数据片段手机并组合成单一文件,使该文件可以加载到内存中并执行;
- 执行文件
输入命令“./hello xxx xx 1”,将程序运行起来,期间会涉及到进程的创建,即fork函数,execve函数的调用;
- 信号和异常处理
在程序运行过程中,可能会收到键盘输入的各种信号以及程序产生的各种异常,进程运行中会对这些进行处理;
- 进程回收
在整个进程结束之后,shell会对其进行回收,避免其占用空间资源,成为僵尸进程。
感悟:
在这一学期的计算机系统学习中,我对计算机的观念彻底改变了。在学习之前,我对计算机的实现原理以及它的结构完全不了解,这也是为什么这门学科对我来说十分的困难。而在完成了这一学期的计算机系统课程之后,我对计算机的理解加深了,也能自己解决少量的计算机问题。总之希望这门课越办越好,能让更多的学生学会计算机,理解计算机。
附件
列出所有的中间产物的文件名,并予以说明起作用。
hello.c: 源文件;
hello.i: hello.c文件经预处理后形成的C程序文件;
hello.s: hello.i文件经编译后形成的文件;
hello.o: hello.s文件经汇编后形成的文件;
hello: 经链接后得到的二进制可执行文件;
hello.asm:hello.o的反汇编文件;
hello_2.elf: 可执行文件hello的格式文本文件。
参考文献
[1] 林来兴. 空间控制技术[M]. 北京:中国宇航出版社,1992:25-42.
[2] 辛希孟. 信息技术与信息服务国际研讨会论文集:A集[C]. 北京:中国科学出版社,1999.
[3] 赵耀东. 新时代的工业工程师[M/OL]. 台北:天下文化出版社,1998 [1998-09-26]. http://www.ie.nthu.edu.tw/info/ie.newie.htm(Big5).
[4] 谌颖. 空间交会控制理论与方法研究[D]. 哈尔滨:哈尔滨工业大学,1992:8-13.
[5] KANAMORI H. Shaking Without Quaking[J]. Science,1998,279(5359):2063-2064.
[6] CHRISTINE M. Plant Physiology: Plant Biology in the Genome Era[J/OL]. Science,1998,281:331-332[1998-09-23]. http://www.sciencemag.org/cgi/ collection/anatmorp.