HIT_ICS大作业

计算机系统

大作业

题 目 程序人生-Hello’s P2P
专 业 计算学部
学   号 1190XXXXX
班   级 1903XXX
学 生 XX    
指 导 教 师 史先俊

计算机科学与技术学院
2021年5月
摘 要
本文通过分析hello程序从C文件如何转变为可执行文件的全过程,包括预处理、编译、汇编、链接阶段,进入到内存,各级cache,最后在I/O中输出,最后被回收的过程描述,阐述了各个阶段在Linux下的实现机制及原因,并且以这些过程的分析为例,阐明整个程序的生命周期和运行机制,通过本次大作业,有助于我们对前期所学内容做出一个统筹规划,将各块知识融会贯通,形成知识体系,使我们对于计算机系统的理解进一步深入。

关键词:编译;进程管理;汇编;链接;存储;进程;I/O;

目 录

第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过程:指的是从程序到进程,hello程序编写后,通过预处理(预处理器处理以#开始的预编译指令)、编译(编译器将C程序翻译成汇编代码)、汇编(汇编器将汇编代码转化为二进制机器语言)、链接(链接器将汇编器生成的目标文件外加库链接为一个可执行文件)

				图1-1 程序的处理过程

020过程: 指的是Process在内存中从0到0,使用fork产生一个子进程,shell通过execve加载并执行hello,映射虚拟内存,然后程序载入物理内存,进入 main函数执行目标代码,CPU为运行的hello分配时间片执行逻辑控制流。当程序运行结束后,shell父进程负责回收hello进程,内核删除相关数据结构。

1.2 环境与工具
硬件环境:X64 CPU;2GHz;2G RAM;256GHD Disk以上
软件环境:Ubuntu16.04. LTS 64位, Windows10 64位/优麒麟 64位
开发与调试工具:Visual Studio 2019 64位;EDB;GDB/OBJDUMP;GCC等
1.3 中间结果
文件名 中间结果
hello.c hello源程序
hello.i 预处理后文本文件
hello.s 编译后的汇编文件
hello.o 汇编后的可重定位目标文件
hello 链接后可执行文件
hello.objdump hello的反汇编代码
hello.elf hello的elf文件
helloo.objdump hello.o的反汇编文件
hello_o_elf.txt hello.o的ELF格式

1.4 本章小结
本章介绍了hello程序的相关基本知识,并对P2P和020的过程做出了引入,列出了软硬件环境和开发调试工具,给出了任务过程中出现的中间产物及其作用的表格。

第2章 预处理
2.1 预处理的概念与作用
概念:预处理是编译器在编译开始之前调用预处理器来执行以#开头的命令,包括#include的头文件、#define的宏定义,#if、#ifdef、#endif等条件编译,最终生成以.i结尾的文本文件。
作用:预处理器根据以字符#开头的命令,修改原始的C程序。作用如下:
1)将所有的#define删除,并且展开所有的宏定义;
2)处理所有条件编译指令,如#if,#ifdef等;
3)处理#include预编译指令,将被包含的文件插入到该预编译指令的位置。该过程递归进行,及被包含的文件可能还包含其他文件;
4)删除所有的注释//和 /**/;
5)保留所有的#pragma编译器指令。
2.2在Ubuntu下预处理的命令
Ubuntu下预处理命令为:
gcc -E hello.c -o hello.i

					图2-1 预处理命令执行结果

2.3 Hello的预处理结果解析
处理前的hello.c中包含三条会被预处理的语句,如图2-2,处理后在hello.i中可以看到库文件调用已被解析(图片展示的是第一个头文件,后面两个与之相同,不再赘述),并且程序中的注释已经被删除。

	图2-2 hello.c中的#开头的命令


	  图2-3 hello.i中对于#头文件的处理
总结地来说,预处理过程在main函数之前,预处理器(cpp)读取头文件stdio.h 、stdlib.h 、和unistd.h中的内容,如stdio.h的展开,打开usr/include/stdio.h后,可以看到其含有#开头的宏定义等,预处理器会对此继续递归展开,最终的.i程序中没有#define,以及#开头的语句。
而上述步骤完成之后,main函数未做出改动

				 图2-4 main函数并未改动

2.4 本章小结
本章介绍了hello.c的预处理阶段,预处理是计算机对程序进行操作的第一个步骤,在本章中,了解了预处理命令,并分析了修改后的hello.i文本,,理解了预处理器读取系统头文件中内容,并把它插入程序文本中的作用和实现方式。

第3章 编译
3.1 编译的概念与作用
概念:编译器是编译器(Compiler)对hello.i文件进行处理的过程。此阶段编译器会完成对代码的语法和语义的分析,生成汇编代码,保存至文本文件hello.s。汇编语言为不同高级语言的不同编译器提供了通用的输出语言。
作用:将高级语言翻译成汇编语言,生成汇编文件,从而以一种文本格式描述了一条低级机器指令。
3.2 在Ubuntu下编译的命令
Ubuntu下编译命令为:
gcc -S hello.c -o hello.s

图3.2.1 在Ubuntu下编译的命令
3.3 Hello的编译结果解析
3.3.1 汇编指令
.file C文件声明
.text 代码段
.globl 声明全局变量
.data 已初始化的全局和静态C变量
.align 4 声明对指令或者数据的存放地址进行对齐的方式
.type 指明函数类型或对象类型
.size 声明变量大小
.long .string 声明long型、string型数据
.section .rodata 只读数据段

							图3.3.1hello.s头部段

3.3.2 数据解析
hello.c中的数据类型包括整数、数组、字符串,下面我们通过从变量、常量、表达式以及类型的角度对其进行解析:

  1. 整型变量
    (1)int i:
    这里的i是局部变量,编译器将局部变量存放在栈和寄存器中,这里i存放在-4(%rbp)中,占据4个字节,对应于汇编语句如下:

图3.3.2 整型变量i
(2)int argc
argc是main函数的参数记录传入参数个数,这里参数用寄存器来传递

		图3.3.3 整型变量argc
  1. 数组
    char *argv[]
    argv即一个字符串数组,他是一个二重指针,argv中每一个数组元素都是一个指针指向相应的字符串的首地址,而argv和argc都是main的参数,所以argv同样使用寄存器来传递。对argv数组进行访问的时候用二重指针,比如访问对argv[1]、argv[2]的首地址可以通过每次+16来实现,这个地址的内容就是各个字符串的内容。

    				 	图3.3.4 *argv保存位置
    
  2. 字符串
    (1)printf的输出格式化参数,存放在只读数据段.rodata中,其中,汉字在utf-8编码中占三个字节。

    					图3.3.5 字符串常量
    

3.3.3 赋值解析
源程序中for循环把i初始化为0,循环体是i++。i是保存在栈中的局部变量,直接用mov语句对i进行赋值。因为i是局部变量,保存在栈中,因此这里的赋值采用movl指令对栈中的空间进行立即数赋值。(l代表32位)

						   图3.3.6 i赋值信息

3.3.4 算数操作
for循环中i++
自增指令采用add指令,因为i是4B即32b,所以用addl操作使得i++

						  图3.3.7  i++指令解释
	Linux中算术操作的指令在书中已经有详细地介绍与解释,下面是书上的图,涵盖了算术操作指令用法。
 
					图3.3.8 算数操作

3.3.5 关系操作
Cpu中关系操作主要依靠cmp及test系列指令,cmp指令根据两个操作数之差来设置条件码。一般在此类指令之后都会跟着检查条件码的操作,依此实现操作数的关系操作。
总结进行关系操作的指令如下:

			图3.3.9 关系操作指令

程序中涉及的关系运算如下:
(1)判断argc是否等于4,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值