HIT-ICS-程序人生——Hello‘s P2P
https://img-blog.csdnimg.cn/direct/3d6bb3a7324948f7bcfc9a09dfa05b50.jpeg
计算机体系
大作业
题 目 程序人生-Hello’s P2P
专 业 未来技术学院人工智能领域
学 号 2022113616
班 级 22wl028
学 生 宋旭文
指 导 教 师 郑贵滨
计算机科学与技术学院
2024年5月
摘 要
Hello.c程序是C语言中最简单的一个程序,通常是初学者开始编写的程序之一。然而,在这个简单代码的背后却蕴含着人类的巨大智慧。本文聚焦于hello的一生,包罗hello.c经过预处理、编译、汇编和链接之后,最终形成可执行程序hello,hello在历程中加载、运行和接纳,分析了hello一个生命周期中的所有经历,涉及了从基于天然语言的高级程序到呆板可辨认的二进制代码的转换过程,以及虚拟地址到物理地址的转化过程,通过对hello的分析,揭示计算机体系底层的工作机制。
关键词:计算机体系;Linux;程序;编译;汇编;链接;历程管理;I/O管理;
(摘要0分,缺失-1分,根据内容精彩称都酌情加分0-1分)
目 录
第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简介
根据Hello的自白,利用计算机体系的术语,简述Hello的P2P,020的整个过程。
1、P2P过程
程序员编写C语言源代码(.c文件),实现想要的功能。gcc通过调用预处理器cpp、编译器cc1、汇编器as、链接器ld将.c文件进行预处理、编译、汇编和链接,最终天生hello可执行目的文件,保存在磁盘中。在bash中,操作体系通过解析用户输入的命令,在磁盘中(虚拟地址空间)找到可执行文件hello并确认用户是否具有执行权限,然后将hello加载到物理内存中,最终作为历程在计算机体系中运行。
2、020过程
020 过程是 hello 可执行目的程序从运行到最后被接纳的过程。在 Shell 中运行该程序时,Shell 调用 fork 函数创建子历程。创建完毕后,操作体系内核提供的 execve 函数会创建虚拟内存的映射,即 mmp,然后开始加载物理内存,进入到 main 函数当中执行相干的代码,打印出信息。在历程中,TLB、4级页表、3级 Cache,Pagefile等筹划会加快程序的运行。程序运行完成后,Shell 接纳子历程,操作体系内核删除相干数据结构,释放其占据的资源。至此,hello 的一生就竣事了。
1.2 情况与工具
1.2.1硬件情况
https://img-blog.csdnimg.cn/direct/45b9f1c7478f46fd8a7a519166396a43.png
图1-1 硬件情况
处理器 13th Gen Intel(R) Core(TM) i5-13500H 2.60 GHz
机带 RAM 32.0 GB (31.7 GB 可用)
体系范例 64 位操作体系, 基于 x64 的处理器
1.2.2操作体系
Windows 11、VirtualBox/Vmware 11以上;Ubuntu 18.04 LTS 64位/优麒麟 64位;
1.2.3开辟工具
Vim、gcc、gdb、edb
1.3 中心结果
列出你为编写本论文,天生的中心结果文件的名字,文件的作用等。
文件
作用
hello.c
源代码
hello.i
预处理后的代码
hello.s
汇编代码
hello.o
可重定位目的文件
hello
链接后的可执行目的文件
hello.txt
Hello的反汇编代码
表1-1 中心结果文件及作用
1.4 本章小结
本章概述了hello的P2P和O2O的过程。此外,还介绍了本实行用到的硬软件情况和开辟调试工具,最后介绍了本次实行的中心结果文件。
(第1章0.5分)
第2章 预处理
2.1 预处理的概念与作用
2.1.1概念
预处理是指在编译源代码之前执行的一系列操作,如包含文件、宏替换、条件编译、删除注释等,由预处理器cpp来完成。
2.1.2作用
预处理器通过对源代码进行一系列的预处理操作,可以提高代码的灵活性、可维护性和可读性,同时也可以或许优化编译过程,提高编译效率。
2.2在Ubuntu下预处理的命令
Linux下使用gcc预处理的命令为:
gcc -E hello.c -o hello.i
https://img-blog.csdnimg.cn/direct/5d958f2818444cacb0dd51c3afb18c60.png
图2-1 预处理命令
2.3 Hello的预处理结果解析
2.3.1团体
在Linux上打开文件,hello.c文件只有24行,而hello.i文件有3061行。
https://img-blog.csdnimg.cn/direct/8b7179c678e440378ff8c123f88b20db.png
https://img-blog.csdnimg.cn/direct/da8debe0ad4b455b954caa79a3482c14.png
图2-2 hello.c和hello.i的行数
2.3.2包含其他文件
文件开头有一系列的外部库.h文件路径
https://img-blog.csdnimg.cn/direct/1f04d40c850b4e9c8080f80f0621a178.png
图2-3 hello.i包含.h文件路径
2.3.3替换数据范例名称
接下来是一系列typedef,前面的名称是编写代码时使用的标准数据范例,而反面的那些名称就是上述引入的头文件中使用的范例界说。
https://img-blog.csdnimg.cn/direct/fe1811ecbf424b2692720ce8acaae6ac.png
图2-4 hello.i替换范例名称
2.3.4声明内部函数
中心部门是头文件内部函数的声明。
https://img-blog.csdnimg.cn/direct/6c47790a0d64473285f33c4eb7e653d5.png
图2-5 hello.i包含头文件内部函数声明
2.3.5代码段
.c文件中的代码被放到了文件末尾。
https://img-blog.csdnimg.cn/direct/34ba78165eb04db3b2c9afca55aef235.png
图2-6 hello.i的代码段
2.4 本章小结
本章介绍了 hello.c 的预处理概念及作用,并分析了预处理后的文件 hello.i。
从程序员的角度来说,利用宏界说指令可以让我们轻松写出可读性更好的代码,利用条件编译指令可以让我们更加方便快捷的调试代码。
从hello程序的角度来说,hello.c 是残破的,不完整的,预处理阶段使它健全了四肢,得以最终运行在操作体系的上下文中。
(第2章0.5分)
第3章 编译
3.1 编译的概念与作用
3.1.1概念
编译是指将源代码文件转换为目的代码文件的过程。在这个过程中,编译器cc1会对源代码进行语法分析等操作,并天生于目的平台相干的呆板语言,宜宾啊计算性可以或许执行。
3.1.2作用
编译过程可以将高级语言转换为呆板语言,天生.s文件。不仅云云,编译过程还可以优化代码、检查错误,以提高程序性能。
3.2 在Ubuntu下编译的命令
Linux下使用gcc编译的命令为:
gcc -S hello.i -o hello.s
https://img-blog.csdnimg.cn/direct/5f99c917ad2340acb39a86d425d479b4.png
图3-1 编译命令
3.3 Hello的编译结果解析
3.3.1常量
1、字符型常量
字符串常量存储在.LC0中
https://img-blog.csdnimg.cn/direct/ec704213a17f4792bd7b38f13481148e.png
图3-2-1 hello.c中字符型常量
https://img-blog.csdnimg.cn/direct/1f86a711f0e046df8ab1cb6cd21fa5e7.png
图3-2-2 hello.s中字符型常量
2、其他常量
直接以立刻数的形式出现,例如这段代码中有一个整型常量5,在汇编代码中表示为$5。
https://img-blog.csdnimg.cn/direct/60aecdaa180d4313935596140790cebd.png
图3-3-1 hello.c中立刻数
https://img-blog.csdnimg.cn/direct/7a976784fc6a4485bf94a6b99e305ca9.png
图3-3-2 hello.s中立刻数
3.3.2变量及运算
1、局部变量
在主函数中有一个局部变量i,存储在寄存器或栈中。在汇编代码中,有一条入栈指令pushq %rbp,因此可以看出,i存在栈中。
https://img-blog.csdnimg.cn/direct/a801af398b0d494481ccea8eabec771f.png
图3-4-1 hello.c中的局部变量
https://img-blog.csdnimg.cn/direct/573c016c3dff42148aa49b8b4c1613c4.png
图3-4-2 hello.s中的局部变量
2、算术运算
在for循环中,局部变量i每循环一次就加一,在汇编代码中通过addl指令来实现。
https://img-blog.csdnimg.cn/direct/b4fa7f28dbb24d32ac58734fc4872e8c.png
图3-5-1 hello.c中的算术运算
https://img-blog.csdnimg.cn/direct/5e4aaf2f40d24467998bd26c9ed5f938.png
图3-5-2 hello.s中的算术运算
3.3.3数组/指针操作
函数中将字符串数组argv作为第二个参数,printf函数中用到了argv、argv、argv。在汇编代码中,%rcx、%rdx、%rax分别是第一、二、三个参数寄存器,分别存储argv、argv、argv,也就是说,%rbp-8所指向的栈空间中存的内容是argv的地址,%rbp-16所指向的栈空间中存的内容是argv的地址,%rbp-24所指向的栈空间中存的内容是argv的地址。
https://img-blog.csdnimg.cn/direct/4830670f0f574dadbac8cc502c558e61.png
图3-6-1 hello.c中的数组/指针操作
https://img-blog.csdnimg.cn/direct/784d319f583e4c8294f12d2d5a078982.png
图3-6-2 hello.s中的数组/指针操作
3.3.4控制转移
在for循环中,局部变量i每加一,就必要在循环开头判断i是否小于10,假如不满意小于10的条件,即i即是10时,跳出循环。在汇编代码中接纳cmpl指令比较i和立刻数9的大小,假如小于即是就跳转到循环内部代码。
https://img-blog.csdnimg.cn/direct/9f8b8cefc5e04e13a0542ee62019ef24.png
图3-7-1 hello.c中的控制转移
https://img-blog.csdnimg.cn/direct/a7d1991132664085a7f63bd4a16ff082.png
图3-7-2 hello.s中的控制转移
3.3.5函数
1、main函数
参数为 argc和 argv,是体系调用的且从 Shell 中传入,返回值设置为 0。
2、printf函数
通过设置寄存器%rsi、%rdi的值来传入和调用参数。
https://img-blog.csdnimg.cn/direct/56959e3731d04613935a058787813c8a.png
图3-8 printf函数的汇编代码
3、exit函数
通过设置寄存器%rsi、%rdi的值来传入和调用参数。
https://img-blog.csdnimg.cn/direct/8883d28acdf145929ca4cf898598753b.png
图3-9 exit函数的汇编代码
4、sleep函数
通过设置寄存器%rdi的值来传入和调用参数。
https://img-blog.csdnimg.cn/direct/aaaf4c0a804f4cf4bcd76bf3f5b04743.png
图3-10 sleep函数的汇编代码
5、atoi函数
将一个字符串的首地址存在寄存器%rdi中,通过%rdi来传入和调用参数,函数将该字符串转成的整数值返回到寄存器%eax中。
https://img-blog.csdnimg.cn/direct/af2592055562444f83e0b4f7bd00b57b.png
图3-11 atoi函数的汇编代码
6、getchar函数
无参数、无返回值。
3.4 本章小结
本章介绍了从 hello.i 文件编译成 hello.s 文件的过程,以及 .c 文件中各部门变量、常量、控制转移以及函数调用在汇编代码中相对应的样子。
(第3章2分)
第4章 汇编
4.1 汇编的概念与作用
汇编就是汇编器as将 hello.s 翻译成呆板语言指令,把这些指令打包成可重定位目的程序的格式,并将结果保存在二进制文件 hello.o 中。
4.2 在Ubuntu下汇编的命令
在Linux中使用gcc汇编的指令为:
gcc -C hello.s -o hello.o
https://img-blog.csdnimg.cn/direct/2adeecaef2c540d6b41a8063883eb9b5.png
图4-1 汇编指令
4.3 可重定位目的elf格式
4.3.1分析hello.o的ELF格式
可重定位目的文件的elf格式如下:
https://img-blog.csdnimg.cn/direct/226b397f21f14da6aa3f8ee46414c551.png
图4-2 可重定位目的文件elf格式
4.3.2用readelf等列出其各节的根本信息
1、ELF头
用readelf -h hello.o指令检察ELF头。
EFL 头以 16 字节的序列 Magic 开始,这个序列描述了天生该文件的体系字的大小和字节次序,ELF 头剩下的部门包含资助链接器语法分析和表明目的文件的信息,其中包罗 ELF 头的大小、目的文件的范例、呆板范例、字节头部表的文件偏移,以及节头部表中条目的大小和数量等信息。
EFL头中还包罗程序的入口点,也就是程序运行时要执行的第一条指令的地址为 0x0,通过hello.o 的反汇编代码可以看出,程序的入口点地址确实是0x0。
https://img-blog.csdnimg.cn/direct/68d24e9a11d74caf8b459d5cb8d6c5d4.png
图4-3 hello.o的elf头
https://img-blog.csdnimg.cn/direct/bec03c9d66604b6d97b7337e595b6d71.png
图4-4 main函数的反汇编代码
2、节头部表
用readelf -S hello.o检察ELF的节头部表。
每个节都包含了特定范例的数据,如代码、数据、符号表、重定位信息等。节头部表提供了有关这些节的元数据,包罗节的位置、大小、标记等。由于这是可重定位目的文件,为了方便后续的内存映射,各个节的地址均从0开始。
它还用flags描述各个节的读写权限。
https://img-blog.csdnimg.cn/direct/dca3f9bfbe044bf8b3b4c139d6c03006.png
图4-5 hello.o的节头部表
3、符号表
用readelf -s hello.o指令检察.symtab节中的ELF符号表。
.symtab节存储了程序中使用的各种标识符(如变量、函数、类等)的信息,提供了这些标识符的定名、范例等,如main函数、printf函数。
https://img-blog.csdnimg.cn/direct/82798bd67d5a4bf3b11e10077abea55a.png
图4-6 hello.o的符号表
4、重定位条目
用readelf -r hello.o指令检察重定位条目。
当hello.o中某一模块引用另一模块界说的函数或全局变量时,重定位条目告诉链接器应该怎样修改代码或数据段中的地址,使其精确指向目的符号的位置,使得程序可以在运行时顺利地连接各个模块并精确访问全局变量和函数。
https://img-blog.csdnimg.cn/direct/ea9ce007256e4accbc2ab9c0ddba427b.png
图4-7 hello.o的重定位条目
4.4 Hello.o的结果解析
用objdump -d -r hello.o指令检察hello.o的反汇编。
https://img-blog.csdnimg.cn/direct/828ef4cc9126408b80f3367b5033fa02.png
https://img-blog.csdnimg.cn/direct/1849add8603d4c48ac0bb7bb9f88cb7b.png
图4-8 hello.o的反汇编代码
与第3章的 hello.s进行对照来看,在 hello.s 中,分支跳转的目的位置是通过 .L1、.L2 这样的助记符来实现的,而 hello.o中,跳转的目的位置是指令的地址;在 hello.s 中,call 反面的目的函数是它的函数名,而在 hello.o 中,call 的是目的函数的相对偏移地址。
呆板语言是由操作码、操作数、寻址方式和控制信息构成的。操作码是指令中用来表示操作范例的部门,指定了要执行的操作,如加法、减法、移动数据等。操作数是指令中用来表示操尴尬刁难象或操作数据的部门,它可以是寄存器、内存地址或立刻数等。寻址方式指定了怎样找到操作数在内存中的实际位置,常见的寻址方式包罗直接寻址、间接寻址、寄存器间接寻址、相对寻址等。控制信息用于控制程序的执行流程和决定。
呆板语言和汇编语言是逐一对应的关系,汇编语言中的每个助记符都对应着一条特定的呆板语言指令,这些助记符通常与呆板语言指令的操作码相对应。
4.5 本章小结
本章分析了汇编的过程,并分析了 ELF 头、节头部表、符号表以及重定位条目,同时还比较了 hello.s 和 hello.o 反汇编之后的代码的不同。
(第4章1分)
第5章 链接
5.1 链接的概念与作用
5.1.1概念
链接是指将多个目的文件或库文件归并为一个可执行程序或共享库的过程。链接器ld是负责执行链接操作的工具。
5.1.2作用
链接的过程会解析符号引用,将代码和数据的相对地址转换成精确的绝对地址,将程序的目的文件与程序所依赖的外部函数库文件链接,节省了空间并提高了代码的重用性。
5.2 在Ubuntu下链接的命令
在Linux上使用ld的链接命令为:
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-blog.csdnimg.cn/direct/a8e8bea16bfe47b3965b82ba8aafbebf.png
图5-1 链接命令
5.3 可执行目的文件hello的格式
5.3.1hello的ELF格式
https://img-blog.csdnimg.cn/direct/a7051f1687094785ae6771d0b1792312.png
图5-2 可执行文件的elf格式
5.3.2各段信息
1、ELF头
用readelf -h hello指令检察可执行目的文件的ELF头。
程序入口分配到了地址,变成0x4010f0,文件范例从REL变成了可执行文件EXEC。
https://img-blog.csdnimg.cn/direct/5de387a1af454804a9bfddc882162247.png
图5-3 hello的elf头
2、节头部表
用readelf -S hello指令检察节头部表。
链接器将各个文件对应的段归并,并重新分配和计算相应节的范例、位置和大小等信息。
各个节的地址也从 0变成了详细的值。可以看到 .text 节的起始地址为 0x4010f0,与程序入口地址雷同,与 .text 中存放程序的呆板代码符合。
https://img-blog.csdnimg.cn/direct/55b1158cf1d644a68ebf24d62536d06b.png
https://img-blog.csdnimg.cn/direct/98b1013510ad441a8b9be8a42516ee7c.png
图5-4 hello的节头部表
3、符号表
用readelf -s hello指令检察hello的符号表。
与hello.o的符号表相比,hello的符号表多了.dynsym动态链接节。
https://img-blog.csdnimg.cn/direct/40ad02541c654892adeb7521da138e52.png
图5-5 hello的符号表
4、重定位条目
用readelf -r hello指令检察重定位条目。
可以看出,与hello.o的重定位条目相比,hello的重定位条目被分成两部门,代码重定位条目放在 .rela.plt 中,已初始化数据的重定位条目放在 .rela.dyn中。同时每一部门均有了精确的偏移量。
https://img-blog.csdnimg.cn/direct/5130812e7cf741daac28f2b1c2f0808b.png
图5-6 hello的重定位条目
5.4 hello的虚拟地址空间
使用edb加载hello,检察本历程的虚拟地址空间各段信息。
可以看到,hello的虚拟地址起始为0x401000,检察hello的反汇编代码可知,起始地址0x401000对应的是init。
https://img-blog.csdnimg.cn/direct/6f224bb6a30347ebb3b141ebb9b5c9e2.png
图5-7 init函数的反汇编代码
5.5 链接的重定位过程分析
5.5.1检察反汇编代码
用objdump -d -r hello 检察hello的反汇编代码
https://img-blog.csdnimg.cn/direct/057971800aaf4bc79e7d84aee0fa2221.png
图5-8 hello的反汇编代码
5.5.2分析与hello.o的不同
1、新增函数
链接之后,参加了许多必要用到的库函数,如puts、printf等。
https://img-blog.csdnimg.cn/direct/44c9635aaff144358e95e6f3743c77bf.png
图5-9 hello反汇编代码中新增库函数
2、新增节
增长了.init节和.plt节,.init 节用于执行一些初始化操作,而 .plt 节则用于实现函数调用的延迟绑定,支持动态链接。
https://img-blog.csdnimg.cn/direct/87bd92d25c6142a38fc0724371af720f.png
图5-10 hello反汇编代码中新增节
3、新增代码endbr64
可以观察到,在hello的反汇编代码中endbr64这句反复出现。endbr64 指令通常由编译器大概体系库自动天生,而且在一般情况下,程序员不必要直接操作这个指令。它是作为体系安全增强的一部门,通过编译器和操作体系的支持来实现对抗特定范例攻击的目的。
https://img-blog.csdnimg.cn/direct/577f3fb7f9c44cdc979b4959c2216858.png
图5-11 hello反汇编代码中新增endbr64
4、函数调用与跳转
由于hello文件是已经重定位后的可执行文件,所以call和jmp语句后的目的地址都是确切的虚拟地址。
https://img-blog.csdnimg.cn/direct/56bff909c63c4e0a93647a243fb3d6d6.png
图5-12 hello反汇编代码中的函数调用与跳转
5.6 hello的执行流程
使用gdb执行hello。程序入口为0x4010f0,程序先从_start开始执行。在_start处设置一个断点,然后开始单步调试运行。程序执行完_start函数后,来到__libc_start_main,向main函数传递参数,然后才调用main函数。
https://img-blog.csdnimg.cn/direct/4932e5a929084a75b4d311a243c3ec7b.png
https://img-blog.csdnimg.cn/direct/c1526e2939fe4e6696a5a4bc606f1f01.png
图5-13 使用gdb执行hello
其调用与跳转的各个子程序名为:_start(0x4010f0),_init(0x401000),main(0x40112d),puts@plt(0x401090),exit@plt(0x4010d0),_finl(0x4011c0),sleep@plt(0x4010e0),atoi@plt(0x4010c0),printf@plt(0x4010a0)。
5.7 Hello的动态链接分析
在进行动态链接前,首先辈行静态链接,天生部门链接的可执行目的文件 hello。此时共享库中的代码和数据没有被归并到 hello 中。只有在加载 hello 时,动态链接器才对共享目的文件中的相应模块内的代码和数据进行重定位,加载共享库,天生完全链接的可执行目的文件。
使用edb检察_GLOBAL_OFFSET_TABLE 的内容。
https://img-blog.csdnimg.cn/direct/1ce96ef34f304e4399e54a424a5dd5dd.png
图5-14 使用edb检察_GLOBAL_OFFSET_TABLE
在dl_init前后,地址值发生改变。当调用一个动态链接库中的函数时,该地址内容值会发生变化,使其跳转到所调用的对应的函数地址处。
https://img-blog.csdnimg.cn/direct/a1b019e721254ad0828cf38eaa9e9b69.png
图5-15-1 dl_init前的地址值
https://img-blog.csdnimg.cn/direct/8dbb19599ee94c22995ffde5542c0fac.png
图5-15-2 dl_init后的地址值
5.8 本章小结
本章详细介绍了 hello 的链接过程,比较链接后的 hello 与 hello.o 的不同,最后使用 gdb 工具逐行检察 hello 的运行过程。
(第5章1分)
第6章 hello历程管理
6.1 历程的概念与作用
6.1.1概念
历程是计算机中正在运行的程序的实例。每个历程都有自己独立的内存空间,包罗代码、数据和堆栈,以及其他体系资源的拷贝,如打开的文件、网络连接等。操作体系通过调度算法来分配处理器时间给不同的历程,从而实现多任务并发执行。
6.1.2作用
历程是操作体系中的核心概念,它使得计算机可以同时执行多个任务,而且有效地管理体系资源,从而实现高效的并发执行和多任务处理。
6.2 简述壳Shell-bash的作用与处理流程
Shell 是一种命令行表明器,它是用户与操作体系内核之间的接口。Bash(Bourne Again Shell)是一种常见的 Unix/Linux 体系下的 shell 表明器。Shell-Bash使得用户可以或许方便地与操作体系交互,执行命令、管理情况变量、重定向输入输出、进行条件判断和循环等。
当用户在命令行中输入命令后,Shell-Bash 的处理流程大致如下:
1. 读取输入:Shell-Bash 会读取用户在命令行输入的内容,包罗命令、参数和操作符等。
2. 解析命令:Shell-Bash 对输入的命令进行解析,包罗辨认命令名称、参数、操作符(如重定向符号、管道符号等)、变量替换等。
3. 查找命令:Shell-Bash 会在体系的执行路径中(通常是 PATH 情况变量所指定的路径列表)查找用户输入的命令。假如找到了对应的可执行文件,就准备执行该命令。
4. 创建子历程:假如找到了要执行的命令,Shell-Bash 将创建一个新的子历程来执行该命令。这样可以保持 Shell 历程的稳固性,纵然子历程发生错误也不会影响到 Shell 历程自己。
5. 执行命令:在新创建的子历程中,Shell-Bash 会加载并执行对应的可执行文件。假如是内置命令(例如 cd、echo 等),则由 Shell-Bash 自己来执行,不必要创建新的子历程。
6. 等待命令执行完毕:Shell-Bash 会等待子历程执行完毕,并网络子历程的返回状态码。根据返回状态码来判断命令执行的结果是成功照旧失败。
7. 处理输入输出重定向:假如命令中包含了输入输出重定向操作符(如 >、>>、<、| 等),Shell-Bash 会根据这些符号来调整命令的输入输出流。
8. 显示输出:最后,Shell-Bash 会将命令执行的结果输出到标准输出设备,供用户检察。
6.3 Hello的fork历程创建过程
Hello程序的fork历程创建过程如下:
1. 在运行Hello程序之前,操作体系会为该程序创建一个父历程。父历程是指在执行fork体系调用之前已经存在的历程。
2. 当Hello程序中遇到fork体系调用时,操作体系会创建一个新的子历程。子历程是通过复制父历程的副原来创建的。
3. 在创建子历程时,操作体系将父历程的所有资源(包罗代码、数据、打开的文件、堆栈等)复制到子历程的地址空间中。
4. 然后,操作体系为子历程分配一个唯一的历程ID(PID),用于标识该历程。
5. 子历程的代码从fork体系调用的下一条语句开始执行,而父历程则继续执行原来的代码。这样,就实现了父历程和子历程的并发执行。
6. fork体系调用的返回值不同,对于父历程,fork体系调用返回子历程的PID;对于子历程,fork体系调用返回0。这样可以通过返回值来区分父历程和子历程。
7.父历程和子历程之间相互独立运行,它们有各自独立的地址空间和资源。子历程可以修改自己的地址空间和资源,而不会影响到父历程。
8. Hello程序中的父历程和子历程可以继续执行各自的逻辑,输出各自的结果。
https://img-blog.csdnimg.cn/direct/af153e7f6bb54262b9914372d4362637.png
图6-1 fork函数
6.4 Hello的execve过程
当一个程序调用execve函数时,操作体系会执行以下过程:
1. 加载可执行文件:execve函数将hello文件的路径作为参数,操作体系首先会根据路径找到对应的可执行文件hello,并将其加载到内存中。
2. 创建新的地址空间:操作体系会它创建一个新的地址空间,该地址空间将用于存储程序的代码、数据、堆栈等信息。这个新的地址空间会替换当前历程的地址空间。
3. 初始化程序的上下文:操作体系会初始化程序的上下文,包罗清空寄存器、设置堆栈指针、设置程序计数器等。这些操作确保了程序在开始执行时处于一个清晰的状态。
4. 转移控制权:一旦新的地址空间和程序上下文准备就绪,操作体系会将控制权转移到新加载的程序,使其开始执行。这意味着原来的程序代码、数据和堆栈都将被替换为新程序的内容。
5. 执行hello程序:一旦控制权转移到新程序,操作体系会开始执行新程序的代码。
https://img-blog.csdnimg.cn/direct/aac27d179a9443bd94bd5bfc1a8bbf1a.png
图6-2 execve函数流程
6.5 Hello的历程执行
6.5.1 逻辑控制流
操作体系将一个 CPU 物理控制流,分成多个逻辑控制流,每个历程独占一个逻辑控制流。当一个逻辑控制流执行的时候,其他的逻辑控制流大概会临时停息执行。一般来说,每个逻辑控制流都是独立的。当两个逻辑控制流在时间上发生重叠,我们说是并行的。
处理器在多个历程中往返切换称为多任务,每个时间当处理器执行一段控制流称为时间片。因此多任务也指时间分片。
6.5.2 用户模式和内核模式
为了限制一个应用可以执行的指令以及它可以访问的地址空间范围,处理器用一个控制寄存器中的一个模式位来描述历程当前的特权。
用户模式:用户模式中的历程不允许执行特权指令,好比停止处理器、改变模式位,大概发起一个 I/O 操作。也不允许用户模式的历程直接引用地址空间中内核区内的代码和数据。用户程序必须通过体系调用接口间接地访问内核代码和数据。
历程从用户模式变为内核模式的唯一方法是通过诸如中断、故障大概陷入体系调用这样的非常。当非常发生时,控制传递到非常处理程序,处理器将模式从用户模式变为内核模式。处理程序运行在内核模式中,当它返回到应用程序代码时,处理器就把模式从内核模式改回到用户模式。
6.5.3 上下文切换
操作体系内核为每个历程维护一个上下文。所谓上下文就是内核重新启动一个被抢占的历程所需的状态。它由一些对象的值构成,这些对象包罗通用寄存器、浮点寄存器、程序计数器、用户栈、状态寄存器、内核栈和各种内核数据结构,好比描述地址空间的页表,包含有关当前历程信息的历程表,以及包含历程已打开文件的信息的文件表。
https://img-blog.csdnimg.cn/direct/db6b8124d5e04defa49ab8e85fd8967b.jpeg
图6-3 上下文切换
6.5.4 hello 的执行
从 Shell 中运行 hello 时,它运行在用户模式。运行过程中,内核不停切换上下文,使运行过程被切分成时间片,与其他历程交替占用执行,实现历程的调度。假如在运行过程中收到信号等,那么就会进入内核模式,运行信号处理程序,之后再返回用户模式。
6.6 hello的非常与信号处理
6.6.1非常
hello执行过程中会出现四类非常:中断、陷阱、故障和终止。
[*]中断(Interrupt):
特点:由硬件大概其他外部设备引起,打断当前程序的正常执行流程。
例子:定时器中断、I/O设备中断等。
目的:允许操作体系与外部设备进行交互,处理外部变乱。
https://img-blog.csdnimg.cn/direct/6605165170304ea3bf9fc836cf53df86.png
图6-4 中断
[*]陷阱(Trap):
特点:由当前运行的程序主动触发,通常用于执行体系调用大概软中断。
例子:体系调用、断点调试等。
目的:提供一种用户空间向内核空间进行转换的手段,以便执行特权指令或哀求操作体系提供服务。
[*]故障(Fault):
特点:由当前运行的程序引起的可恢复非常,例如页面错误(Page Fault)。
例子:缺页故障、缓存未命中等。
目的:让程序可以或许处理一些特殊情况,例如虚拟内存的页面错误必要操作体系进行页面置换。
4. 终止(Abort):
特点:由当前运行的程序引起的不可恢复非常,导致程序被终止。
例子:除数为零、非法指令等。
目的:掩护体系免受严峻错误的影响,确保不良行为不会对体系造成陵犯。
6.6.2信号
Linux中的信号如下图:
https://img-blog.csdnimg.cn/direct/9872ddd993824b72b95535e5fac87866.png
图6-5 常见信号图
在hello运行过程中,测试其中部门信号。
SIGSTP:当 hello 在前台运行时,按下 Ctrl+z 会向它发送 SIGSTP 信号,这个历程就会暂时挂起,可以使用 fg %<pid> 命令,让它在前台继续执行:
https://img-blog.csdnimg.cn/direct/734710dc7ee74216b5d9efaad1b6dcb5.png
图6-6 测试SIGSTP信号
SIGINT:当 hello 在前台运行时,按下 Ctrl+c 会向它发送 SIGINT 信号,这个历程就会被终止:
https://img-blog.csdnimg.cn/direct/1d19f17615374f6388d142ed673676ec.png
图6-7 测试SIGONT信号
在执行 hello 程序的命令反面加上 &,这样它就会在后台运行,分别使用 ps 和 jobs 来检察 hello 历程。ps命令可以监视后台别的的历程。jobs命令可显示当前shell情况中已启动的作业状态。
https://img-blog.csdnimg.cn/direct/7e487286c0b94cde97a57c5b8d865aec.png
图6-8 检察后台运行的hello历程
当历程在后台运行时,我们用键盘发送的信号是无法发送给它,这时可以用 kill 命令来终止它:
https://img-blog.csdnimg.cn/direct/dddc4732026045b793476876b8f90c16.png
图6-9 使用kill终止后台历程
6.7本章小结
这章解说了 hello 怎样运行在操作体系的上下文中,以及它怎样受到信号的控制。
(第6章1分)
第7章 hello的存储管理
7.1 hello的存储器地址空间
hello 历程是与别的历程共享 CPU 和主存资源的,为了更加有效地管理内存而且少堕落,今世操作体系提供了一种对主存的抽象概念,叫做虚拟内存。虚拟内存是硬件非常、硬件地址翻译、主存、磁盘文件和内核软件的完美交互,它为每个历程提供了一个大的、同等的和私有的地址空间。
逻辑地址:格式为“段地址:偏移地址”,是 CPU 天生的地址,在内部和编程使用,并不唯一。
线性地址:逻逻辑地址到物理地址变更之间的中心层,逻辑地址经过段机制后转化为线性地址。
虚拟地址:掩护模式下,hello 运行在虚拟地址空间中,它访问存储器所用的逻辑地址。
物理地址:加载到内存地址寄存器中的地址,内存单元的真正地址。CPU 通过地址总线的寻址,找到真实的物理内存对应地址。
7.2 Intel逻辑地址到线性地址的变更-段式管理
段式管理是一种内存管理机制,它将内存划分为多个段(segment),每个段都有自己的基地址和长度。当程序使用逻辑地址访问内存时,必要经过以下步骤进行段式管理的变更:
1、逻辑地址天生:程序中产生的逻辑地址由段选择符和偏移量构成。段选择符用于指定所需访问的段,偏移量则表示相对于该段基地址的偏移量。
2、段选择符解析:根据段选择符从全局描述符表(GDT)或局部描述符表(LDT)中找到对应的段描述符。
3、段描述符表明:段描述符包含了段的基址、段限长、访问权限等信息。通过表明段描述符,可以得到段的基地址。
4、线性地址计算:将段的基地址与偏移量相加,即可得到线性地址。
https://img-blog.csdnimg.cn/direct/5a6352906a4b42848e16f438c7c452c8.jpeg
图7-1 段式管理
7.3 Hello的线性地址到物理地址的变更-页式管理
页式管理是一种内存管理机制,它将内存划分为固定大小的页(page),同时将逻辑地址和物理地址分别划分为雷同大小的页。当程序使用逻辑地址访问内存时,必要经过以下步骤进行页式管理的线性地址到物理地址的变更:
1、逻辑地址天生:程序中产生的逻辑地址由页号和偏移量构成,其中页号表示所在页的索引,偏移量表示相对于该页起始地址的偏移量。
2、页表查找:操作体系维护了一张页表,用于将逻辑地址中的页号映射到对应的物理页框(frame)。通过页号在页表中查找,可以得到该逻辑页对应的物理页框号。
3、物理地址计算:将页表查找得到的物理页框号与偏移量相加,即可得到物理地址。
在这个过程中,页表的查找和物理地址的计算是由硬件的内存管理单元(MMU)来完成的。MMU利用页表中的映射关系来将逻辑地址转换为物理地址,同时还会进行访问权限的检查,以确保内存访问的安全性。
https://img-blog.csdnimg.cn/direct/db67d30e6e894ebb9c3f74f998b782e0.png
图7-2 页式管理
7.4 TLB与四级页表支持下的VA到PA的变更
在今世计算机体系结构中,虚拟地址(VA)到物理地址(PA)的变更是通过使用页表和TLB来实现的。四级页表指的是一个具有四级索引结构的页表,这种结构常见于一些今世处理器架构中。
使用TLB和四级页表进行VA到PA变更的根本步骤为:
1、虚拟地址天生:程序中产生的虚拟地址由页号和偏移量构成,其中页号表示所在页的索引,偏移量表示相对于该页起始地址的偏移量。
2、TLB查找:TLB是一个高速缓存,用于存储近来使用的页表项的映射关系。处理器首先会在TLB中查找虚拟地址对应的物理地址映射。假如TLB中存在这个映射,则可以直接得到相应的物理地址;假如TLB未命中,则必要进行额外的步骤。
3、页表查找:假如TLB未命中,处理器会根据页表的索引结构(包罗四级页表)逐级查找,以获取虚拟地址对应的物理页框号。
4、物理地址计算:将页表查找得到的物理页框号与偏移量相加,即可得到最终的物理地址。
在这个过程中,TLB充当了一个高速缓存,可以或许加速常用地址映射的查找,从而提高了地址转换的速率。同时,四级页表的结构可以或许更好地组织和管理大内存空间,使得操作体系可以更灵活地管理内存。
https://img-blog.csdnimg.cn/direct/f2db8adfb56444b1bab9720e03d225c4.png
图7-3 TLB和四级页表进行VA到PA变更
7.5 三级Cache支持下的物理内存访问
三级缓存是今世处理器中常见的一种层次化的缓存结构,通常包罗L1缓存、L2缓存和L3缓存。物理内存访问在这个结构下的流程为:
1、L1缓存查找:当处理器必要访问一个物理内存地址时,首先会查询L1缓存,即最靠近处理器核心的缓存。假如所需数据在L1缓存中命中(即缓存中存在对应的数据块),则可以直接从L1缓存中读取或写入数据。
2、L1缓存未命中:假如在L1缓存中未命中,处理器将会继续查询L2缓存。L2缓存位于L1缓存之后,容量较大。假如所需数据在L2缓存中命中,处理器会从L2缓存中读取或写入数据,而且将这些数据同时加载到L1缓存中,以提高后续对同一数据的访问速率。
3、L2缓存未命中:假如在L2缓存中也未命中,处理器将进一步查询L3缓存。L3缓存通常位于多个处理器核心之间共享,容量更大。假如所需数据在L3缓存中命中,处理器会从L3缓存中读取或写入数据,而且将这些数据同时加载到L2和L1缓存中。
4、L3缓存未命中:假如在L3缓存中也未命中,处理器将会直接访问主存(即物理内存)。主存访问速率相对较慢,因此在此阶段大概会引发较长的访问延迟。同时,处理器会将主存中的数据加载到L3、L2和L1缓存中,以提高后续对同一数据的访问速率。
https://img-blog.csdnimg.cn/direct/db82dd8f1548495599b02b1433831aeb.jpeg
图7-4 三级Cache支持下的物理内存访问
7.6 hello历程fork时的内存映射
在fork操作期间,操作体系会执行以下步骤来处理内存映射:
1、初始状态:父历程拥有一段内存空间,其中包罗代码段、数据段、堆和栈等不同的地区。
2、调用fork():当父历程调用fork()创建子历程时,操作体系会复制父历程的整个地址空间,并分配给子历程独立的物理内存空间。但是,这个时候并不会立刻复制父历程的整个地址空间,而是接纳写时复制的方式。
3、写时复制:在写时复制的过程中,操作体系会将父历程的地址空间标记为只读,当父历程或子历程尝试修改内存内容时,操作体系会检测到这种行为,并为子历程分配新的物理页,然后将必要修改的数据复制到子历程的物理页上,使得父子历程拥有各自独立的物理内存空间。
7.7 hello历程execve时的内存映射
execve()体系调用执行过程中处理内存映射步骤如下:
1、调用execve():当历程调用execve()体系调用时,操作体系会加载新的可执行程序文件,并创建一个新的地址空间和内存映射。
2、清理旧地址空间:首先,操作体系会清理旧程序的地址空间,包罗打扫旧程序的代码段、数据段、堆和栈等地区所占用的内存空间。
3、加载新程序:接着,操作体系会根据新程序的可执行文件格式(如ELF格式)来创建新的地址空间,并将新程序的代码段、数据段、堆和栈等地区加载到新的地址空间中。
4、更新页表:操作体系会更新历程的页表,建立新的虚拟地址到物理地址的映射关系,以确保历程可以或许精确访问新程序的地址空间。
7.8 缺页故障与缺页中断处理
7.8.1缺页故障
缺页故障(Page Fault)指的是当程序试图访问虚拟内存中的一个页面,而该页面当前并不在物理内存中时所引发的非常情况。
操作体系在收到缺页故障时会进行相应的处理:
1、页表检查:首先,操作体系会检查历程的页表,判断导致缺页故障的虚拟地址对应的页面是否已经被加载到物理内存中。假如页面已经在物理内存中,那么大概是由于权限问题或其他原因导致的访问非常,操作体系将会相应地处理这些情况。
2、页面调度:假如所需页面尚未加载到物理内存中,操作体系将必要将这个页面从磁盘加载到内存中。这个过程称为页面调度(Page Replacement)。操作体系会根据一定的置换算法(如LRU、LFU等)选择一个捐躯页面,将其写回磁盘,并将必要的页面加载到空闲的物理页面中。
3、更新页表:一旦页面已经被加载到内存中,操作体系会更新历程的页表,建立新的虚拟地址到物理地址的映射关系,以便程序可以或许精确访问所需的页面。
7.8.2缺页中断
缺页中断(Page Fault Interrupt)是处理缺页故障的一种机制,当操作体系检测到缺页故障时,会产生一个中断,这个中断称为缺页中断。操作体系会在收到缺页中断后,根据上述步骤来处理缺页故障,确保程序可以或许精确访问所需的页面。
7.9动态存储分配管理
动态存储分配管理是指在程序运行时动态地为程序分配和释放内存空间的管理方式。动态存储分配管理通常由操作体系大概运行时库来实现,可以或许有效地利用内存资源并满意程序对内存空间动态变化的需求。
以下是一些常见的动态内存管理方法:
1、堆内存分配:堆内存分配是最常见的动态内存管理方法之一,通过调用类似malloc()、new等函数来申请一定大小的内存块,并返回该内存块的起始地址。程序员必要手动管理这些内存块的生命周期,确保及时释放不再使用的内存块,以避免内存泄漏。
2、内存池:内存池是一种预先分配一定大小的内存空间池的管理方式。程序可以从内存池中动态地分配内存块,并在使用完毕后将内存块归还给内存池而不是直接释放。内存池可以或许镌汰内存分配和释放操作的频率,提高内存分配的效率。
3、垃圾接纳:垃圾接纳是一种自动化的内存管理方法,通过辨认和接纳不再使用的内存块来释放内存空间。垃圾接纳器会自动跟踪程序中的对象引用关系,并在必要时接纳没有被引用的对象。常见的垃圾接纳算法包罗标记-打扫、引用计数、复制等。
4、内存碎片整理:内存碎片整理是指对内存中的碎片进行整理和归并,以便更好地利用可用内存空间。内存碎片化是由于频繁的内存分配和释放操作导致的,通过整理内存空间可以镌汰碎片化,提高内存利用率。
动态内存管理还涉及到怎样选择符合的内存分配计谋。常见的计谋包罗初次顺应、最佳顺应、最坏顺应等。不同的计谋对内存分配的速率、内存碎片化程度等方面有不同的影响,必要根据详细的应用场景选择适合的计谋。
7.10本章小结
本章介绍了存储器地址空间、段式管理、页式管理,VA 到 PA 的变更、物理内存访问, hello 历程 fork 时和 execve 时的内存映射、缺页故障与缺页中断处理。这些巧妙的筹划使得我们的 hello 最终得以运行。
(第7章 2分)
第8章 hello的IO管理
8.1 Linux的IO设备管理方法
设备的模子化:文件
设备管理:unix io接口
在Linux体系中,文件被视为一个包含m个字节序列的实体,用B0、B1直到Bm-1来表示。此外,所有的I/O设备都被抽象成文件。文件分为几种范例:1、平凡文件,包罗文本文件(只包含ASCII码或Unicode字符)和二进制文件;2、目录,包含一组链接的文件,每个链接将文件名映射到一个文件;3、套接字,用于与另一个历程进行跨网络通信的文件。所有的输入和输出都被视尴尬刁难相应文件的读和写操作。这种将设备映射为文件的方式允许Linux内核引入了一个简单、低级的应用接口,称为Unix I/O,这使得所有的输入和输出都能以一种统一且同等的方式来执行。
8.2 简述Unix IO接口及其函数
IO(Input/Output)接口是计算机体系中用于实现输入和输出操作的一种通用接口。它界说了程序与外部设备之间的数据传输规则和方式。在计算机体系中,常见的外部设备包罗键盘、鼠标、显示器、打印机、硬盘等。
IO接口的重要目的是提供简单、统一的方式来进行数据的读取和写入。它通过抽象和封装底层硬件设备的细节,使得程序开辟者可以或许更加方便地进行IO操作。常见的IO接口函数有以下几个:
1. open():打开文件或设备,并返回一个文件描述符(File Descriptor)。可以指定打开的模式(如只读、只写、读写等)和其他参数。
2. close():关闭文件或设备,释放文件描述符。
3. read():从文件或设备中读取数据。必要指定读取的字节数或缓冲区的大小。
4. write():向文件或设备写入数据。必要指定写入的字节数或要写入的数据。
5. seek():在文件或设备中移动文件指针的位置。可以用于随机访问文件或设备的不同部门。
6. flush():将缓冲区中的数据立刻写入文件或设备,确保数据的及时更新。
7. ioctl():用于控制设备的特定操作,如设置设备参数、查询设备状态等。
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;
}
可以看到,printf函数输入的参数中含有“…”,这代表可变形参,即传递参数的个数不确定。在va_list arg = (va_list)((char*)(&fmt) + 4);这句中, va_list界说为一个字符指针,(char*)(&fmt) + 4) 表示的是...中的第一个参数。fmt是一个指针,这个指针指向第一个const参数(const char *fmt)中的第一个元素。这也就分析确(char*)(&fmt) + 4) 表示的是...中的第一个参数的地址。
Vsprintf函数界说为int vsprintf(char *buf, const char *fmt, va_list args)。vsprintf的作用就是格式化。它接受确定输出格式的格式字符串fmt。用格式字符串对个数变化的参数进行格式化,产生格式化输出。
最后write函数就会把buf中的i个元素的值写到终端。
但从硬件上看,从vsprintf到最终显示器上显示出字符串对应一下过程:
从vsprintf天生显示信息,到write体系函数,到陷阱-体系调用 int 0x80或syscall等。字符显示驱动子程序:从ASCII到字模库到显示vram(存储每一个点的RGB颜色信息)。显示芯片按照革新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量)。
8.4 getchar的实现分析
int getchar(void)
{
static char buf;
static char* bb = buf:
static int n = 0;
if (n == 0) {
n = read(0, buf, BUFSIZ);
bb = buf;
}
return (–n >= 0) ? (unsigned char)*bb++ : EOF;
}
异步非常-键盘中断的处理:键盘中断处理子程序。接受按键扫描码转成ascii码,保存到体系的键盘缓冲区。
getchar等调用read体系函数,通过体系调用读取按键ascii码,直到接受到回车键才返回。
当用户通过键盘输入字符串时,会触发键盘中断非常,导致执行键盘中断处理子程序。在处理子程序中,键盘输入的字符会被转化成对应的ASCII码,并保存到体系的键盘缓冲区中。当程序调用getchar函数时,实际上会调用read函数来从键盘缓冲区中读取字符,并将它们保存到内存中的一个缓冲区(好比buf)中。接着程序会测量该字符串的长度,假设为n,然后让字符指针bb指向buf。最后,getchar会返回buf中的第一个字符。假如测得的字符串长度n小于0,意味着出现了错误,大概是遇到了EOF(文件竣事)标记,程序会陈诉相应的错误。
8.5本章小结
本章简单介绍了Linux下体系I/O的一些相干概念和体系级函数调用,介绍了Linux下一些接口的使用和一些读写函数,同时分析了printf函数和getchar函数的实现过程。
(第8章1分)
结论
至此,hello 终于走完了它的一生,让我们为它的一生做个小结:
1、程序筹划者编写出它的基因——hello.c
2、预处理器完善它的基因——hello.i
3、编译器为它注入的魂魄——hello.s
4、汇编器为它的诞生做最后的准备——hello.o
5、链接器让它长出完整的躯体——hello
6、Shell 为它创建子历程,让它真正成为体系中的个体
7、加载器映射虚拟内存,给予它发展的条件
8、CPU 的逻辑控制流让它驰骋在硬件与操作体系之上
9、虚拟地址这一计算机体系最巨大的抽象为它的驰骋导航
10、malloc 的高效管理让它的驰骋拥有更广阔的天地
11、信号与非常束缚它的行为,让它总是走在康庄大道之上
12、Unix I/O 打开它与程序使用者交换的窗口
13、当 hello 垂老迈矣,运行完最后一行代码,__libc_start_main 将控制转移给内核,Shell 接纳子历程,内核删除与它相干的所有数据结构,它在这个世界的所有陈迹至此被抹去。
回首它的一生,惊心动魄,千难万险。其中的每个阶段无不凝结着人类最巨大的智慧!
(结论0分,缺失 -1分,根据内容酌情加分)
附件
列出所有的中心产物的文件名,并予以分析起作用。
(附件0分,缺失 -1分)
文件
作用
hello.c
源代码
hello.i
预处理后的代码
hello.s
汇编代码
hello.o
可重定位目的文件
hello
链接后的可执行目的文件
hello.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.
(参考文献0分,缺失 -1分)
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]