程序人生-Hello’s P2P
计算机体系
大作业
题 目 程序人生-Hello’s P2P
专 业 计算机科学与技术
学 号 2022112421
班 级 2203103
学 生 李德鑫
指 导 教 师 史先俊
计算机科学与技术学院
2023年4月
摘 要
本文介绍了hello程序的一生,详细分析了从hello.c编译成hello,再在计算机中执行直至进程终止的全过程,论述了编译过程中各个软件的功能,进程执行过程中各个软硬件之间的协作联系,各自实现的功能,深入探究了计算机编译高级语言,成功执行程序的全过程。
关键词:C语言;hello;预处理;编译;汇编;链接;进程;信号;存储;内存;IO
目 录
第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:From Program to Process
源程序hello.c,经cpp预处理天生hello.i,再由编译器ccl翻译成汇编程序hello.s,然后由汇编器as天生可重定位目的文件hello.o,最后经过链接器ld与其他目的文件链接成可执行程序hello
020:From Zero to Zero
shell中fork创建子进程,再由execve加载可执行程序hello,分配虚拟内存,映射到物理内存,然后CPU执行指令,举行取址,译码,执行等操纵,通过I/O信号处理输出效果,程序运行结束后,父进程对其举行回收,内核清除与hello相关的数据。
1.2 情况与工具
Ubuntu,gcc,edb,cpp,ccl,as,ld,objdump,readelf
1.3 中间效果
hello.i hello.c经过预处理得到的文本文件
hello.s hello.i经过编译得到的汇编文件
hello.o hello.s经过汇编得到的二进制文件,执行呆板级代码
hello.elf hello.o的elf格式,用于分析hello.o
objdump.txt hello.o的反汇编文件
hello hello.o经过链接得到的可执行文件
hello2.elf hello的elf格式,用于分析hello
objdump2.txt hello的反汇编文件
1.4 本章小结
本章介绍了hello程序的两个过程:P2P和020,介绍了编译运行hello的过程中用到的软硬件工具,编译过程中产生的中间文件。
第2章 预处理
2.1 预处理的概念与作用
概念:预处理是指预处理器(cpp)根据以字符#开头的下令,修改原始的C程序。预处理后的文件后缀为(.i)
作用:1.举行宏替换,用常量代替符号
2.递归处理#include指令,将必要的文件插入到程序文本中。
3.处理条件编译指令
4.删除表明
2.2在Ubuntu下预处理的下令
gcc -E hello.c -o hello.i
https://i-blog.csdnimg.cn/blog_migrate/caa6980d2879a32059fadb9df22b5ef6.png
2.3 Hello的预处理效果解析
将hello.i以文本的形式打开,发现代码段在文件的最后,并且删除了表明部门,前面添加了hello.c文件中引用的stdio.h,unistd.h,stdlib.h三个头文件的内容和一些应该在这三个头文件中引用的其他头文件中的内容。
https://i-blog.csdnimg.cn/blog_migrate/d66b13feb281b2a3d288ff7d7dea7577.png
https://i-blog.csdnimg.cn/blog_migrate/5fade189c1e82fad8bdb069ca33c4e37.png
2.4 本章小结
本章对hello.c文件举行预处理得到了hello.i,通过读取hello.i文件可以发现预处理器对c代码举行了删除表明,将头文件插入到代码中等一系列操纵。
第3章 编译
3.1 编译的概念与作用
概念:编译是指编译器(ccl)将文本文件.i处理成汇编文件.s的过程
作用:编译器将高级语言转化成较为底层的汇编语言,并在这个过程中完成对程序的语法分析和适当的优化等,为后续天生呆板级代码做准备。
3.2 在Ubuntu下编译的下令
gcc -S hello.i -o hello.s
https://i-blog.csdnimg.cn/blog_migrate/711dd3841578c63f740921aa8f893f3a.png
3.3 Hello的编译效果解析
hello.s文本:
https://i-blog.csdnimg.cn/blog_migrate/9f61a4bc19912f883e0e67a0345d8de9.png
https://i-blog.csdnimg.cn/blog_migrate/31dc67dbd5edd35ae7abdcb85b1fac68.png
3.3.1数据
(1)常量:
https://i-blog.csdnimg.cn/blog_migrate/1babb4c15ed87833de8cffeff703018a.jpeg
https://i-blog.csdnimg.cn/blog_migrate/e2babbe802b7bade0b5bab6fc05e7fea.jpeg
https://i-blog.csdnimg.cn/blog_migrate/ae0e2ee510f4074d003918fe2aeb6649.jpeg
常量4和7以立即数的形式表示
(2)字符串常量:
https://i-blog.csdnimg.cn/blog_migrate/5dea6e135a3c1abe45262f8c5e6595d1.png
https://i-blog.csdnimg.cn/blog_migrate/2eec7593abbb48d8c47f9fff464f12f6.png
字符串常量先存入寄存器rip中,再举行操纵
(3)局部变量:int i被存在了-4(%rbp)的位置
https://i-blog.csdnimg.cn/blog_migrate/a5ebdec72a4f654ed2b2020325a92470.png
(4)main参数:main函数的两个参数(int argc,char *argv[])分别被存在了-20(%rbp)和-32(%rbp)处
https://i-blog.csdnimg.cn/blog_migrate/f447421fb6586bb595dd07b5af6271f4.png
3.3.2赋值:i赋值为0
https://i-blog.csdnimg.cn/blog_migrate/e5b353617ac556eb07de96bea1580569.jpeg
https://i-blog.csdnimg.cn/blog_migrate/a5f2dd53ed264a4f7f9483725a0c41b4.jpeg
3.3.3算数操纵:每次循环i加1
https://i-blog.csdnimg.cn/blog_migrate/2fb735938acdc05d2d65aad6db2d4e91.jpeg
https://i-blog.csdnimg.cn/blog_migrate/ce50aa85fdd0ae494d58f07dbe3a38f0.png
3.3.4关系操纵:两个比力操纵
https://i-blog.csdnimg.cn/blog_migrate/bd5cfdcdaea0aed6a5b0e6d5a6ab9692.png
https://i-blog.csdnimg.cn/blog_migrate/41d62c86813429a4675a3b9a4b7d5e2a.png
https://i-blog.csdnimg.cn/blog_migrate/61b32ceda635b25485b377ee8b699fbe.png
3.3.5数组操纵:数组argv[]
argv:
https://i-blog.csdnimg.cn/blog_migrate/914aebe6da6c86bd1441c0b3ce00e8d2.png
argv:
https://i-blog.csdnimg.cn/blog_migrate/68f2589867d48ac31e6a4dbb0a2bd6a9.png
argv:
https://i-blog.csdnimg.cn/blog_migrate/9d218cb5d40eb8207de9cb12257dd03e.png
3.3.6控制转移:if跳转和for循环
条件跳转:
https://i-blog.csdnimg.cn/blog_migrate/93dde7c1a60d3963ae539f3e1a300d2f.png
https://i-blog.csdnimg.cn/blog_migrate/15293068d2e9ef9bceda5c5bb9670734.jpeg
无条件跳转:
https://i-blog.csdnimg.cn/blog_migrate/769c92e91c83e0c00c2506711b98a9d9.png
3.3.7函数操纵:
1.printf():if判断中的,输出效果为字符串,编译器将printf函数优化成puts函数
https://i-blog.csdnimg.cn/blog_migrate/5249c7949394d16587db3e679dc7c0dc.png
for循环中的:
https://i-blog.csdnimg.cn/blog_migrate/2d6f8531b3ce46efe7867bf00faf6d2d.png
2.exit():传入参数为1,存储在edi中
https://i-blog.csdnimg.cn/blog_migrate/9be961f950e4e20caf83757dd4907985.png
3.atoi():
https://i-blog.csdnimg.cn/blog_migrate/09dd10535f6cc1a4a3443918c80b1187.png
4.sleep():
https://i-blog.csdnimg.cn/blog_migrate/1a611f8acea6a783fc160b94f1d4c7e0.png
5.getchar():无参数
https://i-blog.csdnimg.cn/blog_migrate/d7a2dfbef430a08ef22284840ac5b1e2.png
3.4 本章小结
本章演示了编译器(ccl)将文本文件hello.i处理成汇编文件hello.s的过程,并通过查察hello.s的内容具体分析了编译器对hello.c代码中的数据类型,赋值操纵,算术操纵,关系操纵,数组操纵,控制转移,函数操纵的处理。
第4章 汇编
4.1 汇编的概念与作用
概念:汇编是指汇编器(as)将.s汇编语言,处理成二进制呆板语言,并将指令打包成可重定位目的程序的格式,天生.o可重定位目的文件的过程
作用:将汇编语言翻译成二进制呆板语言,成为呆板可直接辨认的程序
4.2 在Ubuntu下汇编的下令
as hello.s -o hello.o
https://i-blog.csdnimg.cn/blog_migrate/a619ada3f574d41b75c44435c240907a.jpeg
4.3 可重定位目的elf格式
https://i-blog.csdnimg.cn/blog_migrate/e1b8011c917ee22e83a3607e3fac2fe6.jpeg
打开文本hello.elf:
ELF头:
https://i-blog.csdnimg.cn/blog_migrate/425fe97b8f07ef6db4a41ef3b3e7fb0b.jpeg
ELF头以一个16字节的序列开始,这个序列描述了天生该文件体系下的字的巨细以及一些其他信息。ELF头剩下的部门包含资助链接器语法分析和表明目的文件的信息:包罗ELF头的巨细、目的文件的类型、呆板类型、节头部表的文件偏移,以及节头部表中条目的巨细和数目。
节头:
https://i-blog.csdnimg.cn/blog_migrate/33e81eb8529a4cd2c964e691d15f35ba.jpeg
节头包含.o文件中的每个节的信息:包罗名称,巨细,类型,全体巨细,地点,旗标,链接,信息,偏移量与对齐
重定位节:
https://i-blog.csdnimg.cn/blog_migrate/7931e4fc5b918084e8a45b229b49f915.jpeg
分为’.rela.text’和’rela.eh_frame’两个部门,告知链接器(ld)在与其他文件链接时必要重定位的位置,类型和偏移量
Symbol表:
https://i-blog.csdnimg.cn/blog_migrate/f5c35513359bcd7bfa8e5a4aac9c86a4.png
Symbol表包含程序中全部利用的函数以及全局变量的基本信息,包罗巨细、类型、类别与名称
4.4 Hello.o的效果解析
反汇编hello.o效果:
https://i-blog.csdnimg.cn/blog_migrate/67ea483c7c716d32a5d1ee503a3695ed.png
https://i-blog.csdnimg.cn/blog_migrate/173cd02da3c5c7e0113868d496284955.png
差别点:
1.地点:每条呆板指令从地点0开始获得了地点
2.立即数进制转换
hello.s中10进制表示的立即数,在hello.o中转化为16进制表示
如:
https://i-blog.csdnimg.cn/blog_migrate/1b74890efa0a2d87c43081d711e2bbd6.png
https://i-blog.csdnimg.cn/blog_migrate/e9326d071b12f03720c542f067c044f6.png
https://i-blog.csdnimg.cn/blog_migrate/ddf5d9e557c425eeb36787063aa259d2.png
https://i-blog.csdnimg.cn/blog_migrate/ef8f99a9be19ff247559f209d67d3378.png
3.函数调用
hello.s中调用外部函数的部门在hello.o中转化为了重定向条目,hello.s中call背面跟的是函数名,hello.o中call背面是函数地点
如:
https://i-blog.csdnimg.cn/blog_migrate/0b045a324201e82ce5dedc6ae3fac61d.png
https://i-blog.csdnimg.cn/blog_migrate/e677b313e330c13c06c189643b64135b.png
4.跳转
在hello.i中,用L1,L2...来表示跳转地点,而在hello.o中直接给出了确定的跳转地点
如:
https://i-blog.csdnimg.cn/blog_migrate/a68db1b1444c4560ff7df6f158203fe7.png
https://i-blog.csdnimg.cn/blog_migrate/f611b0a9bba0346384a6f09ff54654b4.png
4.5 本章小结
本章通过汇编器(as)将汇编代码hello.s转化成了呆板级代码hello.o,用readelf查察了hello.o的ELF文件(ELF头,节头,重定位,Symbol表),再通过反汇编比力出了呆板语言与汇编语言之间的区别,主要体现在地点和重定位等方面。
第5章 链接
5.1 链接的概念与作用
概念:链接是将差别部门的代码和数据片段网络并组合成一个单一文件的过程,这个文件可被加载或拷贝到内存并执行。
作用:将可重定位目的文件hello.o与其他目的文件和链接库合并,举行符号解析和重定位。天生可执行目的文件hello,使分离编译成为了可能。
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
https://i-blog.csdnimg.cn/blog_migrate/849d4eb22d31407597a3f5919bb78a2c.jpeg
5.3 可执行目的文件hello的格式
ELF头:文件类型变为了可执行文件,有了程序执行的入口点地点
https://i-blog.csdnimg.cn/blog_migrate/b0ea32dc58846c6696bf5a869cc38a6a.jpeg
节头:
https://i-blog.csdnimg.cn/blog_migrate/fdc8399654bb9b69fbb85e1a313c03b4.jpeg
重定位节:
https://i-blog.csdnimg.cn/blog_migrate/d0783860772005833e00463a9c15bae4.jpeg
Symbol表:
https://i-blog.csdnimg.cn/blog_migrate/ead2f6bd863031f7deebed0e5f9699f4.jpeg
https://i-blog.csdnimg.cn/blog_migrate/19e838eb82187a1e3a3bf09f35ee840a.jpeg
5.4 hello的虚拟地点空间
在hello2.elf文件的程序头中,可以看到各段的虚拟地点
https://i-blog.csdnimg.cn/blog_migrate/70acde261daac8de8ab5f8ca7361673d.jpeg
用edb加载hello,查察第一个load的信息:
https://i-blog.csdnimg.cn/blog_migrate/74d2cbee1bf8392bb1d5160960645f71.jpeg
5.5 链接的重定位过程分析
https://i-blog.csdnimg.cn/blog_migrate/27a2c6e04c88fb8653d362a000b3a5d0.jpeg
代码段:hello.o中仅有main函数的反汇编代码,hello中有了各个调用函数的反汇编代码
地点:hello中每个函数都完成了重定位有了确定的虚拟地点,从而使call调用的位置为固定的虚拟地点
如:
https://i-blog.csdnimg.cn/blog_migrate/3b994c82014060bd7f2a861493e05aa4.jpeg
https://i-blog.csdnimg.cn/blog_migrate/808dd13d3d90505ac3331701f0084ccf.jpeg
字符串常量也有了存储地点:
https://i-blog.csdnimg.cn/blog_migrate/2bdb13b1a2016a1489db4942933ef251.jpeg
链接器在完成符号解析后,将每个符号分配运行时的虚拟内存,在每个必要重定位的地方分配函数和全局变量的虚拟地点,并修改call和跳转指令的调用地点。
5.6 hello的执行流程
子程序名 地点
libc-2.31.so!__ctype_init 0x7fca2ef54fc0
_start 0x4010f0
libc-2.31.so!__libc_start_main 0x7fca2ef54fc0
libc-2.31.so!__cxa_atexit 0x7fca2ef77e10
__libc_csu_init 0x4011c0
libc-2.31.so!_setjmp 0x7fca2ef73cb0
libc-2.31.so!_sigsetjmp 0x7fca2ef73be0
hello!main 0x401125
hello!puts@plt 0x401030
hello!exit@plt 0x401070
5.7 Hello的动态链接分析
当程序调用一个共享库的函数时,编译器不能猜测这个函数在什么地点,因为定义它的共享模块在运行时可以加载到任何位置。这时,编译体系提供了耽误绑定的方法,耽误绑定通过全局偏移量表GOT和过程链接表PLT的协作来解析函数的地点。假如一个目的模块调用定义在共享库中的任何函数,那么他就有本身的GOT和PLT。GOT是数据段的一部门,而PLT是代码段的一部门。
在加载时,动态链接器会重定位GOT中的每个条目,查察hello2.elf文件得到.got.plt的起始位置是0x404000
https://i-blog.csdnimg.cn/blog_migrate/5e3d153cf71c99031f76fe0b25d041d9.jpeg
dl_init执行之前:
https://i-blog.csdnimg.cn/blog_migrate/f6921a4e33190cc51e0e0e8e14920438.jpeg
dl_init执行之后:
https://i-blog.csdnimg.cn/blog_migrate/91c1107a7dfac74cb30c4d8a1cbd5bea.jpeg
5.8 本章小结
本章介绍了由可重定义目的文件hello.o通过链接器合并成可执行目的文件hello的过程,分析了经链接器重定位之后的hello与hello.o的差别点,分析了hello与hello.o的elf文件的差别点,链接器重定位给hello程序定义了程序执行的虚拟地点,通过objdump反汇编hello得到了hello程序的执行过程,通过edb反汇编查察了hello到_start到call main,再到程序结束的全部过程及执行过程中调用的各个子程序,最后通过分析hello的动态链接过程得到了dl_init执行前后.got.plt的变化
第6章 hello进程管理
6.1 进程的概念与作用
概念:进程就是一个执行中程序的实例。体系中的每个程序都运行在某个进程的上下文中。上下文是由程序精确运行所需的状态构成的。这个状态包罗存放在内存中的程序的代码和数据,它的栈、通用目的寄存器地内容、程序计数器、情况变量以及打开文件描述符的聚集。
作用:进程提供给应用程序的关键抽象:一个独立的逻辑控制流,似乎我们的程序独占地利用处理器;一个私有的地点空间,似乎我们的程序独占地利用内存体系。
6.2 简述壳Shell-bash的作用与处理流程
作用:shell执行一系列的读/求值步调,然后终止。读步调读取来自用户的一个下令行。求值步调解析下令行,并代表用户运行程序。
处理流程:shell打印一个下令行提示符,等候用户在stdin上输入下令行,然后以空格为分隔解析下令行,假如是内部下令,则立即执行,假如是可执行目的文件,则fork创建子进程,并在子进程中用execve加载并运行此文件,&作为结尾时,shell在背景完成此进程,假如没有&,shell在前台运行此作业,等候子进程完成,然后shell开始下一轮迭代。
6.3 Hello的fork进程创建过程
父进程通过调用fork函数创建一个新的运行的子进程,fork函数在子进程中返回0,在父进程中返回子进程的PID。新创建的子进程几乎但不完全与父进程雷同。子进程得到与父进程用户级虚拟地点空间雷同但是独立的一份副本,包罗代码和数据段、堆、共享库以及用户栈。子进程还获得与父进程任何打开文件描述符雷同的副本。父进程和子进程最大的区别在于他们有差别的PID。父进程与子进程是并发运行的独立进程,内核能够以恣意方式交替执行它们的逻辑控制流中的指令。
6.4 Hello的execve过程
在shell给hello举行fork函数创建子进程之后,会调用execve函数,在子进程的上下文中加载并运行hello,调用_start创建新的且被初始化为0的栈,将控制给主函数main,并传入参数列表和情况变量列表。当出现错误时,exceve才会返回到调用程序,否则,exceve调用一次不返回。在exceve加载完毕可执行目的文件hello后,会调用启动代码,启动代码设置栈,将可执行目的文件中的代码和数据从磁盘复制到内存中,然后通过跳转到程序的第一条指令或入口点来运行该程序,由此将控制转移给新程序的主函数。
6.5 Hello的进程执行
当开始运行hello时,内核为hello分配时间片,当hello 执行到 sleep时,hello 会休眠,举行上下文切换,控制交付给其他进程,一段时间后再次上下文切换,恢复hello在休眠前的上下文信息,控制权回到 hello 继承执行。
6.6 hello的异常与信号处理
正常运行时:
https://i-blog.csdnimg.cn/blog_migrate/65bad4d9597f516c828f1e2beba4eaf4.png
恣意乱按:输入的信息在缓冲区中,随着回车按下与程序一起消散
https://i-blog.csdnimg.cn/blog_migrate/90b62ebc55c83a6f7c66b3901ccef47a.png
输入回车时:getchar()读走1个回车,剩余4个回车在终端输出
https://i-blog.csdnimg.cn/blog_migrate/12ebcd92c46ac77e38f3b6156b93ef2d.png
按Ctrl+Z:程序被挂起
https://i-blog.csdnimg.cn/blog_migrate/6fd3dbe72077041ca10711a83ebcfc9e.png
ps打印进程PID:
https://i-blog.csdnimg.cn/blog_migrate/6049790ba7c0a99641818040309ae28a.png
查察当前进程jobs:
https://i-blog.csdnimg.cn/blog_migrate/ba2e95d274547fcb42383009290edec3.png
用pstree -p查察相关进程关系:
https://i-blog.csdnimg.cn/blog_migrate/cf6a7ed6290cc3358fd27ae427dc8f85.png
https://i-blog.csdnimg.cn/blog_migrate/ec5e2bded8c0ea5777b3ea6744c736db.png
fg继承执行:
https://i-blog.csdnimg.cn/blog_migrate/73fadda137ee54aff4ace98a5695bfde.png
按下Ctrl+C:进程被终止
https://i-blog.csdnimg.cn/blog_migrate/51b63599397e0db719fbfca64e5d993c.png
查察ps:发现无hello进程
https://i-blog.csdnimg.cn/blog_migrate/c1df773ad56f81137e42a8145666d5ab.jpeg
6.7本章小结
本章介绍了进程的概念和作用,分析了调用fork函数,execve函数创建进程的过程,分析并测试了hello程序执行异常处理的机制。
第7章 hello的存储管理
7.1 hello的存储器地点空间
逻辑地点:程序产生的和段相关的偏移地点,由一个标识符加上一个指定段内的相对地点的偏移量构成
线性地点:段地点+偏移地点=线性地点,hello的反汇编文件中看到的地点中的偏移量,加上对应段的基地点,便得到了hello中内容对应的线性地点。
虚拟地点:利用虚拟寻址时,CPU通过天生一个虚拟地点来访问主存,这个虚拟地点在被送至内存前先转换成适当的物理地点。在linux中,虚拟地点数值树等于线性地点。
物理地点:指出目前CPU外部地点总线上的寻址物理内存的地点信号,用于内存级芯片的单位寻址,是地点变换的最终效果地点。
7.2 Intel逻辑地点到线性地点的变换-段式管理
一个逻辑地点由段标识符和段内偏移量两部门构成。段标识符是由一个16位长的字段构成,此中前13位是一个索引号,后3位是T1字段,索引号可以在描述符表中找到对应的描述符,TI指示段描述符是在GDT还是LDT中;通过索引号在描述符表内找到一个具体的段描述符。找到的段描述符加上偏移量即为线性地点。
7.3 Hello的线性地点到物理地点的变换-页式管理
线性地点(虚拟地点)由虚拟页号VPN和虚拟页偏移VPO构成。首先,MMU从线性地点中抽取出VPN,这时MMU把VPN解析为两部门(TLBI和TLBT),用TLBI索引TLB组,通过TLBT判断是否掷中,若掷中,则将PPN返回给MMU;若不掷中,则通过VPN查PTE表从内存中读取PPN,若PTE无效或不匹配,则产生缺页,举行缺页处理,然后再读取PPN,将PPN与VPO连接起来就得到了对应的物理地点。
7.4 TLB与四级页表支持下的VA到PA的变换
虚拟地点VA是有VPN和VPO构成的,通过VPN在TLB中查找,若掷中,则直接读取PPN;否则,将VPN划分为四片(VPN1,VPN2,VPN3,VPN4),VPN1、2、3、4分别提供L1、2、3、4 PTE的偏移量,前三级页表的PTE指向一个页表,第四级页表指向虚拟内存的一个页,从而在此中读取PPN,得到物理地点PA
https://i-blog.csdnimg.cn/blog_migrate/73b76953d3597aa22dfb8600ba1278fd.png
7.5 三级Cache支持下的物理内存访问
物理地点分为CT(Cache标记),CI(Cache索引),CO(块偏移)三部门,在L1 Cache中通过CI找到对应组,通过CT查察标记是否存在,再判断tag位是否有用,若掷中,则再通过CO偏移量得到对应的块;若未掷中,则将此物理地点对L2 Cache,L3 Cache直至内存举行雷同的操纵,直到掷中,然后将此地点内容向上一级返回,优先将目的块代替空闲块,否则驱逐缓存中的某些块来安放目的块。
7.6 hello进程fork时的内存映射
Hello进程fork时,内核为其创建一系列数据结构,并分配一个唯一的PID。对每个映射私有对象的进程,其私有区域的页表条目为只读,且每个区域结构为私有的写时复制,在没有进程试图写入其私有区域,每个映射私有对象的进程均共享物理内存中对象的单独副本。当有程序试图写页面时,写时复制机制会创造一个新页面,恢复其可写权限,然后更新页表条目指向新页面。
7.7 hello进程execve时的内存映射
execve函数在当前进程中加载并运行包含在可执行目的文件hello中的程序,用hello程序有用地替换了当出息序。加载并运行hello必要以下步调:
1.删除已存在的用户区域。
2.映射私有区域:为新程序hello的代码、数据、bss和栈区域创建新的区域结构。全部这些新的区域都是私有的、写时复制的。
3.映射共享区域:假如hello程序与共享对象链接,那么这些对象都是动态链接到这个程序的,然后再映射到用户虚拟地点空间中的共享区域内。
4.设置程序计数器(PC),指向代码的入口点
7.8 缺页故障与缺页停止处理
处理缺页是由硬件和操纵体系内核协作完成的。
首先,缺页处理程序确认出物理内存中的捐躯页,假如这个页已经被修改了,则把它写入磁盘,之后缺页处理程序页面调入新的页面,并更新内存中的PTE。然后缺页处理程序返回到原来的进程,再次执行导致缺页的下令CPU将引起缺页的虚拟地点重新发送给MMU。因为虚拟页面已经存在在物理内存中,以是掷中。
7.9动态存储分配管理
1.接纳显示空闲链表
计谋:LIFO后进先出法:将新开释的块放置在链表的开始处
或地点次序法:按地点次序维护链表
2接纳隐式空闲链表
计谋:利用malloc分配直至空间分配达到一定限度,然后标记全部从根节点可以访问到的块,扫描后解放全部没有标记的内存。
7.10本章小结
本章介绍了虚拟内存的相关内容,包罗hello的存储管理,段式管理和页式管理的寻址方法,TLB与四级页表下虚拟地点到物理地点的映射方法,以及三级Cache下的物理内存访问流程,以及hello进程中fork与execve的内存映射方式,分析了缺页处理的流程和动态存储分配管理的基本计谋与方法。
第8章 hello的IO管理
8.1 Linux的IO设备管理方法
一个Linux文件就是一个m字节的序列。全部的I/O设备都被模型化为文件,而全部的输入和输出都被当作对相应的文件的读和写来执行。这种方法允许Linux内核引出一个简单,低级的应用接口,成为Unix I/O,使得全部的输入和输出都能以一种同一且一致的方式来执行。
8.2 简述Unix IO接口及其函数
Unix IO一共实现了五个接口:打开文件,改变当前的文件位置,读文件,写文件和关闭文件。
打开文件:打开文件。一个应用程序通过要求内核打开相应的文件,来宣告它想要访间一个I/O 设备。内核返回一个小的非负整数,叫做描述符,它在后续对此文件的全部操纵中标识这个文件。打开文件可以利用函数open实现,int open(char *filename,int flags,mode_t mode),返回值为此文件的描述符数字
改变文件当前位置:对于每个打开的文件,内核保持着一个文件位置k,初始为 0。这个文件位置是从文件开头起始的字节偏移量。应用程序能够通过执行seek操纵,显式地设置文件的当前位置为k。
读写文件:一个读操纵就是从文件复制n>0个字节到内存,从当前文件位置k 开始,然后将k增加到k+n 。给定一个巨细为m字节的文件,当k>=m时执行读操纵会触发一个称为EOF的条件,应用程序能检测到这个条件。在文件结尾处并没有明确的“EOF符号”;写操纵就是从内存复制n>0个字节到一个文件,从当前文件位置k开始,然后更新k。读写文件的函数是read和write,原型为ssize_t read(int fd, void *buf, size_t n)和ssize_t wirte(int fd, const void *buf, size_t n),read函数从fd文件读最多n个字节到buf,返回-1表示错误,0表示为EOF,整数表示读取的字节数目,write从内存buf中复制最多n个字节到文件描述符fd的文件处。
关闭文件:应用完成了对文件的访问之后,它就关照内核关闭这个文件。作为相应,内核开释文件打开时创建的数据结构,并将这个描述符恢复到可用的描述符池中。无论一个进程因为何种缘故原由终止时,内核都会关闭全部打开的文件并开释它们的内存资源。利用函数close关闭文件,原型为int close(int fd)
8.3 printf的实现分析
printf函数原型:
int printf(const char *fmt, ...)
{
int i;
char buf;
va_list arg = (va_list)((char*)(&fmt) + 4);
i = vsprintf(buf, fmt, arg);
write(buf, i);
return i;
}
此中va_list的定义:typedef char *va_list,这说明它是一个字符指针,而(&fmt)+4表示了传入pirntf的第二个参数,即...中的第一个参数,以是arg指向...中的第一个参数。
vsprintf返回的是要打印出来的字符串的长度,它接受确定输出格式的格式字符fmt。用格式字符串对个数变化的参数举行格式化,产生格式化输出。
追踪write:
write:
mov eax, _NR_write
mov ebx,
mov ecx,
int INT_VECTOR_SYS_CALL
一个int INT_VECTOR_SYS_CALL表示要通过体系来调用sys_call这个函数
sys_call:
call save
push dword
sti
push ecx
push ebx
call
add esp, 4 * 3
mov , eax
cli
ret
一个call save,是为了生存停止前进程的状态,然后实现显示格式化了的字符串,通过字符显示驱动子程序,从ASCII到字模库到显示vram显示芯片按照革新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点,于是打印字符串就显示在了屏幕上。
8.4 getchar的实现分析
异步异常-键盘停止的处理:当用户按键时,键盘接口会得到一个代表该按键 的键盘扫描码,同时产生一个停止请求,停止请求抢占当前进程,运行键盘停止子程序。键盘停止子程序先从键盘接口取得该按键的扫描码,然后将该按键扫描码转换成ASCII码,生存到体系的键盘缓冲区。
当程序调用getchar()时,它会等候用户按键来输入字符。用户输入的字符被存放在缓冲区中,直到用户按了回车键,这时getchar()才会从stdio流中读入一个字符。getchar函数的返回值是用户输入的字符的ASCII码,若出错返回-1,且将用户输入的字符回显到屏幕.若用户在按回车之前输入了不止一个字符,其他字符会保留在键盘缓存区中,等候后续getchar调用读取,后续的getchar调用不会等候用户按键,而直接读取缓冲区中的字符,直到缓冲区中的字符读完为后,才等候用户按键。
8.5本章小结
本章主要介绍了Linux的IO设备管理方法,介绍了Unix I/O 接口的概念和对应的函数,然后分析了printf函数和getchar函数的实现。
结论
hello的一生经历了两个主要阶段,P2P和020
首先,编写代码,存入文本文件hello.c
然后,利用预处理器cpp将hello.c预处理为hello.i,这一步完成了宏替换,删除表明,处理#include指令,引入对应文件的过程
然后,利用编译器ccl将文本文件hello.i编译为汇编文件hello.s,这一步实现了由高级语言(C语言)到程序级语言(二进制文件)的过渡状态,即汇编语言,且对程序举行了初步的优化
之后,利用汇编器as将hello.s汇编语言处理成二进制文件hello.o,真正实现了高级语言到呆板语言的转化,并为链接器提供了重定位节的标记。
最后,利用链接器ld将可重定位目的文件hello.o与其他目的文件和链接库合并,举行符号解析和重定位操纵,天生可执行目的文件hello
至此,hello完成了它生掷中的第一个阶段,P2P:From Program to Process
随后,在shell中运行hello,输入三个参数,
shell进程调用fork创建一个子进程,再调用execve启动加载器加载hello,为其分配虚拟内存空间,创建新的内存区域,并创建一组新的代码、数据、堆和栈段,MMU将虚拟内存空间映射到物理内存空间,然后进入main函数执行目的代码。
CPU为运行的hello分配时间片,执行逻辑控制流。
程序结束后,shell父进程回收子进程hello,内核清理与hello相关的数据
最终,hello完成了它生掷中的最后一个阶段,020:From Zero to Zero
程序就像生命一样,每一个看似简单的程序都是经过前人一步步缜密而又奇妙的计划而诞生的,使计算机的各个软硬部件都能做到各司其职,各尽其能。
附件
hello.i hello.c经过预处理得到的文本文件
hello.s hello.i经过编译得到的汇编文件
hello.o hello.s经过汇编得到的二进制文件,执行呆板级代码
hello.elf hello.o的elf格式,用于分析hello.o
objdump.txt hello.o的反汇编文件
hello hello.o经过链接得到的可执行文件
hello2.elf hello的elf格式,用于分析hello
objdump2.txt hello的反汇编文件
参考文献
林来兴. 空间控制技术. 北京:中国宇航出版社,1992:25-42.
辛希孟. 信息技术与信息服务国际研讨会论文集:A集. 北京:中国科学出版社,1999.
赵耀东. 新时代的工业工程师. 台北:天下文化出版社,1998 . http://www.ie.nthu.edu.tw/info/ie.newie.htm(Big5).
谌颖. 空间交会控制理论与方法研究. 哈尔滨:哈尔滨工业大学,1992:8-13.
KANAMORI H. Shaking Without Quaking. Science,1998,279(5359):2063-2064.
CHRISTINE M. Plant Physiology: Plant Biology in the Genome Era. Science,1998,281:331-332. http://www.sciencemag.org/cgi/ collection/anatmorp.
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]