【HIT】-CSAPP-大作业-程序人生-Hello‘s P2P

计算机系统

大作业

题 目 程序人生-Hello’s P2P
专 业
学   号
班   级
学 生    
指 导 教 师

计算机科学与技术学院
2023年5月
摘 要
摘本文通过描述Hello从预处理,到编译,汇编,链接的全过程,基于vwmare虚拟环境下的ubuntu虚拟机,在linux操作系统的环境下进行编码处理。详细介绍分析了其经过预处理、编译、汇编、链接生成可执行程序的过程。然后结合它的加载、运行整个过程,分析了一个程序运行时需要完成的进程创建与管理、中断和信号处理、虚拟内存分配等内容。

关键词:hello;linux操作系统;预处理;编译;汇编;链接

目 录

第1章 概述 - 4 -
1.1 Hello简介 - 4 -
1.2 环境与工具 - 4 -
1.3 中间结果 - 4 -
1.4 本章小结 - 5 -
第2章 预处理 - 6 -
2.1 预处理的概念与作用 - 6 -
2.2在Ubuntu下预处理的命令 - 6 -
2.3 Hello的预处理结果解析 - 7 -
2.4 本章小结 - 7 -
第3章 编译 - 8 -
3.1 编译的概念与作用 - 8 -
3.2 在Ubuntu下编译的命令 - 8 -
3.3 Hello的编译结果解析 - 10 -
3.4 本章小结 - 13 -
第4章 汇编 - 14 -
4.1 汇编的概念与作用 - 14 -
4.2 在Ubuntu下汇编的命令 - 14 -
4.3 可重定位目标elf格式 - 14 -
4.4 Hello.o的结果解析 - 15 -
4.5 本章小结 - 17 -
第5章 链接 - 18 -
5.1 链接的概念与作用 - 18 -
5.2 在Ubuntu下链接的命令 - 18 -
5.3 可执行目标文件hello的格式 - 18 -
5.4 hello的虚拟地址空间 - 19 -
5.5 链接的重定位过程分析 - 20 -
5.6 hello的执行流程 - 21 -
5.7 Hello的动态链接分析 - 23 -
5.8 本章小结 - 23 -
第6章 hello进程管理 - 24 -
6.1 进程的概念与作用 - 24 -
6.2 简述壳Shell-bash的作用与处理流程 - 24 -
6.3 Hello的fork进程创建过程 - 24 -
6.4 Hello的execve过程 - 24 -
6.5 Hello的进程执行 - 25 -
6.6 hello的异常与信号处理 - 26 -
6.7本章小结 - 26 -
第7章 hello的存储管理 - 27 -
7.1 hello的存储器地址空间 - 27 -
7.2 Intel逻辑地址到线性地址的变换-段式管理 - 27 -
7.3 Hello的线性地址到物理地址的变换-页式管理 - 28 -
7.4 TLB与四级页表支持下的VA到PA的变换 - 28 -
7.5 三级Cache支持下的物理内存访问 - 29 -
7.6 hello进程fork时的内存映射 - 29 -
7.7 hello进程execve时的内存映射 - 29 -
7.8 缺页故障与缺页中断处理 - 30 -
7.9本章小结 - 30 -
结论 - 31 -
附件 - 32 -
参考文献 - 33 -

第1章 概述
(0.5分)

1.1 Hello简介
根据Hello的自白,利用计算机系统的术语,简述Hello的P2P,020的整个过程。
P2P:From Program to Process,即从程序到进程。hello.c文件经过预处理、编译、汇编、链接四个过程,生成可执行文件hello,并在命令行执行后,通过调用fork函数创建子进程执行hello,使得其变成了一个进程。
020:From Zero-0 to Zero-0,即从无到有,再从有到无。产生hello的子进程后,通过调用execve加载hello,映射虚拟内存,并将其载入物理内存。之后开始执行hello程序的相关代码。当进程执行结束后,父进程将回收该进程,并且内核删除其相关的数据结构。hello便结束了其一生。
1.2 环境与工具
软件:X64 CPU;2GHz;2G RAM;256GHD Disk 以上
硬件:Windows11 64位;VirtualBox/Vmware 16;Ubuntu 16.04 LTS 64位/优麒麟 64位 以上
开发工具:Visual Studio 2022 64位;CodeBlocks 64位;vi/vim/gedit+gcc
1.3 中间结果
hello.c——源文件
hello.i——hello.c经过预处理生成的文件
hello.s——hello.i经过编译生成的文件
hello.o——hello.s经过汇编生成的文件
hello——hello.o经过汇编生成的可执行文件
hello.o.elf——hello.o的elf文件
hello.o.objdump——hello.o的反汇编文件
hello.elf——hello的elf文件
hello.objdump——hello的反汇编文件
1.4 本章小结
本章简要描述了hello的P2P和020的整个过程,将本次实验过程中所处的软硬件环境和开发与调试工具简单地列了出来,同时也将整个实验过程中生成的中间文件名称及作用做了说明,是对本次实验主要内容的一个简要概括。

第2章 预处理
(0.5分)

2.1 预处理的概念与作用
概念:程序设计领域中,预处理一般是指在程序源代码被翻译为目标代码的过程中,生成二进制代码之前的过程。预处理器(CPP)根据以字符#开头的命令,修改原始的C程序。结果结果就得到了另一个C程序,通常是以.i作为文件扩展名。
作用:
①文件包含:#include 将文件内容插入到程序中。如hello.c中的#include<stdio.h>命令告诉预处理器读取系统头文件stdio.h的内容,并把它直接插入到程序文本中。
②宏定义:#define 。根据一系列预定义的规则替换一定的文本模式。如#defined N 200,那么程序中就会将所有的N换成200。
③条件编译:#if/#ifdef/#ifndef/#else/#elif/#endif 。通过在程序中加上条件,让编译器只对满足条件的代码进行编译,将不满足条件的代码舍弃。
④行控制:#line 。
⑤错误指令:#error 。
⑥和现实相关的杂注:#pragma 。
⑦空指令:# 。
2.2在Ubuntu下预处理的命令
应截图,展示预处理过程!
命令:gcc -E hello.c -o hello.i

2.3 Hello的预处理结果解析
预处理之后的代码扩展到了3060行,其中主函数在最后面,前面三千多行都是头文件,一些预处理的代码。

2.4 本章小结
本章简要介绍了hello.c通过预处理生成hello.i文件的过程,通过预处理,给源代码加上了头文件和其他预处理的内容,为下一阶段编译过程做了初步的准备。

第3章 编译
(2分)

3.1 编译的概念与作用

编译器会将预处理文件转换为汇编代码。编译器将源代码分析,并生成一组机器指令,这些指令将在计算机上执行。在这个过程中,将hello.i转换为hello.s。编译器的作用首先是检查语法错误,保证C代码的正确性,然后将之转变为汇编代码。

3.2 在Ubuntu下编译的命令

下面是hello.s的部分生成内容展示:

3.3 Hello的编译结果解析
3.1 数据
3.1.1 常量、全局变量和局部变量

1.字符串常量

代码中有两个字符串型的常量,由于是用于printf输出的,故为只读,存放在.rodata节里。.section后的.rodata表示这两个字符串存放在.rodata节中,是只读变量。.align表示以八字节对齐,若不足八字节则会用0补齐。Linux使用utf-8编码,大部分汉字使用三字节来编码,于是在.LC0中会出现三个字一组的字节符,这对应了代码中的汉字。当使用时,会将该字符串的地址放入寄存器中,然后按寄存器寻址去找到字符串,遇到\0表示字符串终止。从这里的汇编代码可以看出,是通过PC相对寻址来找到字符串常量的地址的。

2.立即数(整形常量)

如图所示为立即数:

3.局部变量
局部变量在寄存器或栈中储存,这是i的初始化和更改数值的语句,对应i=0,i++。可以看到,i被分配在栈中,大小是四个字节,刚好在栈最底部。

4.全局变量
这个函数里没有使用全局变量。已初始化的全局变量存放在.data节中,在文件中占据空间,当加载程序时也被加载到内存中。而未初始化的全局变量则在.bss节中,在文件中不占据空间,当使用时在内存中分配这些变量,初始值为0。
3.1.2 数据类型

此函数中一共涉及三种数据类型:整数、字符串、数组。
1.整数:i,argc。Int类型数据使用四个字节存放,使用补码编码方式。
2.字符串:即俩个字符串变量,按照utf-8编码方式编码,不同的符号对应的字节数不同(这里中文三个字节,英文字母和常见标点一个字节)。
3.数组:即argv[]命令行参数数组,存放在栈中,使用地址和偏移量来进行寄存器寻址,找到对应的参数。
3.2 赋值
代码中只有“i=0”一处是赋值操作。
对局部变量的赋值操作是通过mov指令:

3.3 类型转换
Hello.c中并没有进行隐式或显式类型转换,但是使用了atoi函数,该函数作用是把一个数字字符串转换为对应的整数。
通过调用函数传参实现类型转换:

3.4 算术操作
hello.s中设计的算数操作有:

  1. subq $32, %rsp 开辟main函数栈帧(经过分析,其实不用这么多空间)
  2. addq $16, %rax 数组寻址
  3. addq $8, %rax 数组寻址
  4. leaq .LC1(%rip), %rdi 取地址操作
  5. addl $1, -4(%rbp) i++
    3.5 关系操作
  6. argc!=4
    对应的汇编代码是:cmpl $4, -20(%rbp),此处-20(%rbp)即存放argc的地址。
    根据关系式的结果,会设置条件码的值,后续根据条件码的值来进行控制跳转。
    2.i<8 对应汇编代码是:cmpl $7, -4(%rbp) ,当i<=7时,进行跳转。

3.6 数组操作
Hello.c中有一命令行参数数组argv[]。在汇编代码中,该数组地址被存放在栈中:-32(%rbp),当访问数组中元素时,通过(数组基址+偏移量)寻址:

3.7 函数操作
Hello.c中共调用了五次函数。
调用函数时进行的操作如下:
传递控制:
进行函数 Q 的时候,PC必须设置为 Q 的代码的起始地址,然后在返回时,要把PC设置为调用函数中调用 Q 后面那条指令的地址。
传递数据:
调用函数必须能够向 Q 提供一个或多个参数,Q 可以向 P 中返回一个值。
分配和释放内存:
在开始时,Q 可能需要为局部变量在栈中分配空间,而在返回前,又必须释放这些空间。
3.4 本章小结
本章描述了编译的概念和作用,再仔细分析了hello.s文件里面的汇编代码,以及背后的深刻含义,为下一章的汇编做好了准备。

第4章 汇编
(2分)

4.1 汇编的概念与作用
汇编器将汇编代码转换为机器代码。汇编器将汇编代码转换为计算机可以理解的二进制形式。在这个过程中,将hello.s转换为hello.o。编译器将高级语言编写的C语言代码翻译为汇编代码时,尽管结构组成更加简单,但计算机还是不能理解。通过汇编过程将汇编代码转变为二进制机器代码使得CPU可以理解,从而执行我们让它执行的各种操作。
4.2 在Ubuntu下汇编的命令

4.3 可重定位目标elf格式
分析hello.o的ELF格式,用readelf等列出其各节的基本信息,特别是重定位项目分析。

4.4 Hello.o的结果解析

将反汇编结果输出重定向到hello.asm这个文件中
结果如下所示:

hello.s与hello.asm的区别如下所示:
1.开辟main函数的栈帧:

2.地址表示:
(1)字符串常量的引用对比

(2)函数调用对比

4.5 本章小结

本章描述了汇编过程的定义以及作用,通过对于汇编后的hello.o文件的描述和分析,说明了机器语言的构成以及与汇编语言之间的映射关系,特别是机器语言中的操作数与汇编语言不一致,特别是分支转移函数调用等。

第5章 链接
(1分)

5.1 链接的概念与作用
链接是指在电子计算机程序的各模块之间传递参数和控制命令,并把它们组成一个可执行的整体的过程。地址和空间的分配,符号决议和重定位。符号决议:也可以说地址绑定,分动态链接和静态链接;重定位:假设此时又两个文件:A,B。A需要B中的某个函数mov的地址,未链接前将地址置为0,当A与B链接后修改目标地址,完成重定位。
5.2 在Ubuntu下链接的命令
命令:
ld -o hello -dnamic-linker/lib64/ld-linux-x86-64.so.2/usr/lib/x86_64-linux-gnu/crt1.o/usr/lib/x86_64-linux-gnu/crti.ohello.o/usr/lib/x86_64-linux-gnu/libc.so/usr/lib/x86_64-linux-gnu/crtn.o

5.3 可执行目标文件hello的格式
1.ELF头,使用指令(readelf -a hello > hell02.elf)

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

5.5 链接的重定位过程分析
objdump -d -r hello 分析hello与hello.o的不同,说明链接的过程。
结合hello.o的重定位项目,分析hello中对其怎么重定位的。
指令:objdump -d -r hello > hello1.asm

5.6 hello的执行流程
使用edb执行hello,说明从加载hello到_start,到call main,以及程序终止的所有过程。请列出其调用与跳转的各个子程序名或程序地址。
程序名称(上)程序地址(下)
ld-2.27.so!_dl_start

0x7fce8cc38ea0

ld-2.27.so!_dl_init

0x7fce8cc47630

hello!_start

0x400500

libc-2.27.so!__libc_start_main

0x7fce8c867ab0

-libc-2.27.so!__cxa_atexit

0x7fce8c889430

-libc-2.27.so!__libc_csu_init

0x4005c0

hello!_init

0x400488

libc-2.27.so!_setjmp

0x7fce8c884c10

-libc-2.27.so!_sigsetjmp

0x7fce8c884b70

–libc-2.27.so!__sigjmp_save

0x7fce8c884bd0

hello!main

0x400532

hello!puts@plt

0x4004b0

hello!exit@plt

0x4004e0

*hello!printf@plt

*hello!sleep@plt

*hello!getchar@plt

ld-2.27.so!_dl_runtime_resolve_xsave

0x7fce8cc4e680

-ld-2.27.so!_dl_fixup

0x7fce8cc46df0
5.7 Hello的动态链接分析
分析hello程序的动态链接项目,通过edb调试,分析在dl_init前后,这些项目的内容变化。要截图标识说明。
链接的全部内容不局限于生成可执行文件时的静态链接,还包括加载、运行程序时的动态链接。
(1)加载时
共享库是一个目标模块,在运行或加载时,可以加载到任意的内存地址,并和一个在内存中的程序链接起来。这个过程就是动态链接,是由一个叫做动态链接器的程序来执行的。共享库也称为共享目标,在linux系统中通常使用.so后缀来表示。微软的windows系统中称为DLL,以.dll形式的后缀文件形式存在。
经过静态链接的hello程序是部分链接的,然后当加载hello时,需要动态完成链接过程。当加载器加载和运行可执行文件hello时,它注意到hello包含一个.interp节,这一节包含动态链接器的路径名,动态链接器本身就是一个共享目标 (比如我们下图中的ld-linux-x86-64.so.2)。加载器加载和运行这个动态链接器, 然后,动态链接器执行以下重定位完成链接任务:
重定位libc.so的文本和数据到某个内存段。
重定位hello中所有对由libc.so定义的符号引用。
最后,动态链接器将控制传递给应用程序。从这个时刻开始,共享库的位置就固定了,并且在程序执行的过程中都不会改变。
(2)运行时
Hello可以在运行时要求动态链接器加载和链接某个共享库,而无需在编译时将那些库链接到应用中。运行时的链接是通过GOT和PLT这俩个表的配合来实现的。我们以hello来说明这个过程。
.got与.plt节保存着全局偏移量表GOT,其内容从地址0x601000开始。通过edb查看,在dl_init调用前,其内容如下:
5.8 本章小结
本章中介绍了链接的概念与作用,并结合链接后生成的hello可执行文件的ELF格式文本hello2.elf,分析了静态链接对可重定位文件所做的改变。然后,根据反汇编文件hello2.asm与hello.asm的比较,加深了对重定位的理解。之后分析了hello的执行流程,对hello加载和执行时发生的动态链接过程进行了分析。

第6章 hello进程管理
(1分)
6.1 进程的概念与作用
进程的经典定义就是一个执行中程序的实例。系统中的每个程序都运行在某个进程的上下文(context)中。上下文是由程序正确运行所需的状态组成的。这个状态包括存放在内存中的程序的代码和数据,它的栈、通用目的寄存器的内容、程序计数器、环境变量以及打开文件描述符的集合。
给应用程序提供两个关键抽象:
一个独立的逻辑控制流,提供一个假象,好像程序独占地使用处理器;一个私有地址空间,提供一个假象,好像程序独占地使用内存系统。
在现代系统上运行一个程序时,我们会得到一个假象,就好像我们的程序是系统中当前运行的唯一的程序一样。我们的程序好像是独占地使用处理器和内存。处理器就好像是无间断地一条接一条地执行我们程序中的指令。最后,我们程序中的代码和数据好像是系统内存中唯–的对象。这些假象都是通过进程的概念提供给我们的。
6.2 简述壳Shell-bash的作用与处理流程
Shell是一个交互型的应用级程序,它代表用户运行其他程序。Shell执行一系列的读/求值步骤,然后终止。读步骤读取来自用户的一个命令行。求值步骤解析命令行,并代表用户运行程序。
Shell利用fork和execve运行程序。Shell解析用户输入的命令行后,若指令是要求运行一个程序,则通过fork开辟一个新的线程,然后通过execve函数来运行这个程序。并且,shell也负责回收所有的子进程。若命令要求在前台运行程序,那么shell程序显式地调用waitpid函数来等待子进程停止;若命令要求在后台运行程序(即最后一个参数为&),那么shell程序通过SIGCHLD信号处理程序来回收终止的子进程,信号处理程序中依然使用waitpid这个函数。由于信号处理程序同主程序是并发执行的,所以shell可以继续执行其他作业,而不需要等待后台进程停止。所以,一个shell程序可以有一个前台作业和多个后台作业。
6.3 Hello的fork进程创建过程
我们在shell中键入 ./helloworld,运行hello程序。Shell进程会处理我们输入的命令行,对之进行分割、识别。shell识别出我们键入的命令是执行一个程序后,调用fork函数开辟一个新的子进程。新创建的子进程几乎但不完全与父进程相同。子进程得到与父进程用户级虚拟地址空间相同的(但是独立的)一份副本,包括代码和数据段、堆、共享库以及用户栈。子进程还获得与父进程任何打开文件描述符相同的副本,这就意味着当父进程调用fork时,子进程可以读写父进程中打开的任何文件。父进程和新创建的子进程之间最大的区别在于它们有不同的PID。fork函数是有趣的(也常常令人迷惑),因为它只被调用一次,却会返回两次:一次是在调用进程(父进程)中,一次是在新创建的子进程中。在父进程中,fork返回 子进程的PID。在子进程中,fork返回0。因为子进程的PID总是为非零,返回值就提供一个明确的方法来分辨程序是在父进程还是在子进程中执行。
6.4 Hello的execve过程
Execve函数在当前进程的上下文中加载并运行一个程序。
Shell在调用函数fork创建新的子进程之后,子进程会调用execve函数,调用驻留在储存器中称为加载器的操作系统代码来运行hello。加载器在当前进程的上下文中加载并运行hello。
加载器将可执行目标文件中的代码和数据从磁盘复制到内存中,然后通过跳转到程序的第一条指令或入口点来运行该程序。加载器删除子进程现有的虛拟内存段,并创建一组新的代码、数据、堆和栈段。新的栈和堆段被初始化为零。通过将虛拟地址空间中的页映射到可执行文件的页大小的片(chunk),新的代码和数据段被初始化为可执行文件的内容。这个将程序复制到内存并运行的过程叫做加载。在加载过程中,除了一些头部信息,没有任何从磁盘到内存的复制,知道CPU引用一个被映射的虚拟页时才会进行复制。
当加载器运行时,它创建hello的新的内存映像。在程序头部表的引导下,加载器将可执行文件的片(chunk)复制到代码段和数据段。接下来,加载器跳转到程序的.人口点,也就是_ start 函数的地址。这个函数是在系统目标文件ctrl.o中定义的,对所有的C程序都是一样的。_ start 函数调用系统启动函数__ libe_ start. main,该函数定义在libc.so中。它初始化执行环境,调用用户层的main函数,处理main函数的返回值,并且在需要的时候把控制返回给内核。
6.5 Hello的进程执行
结合进程上下文信息、进程时间片,阐述进程调度的过程,用户态与核心态转换等等。Hello进程执行的时候,其实并不是在时间上连续的。一个进程执行的整个周期,可以被划分为多个事件片,在每个事件片中,CPU加载了这个进程的上下文,给它一个独占处理器的假象。而实际上,CPU可以同时执行多个进程,这些进程也被划分为多个事件片,单个CPU通过交替执行不同进程的事件片来并行地执行多个进程。
而在不同进程当中,CPU所加载的上下文信息是不同的,因此在不同的进程切换时,CPU需要加载不同的上下文。操作系统内核使用一种称为上下文切换(context switch)的较高层形式的异常控制流来实现多任务。上下文切换机制是建立在那些较低层异常机制之上的。
内核为每个进程维持一个上下文(context)。上下文就是内核重新启动一个被抢占的进程所需的状态。它由一些对象的值组成,这些对象包括通用目的寄存器、浮点寄存器、程序计数器、用户栈、状态寄存器、内核栈和各种内核数据结构,比如描述地址空间的页表、包含有关当前进程信息的进程表,以及包含进程已打开文件的信息的文件表。
在进程执行的某些时刻,内核可以决定抢占当前进程,并重新开始一个先前被抢占了的进程。这种决策就叫做调度(scheduling),是由内核中称为调度器(scheduler)的代码处理的。当内核选择一个新的进程运行时,我们说内核调度了这个进程。在内核调度了一个新的进程运行后,它就抢占当前进程,并使用一种称为上下文切换的机制来将控制转移到新的进程,上下文切换1)保存当前进程的上下文,2)恢复某个先前被抢占的进程被保存的上下文,3)将控制传递给这个新恢复的进程。
当内核代表用户执行系统调用时,可能会发生上下文切换。如果系统调用因为等待某个事件发生而阻塞,那么内核可以让当前进程休眠,切换到另一个进程。在hello里,get函数需要等待用户在标准输入中输入字符,在等待的过程中,内核可以选择执行上下文切换,运行另外一个进程,而不是等待数据从标准输入到达。另一个示例是sleep系统调用,它显式地请求让调用进程休眠。一般而言,即使系统调用没有阻塞,内核也可以决定执行上下文切换,而不是将控制返回给调用进程。
中断也可能引发上下文切换。比如,所有的系统都有某种产生周期性定时器中断的机制,通常为每1毫秒或每10毫秒。每次发生定时器中断时,内核就能判定当前进程已经运行了足够长的时间,并切换到一个新的进程。
6.6 hello的异常与信号处理
hello执行过程中会出现哪几类异常,会产生哪些信号,又怎么处理的。
程序运行过程中可以按键盘,如不停乱按,包括回车,Ctrl-Z,Ctrl-C等,Ctrl-z后可以运行ps jobs pstree fg kill 等命令,请分别给出各命令及运行结截屏,说明异常与信号的处理。
6.7本章小结
本章叙述了进程的概念和作用,然后讲解了开辟一个进程的过程,结合hello文件叙述了fork和execve函数的功能和作用。之后通过实际操作演示了进程的运行和接受并处理信号的方式。

第7章 hello的存储管理
( 2分)

7.1 hello的存储器地址空间
结合hello说明逻辑地址、线性地址、虚拟地址、物理地址的概念。
1.逻辑地址
逻辑地址是指由程序产生的与段相关的偏移地址部分,逻辑地址由选择符和偏移量两部分组成。具体而言,其为hello.asm中的相对偏移地址,即L0、L1、LC0、LC1这种的标记。
2.线性地址
逻辑地址经过段机制转化后为线性地址,其为处理器可寻址空间的地址,用于描述程序分页信息的地址。具体以hello而言,线性地址标志着 hello 应在内存上哪些具体数据块上运行。
3.虚拟地址
根据CSAPP教材,虚拟地址即为上述线性地址。
4.物理地址
通过MMU将虚拟地址翻译为物理地址,CPU通过地址总线的寻址,找到真实的物理内存对应地址。
7.2 Intel逻辑地址到线性地址的变换-段式管理
Intel处理器从逻辑地址到线性地址的变换通过段式管理的方式实现。每个程序在系统中都保存着一个段表,段表保存着该程序各段装入主存的状况信息,包括段号或段名、段起点、装入位、段的长度、主存占用区域表、主存可用区域表等,从而方便进行段式管理。
在段寄存器中,存放着段选择符,可以通过段选择符来得到对应段首地址。
其包含三部分:索引,TI,RPL:
索引:用来确定当前使用的段描述符在描述符表中的位置;
TI:根据TI的值判断选择全局描述符表(TI=0,GDT)或选择局部描述符表(TI=1,LDT);
RPL:判断重要等级。RPL=00,为第0级,位于最高级的内核,RPL=11,为第3级,位于最低级的用户状态;
通过一个索引,可以定位到段描述符,进而通过段描述符得到段基址。段基址与偏移量结合就得到了线性地址,虚拟地址。
7.3 Hello的线性地址到物理地址的变换-页式管理
线性地址(VA)到物理地址(PA)之间的转换通过对虚拟地址内存空间进行分页的分页机制完成。
通过7.2节中的段式管理过程,可以得到了线性地址/虚拟地址,记为VA。虚拟地址可被分为两个部分:VPN(虚拟页号)和VPO(虚拟页偏移量),根据计算机系统的特性可以确定VPN与VPO的具体位数,由于虚拟内存与物理内存的页大小相同,因此VPO与PPO(物理页偏移量)一致。而PPN(物理页号)则需通过访问页表中的页表条目(PTE)获取。
若PTE的有效位为1,则发生页命中,可以直接获取到物理页号PPN,PPN与PPO共同组成物理地址。
若PTE的有效位为0,说明对应虚拟页没有缓存到物理内存中,产生缺页故障,调用操作系统的内核的缺页处理程序,确定牺牲页,并调入新的页面。再返回到原来的进程,再次调用导致缺页的指令。此时发生页命中,获取到PPN,与PPO共同组成物理地址。
7.4 TLB与四级页表支持下的VA到PA的变换
针对Intel Core i7 CPU研究VA到PA的变换。
Intel Core i7 CPU的基本参数如下:
虚拟地址空间48位(n=48)
物理地址空间52位(m=52)
TLB四路十六组相连
L1,L2,L3块大小为64字节
L1,L2八路组相连
L3十六路组相连
页表大小4KB(P=4x1024=2^12),四级页表,页表条目(PTE)大小8字节
由上述信息可以得知,VPO与PPO有p=12位,故VPN为36位,PPN为40位。单个页表大小4KB,PTE大小8字节,则单个页表有512个页表条目,需要9位二进制进行索引,而四级页表则需要36位二进制进行索引,对应着36位的VPN。TLB有16组,故TLBI有t=4位,TLBT有36-4=32位。
7.5 三级Cache支持下的物理内存访问
因为三级Cache的工作原理基本相同,所以在这里以L1 Cache为例,介绍三级Cache支持下的物理内存访问。
L1 Cache的基本参数如下:
8路64组相连
块大小64字节
由L1 Cache的基本参数,可以分析知:
块大小64字节→需要6位二进制索引→块偏移6位
共64组→需要6位二进制索引→组索引6位
余下标记位→需要PPN+PPO-6-6=40位
故L1 Cache可被划分如下(从左到右):
CT(40bit)CI(6bit)CO(6bit)
在7.4中我们已经由虚拟地址VA转换得到了物理地址PA,首先使用CI进行组索引,每组8路,对8路的块分别匹配CT(前40位)如果匹配成功且块的valid标志位为1,则命中(hit),根据数据偏移量CO取出相应的数据后返回。
若没有匹配成功或者匹配成功但是标志位是1,则不命中(miss),向下一级缓存中请求数据(请求顺序为L2 Cache→L3 Cache→主存,若仍不命中才继续向下一级请求)。查询到数据之后,需要对数据进行读入,一种简单的放置策略如下:若映射到的组内有空闲块,则直接放置在空闲块中,若当前组内没有空闲块,则产生冲突(evict),采用LFU策略进行替换。
7.6 hello进程fork时的内存映射
当fork函数被当前进程hello调用时,内核为新进程hello创建各种数据结构,并分配给它一个唯一的PID。为了给这个新的hello创建虚拟内存,它创建了当前进程的mm_struct、区域结构和页表的原样副本。它将两个进程中的每个页面都标记为只读,并将两个进程中的每个区域结构都标记为私有的写时复制。
当fork在新进程中返回时,新进程现在的虚拟内存刚好和调用fork时存在的虚拟内存相同。当着两个进程中的任一个后来进行写操作时,写时复制机制就会创建新页面,因此,也就为每个进程保持了私有地址空间的抽象概念。
7.7 hello进程execve时的内存映射
execve函数加载并运行hello需要以下几个步骤:
1.删除已存在的用户区域
删除当前进程hello虚拟地址的用户部分中的已存在的区域结构。
2.映射私有区域
为新程序的代码、数据、bss和栈区域创建新的私有的、写时复制的区域结构。其中,代码和数据区域被映射为hello文件中的.text和.data区。bss区域是请求二进制零的,映射到匿名文件,其大小包含在hello中。栈和堆区域也是请求二进制零的,初始长度为零。
3.映射共享区域
若hello程序与共享对象或目标(如标准C库libc.so)链接,则将这些对象动态链接到hello程序,然后再映射到用户虚拟地址空间中的共享区域内。
4.设置程序计数器
最后,execve设置当前进程上下文中的程序计数器,使之指向代码区域的入口点。
7.8 缺页故障与缺页中断处理
发生一个缺页异常后,控制会转移到内核的缺页处理程序。判断虚拟地址是否合法,若不合法,则产生一个段错误,然后终止这个进程。
若操作合法,则缺页处理程序从物理内存中确定一个牺牲页,若该牺牲页被修改过,则将它换出到磁盘,换入新的页面并更新页表。当缺页处理程序返回时,CPU 再次执行引起缺页的指令,将引起缺页的虚拟地址重新发送给MMU。因为虚拟页面现在缓存在物理内存中,所以就会命中,主存将所请求字返回给处理器。
7.9本章小结
本章主要介绍了hello 的存储器地址空间、intel 的段式管理、hello 的页式管理, VA 到PA 的变换、物理内存访问,hello进程fork、execve 时的内存映射、缺页故障与缺页中断处理,对于存储器空间的认识又深入了一步。

结论
hello程序的一生经历了如下过程:
1.代码的编写
首先需要由程序员写出正确的hello.c的代码。
2.预处理
预处理器根据#之后的指令对hello.c进行文本处理,生成hello.i文件。将#include引入的头文件在原地复制;将#define进行的宏定义进行文本替换;根据条件编译的指令在不同情况编译不同的代码。
3.编译
编译器通过词法分析和语法分析,将C语言指令翻译成等价的汇编代码,生成hello.s文件。
4.汇编
汇编器将hello.s汇编程序翻译成二进制的机器语言,并把这些指令打包成可重定位目标程序格式,保存在hello.o 目标文件中;
5.链接
通过链接器,将hello.o文件与其他可重定位文件、静态库链接到一起,然后进行符号解析,再将所相同类型的节合并为同一类型的新的聚合节,最后修改代码节和数据节中对每个符号的引用,使得他们指向正确的运行时地址。至此,已经生成hello可执行程序。但是链接并没有结束,在加载时、运行时,hello仍然需要与动态库进行链接,从而调用动态库函数。
6.加载运行
打开Shell,在其中键入 ./hello 120L020701 董琦,shell为其fork新建进程,然后通过execve将hello加载到内存中,为其更改进程的上下文,开始执行hello进程。
7.执行指令
在该进程被调度时,CPU为hello其加载上下文、分配时间片,在一个时间片中,hello享有CPU全部资源,PC寄存器一步一步地更新,CPU不断地取指,顺序执行自己的控制逻辑流;
8.访存
内存管理单元MMU将虚拟地址映射为物理地址,进而通过三级高速缓存系统访问物理内存/磁盘中的数据;
9.信号处理
进程在运行时可以接收信号,与信号处理程序并发地执行。如果hello运行途中键入ctr-c ctr-z 则调用shell 的信号处理函数分别进行终止、停止等操作。
10.终止并被回收
Shell父进程等待并回收hello子进程,内核删除为hello进程创建的所有数据结构。

附件
列出所有的中间产物的文件名,并予以说明起作用。
hello.c——源文件
hello.i——hello.c经过预处理生成的文件
hello.s——hello.i经过编译生成的文件
hello.o——hello.s经过汇编生成的文件
hello——hello.o经过汇编生成的可执行文件
hello.o.elf——hello.o的elf文件
hello.o.objdump——hello.o的反汇编文件
hello.elf——hello的elf文件

参考文献
[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.

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 、4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、下载 4使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、 4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.m或d论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 、1资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。、资源 5来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。、资 5源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值