程序人生-Hello’s P2P-HIT计统大作业
摘 要
在硅基世界中,hello.c程序的旅程始于预处置处罚阶段,利用宏界说构建起代码框架。编译器将C语言转化为汇编语言,汇编器再将其转化为可重定向目标文件,而链接器整合库函数和目标文件形成可执行目标文件。当shell启动程序执行,操作系统为其分配虚拟内存,MMU通过页表管理虚实地点映射。指令流在CPU中有序执行,数据总线传输着海量二进制信息,主函数执行完毕后,exit()触发进程终止,系统回收资源并生存退出状态,存储设备中留存着完整的程序痕迹。
关键词:hello;预处置处罚;编译;链接;进程管理;存储管理;动态链接;P2P;020
第1章 概述
1.1 Hello简介
1.2 情况与工具
1.3 中间效果
1.4 本章小结
第2章 预处置处罚
2.1 预处置处罚的概念与作用
2.2在Ubuntu下预处置处罚的下令
2.3 Hello的预处置处罚效果剖析
2.4 本章小结
第3章 编译
3.1 编译的概念与作用
3.2 在Ubuntu下编译的下令
3.3 Hello的编译效果剖析
3.4 本章小结
第4章 汇编
4.1 汇编的概念与作用
4.2 在Ubuntu下汇编的下令
4.3 可重定位目标elf格式
4.4 Hello.o的效果剖析
4.5 本章小结
第5章 链接
5.1 链接的概念与作用
5.2 在Ubuntu下链接的下令
5.3 可执行目标文件hello的格式
5.4 hello的虚拟地点空间
5.5 链接的重定位过程分析
5.6 hello的执行流程
5.7 Hello的动态链接分析
5.8 本章小结
第6章 hello进程管理
6.1 进程的概念与作用
6.2 简述壳Shell-bash的作用与处置处罚流程
6.3 Hello的fork进程创建过程
6.4 Hello的execve过程
6.5 Hello的进程执行
6.6 hello的异常与信号处置处罚
6.7本章小结
第7章 hello的存储管理
7.1 hello的存储器地点空间
7.2 Intel逻辑地点到线性地点的变更-段式管理
7.3 Hello的线性地点到物理地点的变更-页式管理
7.4 TLB与四级页表支持下的VA到PA的变更
7.5 三级Cache支持下的物理内存访问
7.6 hello进程fork时的内存映射
7.7 hello进程execve时的内存映射
7.8 缺页故障与缺页制止处置处罚
7.9动态存储分配管理
7.10本章小结
第8章 hello的IO管理
8.1 Linux的IO设备管理方法
8.2 简述Unix IO接口及其函数
8.3 printf的实现分析
8.4 getchar的实现分析
8.5本章小结
结论
附件
参考文献
第1章 概述
1.1 Hello简介
一、P2P:从程序到进程的诞生
[*]编程与编译(Editor + Compiler)
[*]源代码(Program):用户编写 hello.c,通过文本编辑器生存为文本文件。
[*]预处置处罚:展开宏(#define)、处置处罚头文件(#include),生成 hello.i。
[*]编译:将预处置处罚代码翻译为汇编代码(hello.s)。
[*]汇编:将汇编代码转为呆板指令(目标文件 hello.o)。
[*]链接:链接器(LD)合并库(如 libc)与目标文件,生成可执行文件 hello。
[*]
[*]进程创建(Bash + OS)
[*]Shell调用:用户在Bash中输入 ./hello,触发执行请求。
[*]fork():OS通过 fork 创建子进程,复制父进程(Shell)上下文(如文件形貌符)。
[*]execve():子进程调用 execve,加载 hello 可执行文件到内存,覆盖原有进程映像。
[*]mmap():OS为进程映射虚拟内存空间(代码段、数据段、堆栈等)。
[*]进程调理:OS分配时间片,将进程参加调理队列,等待CPU执行。
[*]
二、O2O:从零到零的闭幕
[*]进程终止
[*]正常退出:main 函数返回或调用 exit(),开释资源(内存、文件句柄)。
[*]信号终止:如 SIGSEGV(段错误)或外部强制终止(kill -9)。
[*]资源回收(OS收尸)
[*]内存开释:OS回收进程占用的物理页面与虚拟地点空间。
[*]文件关闭:开释打开的文件形貌符(如尺度输入输出)。
[*]进程表项删除:清除进程控制块(PCB),移除调理队列。
1.2 情况与工具
Vmware Workstation Pro 17、Ubuntu、codeblocks、gcc、gdb、vim
1.3 中间效果
hello.c
hello源代码
hello.i
预处置处罚之后的文本文件
hello.s
hello的汇编代码
hello.o
hello的可重定位文件
hello
hello的可执行文件
1.4 本章小结
本章介绍了 hello 从编译生成、到执行、再到终止的全过程,从整体上大抵介
绍了 hello 的一生,并且列出了做本次作业的软硬件情况以及工具,末了列出了从 hello.c 到 hello 的过程中产生的中间文件。
第2章 预处置处罚
2.1 预处置处罚的概念与作用
在程序设计中,预处置处罚是编译前的核心准备阶段,通过预处置处罚器对源代码进行文本级操作,重要包括宏界说更换(如#define简化代码复用)、文件包罗(#include引入头文件实现模块化)和条件编译(#ifdef等指令控制代码分支),其核心作用是优化代码结构、提升跨平台兼容性并减少冗余。例如,宏展开可避免函数调用开销,条件编译能根据情况剔除无效代码以缩小程序体积,而文件包罗则集中管理公共声明,加强代码可维护性。预处置处罚通过分离情况配置与核心逻辑,为后续编译奠定高效、灵活的底子。
2.2在Ubuntu下预处置处罚的下令
在Linux利用gcc预处置处罚的下令为:
gcc -E hello.c -o hello.i
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps48.jpg&pos_id=QM30j6qv
图2.1 预处置处罚下令
2.3 Hello的预处置处罚效果剖析
hello.i相较hello.c而言,失去了头文件#include <stdio.h>#include <unistd.h> #include <stdlib.h>,更换为一些以#开头的文件路径,如
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps2.jpg&pos_id=qK8NzgVT
系统级界说,包罗完整的类型界说和结构体声明
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps3.jpg&pos_id=ReOBJZbK
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps4.jpg&pos_id=A4h4fEEK
以及系统调用封装
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps5.jpg&pos_id=8FYM3k51
在文件的末尾是我们原始的main函数
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps6.jpg&pos_id=mDt7ngWs
2.4 本章小结
预处置处罚的操作总体而言可以概括为,扩展了源代码,插入所有用#include下令指定的文件,并扩展所有用#define声明指定的宏。
第3章 编译
3.1 编译的概念与作用
概念:C语言是高级语言,而汇编语言是面向呆板的程序设计语言。编译把预处置处罚文件转化成汇编语言
作用:生成相对低级的、但能被人看懂的汇编语言,为后续生成呆板语言奠定底子。
3.2 在Ubuntu下编译的下令
Linux下编译下令为:
gcc -S hello.i -o hello.s
实现如下
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps7.jpg&pos_id=GTDBxHof
图3.1 编译下令
3.3 Hello的编译效果剖析
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps8.jpg&pos_id=9E4ZfZuo
图3.2 汇编代码
3.3.1 寄存器保护
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps9.jpg&pos_id=fJRiyJej
%rbp属于被调用者生存寄存器,压入栈中,在函数返回时规复,虽然hello.c只有一个hello函数没什么用。
3.3.2 赋值
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps10.jpg&pos_id=F9wIQpmX
i赋初值为0
3.3.3 关系比力
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps11.jpg&pos_id=GXE3a3LD
-20(%rbp)存储的是argc的值,如果为5,跳转到L2继续执行,如果不为5,输出一个字符串后,exit(1)退出。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps12.jpg&pos_id=YHGKSj9X
这是i与9的比力,循环遍历直到i大于9.
3.3.4 控制转移
上图中如果小于便是9,会跳转到L4执行。
3.3.5 参数通报
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps13.jpg&pos_id=HpZWFL0N
Call之前把参数通报到了%rdi(%edi)中。
3.3.6 函数调用
上图中有两个函数调用
3.3.7 指针数组操作
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps14.jpg&pos_id=H3NQe7vE
这是取argv和argv的汇编代码,分别存储在%rcx和%rdx中,以便后续的print函数调用。
3.4 本章小结
本章解释了怎样在linux上实现编译,并且大抵解说了汇编代码中各部门的含义,涉及过程调用、参数通报、数组操作、关系操作、赋值等。
(第3章2分)
第4章 汇编
4.1 汇编的概念与作用
概念:通过汇编器将hello.s文件翻译成hello.o文件,即可重定位目标文件。
作用:可重定位目标文件已经进入呆板语言的范畴,属于二进制文件,为接下来的链接提供前提。
4.2 在Ubuntu下汇编的下令
在linux下汇编可采用代码:
gcc -c hello.s -o hello.o
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps15.jpg&pos_id=CJNWBjXQ
图4.1 汇编下令
4.3 可重定位目标elf格式
一个典型的ELF可重定位目标文件的格式包括三个部门,ELF头,节头部表以及夹在二者之间的节。
1.ELF头
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps16.jpg&pos_id=snQ1Y3qP
图4.2 ELF头
Magic:7f 45 4c 46 表现正当的ELF文件。
文件类型:REL (可重定位文件),这是一个尚未链接的目标文件。
架构:Advanced Micro Devices X86-64。
节头部表信息:14个节头,起始位置为文件偏移1264字节。
2.节头部表
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps17.jpg&pos_id=8hWlicxT
图4.3 节头部表
.text节大小为0x9d字节,包罗main函数的呆板码;
.data和.bss节分别存储已初始化全局和静态变量以及未初始化全局和静态变量;
.rodata节存储两个字符串常量(.LC0和.LC1),总大小0x40字节;
.rela.text和.rela.eh_frame是重定位表,记载需链接时修正的地点。
[*]重定位条目分析
无论何时汇编器遇到对终极位置未知的目标引用,它就会生成一个重定位条目。代码的重定位条目放在.rel.text中,已初始化数据的条目放在.rel.data中。
利用下令 readelf -r hello.o检察重定位条目信息,
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps18.jpg&pos_id=lIsnJXaC
图4.4 重定位条目
重定位类型:
R_X86_64_32:32位绝对地点引用。
R_X86_64_PC32:32位PC相对地点引用。
R_X86_64_PLT32:32位PLT(过程链接表)相对偏移,用于动态链接库函数调用(如printf)。
偏移量为需要被修改的引用的节偏移;
信息告知链接器怎样修改符号引用;
加数是一个有符号常数,做偏移调整;
符号标识被修改引用应该指向的符号。
4.4 Hello.o的效果剖析
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps19.jpg&pos_id=FRWgQKlz
4.4.1呆板代码的构成
呆板指令由操作码和操作数两部门组成。操作码指定该指令要完成的功能,操作数指定该指令执行的对象。以第二十行的callq指令为例,e8为操作码,也就是callq,后面的0为操作数,应该存放调用的函数的地点,但因为还未链接,这里用0占位。
4.4.2呆板代码与汇编代码的映射关系
呆板代码的操作码部门映射为汇编代码的一种类型的指令,如e8可映射为函数调用的callq指令。操作数部门可以映射为立刻数,也可映射为寄存器值、地点等。映射的立刻数既大概是要到场运算的立刻常数,也大概是一个地点常量。
4.4.3与hello.s对比分析
分支转移不同。hello.s中无论是条件跳转还是无条件跳转,都利用诸如.L6,.L2等标志来标识;而hello.o的反汇编代码中是有一个明确的地点如jne 15,jmp57等。
增加了重定位条目,如92:R_X86_64_PLT32等,为链接做准备。
4.5 本章小结
本章通过剖析目标文件格式与反汇编技术,阐述了汇编器将hello.s转换为可重定位目标文件hello.o的实现机制。基于ELF文件格式的二进制分析表明,生成的目标文件包罗三个核心段:可执行呆板指令的.text节、只读字符串常量的.rodata节,以及记载代码段重定位信息的.rela.text节。
(第4章1分)
第5章 链接
5.1 链接的概念与作用
概念:链接将各种代码和数据片断收集并组合成可执行文件的过程,这个文件可被加载到内存并执行。
作用:链接利用重定位信息将各种代码和数据包括库函数重新组合,生成可执行文件。
5.2 在Ubuntu下链接的下令
Linux链接hello.o文件的代码为
ld -o hello -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/crti.o hello.o /usr/lib/x86_64-linux-gnu/libc.so /usr/lib/x86_64-linux-gnu/crtn.o
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps20.jpg&pos_id=8olXacV8
图5.1 链接下令
5.3 可执行目标文件hello的格式
readelf -h hello检察ELF头
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps21.jpg&pos_id=REkgk7We
readelf -S hello检察节头部表
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps22.jpg&pos_id=gnTi6eGN
readelf -s hello检察符号表
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps23.jpg&pos_id=NmaxcwWu
readelf -l hello检察段头部表
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps24.jpg&pos_id=1Y8SfrF2
5.4 hello的虚拟地点空间
通过symbol viewer可以清楚地看到各节起始和终止地点,与5.3节头部表可以对应起来。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps25.jpg&pos_id=FCvP3mcu
5.5 链接的重定位过程分析
hello.o反汇编
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps26.jpg&pos_id=nPdCwFnP
hello反汇编部门截图
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps27.jpg&pos_id=b6qp8jhq
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps28.jpg&pos_id=xCZlJwVo
我们看到call语句中都跟上了调用函数的地点,它们是PC相对引用的。举个例子。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps29.jpg&pos_id=C2cPhoQh
我们看调用puts函数,它的地点是0x401090,而call语句后紧跟的下一条指令地点是0x40114a,两者相减0x401090-0x40114a得0xffffff46,再根据小端法得46 ff ff ff 这便是呆板指令中的字节表现了
5.6 hello的执行流程
通过edb调试可观测程序执行流程:在main函数调用前,系统先执行_init完成初始化并完成动态链接重定位,此时代码段中调用的库函数(如printf/exit)仅为符号占位,现实代码位于内存高地点的共享库映射区。随后_start入口启动程序,转入main函数执行核心逻辑(第三章已剖析其内部调用)。main结束后,依次执行全局构造/析构函数(_libc_csu_init、_libc_csu_fini)和_fini完成资源清理,终极进程终止。
以下是其调用与跳转的各个子程序名或程序地点:
[*]_init <0x00000000004004e0>
[*]puts@plt <0x0000000000400510>
[*]printf@plt <0x0000000000400520>
[*]getchar@plt <0x0000000000400530>
[*]atoi@plt <0x0000000000400540>
[*]exit@plt <0x0000000000400550>
[*]sleep@plt <0x0000000000400560>
[*]_start <0x0000000000400570>
[*]_dl_relocate_static_pie <0x00000000004005a0>
[*]deregister_tm_clones <0x00000000004005b0>
[*]register_tm_clones <0x00000000004005e0>
[*]__do_global_dtors_aux <0x0000000000400620>
[*]frame_dummy <0x0000000000400650>
[*]main <0x0000000000400657>
[*]__libc_csu_init <0x00000000004006f0>
[*]__libc_csu_fini <0x0000000000400760>
[*]_fini <0x0000000000400764>
5.7 Hello的动态链接分析
针对动态共享库中的PIC函数,其运行时地点需通过动态链接器剖析重定位记载确定。耽误绑定技术将函数地点绑定推迟至首次调用时,核心动机在于典型应用仅调用共享库(如libc.so)的少数函数,避免加载时处置处罚大量无效重定位。首次调用需通过**GOT(全局偏移表,数据段)与PLT(过程链接表,代码段)**交互完成动态剖析(耗时较高),后续调用仅需一次间接寻址。关键数据结构中,GOT和GOT存放动态链接信息,GOT指向动态链接器(ld-linux.so)入口,PLT通过跳转至GOT中缓存的真实地点实现高效调用。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps30.jpg&pos_id=R30Iy4Y1
观察 dl_init 前后动态链接项目标变化。.got.plt 节的起始地点是 0x601000,在 DataDump 中如下
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps31.jpg&pos_id=GJtkHJm3
edb执行后发生改变
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps32.jpg&pos_id=Ip1VriCj
可以看到 dl_init 后出现了两个地点0x7f27f6a3el70和0x7f27f682c750,这便是 GOT和 GOT。
5.8 本章小结
链接是将分散的代码与数据整合为单一可执行文件的过程,该文件可被加载至内存运行。链接器处置处罚三类目标文件(可重定位文件、可执行文件、共享对象文件),其核心任务为 符号剖析(匹配变量与函数引用)和 重定位(调整代码地点偏移)。链接活动可发生在编译时(静态链接器)、程序加载时或运行时(动态链接器),分别对应静态库嵌入、共享库按需加载等场景。
(第5章1分)
第6章 hello进程管理
6.1 进程的概念与作用
6.1.1 进程的概念
进程是执行中的程序的实例,是系统资源分配和调理的基本单位。
进程包罗三部门:
文本区域:存储可执行代码。
数据区域:存储全局变量和动态分配的内存(堆)。
堆栈区域:存储活动过程调用的指令和局部变量。
6.1.2 进程的作用
逻辑流抽象:提供程序独占处置处罚器的假象。
私有地点空间:提供程序独占内存的假象。
6.2 Shell-bash 的作用与处置处罚流程
作用:
Shell 是用户与操作系统的交互接口,负责解释并执行用户输入的下令。
常见类型:sh、csh/tcsh、bash(Linux 默认)。
处置处罚流程:
(1) 读取用户输入的下令行。
(2) 剖析下令行参数,构造 argv 向量。
(3) 检查首个参数是否为 Shell 内置下令。
(4) 若非内置下令,调用 fork() 创建子进程。
(5) 子进程中调用 execve() 执行目标程序。
(6) 根据是否后台运行(& 符号)决定是否调用 waitpid 等待子进程结束。
6.3 Hello 的 fork 进程创建过程
输入下令:./hello 1183200123 祁天 1。
Shell 分析步骤:
(1) 判定 ./hello 非内置下令。
(2) 调用 fork() 创建子进程:
子进程复制父进程的虚拟地点空间(代码、数据、堆栈、文件形貌符)。
子进程与父进程唯一区别为 PID。
(3) 子进程中加载并执行 hello 程序。
6.4 Hello 的 execve 过程
execve 调用:
更换子进程的虚拟内存段,新建代码、数据、堆栈段(初始化为零)。
加载流程:
删除原有虚拟内存段,映射可执行文件内容到内存。
跳转到 _start,调用 __libc_start_main 初始化情况。
执行 main 函数,终极返回内核。
6.5 Hello 的进程执行
逻辑控制流与上下文切换
逻辑控制流:程序计数器(PC)序列体现进程的独立执行流。
上下文切换机制:
(1) 生存当前进程上下文(寄存器、栈、内核数据结构)。
(2) 规复被抢占进程的上下文。
(3) 将控制权转移至新进程。
用户模式与内核模式
模式位控制:
用户模式:禁止执行特权指令或访问内核空间。
内核模式:可执行所有指令并访问全部内存。
Hello 的调理示例
调用 sleep:
显式触发上下文切换,计时结束后通过制止规复进程。
调用 getchar:
用户模式切换至内核模式,触发 DMA 传输键盘数据。
传输完成后制止唤醒进程,返回用户模式继续执行。
进程终止:main 返回后执行 __libc_csu_fini 和 _fini 清理资源。
注:以上分析基于 Linux 进程管理与 Shell 运行机制的核心原理。
6.6 hello的异常与信号处置处罚
Hello 程序执行过程中的异常与信号处置处罚分析
1. 制止(Interrupt)
场景:用户通过键盘输入 Ctrl+C(发送 SIGINT 信号)制止 Hello 进程。
处置处罚机制:
制止由 I/O 设备异步触发,内核调用制止处置处罚程序强制终止进程。
默认活动是立刻终止程序,但用户可自界说信号处置处罚函数(如清理资源)后退出。
2. 陷阱(Trap)
场景:Hello 调用系统服务(如 sleep()、exit())或调试断点。
处置处罚机制:
陷阱是程序主动触发的同步异常,用于切换至内核模式执行特权指令。
sleep() 触发陷阱进入内核调理器,挂起进程并启动计时器;唤醒后返回用户模式继续执行后续指令。
3. 故障(Fault)
场景:
无效内存访问(如空指针解引用触发 SIGSEGV)。
动态链接错误(如共享库加载失败,错误码 ENOENT)。
处置处罚机制:
故障处置处罚程序尝试修复错误(如重新映射内存页或加载缺失库)。
可规复:修复后重新执行触发故障的指令(如缺页制止)。
不可规复:若故障无法修复(如非法指令 SIGILL),则终止进程。
4. 终止(Abort)
场景:
硬件错误(如内存校验错误 SIGBUS)。
不可规复软件错误(如 SIGABRT 或 abort() 调用)。
处置处罚机制:
终止处置处罚程序直接回收进程资源,不尝试规复执行。
下面说明各种信号的处置处罚
)hello执行过程中会出现哪几类异常,会产生哪些信号,又怎么处置处罚的。
程序运行过程中可以按键盘,如不绝乱按,包括回车,Ctrl-Z,Ctrl-C等,Ctrl-z后可以运行ps jobs pstree fg kill 等下令,请分别给出各下令及运行结截屏,说明异常与信号的处置处罚。
6.7本章小结
(以下格式自行编排,编辑时删除)
(第6章2分)
第7章 hello的存储管理
7.1 hello的存储器地点空间
物理地点直接对应内存芯片单位,是CPU地点总线的终极输出信号。若启用分页机制,线性地点通过页表转换为物理地点;否则线性地点直接作为物理地点。
逻辑地点以[段标识符:段内偏移量]形式呈现,由程序生成。
线性地点是逻辑地点经段式转换后的中间效果。未启用分页时等同于物理地点,启用时需页表二次转换。
虚拟地点包罗VPN(虚拟页号)、VPO(页内偏移)、TLBI(TLB索引)和TLBT(TLB标记),构成进程视角的一连内存空间。
7.2 Intel逻辑地点到线性地点的变更-段式管理
段选择符剖析:
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps33.jpg&pos_id=ReMs3lAb
段寄存器(CS/SS/DS等)存储16位段选择符
TI位(0=GDT,1=LDT)选择形貌符表
高13位作为索引定位形貌符表中的段形貌符
段形貌符提取:
从GDT/LDT中读取32位段基址
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps34.jpg&pos_id=RynAF1DX
线性地点生成:
段基址 + 32位偏移地点 = 线性地点 模式差异:
实模式:物理地点 = 段寄存器值×16 + 偏移量
保护模式:通过特权级检查与形貌符权限验证确保访问安全
下图展示了具体过程:
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps35.jpg&pos_id=9bcGLbP8
7.3 Hello的线性地点到物理地点的变更-页式管理
Linux下,虚拟地点到物理地点的转化与翻译是依靠页式管理来实现的,虚拟内存作为内存管理的工具。概念上而言,虚拟内存被组织为一个由存放在磁盘上的N个一连的字节大小的单位组成的数组。磁盘上数组的内容被缓存在物理内存中(DRAM cache)这些内存块被称为页 (每个页面的大小为P = 2p字节)。
而分页机制的作用就是通过将虚拟和物理内存分页,并且通过MMU建立起相应的映射关系,可以充实利用内存资源,便于管理。一样平常来说一个页面的尺度大小是4KB,有时可以到达4MB。而且虚拟页面作为磁盘内容的缓存,有以下的特点:DRAM缓存为全相联,任何虚拟页都可以放置在任何物理页中需要一个更大的映射函数,不同于硬件对SRAM缓存更复杂精密的更换算法太复杂且无限定以致无法在硬件上实现DRAM缓存总是利用写回,而不是直写。
虚拟页面地集合被分为三个不相交的子集:已缓存、未缓存和未分配。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps36.png&pos_id=rSvGkVh0
页表实现从虚拟页到物理页的映射,依靠的是页表,页表就是是一个页表条目 (Page Table Entry, PTE)的数组,将虚拟页地点映射到物理页地点。这个页表是常驻与主存中的。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps37.png&pos_id=XQwFn56z
下图展示了页式管理中虚拟地点到物理地点的转换:
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps38.jpg&pos_id=d2m6OQV3
下图a展示了当页面掷中时,CPU硬件执行的步骤:
第1步:处置处罚器生成一个虚拟地点,并把它传送给MMU;
第2步:MMU生成PTE地点,并从高速缓存/主存请求得到它;
第3步:高速缓存/主存向MMU返回PTE;
第4步:MMU构造物理地点,并把它传送给高速缓存/主存;
第5步:高速缓存/主存返回所请求的数据字给处置处罚器
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps39.png&pos_id=YCxiDwFm
处置处罚缺页如图b所示:
第1~3步:和图a中的第1步到第3步相同;
第4步:PTE中的有效位是零,以是MMU触发了一次异常,传给CPU中的控制到操作系统内核中的缺页异常处置处罚程序;
第5步:缺页处置处罚程序确定出物理内存中的断送页,如果这个页面已经被修改了,则把它换出到磁盘;
第6步:缺页处置处罚程序页面调入新的页面,并更新内存中的PTE;
第7步:缺页处置处罚程序返回到原来的进程,再次执行导致缺页的指令。CPU将引起缺页的虚拟地点重新发送给MMU。因为虚拟页面如今缓存在物理内存中,以是就会掷中,在MMU执行了图b中的步骤之后,主存就会将所请求字返回给处置处罚器。
7.4 TLB与四级页表支持下的VA到PA的变更
为了消除每次 CPU 产生一个虚拟地点,MMU 就查阅一个 PTE 带来的时间开销,许多系统都在 MMU 中包括了一个关于 PTE 的小的缓存,称为TLB(快表),用以缓存近期PTE条目,通过VPN的TLBT/TLBI快速匹配
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps40.png&pos_id=zyuMNo24
在四级页表条理结构的地点翻译中,虚拟地点被划分为 4 个 VPN 和 1 个 VPO。每个 VPNi 都是一个到第 i 级页表的索引,第 j 级页表中的每个 PTE 都指向第 j+1级某个页表的基址,第四级页表中的每个 PTE 包罗某个物理页面的 PPN,或者一个磁盘块的地点。下面是四级页表的结构图
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps41.jpg&pos_id=vYqBH9B4
7.5 三级Cache支持下的物理内存访问
Core i7的内存系统如图所示。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps42.png&pos_id=m5qV635K
物理内存访问流程
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps43.jpg&pos_id=KlEYNStq
首先,根据前面提到的地点转换,先将VA转换成PA,然后根据物理地点的 s 位组索引索引到 L1 cache中的某个组,然后在该组中查找是否有某一行的标记便是物理地点的标记并且该行的有效位为 1,若有,则说明掷中,从这一行对应物理地点 b 位块偏移的位置取出一个字节,若不满足上面的条件,则说明不掷中,需要继续访问下一级 cache,访问的原理与 L1 相同,如果三级 cache 都没有要访问的数据,则需要访问内存,从内存中取出数据并放入cache。
7.6 hello进程fork时的内存映射
数据结构复制:子进程复制父进程的mm_struct、区域表、页表
写时复制(COW):
父子进程页表项设为只读
写操作触发保护异常,内核复制物理页并更新页表
资源隔离:父子进程拥有独立物理页副本
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps44.jpg&pos_id=3mXIb4RT
7.7 hello进程execve时的内存映射
execve 函数调用驻留在内核区域的启动加载器代码,在当前进程中加载并运 行包罗在可执行目标文件 hello 中的程序,用 hello 程序有效地替代了当前程序。 加载并运行 hello 需要以下几个步骤:
1. 删除已存在的用户区域,删除当前进程虚拟地点的用户部门中的已存在的 区域结构。
2. 映射私有区域,为新程序的代码、数据、bss 和栈区域创建新的区域结构, 所有这些新的区域都是私有的、写时复制的。代码和数据区域被映射为hello 文件中的.text 和.data 区,bss 区域是请求二进制零的,映射到匿名文件,其大小包罗在 hello 中,栈和堆地点也是请求二进制零的,初始长度为零。
3. 映射共享区域,hello 程序与共享对象 libc.so 链接,libc.so 是动态链接到 这个程序中的,然后再映射到用户虚拟地点空间中的共享区域内。
4. 设置程序计数器(PC),execve 做的末了一件事情就是设置当前进程上下 文的程序计数器,使之指向代码区域的入口点。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps45.jpg&pos_id=INjsbMO1
7.8 缺页故障与缺页制止处置处罚
当MMU检测PTE有效位=0,触发缺页异常,并将控制通报给缺页异常处置处罚程序。
这时内核会产生如下活动:
1.检查虚拟地点正当性
2.分配物理页帧,选择断送页(若脏页则写回磁盘)
3.数据加载:从磁盘读取缺失页至物理内存
4.PTE更新:设置有效位并关联物理页
5.规复执行:重新执行触发缺页的指令
7.9 动态存储分配管理
动态内存分配器维护着一个进程的虚拟内存区域,称为堆。分配器将堆视为 一组不同大小的块的集合来维护。每个块就是一个一连的虚拟内存片,要么是已 分配的,要么是空闲的。已分配的块显式地保留为供应用程序利用。空闲块可用来分配。空闲块保持空闲,直到它显式地被应用所分配。一个已分配的块保持已分配状态,直到它被开释,这种开释要么是应用程序显式执行的,要么是内存分配器自身隐式执行的。
分配器分为两种基本风格:显式分配器、隐式分配器。
1. 显式分配器:要求应用显式地开释任何已分配的块。
2. 隐式分配器:要求分配器检测一个已分配块何时不再利用,那么就开释这 个块,自动开释未利用的已经分配的块的过程叫做垃圾收集。
带边界标签的隐式空闲链表分配器原理:
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps46.png&pos_id=cLSChfDK
每个块增加四字节的头部和四字节的脚部生存块大小和是否分配信息,可以在 常数时间访问到每个块的下一个和前一个块,使空闲块的合并也变为常数时间,而且可以遍历整个链表。隐式空闲链表即为,利用边界标签区分已分配块和未分配块,根据不同的分配战略(首次适配、下一次适配、最佳适配),遍历整个链表,一旦找到符合要求的空闲块,就把它的已分配位设置为1,返回这个块的指针。隐式空闲链表并不是真正的链表,而是"隐式"地把空闲块连接了起来(中间混合着已分配块)。
显式空闲链表的基本原理:
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5Cdddlllll%5CAppData%5CLocal%5CTemp%5Cksohtml2712%5Cwps47.jpg&pos_id=l63eFjY8
因为隐式空闲链表每次查找空闲快都需要线性地遍历整个链表,而此中的已分配块显然是不需要遍历的,以是浪费了大量时间,一种更好的方式是把空闲块组织成一个双向链表,每个空闲块中包罗一个 pred 和 succ 指针,指向它的前驱和后继,在申请空闲块时,就不需要遍历整个堆,只需要利用指针,在空闲链表中遍历空闲块即可。一旦空闲块被分配,它的前驱和后继指针就不再有效,变成了有效载荷的一部门。显式空闲链表的已分配块与隐式空闲链表的堆块的格式相同。
7.10 本章小结
地点转换:段式与页式协同完成逻辑→线性→物理地点转换
加快机制:TLB减少页表查询开销,三级Cache缩短内存耽误
进程内存:COW实现高效fork,execve重建虚拟空间
异常处置处罚:缺页制止实现按需调页
动态管理:隐式/显式分配器均衡空间与时间效率 通过多级抽象与硬件协同,实现内存安全隔离与高效利用。
第8章 hello的IO管理
8.1 Linux的IO设备管理方法
(以下格式自行编排,编辑时删除)
设备的模子化:文件
设备管理:unix io接口
8.2 简述Unix IO接口及其函数
(以下格式自行编排,编辑时删除)
8.3 printf的实现分析
(以下格式自行编排,编辑时删除)
[转]printf 函数实现的深入剖析 - Pianistx - 博客园
从vsprintf生成表现信息,到write系统函数,到陷阱-系统调用 int 0x80或syscall等.
字符表现驱动子程序:从ASCII到字模库到表现vram(存储每一个点的RGB颜色信息)。
表现芯片按照革新频率逐行读取vram,并通过信号线向液晶表现器传输每一个点(RGB分量)。
8.4 getchar的实现分析
(以下格式自行编排,编辑时删除)
异步异常-键盘制止的处置处罚:键盘制止处置处罚子程序。接受按键扫描码转成ascii码,生存到系统的键盘缓冲区。
getchar等调用read系统函数,通过系统调用读取按键ascii码,直到接受到回车键才返回。
8.5本章小结
(以下格式自行编排,编辑时删除)
(第8章 选做 0分)
结论
Hello的一生:从代码到运行
诞生:
预处置处罚:展开头文件和宏,生成.i文件。
编译:转成汇编代码.s,像人类语言变呆板方言。
汇编:翻译成二进制.o文件,呆板终于能读懂了。
链接:把调用的库函数(如printf)连进来,生成可执行文件hello。
苏醒:
Shell召唤:输入下令后,fork克隆一个子进程,execve加载hello到内存,更换原有内容,开始执行。
历险:
陷阱:调用sleep时主动让出CPU,等时钟叫醒。
制止:按Ctrl+C会被强行终止。
故障:访问非法内存直接“猝死”。
初学像听天书,三刷课本才懂个大概:
盘算机如精密钟表,缓存、流水线设计妙到毫巅。
一个hello背后竟是编译、链接、进程、异常的庞大世界。
学完深感:代码不是魔法,只是层层拆解的逻辑。路还长,但至少不再怕“黑盒”了。
附件
hello.c
hello源代码
hello.i
预处置处罚之后的文本文件
hello.s
hello的汇编代码
hello.o
hello的可重定位文件
hello
hello的可执行文件
参考文献
操作系统的内存管理——页式、段式管理、段页式管理 .操作系统的内存管理——页式、段式管理、段页式管理-CSDN博客. 2022-05-08.
printf 函数实现的深入剖析 .[转]printf 函数实现的深入剖析 - Pianistx - 博客园. .
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]