CSAPP大作业hello的程序人生

计算机系统

大作业

题 目 程序人生-Hello’s P2P
专 业 计算机
学   号 1190202413
班   级 05
学 生 庄雨杰    
指 导 教 师 史先俊

计算机科学与技术学院
2021年5月
摘 要
本文介绍了hello程序的一生,在linux下借助一些工具,对hello程序如何从一个文本文件hello.c经过预处理、编译、汇编及链接,再通过进程管理、异常与信号处理、内存管理及I/O管理一步步地在计算机中运行的过程做了详细地描述,下面让我们走进hello辉煌的程序人生。
摘要是论文内容的高度概括,应具有独立性和自含性,即不阅读论文的全文,就能获得必要的信息。摘要应包括本论文的目的、主要内容、方法、成果及其理论与实际意义。摘要中不宜使用公式、结构式、图表和非公知公用的符号与术语,不标注引用文献编号,同时避免将摘要写成目录式的内容介绍。

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

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

目 录

第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简介
Hello的P2P:
P2P,即From Program to Process。使用vim、CodeBlocks等工具进行编程,最后得到一个hello.c文件的过程叫做program。
如图1.1所示,hello.c经过预处理、编译、汇编、链接这四个阶段后,生成可执行文件hello。然后在linux下的命令行输入./hello 1190202413 庄雨杰 1,Shell会会调用fork函数创建一个子进程,并调用execve函数子进程的上下文中运行这个程序。execve函数加载并运行可执行文件hello,且带参数列表argv(这里的参数列表就是hello、1190202413、庄雨杰、1)和环境变量envp,通过将虚拟内存映射到物理内存以及内核的进程调度与其他程序并发地运行。这就是hello的process。以上就是hello的P2P。

图1.1 hello.c编译过程
Hello的020:
020,即从无到有,再从有到无。一开始的无是hello运行之前,不占任何内存资源。而之后在linux终端下运行hello,shell为其fork一个子进程,子进程通过execve系统调用启动加载器,加载器删除子进程现有的虚拟内存段,并创建一组新的代码、数据、堆和栈段。通过将虚拟地址空间中的页映射到可执行文件hello的页大小的片,新的代码和数据段被初始化为可执行文件的内容。然后开始执行hello程序,通过段式管理、页式管理、多级cache、I/O设备等联动,CPU为hello程序分配时间片,对每条指令在流水线上进行取值、译码、执行、访存、写回、更新PC。最后当程序运行结束时,父进程shell将子进程hello回收,释放其内存和上下文信息,此时hello不占任何内存资源。这就是hello的020(从无到有,再从有到无)的过程。
1.2 环境与工具
硬件环境:笔记本电脑(x64 Intel Core i5-9300H CPU;2.40GHz;8G RAM;256GHD Disk)
软件环境:Windows10 64位;Vmware 15.5.0 build-14665864;Ubuntu 20.04.2 LTS 64位
开发工具:Visual Studio 2019 64位;CodeBlocks;Winhex; 记事本;vi/vim/gpedit+gcc;EDB;GDB/OBJDUMP;TestStudio;Gprof;Valgrind
1.3 中间结果
列出你为编写本论文,生成的中间结果文件的名字,文件的作用等。
hello.c:源程序
hello.i:预处理后的文本文件
hello.s:编译后汇编程序文本文件
hello.o:汇编后的可重定位目标程序(二进制文件)
hello:链接后的可执行目标文件
1.4 本章小结

(第1章0.5分)

第2章 预处理
2.1 预处理的概念与作用
概念:
程序设计领域中,预处理一般是指在程序源代码被翻译为目标代码的过程中,生成二进制代码之前的过程,其实就是预处理器将.c文件翻译成.i文件的过程。典型地,由预处理器(preprocessor) 对程序源代码文本进行处理,得到的结果再由编译器核心进一步编译。这个过程并不对程序的源代码进行解析,但它把源代码分割或处理成为特定的单位——(用C/C++的术语来说是)预处理记号(preprocessing token)用来支持语言特性(如C/C++的宏调用)。
常见的预处理是C语言和C++语言。ISO C和ISO C++都规定程序由源代码被翻译分为若干有序的阶段(phase) [1] [2] ,通常前几个阶段由预处理器实现。预处理中会展开以#起始的行,试图解释为预处理指令(preprocessing directive) ,其中ISO C/C++要求支持的包括#if/#ifdef/#ifndef/#else/#elif/#endif(条件编译)、#define(宏定义)、#include(源文件包含)、#line(行控制)、#error(错误指令)、#pragma(和实现相关的杂注)以及单独的#(空指令) 。预处理指令一般被用来使源代码在不同的执行环境中被方便的修改或者编译。
作用:
C语言预处理程序的作用是根据源代码中的预处理指令修改你的源代码。预处理指令是一种命令语句(如#define),它指示预处理程序如何修改源代码。在对程序进行通常的编译处理之前,编译程序会自动运行预处理程序,对程序进行编译预处理,这部分工作对程序员来说是不可见的。
例如#define指令定义了一个宏—用来代表其他东西的一个命令,通常是某一个类型的常量。预处理会通过将宏的名字和它的定义存储在一起来响应#define指令。当这个宏在后面的程序中使用到时,预处理器”扩展”了宏,将宏替换为它所定义的值。
#include指令告诉预处理器打开一个特定的文件,将它的内容作为正在编译的文件的一部分“包含”进来。例如:下面这行命令:
#include<stdio.h>指示预处理器打开一个名字为stdio.h的文件,并将它的内容加到当前的程序中。
预处理器的输入是一个C语言程序,即.c文件。程序可能包含预处理指令。预处理器会执行这些指令,并在处理过程中删除这些指令。预处理器的输出是另外一个程序:原程序的一个编辑后的版本,不再包含指令,即.i文件。预处理器的输出被直接交给编译器。
2.2在Ubuntu下预处理的命令
指令:gcc -m64 -no-pie -fno-PIC -E hello.c -o hello.i
截图:

						图2.1 Ubuntu下预处理指令

2.3 Hello的预处理结果解析
截图:

图2.2 预处理生成hello.i

				图2.3 hello.i部分内容1

图2.4 hello.i部分内容2

图2.5 hello.i部分内容3
解析:
如图2.3、2.4、2.5所示,我们可以看到源程序短短23行代码,经预处理成hello.i文件包含了3060行代码。这是因为源程序hello.c中有如下三条预处理指令:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
这三条预处理指令告诉预处理器读取系统头文件stdio.h、unistd.h、stdlib.h的内容,并把它们插入到程序文本中,一般包括结构体的定义(typedef struct)、函数声明(extern)、对引用目录的标注(# 28 “/usr/include/stdio.h” 2 3 4)等内容。若源程序中有#define预处理指令还会对相应的符号进行替换,或者其他类型的预处理指令,预处理器也会执行对于的操作。
我们再看源程序的其他部分,预处理得到的hello.i中的main函数和源程序保持一致,因为预处理器不会对其他部分进行修改。
2.4 本章小结
本章介绍了预处理的概念与作用,以及在linux下源程序hello.c文件怎么经过预处理将头文件插入到程序文本中,最后得到hello.i文件的过程。

(第2章0.5分)

第3章 编译
3.1 编译的概念与作用
概念:
编译,就是编译器(cll)将.i文本文件翻译成.s文本文件的过程,即把预处理后的代码转化为汇编指令的过程。汇编指令只是CPU相关的,也就是说C代码和python代码,代码逻辑如果相同,编译完的结果其实是一样的。
作用:
1.扫描(词法分析)
2.语法分析
3.语义分析
4.源代码优化(中间语言生成)
5.代码生成,目标代码优化
编译过程中会检查语法是否存在错误。编译后生成的.s文件,即汇编程序比预处理文件更容易让机器理解、比.o可重定位目标文件更容易让程序员理解。生成的汇编程序可以由汇编器(as)汇编后进一步形成可重定位目标程序(二进制)的.o文件。
3.2 在Ubuntu下编译的命令
指令:gcc -m64 -no-pie -fno-PIC -S hello.c -o hello.s
截图:

图3.1 Ubuntu下编译指令
3.3 Hello的编译结果解析
截图:

		图3.2 编译生成hello.s

3.3.1数据
hello.s中的数据有常量、
<1>常量
如图3.3所示,源程序hello.c中有两个字符串常量,都是作为printf的格式参数,一个是"用法: Hello 学号 姓名 秒数!\n",另一个是"Hello %s %s\n"。
如图3.4所示,在hello.s文件中,编译器把它们放在标号LC0中和标号LC1中。至于为何如此表示,根据UTF-8的编码原则,汉字被编码为三个字节,在hello.s中以编码形式保存;而英文、\n、%、空格等字符串,则被编码为一个字节,与ASCII码的规则兼容,这些字符在hello.s中以原来的形式保存。

					图3.3 hello.c中的main函数

图3.4 hello.s中的字符串常量

图3.5 hello.s中main的部分内容

<2>局部变量
如图3.3所示,在源程序hell
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值