关注

计算机系统大作业--程序人生-Hello’s P2P

计算机系统

大作业

题     目  程序人生-Hello’s P2P 

专       业       计算机与电子通信  

学     号       2023113375        

班     级       23L0507           

学       生      刘道忠            

指 导 教 师       史先俊              

计算机科学与技术学院

2025年5月

摘  要

本文以`hello`程序为例,系统性地探讨了计算机系统中程序从源代码到进程执行的全生命周期管理机制。首先分析了`hello`的P2P(Program to Process)和O2O(Zero to Zero)过程,详细阐述了预处理、编译、汇编、链接等关键步骤的实现原理。在进程管理方面,深入研究了`fork()`的写时复制机制、`execve()`的内存映射重建以及进程调度策略。在存储管理部分,完整解析了从逻辑地址到物理地址的四级转换过程(逻辑地址→线性地址→虚拟地址→物理地址),重点讨论了Intel处理器的段式管理、现代操作系统的页式管理、TLB与四级页表的协同工作机制,以及三级Cache的物理内存访问优化。此外,通过缺页故障处理案例,揭示了虚拟内存管理的核心机制。本文通过理论分析与实验验证相结合的方式,展现了操作系统如何通过硬件(MMU/TLB/Cache)与软件(页表/COW/动态链接)的协同,实现高效、安全的内存与进程管理。

关键词:计算机系统、预处理、编译、汇编、链接、进程                 

目  录

第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 本章小结......................................................................................................... - 8 -

第3章 编译............................................................................................................. - 9 -

3.1 编译的概念与作用......................................................................................... - 9 -

3.2 在Ubuntu下编译的命令............................................................................. - 9 -

3.3 Hello的编译结果解析.................................................................................. - 9 -

3.4 本章小结....................................................................................................... - 14 -

第4章 汇编........................................................................................................... - 15 -

4.1 汇编的概念与作用....................................................................................... - 15 -

4.2 在Ubuntu下汇编的命令........................................................................... - 15 -

4.3 可重定位目标elf格式............................................................................... - 15 -

4.4 Hello.o的结果解析.................................................................................... - 18 -

4.5 本章小结....................................................................................................... - 20 -

第5章 链接........................................................................................................... - 21 -

5.1 链接的概念与作用....................................................................................... - 21 -

5.2 在Ubuntu下链接的命令........................................................................... - 21 -

5.3 可执行目标文件hello的格式.................................................................. - 21 -

5.4 hello的虚拟地址空间................................................................................ - 24 -

5.5 链接的重定位过程分析............................................................................... - 24 -

5.6 hello的执行流程........................................................................................ - 26 -

5.7 Hello的动态链接分析................................................................................ - 27 -

5.8 本章小结....................................................................................................... - 28 -

第6章 hello进程管理................................................................................... - 29 -

6.1 进程的概念与作用....................................................................................... - 29 -

6.2 简述壳Shell-bash的作用与处理流程..................................................... - 29 -

6.3 Hello的fork进程创建过程..................................................................... - 29 -

6.4 Hello的execve过程................................................................................. - 29 -

6.5 Hello的进程执行........................................................................................ - 29 -

6.6 hello的异常与信号处理............................................................................ - 29 -

6.7本章小结....................................................................................................... - 30 -

第7章 hello的存储管理............................................................................... - 31 -

7.1 hello的存储器地址空间............................................................................ - 31 -

7.2 Intel逻辑地址到线性地址的变换-段式管理............................................ - 31 -

7.3 Hello的线性地址到物理地址的变换-页式管理...................................... - 31 -

7.4 TLB与四级页表支持下的VA到PA的变换............................................. - 31 -

7.5 三级Cache支持下的物理内存访问.......................................................... - 31 -

7.6 hello进程fork时的内存映射.................................................................. - 31 -

7.7 hello进程execve时的内存映射.............................................................. - 31 -

7.8 缺页故障与缺页中断处理........................................................................... - 31 -

7.9动态存储分配管理....................................................................................... - 31 -

7.10本章小结..................................................................................................... - 32 -

第8章 hello的IO管理................................................................................. - 33 -

8.1 Linux的IO设备管理方法.......................................................................... - 33 -

8.2 简述Unix IO接口及其函数....................................................................... - 33 -

8.3 printf的实现分析........................................................................................ - 33 -

8.4 getchar的实现分析.................................................................................... - 33 -

8.5本章小结....................................................................................................... - 33 -

结论......................................................................................................................... - 34 -

附件......................................................................................................................... - 35 -

参考文献................................................................................................................. - 36 -

第1章 概述

1.1 Hello简介

P2P过程:

Hello的P2P过程始于程序员将代码敲入电脑形成源文件hello.c,随后经历预处理、编译、汇编、链接等一系列操作,最终生成可执行文件hello。在操作系统(OS)的壳(Bash)中,通过fork系统调用创建子进程,再通过execve系统调用将可执行文件加载到内存中运行。运行过程中,操作系统为Hello分配时间片,使其能够在硬件(CPU、RAM、IO)上执行,同时操作系统(OS)的存储管理功能与内存管理单元(MMU)处理虚拟地址到物理地址的转换,利用TLB、4级页表、3级Cache等机制为Hello提供高效的内存支持。I/O管理与信号处理机制则确保Hello能够在键盘、主板、显卡、屏幕等设备之间进行交互,完成其功能

O2O过程:

Hello的O2O过程描述了其从无到有再到无的整个生命周期。最初,Hello以程序代码的形式被编写出来,存储在计算机系统中,从零开始。在计算机系统的支持下,Hello经历P2P过程,从程序转变为进程,在硬件和软件的协同作用下运行,与用户和外部设备进行交互,但其运行过程短暂且效果可能并不显著。运行结束后,操作系统会对其进行清理,回收其占用的资源,使其从计算机系统的运行状态中彻底消失,再次回到零的状态。整个过程中,只有计算机系统(CS)知道Hello的生与死,记录了它的存在与消亡。

1.2 环境与工具

处理器:Intel(R) Core(TM) i5-10210U CPU @ 1.60GHz   2.11 GHz

机带RAM:8.00 GB (7.84 GB 可用)

系统类型:64 位操作系统, 基于 x64 的处理器

软件环境:Windows11 64位;VMware,Ubuntu 24.04 .1LTS 64位

开发与调试工具:Visual Studio ;vim,gidit ,objdump,edb,gcc,readelf等开发工具。

1.3 中间结果

hello          可执行文件

hello.i         hello.c预处理后得到的文本文件

hello.s         hello.i编译后得到的汇编语言文件

hello.o         hello.s汇编后得到的可重定位目标文件

1.4 本章小结

本章首先介绍了hello的P2P,020流程,包括流程的设计思路和实现方法;然后详细说明了本实验所需的硬件配置、软件平台、开发工具以及本实验生成的各个中间结果文件的名称和功能。

第2章 预处理

2.1 预处理的概念与作用

概念:

预处理是编译过程中的初始阶段,主要处理源代码文件中的预处理指令。它支持宏定义,允许用简短符号代表复杂表达式或代码片段,提高代码可读性和可维护性;提供条件编译功能,可根据特定条件选择性编译代码,便于多平台开发和调试;通过#include指令包含头文件,避免代码重复,便于管理;还支持其他指令如#error和#pragma等,用于生成错误信息和提供编译器特定的指令。

作用:

为编译器准备源代码,使其更易于编译,通过处理预处理指令,生成预处理后的文件,为后续编译阶段提供更简洁、易于处理的源代码,同时支持代码复用、条件编译和简化代码,帮助提前检测错误。

2.2在Ubuntu下预处理的命令

预处理命令:gcc -m64 -no-pie -fno-PIC -E hello.c -o hello.i(gcc -E hello.c -o hello.i)

2.3 Hello的预处理结果解析      

经过预处理之后,与hello.c相比,hello.i的代码行数明显增加,由近三十行扩展至三千多行。同时hello.c的注释部分消失,前一部分的代码(#include <stdio.h>、#include <unistd.h> 、#include <stdlib.h>)被扩展。hello.i的剩余部分(main函数)与hello.c文件相同,并未被改变。

以stdio文件为例,通过预处理,源代码文件被扩展为包含所有必要的头文件内容,包含了标准库的全部内容。

预处理后的文件通常很大,因为系统头文件会包含许多其他头文件,并且预处理只是编译的第一步,不会检查语法或语义错误,之后代码仍然需要进一步编译才能生成可执行文件。

2.4 本章小结

本章主要介绍了预处理的概念与作用,同时在Linux环境下演示了如何使用相关命令对C语言程序进行预处理。以hello.c程序文件为例,演示了在Ubuntu下如何对程序进行预处理,并对预处理生成的hello.i文件内容进行了分析。通过分析,发现经过预处理之后,hello.c文件中的注释会消失、头文件会被扩展、main函数中的内容不变。

第3章 编译

3.1 编译的概念与作用

概念:

编译是一种将高级编程语言编写的源代码转换成计算机能够理解和执行的机器语言(或汇编语言)的过程。它涉及多个步骤,包括词法分析、语法分析、语义分析、中间代码生成、代码优化和目标代码生成。

作用:

编译的作用在于它使得开发者可以使用高级语言编写程序,而无需直接与复杂的机器指令打交道。它为开发者提供了便利,降低了编程的难度,并且通过优化和错误检测确保了程序的质量和性能。此外,编译器还支持跨平台开发,允许相同的源代码在不同的硬件和操作系统上编译运行,促进了代码的重用和维护,为软件开发提供了强大的支持。       

3.2 在Ubuntu下编译的命令

编译命令:gcc -m64 -no-pie -fno-PIC -S hello.c -o hello.s(gcc -S hello.i -o hello.s)

3.3 Hello的编译结果解析

经过编译后源文件转换成了汇编语言。

.file:声明源文件。

.text 和 .rodata:这两个指令标识了接下来的代码分别属于代码段(.text)和只读数据段(.rodata)。代码段存储可执行的机器指令,而只读数据段存储不会改变的数据。

.align 8:这条指令用于确保接下来的数据或指令在内存中按照8字节对齐。

.string:用于定义字符串常量,定义了.LC0 和 .LC1。

.globl:声明全局符号。

.type:声明变量的类型。

3.3.1局部变量

hello.c文件中涉及局部变量是int i。

在对应的汇编语言中,局部变量会被存储在栈上。在进入函数时,会在栈上申请一段空间来供局部变量使用。这条指令(红框中)将栈指针%rsp向下移动32字节,为局部变量i分配空间。在函数结束时,通常会有相应的指令来释放栈上为局部变量分配的空间。

3.3.2字符串常量

在main函数中使用字符串时,得到字符串的首地址。

3.3.3赋值操作

对局部变量i赋值0。

3.3.4算术操作

循环i算术加1(i++)。

3.3.5关系操作

Argc与4进行比较

i与9进行比较

3.3.6数组操作

红框指令从栈上%rbp下方32字节的位置加载值到寄存器%rax中;

黄框指令将24、16、8、32加到寄存器%rax的值上,然后存储结果回%rax,这通常用于调整数组索引。

绿框指令将数组的元素(64位)加载到 %rdx 寄存器中

3.3.7控制转移

if:如果argc等于5则跳转.L2.

for:如果i小于9,则跳转.L4阶段,继续循环。

3.3.8函数操作

函数调用:printf函数,exit函数,atoi函数,sleep函数,getchar函数和puts函数。

printf:

exit:

atoi:

sleep:

getchar:

puts:

3.4 本章小结

本章主要阐述了编译的概念和作用,介绍了如何把hello.c文件编译成hello.s文件,演示了如何通过Linux指令对hello.c进行编译,并对汇编代码进行解析。探讨了数据处理,函数调用,赋值、算术、关系等运算以及控制跳转、类型转换等方面,比较了源代码和汇编代码分别是怎样实现这些操作的。

第4章 汇编

4.1 汇编的概念与作用

概念:

汇编是将汇编语言代码转换成机器语言代码的过程,它通过汇编器实现,是编译过程中的一个关键步骤。这个过程生成的目标文件(通常以.o扩展名)包含机器语言代码,可以直接被计算机的处理器执行。

作用:

负责将预处理后的高级语言代码转换为目标机器的汇编指令,实现了高级语言到机器指令的转换,也是性能优化、底层调试和逆向工程的重要基础。

4.2 在Ubuntu下汇编的命令

以下格式自行编排,编辑时删除

汇编命令:gcc -C hello.c -o hello.o

4.3 可重定位目标elf格式

4.3.1elf头   

通过输入readelf -h hello.o指令来获得解析elf文件头。

ELF头以一个16字节的序列Magic开始,这个序列描述了生成文件的系统的字的大小和字节顺序。ELF头剩下部分的信息包含帮助连接器语法分析和解释目标文件的信息。包含了hello.o文件的相关信息,例如入口点地址,节头部的大小等。

4.3.2 节头

通过输入readelf -S hello.o查看节头。

输出显示共有14个节头,每个节头包含编号、名称、类型、地址、偏移量、大小、旗标、链接、信息和对齐。

4.3.3 重定位节

输入readelf -r hello.o并回车可查看可重定位段信息。

包括了重定位的偏移量,信息,类型,符号值,符号名称,加数

4.3.4 符号表

输入命令readelf -s hello.o查看。

在符号表中,Num为某个符号的编号,Name是符号的名称。Size表示他是一个位于.text节中偏移量为0处的146字节函数。Bind表示这个符号是本地的还是全局的,由上图可知main函数名称这个符号变量是本地的。

4.4 Hello.o的结果解析

通过指令objdump -d -r hello.o得到结果如下:

hello.o与hello.s机器语言的构成基本一致。

与hello.s对照:

4.4.1进制不同:hello.s为十进制,而hello.o则为十六进制。

hello.s

hello.o

4.4.2分支转移:不同,hello.s为跳转的名称,此处为跳转地址。

hello.s

hello.o

4.4.3函数调用不同,hello.s为函数名称,此处为偏移地址.

hello.s

hello.o

4.4.4字符串调用不同,hello.s为全局变量名称+%rdi,此处为偏移量+%rdi

hello.s

hello.o

4.5 本章小结

本章主要阐述了汇编的概念和作用,介绍了如何把hello.s文件编译成hello.o文件,演示了如何通过Linux指令对hello.s进行编译,并对汇编代码进行解析。比较了hello.s与hello.o之间的异同。

5章 链接

5.1 链接的概念与作用

概念:

链接是编译过程中的一个关键步骤,它负责将一个或多个目标文件(如.o文件)以及可能用到的库文件合并成一个完整的可执行文件或库文件。在这个过程中,链接器解析目标文件中的符号引用,将它们与符号定义匹配起来,完成地址的重定位,确保程序中的函数调用和变量访问都指向正确的内存位置。此外,链接器还执行优化操作,如去除未使用的代码(死代码消除),合并相同代码段,以及处理库文件的合并,最终生成可以在操作系统上直接执行的文件。

作用:

链接的作用在于确保程序的完整性和可执行性,它使得开发者能够构建复杂的应用程序,同时利用库文件中的功能,提高代码的模块化和可重用性。通过链接,程序的不同部分被有效地组织和整合,同时链接器还会检测并报告符号引用错误,如未定义或多重定义的符号,确保最终生成的程序没有链接错误,可以正确运行。

5.2 在Ubuntu下链接的命令

链接命令: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

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

5.3.1elf头

输入readelf -h hello并回车,查看hello文件的ELF头。

通过与hello.o的elf头对比分析可知,两个文件在多数字段上是相同的,主要区别在于文件类型、入口地址、节头数量。

5.3.2节头

输入readelf -S hello并回车,查看hello文件的节头。

输出显示共有27个节头,每个节头包含编号、名称、类型、地址、偏移量、大小、旗标、链接、信息和对齐。对应的段都合并了,并且重新计算了大小,地址,偏移量。

5.4 hello的虚拟地址空间

使用gdb/edb加载hello,查看本进程的虚拟地址空间各段信息,并与5.3对照分析说明。

hello的可执行部分(代码段)起始地址为0x400000。

由5.3可知.interp段的起始地址为4002e0。

由5.3节我们可得知,.init的起始地址为0x401000。

由5.3节我们可得知,.text的起始地址为0x4010f0。

5.5 链接的重定位过程分析

输入命令objdump -d -r hello查看。

1.虚拟地址不同,hello.o的反汇编代码虚拟地址从0开始,而hello的反汇编代码虚拟地址从0x401000开始。这是因为hello.o在链接之前只能给出相对地址,而hello在链接之后得到的是绝对地址。

2.反汇编节数不同,hello.o只有.text节,里面只有main函数的反汇编代码。而hello在main函数之前加上了链接过程中重定位而加入的各种在hello中被调用的函数、数据,增加了.init,.plt,.plt.sec等节的反汇编代码。

  1. hello.o指令后加的主要是汇编代码块前的标号,而hello中的指令后加的则是具体的地址,但相对地址没有发生变化。

在链接过程中,链接器会解析目标文件(如hello.o)中的符号引用,并根据重定位表中的信息将这些引用映射到可执行文件(如hello)中的实际内存地址。对于动态链接的函数调用,如puts和printf,链接器使用过程链接表(PLT)和全局偏移表(GOT)来实现延迟绑定,确保在程序运行时能够正确调用这些函数。链接器为可执行文件中的每个节分配内存地址,并应用重定位条目来调整目标文件中的地址,最终生成包含所有必要代码、数据和重定位信息的可执行文件,使其能够直接在操作系统上运行。

5.6 hello的执行流程

使用edb执行hello。

_start 函数:

地址:0x401040

_init 函数:

地址:0x401016

puts 函数(来自 libc):

地址:0x781efd41f780

printf 函数(来自 libc):

地址:0x781efd3f5380

atoi 函数(来自 libc):

地址:0x781efd407b40

sleep 函数(来自 libc):

地址:0x781efd40f56d

exit 函数(来自 libc):

地址:0x781efd40f56d

5.7 Hello的动态链接分析

   调用前后:动态链接发生了变化:

5.8 本章小结

本章节简要介绍了链接的相关过程,首先简要阐述了链接的概念和作用,给出了链接在Ubuntu系统下的指令。之后研究了可执行目标文件hello的ELF格式,并通过edb调试工具查看了虚拟地址空间和几个节的内容,之后依据重定位条目分析了重定位的过程,并借助edb调试工具,研究了程序中各个子程序的执行流程,最后则借助edb调试工具通过对虚拟内存的查取,分析研究了动态链接的过程。

6章 hello进程管理

6.1 进程的概念与作用

概念:

进程是操作系统中表示程序执行实例的基本单位,它不仅包含了程序代码,还包含了程序执行时所需的资源和状态信息。进程的引入使得操作系统能够实现多任务并发执行,提高了系统资源的利用率和响应速度,同时通过进程间的隔离机制保障了系统的稳定性和安全性。

作用:

进程的作用主要体现在资源分配、并发执行、隔离性、调度等方面。它们允许操作系统有效地管理内存、CPU等资源,并通过进程调度算法来决定哪个进程应该获得CPU时间。此外,进程的隔离性确保了程序间的相互独立,避免了单个程序的崩溃影响到整个系统,从而增强了系统的健壮性。

6.2 简述壳Shell-bash的作用与处理流程

作用:

Shell是一种交互型程序,用于代表用户运行其他程序

流程:

处理流程开始于启动阶段,此时它会读取配置文件并显示命令提示符。用户输入命令后,Bash 解析并执行命令,可能是内部命令或调用外部程序。脚本文件的执行涉及逐行读取和执行命令。用户可以通过输入特定命令如exit来结束Bash Shell会话,或关闭终端窗口来退出。

6.3 Hello的fork进程创建过程

fork是 Unix-like 操作系统中用于创建新进程的关键系统调用,它通过复制当前进程的地址空间、文件描述符、信号处理等资源来生成一个子进程,子进程通常从fork调用之后的代码开始执行。fork 返回值在父进程中是子进程的 PID,在子进程中为 0,失败时返回 -1。父进程和子进程可以独立运行,父进程通常需要等待子进程结束,以释放资源或获取子进程的退出状态。

6.4 Hello的execve过程

execve 是 Unix-like 操作系统中的一个系统调用,用于替换当前进程的映像为一个新的程序,从而启动一个不同的进程。它接受三个参数:程序路径、参数数组和环境变量数组,分别指定要执行的程序、传递给程序的参数和环境变量。在调用 execve 后,当前进程的内存空间会被新程序的代码和数据替换,新程序开始执行,而原进程的执行流被终止。如果 execve 调用失败,它会返回 -1 并设置 errno以指示错误原因,此时原进程继续执行。

6.5 Hello的进程执行

进程调度是操作系统管理进程执行的核心机制,它决定了哪个进程能够获得CPU时间片并执行。操作系统必须在多个并发运行的进程之间公平地分配CPU资源,以确保系统的响应性和效率。

进程上下文包含了操作系统为管理进程而保存的所有信息,如寄存器状态、程序计数器、内存管理信息等。当操作系统进行进程调度时,它需要保存当前进程的上下文,并加载下一个要执行的进程的上下文。

进程时间片是操作系统分配给每个进程的CPU时间的一小部分。当一个进程的时间片用完时,操作系统会暂停该进程的执行,保存其状态,并调度另一个进程运行。这种机制确保了所有进程都能获得公平的CPU时间。

用户态和核心态是进程执行的两种状态。在用户态下,进程执行用户程序代码,只能访问受限的资源。当进程需要请求操作系统服务时,会发生从用户态到核心态的转换。操作系统处理完请求后,会将控制权返回给用户程序,从而发生从核心态到用户态的转换。这种状态转换是进程调度过程中的一个重要环节,它确保了操作系统内核的安全性和稳定性。

6.6 hello的异常与信号处理

6.6.1异常类型

中断、陷阱、故障和终止。

6.6.2产生的信号

SIGSTP、SIGCONT、SIGKILL、SIFGINT等。

6.6.3乱按

在键盘中乱打字并没有改变printf的输出,不影响程序的正常运行,输入的字会直接显示。

6.6.4回车

在键盘中回车并没有改变printf的输出,不影响程序的正常运行。

6.6.5 Ctrl-Z

Ctrl+Z的功能是向进程发送SIGSTP信号,进程接收到该信号之后会将该作业挂起,但不会回收。

ps指令,显示相关进程。

jobs指令,显示当前 shell 会话中的后台作业列表。hello后台id为1显示已停止。

pstree指令,以树状图的形式显示进程之间的父子关系。

fg指令,将后台作业带到前台运行。

kill指令,用于发送信号给进程,以控制或终止进程。

6.6.6 Ctrl-C

Ctrl-C命令内核向前台发送SIGINT信号,终止了前台作业。

6.7本章小结

本章概述了hello进程大致的执行过程,阐述了进程、shell、fork、execve等相关概念,之后从逻辑控制流、时间分片、用户模式/内核模式、上下文切换等角度详细分析了进程的执行过程。并在运行时尝试了不同形式的命令和异常,每种信号都有不同处理机制,针对不同的shell命令,hello会产生不同响应。

7章 hello的存储管理

7.1 hello的存储器地址空间

逻辑地址:逻辑地址是程序在编写时使用的地址,它基于程序的起始地址,是相对于程序代码段、数据段等的偏移量。程序员在编写程序时使用逻辑地址来访问内存中的数据结构,如数组和变量。

线性地址:线性地址是逻辑地址与程序加载到内存中的基地址相加得到的结果。在没有启用虚拟内存的系统中,线性地址直接映射到物理地址。在启用虚拟内存的系统中,线性地址需要通过页表转换为物理地址。

虚拟地址:虚拟地址是操作系统为每个进程提供的地址空间中的地址。它使得每个进程都拥有独立的地址空间,从而实现进程间的隔离。虚拟地址通过操作系统的内存管理单元(MMU)转换为物理地址。

物理地址:物理地址是实际内存芯片上的地址,用于直接访问内存中的数据。在虚拟内存系统中,虚拟地址需要经过转换才能得到物理地址,这一转换由操作系统和硬件共同完成。

7.2 Intel逻辑地址到线性地址的变换-段式管理

索引(Index)用于在全局描述符表(GDT)或局部描述符表(LDT)中选择一个段描述符(Segment Descriptor)。每个段描述符包含了该段的详细信息,如基地址、界限和访问权限等。高13位-8K个索引用来确定当前使用的段描述符在描述符表中的位置

TI 位用于指示该段选择子指向全局描述符表(GDT)还是局部描述符表(LDT)。TI=0,选择全局描述符表(GDT),TI=1,选择局部描述符表(LDT)

RPL(Requested Privilege Level):是位 1 和位 0,用于指定访问该段所需的特权级别。RPL 值越低,所需的特权级别越高。RPL=00,为第0级,位于最高级的内核态,RPL=11,为第3级,位于最低级的用户态,第0级高于第3级

Intel 处理器采用段式管理,将逻辑地址转换为线性地址。逻辑地址由段寄存器(如 CS、SS)和偏移量组成。段寄存器中保存的是段选择符,用于在段描述符表中查找对应的段描述符,获得段的基址、限长和访问权限。

接着,通过基址寄存器、变址寄存器、比例因子和偏移量等计算出有效地址(EA)。将段基址与有效地址相加,得到线性地址。

整个过程是:段寄存器 → 段选择符 → 段描述符 → 段基址 + 有效地址 → 线性地址。这个转换是段式内存管理的核心步骤,为分页机制提供线性地址输入。

7.3 Hello的线性地址到物理地址的变换-页式管理

页式管理是现代操作系统用于处理线性地址到物理地址转换的一种内存管理技术。它通过将虚拟内存和物理内存划分为固定大小的页和页框,并通过页表维护虚拟页与物理页框之间的映射关系。

在页式管理中,虚拟地址被分为页号和页内偏移量两部分。页号用于在页表中查找对应的页表项,而页内偏移量则用于确定在页内的具体位置。操作系统利用页表来跟踪每个虚拟页对应的物理页框地址,从而实现虚拟地址到物理地址的转换。

页式管理的优势包括内存保护、内存隔离、内存共享和内存的动态分配。此外,它还支持虚拟内存技术,如分页交换(paging),允许操作系统将不常访问的页从物理内存交换到磁盘上,从而为当前需要的页腾出空间。

7.4 TLB与四级页表支持下的VA到PA的变换

TLB(Translation Lookaside Buffer)是页式内存管理中的一个高速缓存,用于存储最近使用的页表项(即虚拟地址到物理地址的映射)。当处理器需要将虚拟地址(VA)转换为物理地址(PA)时,它会首先检查TLB以查看是否已经有该映射的缓存条目。如果TLB命中,地址转换会非常快速;如果没有命中,则需要访问页表。

四级页表是x86-64架构中用于虚拟地址到物理地址转换的一种机制。在四级页表结构中,虚拟地址被分为五个部分:P4索引、P3索引、P2索引、P1索引和P0索引,以及页内偏移。以下是详细的转换过程:

P4索引:虚拟地址的最高位用于P4索引,它指向四级页目录表中的一个条目。该条目包含下一级页表(P3页表)的物理地址。

P3索引:虚拟地址的次高位用于P3索引,它指向P3页表中的一个条目。该条目包含P2页表的物理地址。

P2索引:接下来的位用于P2索引,它指向P2页表中的一个条目。该条目包含P1页表的物理地址。

P1索引:随后的位用于P1索引,它指向P1页表中的一个条目。该条目包含页表的物理地址。

P0索引和页内偏移:最低的位用于P0索引和页内偏移。P0索引指向页表中的一个条目,而页内偏移指定页内的具体位置。

在四级页表结构中,每次索引查找页表时,处理器都会更新TLB。如果TLB未命中,处理器会逐级访问页表,直到找到页表项。找到页表项后,处理器将该项中的物理页框地址与页内偏移组合,形成完整的物理地址。

TLB的使用大大加速了地址转换过程,因为它减少了访问主内存中页表的次数。然而,TLB也有其大小限制,当TLB未命中时,处理器必须进行页表遍历,这可能会导致性能下降,这种情况称为TLB未命中(TLB Miss)。

7.5 三级Cache支持下的物理内存访问

获得物理地址PA之后,取出CI组索引寻找对应组,如果匹配成功且valid为1则命中,取出值返回,如果没有匹配成功则在下一级缓存查询,直到匹配成功,查询到数据后,如果存在空闲块则将相应的块放入当前的缓存,否则采用替换算法驱逐并放入。

7.6 hello进程fork时的内存映射

在进程调用fork()时,操作系统会为子进程创建一份与父进程相同的虚拟地址空间,但并不会立即复制物理内存,而是采用“写时复制(Copy-On-Write, COW)”机制:父子进程初始共享相同的物理内存页,并将这些页标记为只读;只有在任一进程尝试写入共享页时,操作系统才会为该进程分配新的物理页并复制数据,从而实现延迟复制,提高资源利用率。同时,页表会被复制一份,且共享内存区域仍保持共享状态。

7.7 hello进程execve时的内存映射

当进程调用execve()系统调用时,操作系统会将当前进程的用户空间完全替换为新程序的内存映像。这意味着原有的代码段、数据段、堆、栈以及所有的内存映射都会被卸载,新的程序映像将被加载到进程的虚拟地址空间中。

在加载新程序时,操作系统会根据可执行文件的格式(如 ELF)将其各个段(如 .text、.data、.bss)映射到进程的虚拟地址空间中。同时,操作系统会设置新的堆栈,并将传递给execve()的参数和环境变量复制到新的内存空间中。

这种机制确保了新程序的执行环境与原进程完全隔离,提供了安全性和稳定性。此外,现代操作系统通常采用按需分页(demand paging)技术,仅在程序访问特定内存页时才将其加载到物理内存中,从而提高内存使用效率。

7.8 缺页故障与缺页中断处理

缺页故障(Page Fault)是指当CPU访问的虚拟内存页面尚未加载到物理内存时,由内存管理单元(MMU)触发的异常。此时操作系统会介入处理:若该页面存在于磁盘交换区(如Swap空间)则将其调入物理内存并更新页表;若属于非法访问(如越界)则终止进程;对于写时复制(COW)场景则会复制新物理页。该机制实现了按需调页、内存共享和写时复制等关键功能,是虚拟内存管理的核心机制之一。

处理过程:

1) 处理器将虚拟地址发送给 MMU

2-3) MMU 使用内存中的页表生成PTE地址

4) 有效位为零, 因此 MMU 触发缺页异常

5) 缺页处理程序确定物理内存中牺牲页 (若页面被修改,则换出到磁盘)

6) 缺页处理程序调入新的页面,并更新内存中的PTE

7) 缺页处理程序返回到原来进程,再次执行缺页的指令

7.9动态存储分配管理

以下格式自行编排,编辑时删除

Printf会调用malloc,请简述动态内存管理的基本方法与策略。(此节课堂没有讲授,选做,不算分)

7.10本章小结

本章系统阐述了程序(如hello)在计算机系统中的内存管理机制,详细解析了从逻辑地址到物理地址的完整转换过程。首先介绍了地址空间的四个层次:逻辑地址、线性地址、虚拟地址和物理地址,重点讲解了Intel处理器的段式管理机制和现代操作系统的页式管理机制。随后深入分析了TLB和四级页表在地址转换中的关键作用,以及三级Cache对物理内存访问的优化。在进程管理方面,详细说明了fork()时的写时复制(COW)机制和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本章小结

以下格式自行编排,编辑时删除

结论

用计算机系统的语言,逐条总结hello所经历的过程。

  1. 源代码生成:程序员编写hello.c,定义程序逻辑(如printf输出)。

2. 预处理:宏展开、头文件包含(#include <stdio.h>被替换为标准库内容),生成hello.i(纯文本,移除注释,扩展代码)。

3.编译:编译器(GCC)将hello.i转换为汇编代码hello.s(如mov, call指令)。

4. 汇编:汇编器将hello.s转为机器码hello.o(可重定位目标文件),生成ELF格式,包含符号表、重定位条目(如printf未解析地址)。

5. 链接:链接器合并hello.o与libc.so,解析符号(如printf的实际地址)。生成可执行文件hello,包含完整的虚拟地址空间布局(。

6. 进程创建:Shell调用fork()创建子进程,采用写时复制(COW)共享父进程内存。execve()加载hello,重建内存映射(代码段0x400000,栈0x7fffffff0000)。

7. 地址转换:

段式管理:逻辑地址(CS:0x401000)→线性地址(平坦模式直接映射)。

页式管理:MMU通过四级页表+TLB将虚拟地址(0x401000)→物理地址(如0x2000)。

Cache加速:L1/L2/L3 Cache缓存物理内存数据(如printf的字符串常量)。

8. 进程调度:操作系统分配时间片,切换上下文(保存寄存器、页表指针),用户态(执行main函数)↔内核态(处理printf系统调用)。

9. 异常处理:缺页故障:访问未加载的虚拟页→触发缺页中断→从磁盘换入页面。

10. 信号处理:Ctrl+C发送SIGINT→内核终止进程。

11. 运行结束:父进程回收子进程

感悟:

  1. 抽象与协作的力量

计算机系统通过分层抽象(语言→汇编→机器码→微架构)和硬件/软件协同设计(如TLB加速页表查询、COW优化进程创建),将复杂性封装为简洁接口。开发者只需关注高级逻辑,而系统底层默默处理优化与容错,这种"分而治之"的哲学是计算机科学的精髓。

  1. 资源管理的精妙平衡

从虚拟内存的按需调页到进程调度的上下文切换,系统始终在效率(CPU缓存命中率)与公平(多进程分时)之间博弈。例如,COW机制通过延迟复制节省内存,而缺页处理又能在必要时透明地加载数据,展现了对时空资源的极致权衡。

  1. 硬件是土壤,软件是生命

硬件提供基础能力(如MMU地址转换),而操作系统通过策略(如LRU页替换)赋予其智能。现代系统更像一个"共生体"——例如,编译器生成分支预测友好的代码,CPU则动态调整流水线,二者配合才能实现高性能。

  1. 简单性背后的复杂性

一个简单的hello程序背后,是预处理器的宏展开、链接器的符号解析、操作系统的进程隔离、硬件的超标量执行等多层机制协作。计算机系统的伟大之处,在于将这些复杂性隐藏后,仍能提供printf("Hello")这样直观的接口。

计算机系统设计教会我们:真正的优雅不在于添加,而在于恰到好处的隐藏。正如hello的输出只需一行代码,但其背后每一个比特的旅程,都承载着工程师们数十年的智慧结晶。

附件

hello.c

源文件

hello.i

hello.c预处理后得到的文本文件

hello.s

hello.i编译后得到的汇编语言文件

hello.o

hello.s汇编后得到的可重定位目标文件

hello

可执行文件

         

        

         

         

         

参考文献

为完成本次大作业你翻阅的书籍与网站等

[1]  林来兴. 空间控制技术[M]. 北京:中国宇航出版社,1992:25-42.

[2]  辛希孟. 信息技术与信息服务国际研讨会论文集:A集[C]. 北京:中国科学出版社,1999.

[3]  赵耀东. 新时代的工业工程师[M/OL]. 台北:天下文化出版社,1998 [1998-09-26]. http://www.ie.nthu.edu.tw/info/ie.newie.htm(Big5).

[4]  谌颖. 空间交会控制理论与方法研究[D]. 哈尔滨:哈尔滨工业大学,1992:8-13.

[5]  KANAMORI H. Shaking Without Quaking[J]. Science,1998,279(5359):2063-2064.

[6]  CHRISTINE M. Plant Physiology: Plant Biology in the Genome Era[J/OL]. Science,1998,281:331-332[1998-09-23]. http://www.sciencemag.org/cgi/ collection/anatmorp.

转载自CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/2301_79906180/article/details/147999736

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--