### 哈工大计算机系统大作业--hello的一生 #### 概述 本文档深入探讨了一个简单的`hello`程序从编写至运行的全过程。这一旅程不仅涉及代码层面的转变,还包括程序如何被加载到内存中执行的具体细节。通过本项目,我们可以更深入地了解计算机系统的工作原理。 #### Hello简介 `Hello`程序起始于一个简单的C语言源文件`hello.c`。此文件包含了`main`函数,用于输出“Hello World!”。整个生命周期可分为几个关键阶段:预处理、编译、汇编、链接,最终形成一个可执行程序。 #### 环境与工具 - **操作系统**:Ubuntu - **开发工具**: - 预处理器:cpp - 编译器:gcc - 汇编器:as - 链接器:ld #### 中间结果 - **预处理**:生成`hello.i`文件,该文件包含所有宏定义和头文件的实际内容。 - **编译**:从`hello.i`生成`hello.s`,这是一个汇编语言程序。 - **汇编**:将`hello.s`转化为二进制格式的`hello.o`,即目标文件。 - **链接**:将`hello.o`与其他库文件链接,生成最终的可执行文件`hello`。 #### 预处理 **预处理的概念与作用**:预处理是编译前的一步,主要负责宏定义的展开、条件编译的处理、头文件的包含等操作。这一步是为了让编译器能更好地理解代码结构。 **预处理命令**:在Ubuntu下,可以通过`cpp`命令对源文件进行预处理。 **Hello的预处理结果解析**:预处理后的`hello.i`文件将不再包含任何宏定义或者条件编译指令,所有的`#include`语句都已经被替换为实际的文件内容。 #### 编译 **编译的概念与作用**:编译器将高级语言(如C)翻译成汇编语言。这一过程涉及到词法分析、语法分析、语义分析及代码优化等。 **编译命令**:在Ubuntu下,通常使用`gcc -S hello.c`来进行编译,生成`.s`文件。 **Hello的编译结果解析**:`hello.s`文件包含了一条条汇编指令,这些指令与源代码中的高级语言语句一一对应。 #### 汇编 **汇编的概念与作用**:汇编器将汇编语言转换为机器码,生成可重定位的目标文件。 **汇编命令**:使用`gcc -c hello.s`命令生成`hello.o`。 **可重定位目标elf格式**:`hello.o`遵循ELF格式标准,其中包含未解决的符号引用,需要通过链接器进行重定位。 **Hello.o的结果解析**:`hello.o`是一个二进制文件,包含汇编后的指令和数据段,以及符号表和重定位信息。 #### 链接 **链接的概念与作用**:链接器将多个目标文件和库文件组合起来,生成一个可执行文件。 **链接命令**:通过`gcc -o hello hello.o`完成链接过程。 **可执行目标文件hello的格式**:生成的`hello`是一个ELF可执行文件,包含了所有必要的信息以便于操作系统加载和执行。 **hello的虚拟地址空间**:程序运行时,操作系统会为它分配一个虚拟地址空间,包括代码段、数据段、栈段和堆段等。 **链接的重定位过程分析**:链接器根据符号表和重定位信息修改目标文件中的地址,确保所有依赖正确地加载到内存中。 **hello的执行流程**: 1. 当用户在shell中键入`./hello`命令时,shell通过fork和execve系统调用来启动程序。 2. 操作系统将`hello`程序加载到内存中,并初始化进程的上下文。 3. `hello`程序执行`main`函数,输出“Hello World!”。 **Hello的动态链接分析**:对于使用动态链接的程序,链接器会在运行时解析未解决的符号引用,确保所有依赖正确加载。 #### 进程管理 **进程的概念与作用**:进程是操作系统资源分配的基本单位,包含了程序执行所需的全部状态信息。 **Shell-bash的作用与处理流程**:shell是用户的命令行界面,它接收用户输入的命令并通过fork和execve创建并启动新的进程。 **Hello的fork进程创建过程**:fork函数创建一个新的进程副本,具有与父进程相同的资源和状态。 **Hello的execve过程**:execve系统调用用于替换当前进程的映像,加载并执行新的程序。 **Hello的进程执行**:`hello`程序在独立的进程中运行,直到正常结束或出现异常而终止。 **hello的异常与信号处理**:程序执行过程中可能会遇到各种异常情况,如除零错误或内存访问错误,这些异常通过信号传递给操作系统处理。 #### 存储管理 **hello的存储器地址空间**:每个进程都有自己的虚拟地址空间,包括代码段、数据段、栈段和堆段等。 **Intel逻辑地址到线性地址的变换-段式管理**:在x86架构中,逻辑地址通过段寄存器和偏移量组合而成,经过段式管理器转换为线性地址。 **Hello的线性地址到物理地址的变换-页式管理**:线性地址进一步通过页表转换为物理地址。 **TLB与四级页表支持下的VA到PA的变换**:快表(Translation Lookaside Buffer, TLB)用于加速虚拟地址到物理地址的转换。 **三级Cache支持下的物理内存访问**:CPU访问内存时首先尝试从高速缓存中读取数据,以此提高数据访问速度。 **hello进程fork时的内存映射**:在创建子进程时,父进程的内存空间被复制给子进程,但它们共享相同的物理页面,直到某个进程修改了内存内容触发写时复制机制。 **hello进程execve时的内存映射**:当进程执行`execve`调用时,其内存映像会被新程序替换,包括代码段和数据段。 **缺页故障与缺页中断处理**:当CPU尝试访问不在物理内存中的页面时,会产生缺页故障,操作系统需要处理此中断并将所需页面从磁盘加载到内存中。 **动态存储分配管理**:程序运行期间可能需要动态分配和释放内存,通过malloc和free等函数进行管理。 #### IO管理 **Linux的IO设备管理方法**:Linux通过文件描述符来抽象各种设备,使得对设备的操作统一为文件操作。 **UnixIO接口及其函数**:提供了read、write、open、close等函数,用于读写文件和设备。 **printf的实现分析**:`printf`函数内部使用`write`系统调用来向标准输出发送格式化字符串。 **getchar的实现分析**:`getchar`函数用于从标准输入读取字符,底层调用了`read`系统调用来获取数据。 #### 结论 通过本次大作业,我们深入了解了`hello`程序从源代码到可执行文件再到实际运行的全过程。这一过程涵盖了预处理、编译、汇编、链接等多个环节,同时也涉及了进程管理、存储管理和I/O管理等方面。这一系列步骤共同协作,使得一个简单的“Hello World!”程序得以顺利运行。 #### 附件 - `hello.c`源代码 - 各阶段产生的文件(`hello.i`, `hello.s`, `hello.o`) - 可执行文件`hello` #### 参考文献 - [1] Tanenbaum, A.S., Woodhull, A.S. (2006). "Operating Systems: Design and Implementation", 3rd Edition. - [2] Stallings, W. (2010). "Operating Systems: Internals and Design Principles", 7th Edition. - [3] Kernighan, B.W., Ritchie, D.M. (1988). "The C Programming Language", 2nd Edition.
- 粉丝: 1
- 资源: 1
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助