摘 要
本文主要介绍了一个示例程序从编写到执行到介绍的全过程。通过详细介绍各个过程中的具体状态和操作,将计算机系统各个组成部分的工作有机地结合统一起来,完成搭建知识体系、将知识融会贯通的目标。本文主要包括示例程序的预处理、编译、汇编、链接、进程管理、存储管理、I/O管理等部分的具体操作和结果,并最终得出系统性结论。
关键词:编译;内存管理;操作系统;
第1章 概述
1.1 Hello简介
根据Hello的自白,利用计算机系统的术语,简述Hello的P2P,020的整个过程。
首先,使用高级语言(C语言)编写得到hello.c源程序文本文件。然后对其进行预处理,形成hello.i文本文件。接着对其进行编译,形成hello.s汇编语言文本文件。接下来经过汇编程序处理,将其转化为hello.o可重定位目标程序二进制文件。最后将程序与函数库中需要使用的二进制文件进行链接,形成可执行目标程序ELF二进制文件。
执行该目标文件,操作系统会使用fork函数形成一个子进程,分配相应的内存资源,包括CPU的使用权限和虚拟内存等。然后使用execve函数加载进程。至此完成了从程序到进程的转变P2P(From Program to Process)。在CPU工作时,通过取指、译码、执行等微程序,逐步执行目标文件中的程序。同时,CPU使用流水线、进程切换等工作方式实现多进程作业。
在程序的执行过程中会使用到内存中的数据。这些数据通过各级存储,包括磁盘、主存、Cache等,并使用页表等辅助存储,实现访存的加速。在这个过程中还涉及操作系统的信号处理,控制进程,使得系统资源得到充分利用。而IO管理与信号处理通过软硬结合,完成程序从键盘、主板、显卡,再到屏幕的工作。当进程执行结束后,操作系统进行进程回收,实现所谓的O2O:From Zero-0 to Zero-0。
1.2 环境与工具
列出你为编写本论文,折腾Hello的整个过程中,使用的软硬件环境,以及开发与调试工具。
硬件环境:X64 CPU;2.19GHz;4.00GB RAM
软件环境:Windows 8.1 64位;VMware Workstation 14 Player;Ubuntu 16.04 LTS
开发工具:gcc;gdb;objdump;
1.3 中间结果
列出你为编写本论文,生成的中间结果文件的名字,文件的作用等。
中间结果文件名 | 文件作用 |
---|---|
hello.i | 预处理得到的中间结果 |
hello.s | hello.i编译后得到的汇编语言文本文件 |
hello.o | hello.s汇编后得到的可重定位目标文件 |
hello.out | 链接后得到的可执行目标文件 |
1.4 本章小结
hello.c程序从编写、预处理、编译、汇编、链接再到执行,体现了计算机系统系统各部分的具体功能,以及它们之间的的协同合作。
第2章 预处理
2.1 预处理的概念与作用
预处理指的是在编译之前进行的处理。C语言的预处理主要有三个方面的内容:宏定义、文件包含、条件编译。预处理命令以符号“#”开头。
预处理工作也叫做宏展开,将宏名替换为文本。宏定义只需将符号常量替换成后面对应的文本即可。文件包含可以在一个文件中包含另一个文件的内容,被包含的文件称为头文件。头文件的内容可以有函数原型、宏定义、结构体定义。条件编译是在条件满足时才编译某些语句。
使用条件编译可以使目标程序变小,运行时间变短。同时有利于代码的模块化。
2.2在Ubuntu下预处理的命令
gcc hello.c -E -o hello.i
图2-1 Ubuntu下预处理命令
图2-2 预处理结果hello.i文件(部分)
2.3 Hello的预处理结果解析
经过预处理之后,hello.c文件转化为hello.i文件。原文件中的宏进行了宏展开,头文件中的内容被包含进该文件中。打开该文件可以发现,文件长度变为3125行。文件的内容增加,且仍为可以阅读的C语言程序文本文件。
2.4 本章小结
本阶段完成了对hello.c的预处理工作。使用Ubuntu下的预处理指令可以将其转换为.i文件。完成该阶段转换后,可以进行下一阶段的汇编处理。
第3章 编译
3.1 编译的概念与作用
编译程序也称为编译器,是指把用高级程序设计语言书写的源程序,翻译成等价的汇编语言格式目标程序的翻译程序。编译程序属于采用生成性实现途径实现的翻译程序。它以高级程序设计语言书写的源程序作为输入,而以汇编语言表示的目标程序作为输出。
编译程序的基本功能是把源程序(高级语言)翻译成目标程序。除了基本功能之外,编译程序还具备语法检查、调试措施、修改手段、覆盖处理、目标程序优化、不同语言合用以及人机联系等重要功能。
3.2 在Ubuntu下编译的命令
gcc hello.i –S –o hello.s
图3-1 Ubuntu下编译命令
图3-2 编译结果hello.s文件(部分)
3.3 Hello的编译结果解析
3.3.1 全局变量与全局函数
在hello.c中,包含一个全局变量int sleepsecs=2.5;以及一个全局函数int main(int argc,char *argv[]);。经过编译之后,sleepsecs被存放在.rodata节中。而main函数中使用的字符串常量也被存放在数据区。其中,由于sleepsecs被定义为int型,所以为其赋初值2.5后,会进行隐式的类型转换,变为2。
图3-3 全局变量和全局函数
3.3.2 主函数的参数
主函数的参数部分给出了int argc,char *argv[]两个参数。在汇编代码中,分别将其存放在栈中rbp寄存器指向地址-20和-32处,如下图所示。其中%edi代表argc,%rsi代表argv[]。
图3-4 对传入参数的处理
3.3.3 条件判断语句及分支
接着在main函数中,使用if语句进行了条件判断。cmpl语句进行判断条件的比较。如果条件满足则继续顺序执行,调用puts输出给定字符串(这里puts是对printf的优化),然后使用参数1调用exit结束程序。对应的汇编代码如下。