计算机科学与技术学院

2021年5月

摘 要

本文通过分析一个简单的C语言程序在linux系统中从预处理到结束的全过程,加深我们对计算机系统的认识与理解。本文从hello的自白开始,对hello预处理、编译、汇编、链接、hello的进程管理、存储管理、IO管理等相关内容进行了深入的分析,并在linux系统上对该过程的每一步进行实验。最终使我们真正对hello的产生到回收的整个过程有了深刻的理解,从而让我们感受到学习计算机系统的意义和精髓所在。

关键词:linux;hello;预处理;编译;汇编;进程;存储

目 录

第1章 概述… – 4 –

1.1 Hello简介… – 4 –

1.2 环境与工具… – 4 –

1.3 中间结果… – 5 –

1.4 本章小结… – 5 –

第2章 预处理… – 6 –

2.1 预处理的概念与作用… – 6 –

2.2在Ubuntu下预处理的命令… – 6 –

2.3 Hello的预处理结果解析… – 6 –

2.4 本章小结… – 7 –

第3章 编译… – 9 –

3.1 编译的概念与作用… – 9 –

3.2 在Ubuntu下编译的命令… – 9 –

3.3 Hello的编译结果解析… – 9 –

3.4 本章小结… – 13 –

第4章 汇编… – 14 –

4.1 汇编的概念与作用… – 14 –

4.2 在Ubuntu下汇编的命令… – 14 –

4.3 可重定位目标elf格式… – 14 –

4.4 Hello.o的结果解析… – 17 –

4.5 本章小结… – 19 –

第5章 链接… – 20 –

5.1 链接的概念与作用… – 20 –

5.2 在Ubuntu下链接的命令… – 20 –

5.3 可执行目标文件hello的格式… – 20 –

5.4 hello的虚拟地址空间… – 22 –

5.5 链接的重定位过程分析… – 24 –

5.6 hello的执行流程… – 26 –

5.7 Hello的动态链接分析… – 28 –

5.8 本章小结… – 29 –

第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本章小结… – 37 –

第7章 hello的存储管理… – 38 –

7.1 hello的存储器地址空间… – 38 –

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 –

7.8 缺页故障与缺页中断处理… – 40 –

7.9动态存储分配管理… – 40 –

7.10本章小结… – 40 –

第8章 hello的IO管理… – 41 –

8.1 Linux的IO设备管理方法… – 41 –

8.2 简述Unix IO接口及其函数… – 41 –

8.3 printf的实现分析… – 41 –

8.4 getchar的实现分析… – 41 –

8.5本章小结… – 41 –

结论… – 42 –

附件… – 43 –

参考文献… – 44 –

第1章 概述

1.1 Hello简介

hello的整个过程指的是hello从程序员编写到在计算机系统里面运行所经历的一系列步骤。

首先P2P指的是:From Program to Process。即hello.c从程序变为进程的这个过程。

该过程一共分为以下6步:

  1. 程序员在文本编辑器里面写下hello的代码,并将其改为.c文件。hello的源程序便诞生,也是hello的文本文件。
  2. 接下来预处理器(cpp)通过对hello源程序中的头文件、宏定义等进行识别,对原程序进行一系列处理,得到一个新的文本文件hello.i。
  3. 编译器(ccl)将文本文件hello.i翻译成文本文件hello.s,里面存放的是一个汇编语言程序。
  4. 汇编器(as)继续将hello.s进行处理,得到二进制代码文件hello.o,即可重定位目标程序,需要进一步链接的处理。
  5. 最后链接器(ld)对hello.o进行符号解析和重定位,并最终输出二进制的可执行目标程序
  6. 程序员在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 ,#include ,#include 命令告诉预处理器读取系统头文件 stdio.h、unistd.h、stdlib.h中的内容