哈工大计统大作业-程序人生
摘 要
本项目以“程序人生-Hello's P2P”为核心,通过编写、预处理、编译、汇编、链接及运行一个简单的Hello程序,系统探讨了计算机系统中程序从代码到进程的全生命周期。实验基于Ubuntu环境,使用GCC工具链完成代码转换,分析了预处理展开头文件、编译生成汇编指令、汇编生成可重定位目标文件、链接生成可执行文件等关键步骤的底层机制。结合进程管理、存储管理和IO管理,深入揭示了操作系统对程序执行的资源分配、地址转换、异常处理及动态链接的支持。项目通过理论与实践结合,完整呈现了程序在编译系统、操作系统和硬件协同下的运行流程,验证了计算机系统分层抽象与模块化设计的高效性,为深入理解系统级编程与优化提供了重要参考。
关键词:预处理;编译;链接;进程管理;存储管理;动态链接;IO管理
目 录
第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简介
Program:在VSCode中编写hello.c
预处理:gcc -E hello.c -o hello.i → 展开头文件
编译:gcc -S hello.i -o hello.s → 生成x86_64汇编
汇编:gcc -c hello.s -o hello.o → 生成ELF可重定位文件
链接:gcc hello.o -o hello → 动态链接glibc 2.38
Process:Shell通过fork()创建子进程,execve()加载hello。
OS分配虚拟内存,CPU执行指令后调用exit_group(0)终止。
020(From Zero to Zero):0→1:文本文件→可执行文件
1→0:进程终止后,OS回收页表、文件描述符等资源。
1.2 环境与工具
硬件 x86_64 CPU, DELL服务器(Ubuntu)
内核 Linux 6.8.0-54-generic
工具链 GCC 13.3.0(-Og)、GNU Binutils 2.41、glibc 2.38
调试 GDB 14.2、strace 6.8、objdump 2.41
编辑器 VSCode
1.3 中间结果
hello.i # 预处理后代码
hello.s # 汇编代码
hello.o # ELF文件
hello # 动态链接可执行文件
1.4 本章小结
本章简述了Hello程序的P2P(从代码到进程)和020(从无到无)生命周期,列出了实验环境和生成的中间文件。后续章节将深入分析预处理、编译、进程运行等细节。
第2章 预处理
2.1 预处理的概念与作用
预处理(Preprocessing)是C程序编译的第一步,由预处理器(cpp)执行,主要完成以下任务:
宏展开:替换#define定义的宏
头文件包含:递归展开#include指令,插入头文件内容
条件编译:处理#if、#ifdef等指令,决定是否包含代码块
删除注释:移除所有/* ... */和//注释
添加行标记:插入#line指令,便于调试时定位源码位置。
作用:
使代码可移植(如通过条件编译适配不同平台)
减少重复代码(通过头文件和宏)
生成“纯净”的C代码(不含预处理指令),供编译器处理
2.2在Ubuntu下预处理的命令
-m64:64位 -E:仅预处理 -o hello.i:输出到hello.i文件。
2.3 Hello的预处理结果解析
头文件展开:
原始代码中的#include被替换为头文件内容:
stdio.h:插入printf、exit等函数声明
unistd.h:插入sleep、getchar等系统调用声明
stdlib.h:插入atoi的函数声明
注释删除:
源码开头的注释被完全移除
行标记:
插入#line指令,标识原始代码位置
2.4 本章小结
本章通过gcc -E命令对hello.c进行预处理,生成hello.i文件,并分析其内容,进行预处理核心任务:头文件展开(插入stdio.h等)、删除注释、添加行标记。原始代码从24行扩展为3180行(主要因头文件插入),保留了所有函数调用(printf、sleep)的声明。
第3章 编译
3.1 编译的概念与作用
概念:
编译(Compilation)指将预处理后的C代码(.i)转换为汇编代码(.s)的过程,由编译器(GCC的cc1组件)完成
作用:
语法分析:检查代码是否符合C语言规范
语义优化:在-Og优化级别下,平衡可读性与性能
生成汇编:将高级C代码转换为低级机器指令的助记符
3.2 在Ubuntu下编译的命令
-m64:64位 -S:生成汇编代码 -Og:启用调试优化
3.3 Hello的编译结果解析
3.3.1 字符串处理
.LC0:
.string "\347\224\250\346\263\225..." # UTF-8编码的中文字符串
.LC1:
.string "Hello %s %s %s\n" # printf格式字符串
3.3.2 函数框架
函数入口:
main:
endbr64 # 对抗ROP攻击的指令
pushq %rbp # 保存基址指针
pushq %rbx # 保存被调用者保存寄存器
subq $8, %rsp # 分配栈空间
3.3.3 参数检查
cmpl $5, %edi # 比较argc和5
jne .L6 # 不等于则跳转错误处理
movq %rsi, %rbx # 保存argv指针
3.3.4 错误处理
.L6:
leaq .LC0(%rip), %rdi # 加载错误字符串地址
call puts@PLT # 调用puts输出
movl $1, %edi
call exit@PLT # 退出程序
3.3.5 主循环结构
循环初始化:movl $0, %ebp # i = 0
循环条件:
.L2:
cmpl $9, %ebp # 比较i和9
jle .L3 # i 、