计算机科学与技术学院
2021年5月
摘 要
本文通过分析一个简单的C语言程序在linux系统中从预处理到结束的全过程,加深我们对计算机系统的认识与理解。本文从hello的自白开始,对hello预处理、编译、汇编、链接、hello的进程管理、存储管理、IO管理等相关内容进行了深入的分析,并在linux系统上对该过程的每一步进行实验。最终使我们真正对hello的产生到回收的整个过程有了深刻的理解,从而让我们感受到学习计算机系统的意义和精髓所在。
关键词:linux;hello;预处理;编译;汇编;进程;存储
目 录
6.2 简述壳Shell-bash的作用与处理流程... - 30 -
6.3 Hello的fork进程创建过程... - 30 -
7.2 Intel逻辑地址到线性地址的变换-段式管理... - 38 -
7.3 Hello的线性地址到物理地址的变换-页式管理... - 39 -
7.4 TLB与四级页表支持下的VA到PA的变换... - 40 -
7.5 三级Cache支持下的物理内存访问... - 40 -
7.6 hello进程fork时的内存映射... - 40 -
7.7 hello进程execve时的内存映射... - 40 -
第1章 概述
1.1 Hello简介
hello的整个过程指的是hello从程序员编写到在计算机系统里面运行所经历的一系列步骤。
首先P2P指的是:From Program to Process。即hello.c从程序变为进程的这个过程。
该过程一共分为以下6步:
- 程序员在文本编辑器里面写下hello的代码,并将其改为.c文件。hello的源程序便诞生,也是hello的文本文件。
- 接下来预处理器(cpp)通过对hello源程序中的头文件、宏定义等进行识别,对原程序进行一系列处理,得到一个新的文本文件hello.i。
- 编译器(ccl)将文本文件hello.i翻译成文本文件hello.s,里面存放的是一个汇编语言程序。
- 汇编器(as)继续将hello.s进行处理,得到二进制代码文件hello.o,即可重定位目标程序,需要进一步链接的处理。
- 最后链接器(ld)对hello.o进行符号解析和重定位,并最终输出二进制的可执行目标程序
- 程序员在shell中输入./hello 7203610730 ggt 3 ,shell对命令行内容进行识别,由于第一个字符串不是内置命令,故fork一个子进程,对hello进行加载,hello在子进程中运行
接下来020指的是:From Zero-0 to Zero-0,指的是hello从最开始没有空间到最后也被从进程中删除这一过程。在用户在Shell中敲下./hello之前按,hello不占用内存空间,即对应第一个0,接下来shell使用fork以及execve加载hello,然后mmap为其分配虚拟内存空间,接下来由Cache,CPU等硬件资源配合运行程序,直到进程结束。第二个0指的是在进程结束后,hello进程会被父进程回收,并由内核删除相关的数据结构,最终hello不再占用内存空间。
1.2 环境与工具
硬件:处理器:AMD Ryzen 7 4800H with Radeon Graphics 2.90 GHz
RAM : 16GB 系统类型:64 位操作系统, 基于 x64 的处理器
软件 Windows10 64位
Ubuntu 20.04.4
开发与调试工具:vscode,Visual Stdio,2022 ,gcc,edb,gedit
1.3 中间结果
列出你为编写本论文,生成的中间结果文件的名字,文件的作用等。
表格 1 中间产物
文件名 |
作用 |
hello.i |
hello.c预处理后得到的文件 |
hello.s |
编译后的汇编语言文件 |
hello.o |
汇编后得到的可重定位目标文件 |
hello.elf |
用readelf读取hello.o得到的ELF格式信息 |
Dhello.s |
反汇编hello.o得到的反汇编文件 |
helloout.elf |
由hello可执行文件生成的.elf文件 |
Dhelloout.s |
反汇编hello可执行文件得到的反汇编文件 |
hello |
最终链接得到的可执行文件 |
1.4 本章小结
(第1章0.5分)
本章首先讲述了Hello的P2P,020的整个过程的具体含义,然后介绍了完成该论文时所采用的环境与工具以及生成的中间结果。
第2章 预处理
2.1 预处理的概念与作用
预处理的概念:
预处理是指编译器在读取源程序后,在真正的编译开始之前,预处理器(cpp)根据以字符#开头的命令,修改原始的C程序。主要包括宏定义、文件包含、条件编译三方面的内容。例如hello.c程序的第6、7、8行#include <stdio.h>,#include <unistd.h>,#include <stdlib.h>命令告诉预处理器读取系统头文件 stdio.h、unistd.h、stdlib.h中的内容,并把它直接插入程序文本。此外预处理器还会执行删除注释,对#define宏定义会用实际值来替代程序中的字符串等操作。进而得到另一个以.i作为文件扩展名的C程序。