哈工大计算机系统大作业

计算机系统

大作业

题 目 程序人生-Hello’s P2P
专 业 软件工程
学   号 1183000118
班   级 1837101
学 生 张智琦    
指 导 教 师 史先俊

计算机科学与技术学院
2019年12月
摘 要
本文通过对于hello程序的分析,从hello.c直到hello可执行程序进行逐步分析,结合课本上的知识和一些资料,通过乌邦图虚拟机进行试验,试验gdb,edb以及gcc等工具进行试验,把这个学期csapp中各章节知识进行融合,形成自己的语言,展示自己的收获,体现自己对于对计算机系统这门课程的理解。

关键词:计算机系统,hello程序的一生

(摘要0分,缺失-1分,根据内容精彩称都酌情加分0-1分)

目 录

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

第1章 概述
1.1 Hello简介
Hello程序的生命周期是从一个源程序,或者说源文件的,即程序员通过编辑器创建并保存的文本文件,文件名是hello.c.
hello.c分别经过预处理器cpp的预处理,、编译器ccl的编译,汇编器as的汇编依次生成生成hello.i文件,hello.s文件、,生成hello.o文件、最后使用链接器ld进行链接最终成为可执行目标程序hello.
当我们在shell中输入字符串.\hello并使用回车代表输入结束后,shell通过一系列指令的调用将输入的字符读入到寄存器中,之后将Hello目标文件中的代码和数据从磁盘复制到主存。此时shell会调用fork函数创建一个新的进程,并通过加载报存上下文,将控制权交给这个新的进程,具体过程在后面会详细叙述。
在hello加载完成后,处理器就开始执行这个程序,翻译成机器语言再翻译成指令编码,最后把程序的调用如:printf等进行链接。新的代码段和数据段被初始化为hello目标文件的内容.然后,加载器会从_start的地址开始,之后会来到 main 函数的地址,之后进入 main 函数执行目标代码,CPU 为运行的 hello 分配时间片执行逻辑 控制流。
执行阶段把这个等执行的程序分解成几个阶段,分别执行对应的指令,最后输出字符串。之后输出的字符串从主存复制到寄存器文件,再从寄存器文件复制到显示设备,最终显示到屏幕上。
这标志着进程的终止,shell的父进程回收这个进程操作系统恢复shell的上下文,控制权重回shell,由shell等待接受下一个指令的输入。
1.2 环境与工具

硬件环境:Intel Core i7 x64CPU 16G RAM 512G SSD
软件环境:Ubuntu18.04.1 LTS
开发与调试工具:visual studio edb,gcc,gdb,readelf,HexEdit,ld

1.3 中间结果

文件名 文件作用
hello.i 预处理器修改了的源程序,分析预处理器行为
hello.s 编译器生成的编译程序,分析编译器行为
hello.o 可重定位目标程序,分析汇编器行为
hello 可执行目标程序,分析链接器行为
elf.txt hello.o的elf格式,分析汇编器和链接器行为
objdump.txt hello.o的反汇编,主要是为了分析hello.o
5.3.txt 可执行hello的elf格式,作用是重定位过程分析
5.5.txt 可执行hello的反汇编,作用是重定位过程分析

列出你为编写本论文,生成的中间结果文件的名字,文件的作用等。
1.4 本章小结
本章主要介绍了hello程序的P2P、020的过程并列出实验基本信息
(第1章0.5分)

第2章 预处理
2.1 预处理的概念与作用
预处理的基本概念:在源代码编译之前对源代码进行的错误处理。c语言的预错误处理主要包括有三个预处理方面的基本定义内容:1.宏的定义;2.文件的包含;3.条件的编译。c语言预处理的命令以原始的字符符号"#"开头。
c语言的预处理器(cpp)根据以原始的c字符串中#开头的预处理命令,修改原始的c语言程序。在c语言和c/c++中常见的编译程序需要进行预处理的程序指令主要有:#define(宏定义),#include(源文件包含),#error(错误的指令)等。通过一个预处理命令使得一个源代码编译程序可以在不同的程序运行语言环境中被各种语言编译器方便的进行编译。
预处理的作用效果:以#include为例,预处理器(cpp)把程序中声明的文件复制到这个程序中,具体到hello.c的就是#include <unistd.h> #include <stdlib.h>#include<stdio.h>。cpp把这些头文件的内容插入到程序文本中,方便编译器进行下一步的编译。结果就是得到了另一个c程序,通常得到的程序以.i作为文件扩展名。

2.2在Ubuntu下预处理的命令
命令:cpp hello.c > hello.i

图2-2-1

2.3 Hello的预处理结果解析
使用文本编辑器打开输出的hello.i文件:

图2-3-1
我们可以发现,原本仅仅只有几行的头文件hello.c已经被程序扩展到了数千行,hello.i程序的依次开始是程序的头文件stdio.hunistd.hstdlib.h的依次展开。以#define<stdio.h>程序为例:
在乌邦图中发现程序使用的头文件#define<stdio.h>后到一个乌邦图的一个环境变量下寻找一个stdio.h,把其中stdio.h的宏定义内容进行了复制,同样的把其中stdio.h其中的宏定义被复制进行了递归依次展开。

图2-3-2
而我们可以发现原始的hello.c的代码已经在程序的最后,前面都是预处理器复制的内容。
2.4 本章小结
本章首先介绍了预处理的定义与作用、之后结合预处理之后的hello.i程序对预处理的结果进行了简单分析。
预处理过程为接下来对程序的操作打下了基础,是十分重要,不可或缺的。

(第2章0.5分)

第3章 编译
3.1 编译的概念与作用
编译要对程序进行以下的过程:首先进行的是语法分析,编译完成的程序使用语法分析器对编译程序输入的符号进行语法检查,检验其语法是否完全符合了语法的标准,如果不完全符合就是产生了错误。
编译器使用ccl把一个简单文本翻译文件的其中的一个hello.i翻译成为一个新的hello.s,它的翻译目的主要是为了包含一个可以使用多种汇编语言的应用程序。
在机器语言编译的整个过程中,编译器或程序都会产生一种新的中间代码,这种优化就是为了保证下一步的编译器为优化程序进行了充分的准备,大部分的编译器或程序都会针对编译器或程序的功能进行一些优化,目的之一就是在编译器可以很好地实现其原有机器语言功能的前提下提高编译器程序的性能和运行的效率。最后就是使用编译器把已经优化好的编译器和中间代码提取出来进行机器语言编译,调用机器语言汇编的程序,最后生成机器语言的代码。

3.2 在Ubuntu下编译的命令
gcc -S hello.i -o hello.s

图3-2-1
3.3 Hello的编译结果解析

图3-3-1
3.3.1 数据类型
1.局部变量int i

        图3-3-2 

局部数据空间的每个变量被认为储存在一个栈的寄存器或者栈中,在一个hello.s.的范例里面,编译器将i变量存储在栈上的局部空间-4(%rbp)中,i可以作为一个intt的类型大约占4个单字节。

2.局部变量 argc
作为第一个参数存在存在寄存器edi中

图3-3-3
3.数组argv[]
main类型函数程序执行时需要输入的是命令行,char类型单个字符串元素的命令行大小为8为,这个数组文件中存放的指针是输入字符串的指针,程序中的字符串argv[1]和程序中的argv[2]的字符串地址分别被输入的rax分两次进行读取,argv[3]的秒数作为字符串的秒数被第三次读取。

      图3-3-4

4.字符串

字符以UTF-8编码的格式存在只读的数据段(rodata)。

3.3.2 算数操作
算数操作对应的机器语言实现如下

         图3-3-5

i++被实现为:

3.3.3 关系操作
Argc!=3这里是使用je进行条件跳转。

   图3-3-6

I<8 这里是使用jle进行条件跳转。

图3-3-7
3.3.4 控制转移

  1. if(argc!=4)这个条件判断被编译成

       图3-3-8
    

:当argv不等于3的时候执行程序段l2中的第一行代码。cmpl比较执行完毕后,设置一个条件执行代码,je根据zf判断程序段是否完全符合条件,如果符合,就对程序段执行一次跳转,否则程

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值