没腿的鸟 发表于 2024-6-29 02:10:49

步伐人生-Hello’s P2P



https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image002.jpg&pos_id=sjokgVTM

计算机体系

大作业


题     目  步伐人生-Hello’s P2P 
专       业        信息安全         
学     号        2022110890       
班     级        2203202          
学       生        吴柏楠          
指 导 教 师         史先俊           






计算机科学与技能学院
2024年5月
摘  要
    在“hello”的生命周期中,经历了源代码编写、预处置惩罚、编译、汇编、链接、步伐实行、进程实行、信号处置惩罚和步伐终止等关键阶段。这一过程展现了计算机体系中步伐的创建、实行和终止的全貌,那么通过对“hello”走过的具体一生过程的分析,我们将更好的相识计算机工作原理以及把握一个真正的步伐员的必要熟悉。
关键词:源代码编写、预处置惩罚、编译、汇编、链接、步伐实行、进程实行、信号处置惩罚、步伐终止、计算机体系。                         










目  录

第1章 概述................................................................................... - 4 -
1.1 Hello简介............................................................................ - 4 -
1.2 环境与工具........................................................................... - 5 -
1.3 中间效果............................................................................... - 5 -
1.4 本章小结............................................................................... - 5 -
第2章 预处置惩罚............................................................................... - 6 -
2.1 预处置惩罚的概念与作用........................................................... - 6 -
2.2在Ubuntu下预处置惩罚的命令................................................ - 6 -
2.3 Hello的预处置惩罚效果解析.................................................... - 7 -
2.4 本章小结............................................................................... - 8 -
第3章 编译................................................................................... - 9 -
3.1 编译的概念与作用............................................................... - 9 -
3.2 在Ubuntu下编译的命令.................................................... - 9 -
3.3 Hello的编译效果解析...................................................... - 10 -
3.4 本章小结............................................................................. - 16 -
第4章 汇编................................................................................. - 17 -
4.1 汇编的概念与作用............................................................. - 17 -
4.2 在Ubuntu下汇编的命令.................................................. - 17 -
4.3 可重定位目标elf格式...................................................... - 17 -
4.4 Hello.o的效果解析........................................................... - 21 -
4.5 本章小结............................................................................. - 24 -
第5章 链接................................................................................. - 25 -
5.1 链接的概念与作用............................................................. - 25 -
5.2 在Ubuntu下链接的命令.................................................. - 25 -
5.3 可实行目标文件hello的格式......................................... - 26 -
5.4 hello的虚拟地点空间....................................................... - 29 -
5.5 链接的重定位过程分析..................................................... - 31 -
5.6 hello的实行流程............................................................... - 35 -
5.7 Hello的动态链接分析...................................................... - 35 -
5.8 本章小结............................................................................. - 39 -
第6章 hello进程管理.......................................................... - 41 -
6.1 进程的概念与作用............................................................. - 41 -
6.2 简述壳Shell-bash的作用与处置惩罚流程........................... - 41 -
6.3 Hello的fork进程创建过程............................................ - 42 -
6.4 Hello的execve过程........................................................ - 43 -
6.5 Hello的进程实行.............................................................. - 43 -
6.6 hello的异常与信号处置惩罚................................................... - 45 -
6.7本章小结.............................................................................. - 49 -
第7章 hello的存储管理...................................................... - 50 -
7.1 hello的存储器地点空间................................................... - 50 -
7.2 Intel逻辑地点到线性地点的变更-段式管理.................. - 50 -
7.3 Hello的线性地点到物理地点的变更-页式管理............. - 51 -
7.4 TLB与四级页表支持下的VA到PA的变更................... - 52 -
7.5 三级Cache支持下的物理内存访问................................ - 53 -
7.6 hello进程fork时的内存映射......................................... - 53 -
7.7 hello进程execve时的内存映射..................................... - 54 -
7.8 缺页故障与缺页停止处置惩罚................................................. - 55 -
7.9动态存储分配管理.............................................................. - 55 -
7.10本章小结............................................................................ - 56 -
第8章 hello的IO管理....................................................... - 57 -
8.1 Linux的IO装备管理方法................................................. - 57 -
8.2 简述Unix IO接口及其函数.............................................. - 58 -
8.3 printf的实现分析.............................................................. - 59 -
8.4 getchar的实现分析.......................................................... - 60 -
8.5本章小结.............................................................................. - 60 -
结论............................................................................................... - 62 -
附件............................................................................................... - 63 -
参考文献....................................................................................... - 64 -



第1章 概述

1.1 Hello简介

P2P: From Program to Process
步伐的创建(Program Creation)
       用户在文本编辑器中编写代码,并将其保存为hello.c文件。这是步伐的源代码阶段(Program)。
编译过程(Compilation Process)
       源代码颠末预处置惩罚(Preprocessing)、编译(Compilation)、汇编(Assembly)和链接(Linking),生成可实行文件hello。这个过程涉及一系列的工具链,包括预处置惩罚器、编译器、汇编器和链接器。
加载和实行(Loading and Execution)
       当用户在Shell中实行./hello时,操作体系(OS)开始加载可实行文件到内存中,创建一个新的进程。OS使用fork()体系调用创建一个新的进程(Process),使用execve()加载可实行文件,并在硬件(CPU、RAM、IO)上实行。
进程的管理和调理(Process Management and Scheduling)
       操作体系的进程管理模块分配时间片(time slices)给进程,使其能够在CPU上运行。OS使用内存管理单元(MMU)将虚拟地点(VA)映射到物理地点(PA),并使用TLB、页表(Page Table)、缓存(Cache)和页面文件(Pagefile)等机制加速内存访问。
I/O管理(I/O Management)
       输入输出操作通过键盘、主板、显卡和屏幕等硬件装备举行,OS和谐这些操作,使得进程能够与外部装备举行交互。
进程的终止(Process Termination)
       进程完成实行后,通过体系调用退出,OS接纳资源。进程的生命周期结束,从创建到实行再到终止,完成了一个P2P的过程。
O2O: From Zero-0 to Zero-0
从无到有(Zero-0 to Something)
用户在无任何代码的状态下开始,通过编写hello.c文件,将步伐从无到有创建出来。
在线编译和实行(Online Compilation and Execution)
编写的代码通过编译器编译成可实行文件,类似于在线平台上的处置惩罚过程(如在线IDE)。在命令行或IDE中实行可实行文件,实现代码的运行。
线下体验和完成(Offline Experience and Completion)
步伐运行后,用户在屏幕上看到“Hello, World!”的输出,这是线下体验的效果。步伐运行结束后,进程被终止,资源被接纳,回到最初的状态。
从有到无(Something to Zero-0)
步伐的实行过程结束后,体系回到初始状态,等待新的任务。整个过程从零到有,再从有到零,完成了一次完备的生命周期。
1.2 环境与工具

处置惩罚器  12th Gen Intel(R) Core(TM) i5-1235U   1.30 GHz
机带      RAM     16.0 GB (15.7 GB 可用)
体系类型     64 位操作体系, 基于 x64 的处置惩罚器
软件环境     Window11 64位、Vmware 16、Ubuntu 22.04 LTS 64位
开辟与调试工具       GCC、Codeblocks、vim、gcb
1.3 中间效果

hello.c          C语言源文件
hello.i           预处置惩罚产生的文件
hello.s          编译产生的汇编代码文件
hello.o         汇编产生的可重定位目标文件
hello.o.elf     hello.o文件的ELF格式
hello.o.asm  hello.o反汇编生成的文本文件
hello             链接产生的可实行目标文件
hello.elf        hello文件的ELF格式
hello.asm     hello反汇编生成的文本文件
1.4 本章小结

本章解释了在计算机体系中p2p和o2o的含义,并给出了完成这份报告所需要的体系要求以及完成过程中的生成文件。



第2章 预处置惩罚

2.1 预处置惩罚的概念与作用

预处置惩罚的概念:
预处置惩罚是指在编译过程中,对源代码举行一些预处置惩罚操作,以便于编译器更好地理解和处置惩罚源代码。步伐预处置惩罚器通常是一个单独的步伐,它会在编译器之前对源代码举行处置惩罚。预处置惩罚器要按照源步伐最前面的#include引用的库,检索出来库文件的代码,并把代码加入到预处置惩罚后的步伐中,如许之后编译才能使用这些头文件的函数。
C语言的预处置惩罚紧张有三个方面的内容:
1.   宏定义(#define 标识符 文本);
2.   文件包含(#include "文件名");
3.   条件编译(#ifdef,#else,#endif)。
步伐预处置惩罚的作用:
1. 宏定义:预处置惩罚器可以将一些常用的代码片断定义为宏,以便在代码中多次使用。如许可以减少代码量,提高代码的可读性和可维护性。同时预处置惩罚器还负责将源步伐中的宏定义更换成宏常量。
2. 条件编译:预处置惩罚器可以根据条件编译指令来选择性地编译代码。因为在源步伐文件中由于步伐员不可避免的一些不必要语言会导致步伐的冗余(如#ifdef,#else,#endif),过滤掉不需要的代码,如许可以根据差别的编译条件生成差别的代码,以顺应差别的环境和需求。
3. 处置惩罚文件包含:预处置惩罚器可以将头文件中的代码插入到源代码中,以便在源代码中使用头文件中定义的函数和变量。
4. 编译器指令:预处置惩罚器可以使用编译器指令来告诉编译器怎样处置惩罚源代码(如#error)。例如,可以使用#pragma指令来告诉编译器怎样对代码举行优化,使代码更方便被修改和理解。
5.删除C语言源步伐中所有的注释;
总之,步伐预处置惩罚是编译过程中非常紧张的一步,它可以使得源代码更加易读、易维护,同时也可以提高代码的实行效率。
2.2在Ubuntu下预处置惩罚的命令

gcc -E hello.c -o hello.i
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image004.png&pos_id=B7C639iL
2.3 Hello的预处置惩罚效果解析

       在ubuntu中的终端命令行输入gcc -E hello.c -o hello.i,得到hello.c的预处置惩罚过后的文件。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image006.png&pos_id=tHdvEwg2
打开hello.i举行检察,在文件最后可以看到hello.c的原内容:
       在hello.i文件开头部分还可以看到在源步伐中引用的stdio.h,unistd.h和stdlib.h的代码,它们都是在预处置惩罚器的作用下,被直接插入步伐文本之中。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image008.png&pos_id=tWfpZpzb
       通过预处置惩罚,#include <stdio.h>等指令被展开,将尺度库定义的内容插入到hello.i中。这保证了在后续编译过程中,所有尺度类型和函数都有正确的定义和声明。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image010.png&pos_id=FXMzr3qa
       还可以检察到相关结构体的定义:
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image012.png&pos_id=6WDd5aZV
2.4 本章小结

       本章紧张介绍了预处置惩罚的概念以及预处置惩罚在五个方面的作用与功能,并在虚拟机下将hello.c文件颠末预处置惩罚生成了hello.i文件,而且对照hello.c与hello.i分析了预处置惩罚产生的文件与源文件的雷同与差别之处,加深了对预处置惩罚整个过程的理解。

第3章 编译

3.1 编译的概念与作用

编译的概念:
编译是指编译器将颠末预处置惩罚的C语言源文件转换成目标平台的汇编语言代码的过程。这一步骤将高级语言的语法结构解析并转换为汇编语言指令,这些指令能够直接被目标处置惩罚器理解和实行。在.i 到 .s 即预处置惩罚后的文件到生成汇编语言步伐之中,是指高级语言步伐写的代码(C语言源步伐)文本文件hello.i通过编译器(ccl)的资助,翻译成汇编语言步伐hello.s的过程。
编译的作用:
语法分析:查抄源代码的语法是否正确,并将其转换为语法树(Parse Tree)。
词法分析:将代码分解成标记(Tokens),如关键字、标识符、操作符、常量等。
语义分析:查抄源代码的语义是否正确,包括类型查抄、变量作用域查抄等。
类型查抄:确保变量和表达式的类型匹配。
作用域查抄:确保变量在其作用域内合法使用。
中间代码生成:将语法树转换为中间表现(Intermediate Representation,IR),如三地点代码或静态单赋值形式(SSA)。
中间代码优化:对中间代码举行优化,如常量折叠、死代码消除等。
目标代码生成:将中间代码转换为目标平台的汇编语言代码。
指令选择:选择恰当的汇编指令来实现中间代码的每个操作。
寄存器分配:将变量分配到CPU的寄存器或内存位置。
优化:对生成的汇编代码举行进一步优化,以提高实行效率和减少代码大小。
指令优化:重排指令序次,减少跳转,提高指令流水线效率。
寄存器优化:减少内存访问次数,提高寄存器使用率。
3.2 在Ubuntu下编译的命令

gcc -S hello.i -o hello.s
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image014.png&pos_id=hnZGXT5F
3.3 Hello的编译效果解析

3.3.1 数据
1.    数字常量
       for循环中的i<10是由$9来实现的。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image016.png&pos_id=ige6Sxkv
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image017.png&pos_id=JoLYSFx3
2.    字符串常量
       在hello.s文件中发现
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image019.png&pos_id=hZ3TdmxG
如图,根据所学知识文件hello.s中将字符串常量存储在只读段.rodata段,该效果表现编译对中文字符举行了utf-8编码,并存储在只读代码区的.rodata节,在步伐运行时会直接通过寻址找到常量。
hello.c输出字符串常量有如下对应的hello.s关系:
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image021.png&pos_id=tGchaSRa
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image023.png&pos_id=4FN84Ayv
 


https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image025.png&pos_id=cmnWoxMH
 
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image027.png&pos_id=tUEZmTMg
可以发现,打印字符串常量时,编译器将语句翻译为先将字符串存放的地点存入寄存器%rdi,再举行打印。
3.    变量
差别类型的变量在差别位置定义,局部变量在栈上举行定义和开释,未初始化的全局变量和静态变量定义在只读代码区的.bss节,已初始化的全局和静态变量定义在只读代码区的.data节。
       在hello.c中,存在局部变量i,编译器举行编译的时候将局部变量i会放在栈中,如下图所示:
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image028.png&pos_id=MVDPe98m
    传入参数char *argv[]存放在栈中,此中首地点存放在栈中-32(%rbp)的位置,argv地点为-32(%rbp)+8,argv地点为-32(%rbp)+16,argv地点为-32(%rbp)+24。在hello.s中的使用如下图所示。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image030.png&pos_id=Fx3E3Jvt
       由下图可知,局部变量int i存放在栈中-4(%rbp)的位置。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image031.png&pos_id=QriQtqaF
3.3.2 赋值
编译器将赋值的操作紧张为对相应的寄存器或栈举行赋值。在hello.c中,对i赋初值,根据下图,对i:movl  $0, -4(%rbp)。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image032.png&pos_id=SwW8nUD6
       局部变量赋值接纳MOV指令,根据差别大小的数据类型有movb、movw、movl、movq等。
3.3.3 算术操作
对于紧张的算数操作,+转换成add,-转换成sub,*转换成imul,/转换成div。
       如下图,步伐中的算数操作i++在hello.s文件中的汇编代码翻译为用add指令通过操作数$1来实现,通过3.3.2的分析可以知道栈中-4(%rbp)的位置存放的是局部变量i,每次实行这条指令,实现的是i自增1。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image033.png&pos_id=zaJZJvB2
3.4 类型转换
隐式转换:隐式转换就是体系默认的、不需要加以声明就可以举行的转换数据类型自动提拔。显示转换:步伐通过逼迫类型转换运算符将某类型数据转换为另一种类型。
       hello.c步伐中显示类型转换为atoi(argv)。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image034.png&pos_id=ZJSK22Jt
3.5关系操作
如下图,hello.c中有argc!=5,汇编语言为cmpl $5, -20(%rbp)。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image035.png&pos_id=Dbr5sGV4
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image037.png&pos_id=33zFgGDk
hello.c中有i<10汇编语言为cmpl   $9, -4(%rbp)。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image038.png&pos_id=Lu2IrzQe
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image039.png&pos_id=6wzELs25
       以是,编译器通常通过将比较编译为cmp指令实现,成立则返回0。根据差别的数据大小,有cmpb、cmpw、cmpl和cmpq。比较之后,通过jmp系列指令跳转。
3.3.6数组/指针/结构操作
       如下图,编译器对源代码中数组的操作往往翻译为对地点的加减操作,此中首地点存放在栈中-32(%rbp)的位置,argv地点为-32(%rbp)+$8,argv地点为-32(%rbp)+$16,argv地点为-32(%rbp)+$24即举行了地点的加减操作以访问数组。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image040.png&pos_id=BuKxIdG5
3.3.7控制转移
       下图中第一个为条件跳转,当argc=5时才发生跳转,对应的c语言代码为if(argc!=5),第二个为无条件跳转,当i赋初值为0后跳转进入循环体。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image041.png&pos_id=juNxV2BJ
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image042.png&pos_id=rgvDln0y
3.3.8函数操作
       在步伐中一共有6个函数调用,如下图,分别为printf(puts),exit,printf,sleep,atoi,getchar。
int main(int argc,char *argv[]){
    int i;

    if(argc!=5){
        printf("用法: Hello 学号 姓名 手机号 秒数!\n");
        exit(1);
    }
    for(i=0;i<10;i++){
        printf("Hello %s %s %s\n",argv,argv,argv);
        sleep(atoi(argv));
    }
    getchar();
    return 0;
}
从下图可以看到,在C语言源步伐中实行该命令用的是printf函数,由于打印的是一个单纯的字符串,因此编译器对它举行了优化,改用puts函数举行打印,以是hello.s调用puts()函数。起首将调用函数所需要的参数,即需要打印的字符串常量的地点存放在寄存器%rdi中,然后实行call puts@PLT指令打印字符串。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image044.png&pos_id=sAPxB0gU
       对于第二个函数调用,即exit,可以看到函数的第一个参数1保存在%edi中。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image045.png&pos_id=b9B9bXVr
       如下图,对于第三个函数调用printf,%rdi中存放第一个参数,%rsi中存放第二个参数。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image046.png&pos_id=fVCtyy2o
     如下图,对于第四个和第五个函数调用,参数都存放在%rdi中,此中sleep的参数为atoi的返回值。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image047.png&pos_id=NNRtUdHA
       如下图,关于第六个函数调用,由于getchar无参数输入,以是不消寄存器传参。

https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image048.png&pos_id=mAHmrg3v
3.4 本章小结

这一章报告了编译的概念和作用,包括将高级语言指令转换成汇编语言指令,并扼要解释了编译器的优化过程。同时,以hello.i文件在虚拟机下编译生成hello.s文件为例举行了阐明。
随后,通太过析源步伐hello.c文件中的语句怎样转换成hello.s文件中的语句,探讨了差别数据类型和操作类型在C语言中的体现。涵盖了数字常量、字符串常量、局部变量以及赋值、算术运算、关系运算、类型转换、数组、指针、结构操作、控制转移和函数调用等内容。这一过程让我受益匪浅,深入理解了汇编代码和C语言之间的关系,并提拔了阅读汇编代码的本领。
第4章 汇编
4.1 汇编的概念与作用

汇编语言的概念:
汇编语言是一种低级别的计算机编程语言,它使用符号来代表计算机指令,与特定的计算机硬件体系结构密切相关。每种硬件体系结构都有自己的汇编语言,其语法和指令集都各有差别。相比高级编程语言,汇编语言更接近计算机硬件层面,允许步伐员直接操作底层硬件资源。通过汇编语言,步伐员可以直接控制处置惩罚器、内存、以及输入输出装备等硬件,实现对计算机的精致控制。
汇编语言的作用:
1. 直接控制硬件:汇编语言允许步伐员直接控制计算机的底层硬件。通过编写汇编代码,步伐员可以操作处置惩罚器的寄存器、内存的读写、以及装备的输入输出,实现对硬件的直接控制。
2. 性能优化:由于汇编语言更接近计算机硬件层面,步伐员可以更准确地控制代码的实行流程和内存访问。这使得汇编语言成为性能优化的紧张工具,特殊是在对性能要求较高的应用场景下,如游戏开辟、嵌入式体系等。
3. 嵌入式体系开辟:在嵌入式体系开辟中,资源的使用效率和性能往往是至关紧张的。汇编语言可以让步伐员更好地控制代码的大小和实行速度,满足嵌入式体系对性能和资源的要求。
4. 调试和逆向工程: 汇编语言是理解和调试呆板码的紧张工具。在调试过程中,步伐员可以通过检察汇编代码来理解步伐的运行原理和错误产生的缘故原由。此外,汇编语言也是举行逆向工程和软件破解的底子,通太过析步伐的汇编代码,可以相识其内部实现和算法逻辑。
4.2 在Ubuntu下汇编的命令

gcc -C hello.s -o hello.o

https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image050.png&pos_id=vjLhb920
4.3 可重定位目标elf格式

分析hello.o的ELF格式,用readelf等列出其各节的基本信息,特殊是重定位项目分析。
readelf  -a hello.o >hello.o.elf

https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image052.png&pos_id=oawpuJ7P
4.3.1 ELF头
hello.o的ELF格式以一个16字节(一共40字节)的Magic序列开始,描述了生成该文件的体系的字大小和字节序次。ELF头剩下的部分包含资助链接器语法分析和解释目标文件的信息,此中包含ELF头的大小,步伐头部表的大小,目标文件的类型,呆板类型,节头部表的文件偏移,以及节头部表中条目标大小和数量。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image054.png&pos_id=d5tDdgX9
4.3.2 节头目表
ELF文件格式中的节头部表描述了目标文件中差别节的类型、地点、大小、偏移等信息,以及可以对各部分举行的操作权限。
hello.o文件的节头目表如下图:
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image056.png&pos_id=U1bIbuYY
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image058.png&pos_id=YgZQK7CP
4.3.3 重定位节
ELF文件格式中的重定位节包含两个部分:.rela.text节与.rela.eh_frame节。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image060.png&pos_id=7cPFLdul
重定位节分成两部分:节头部分和重定位表部分。节头部分包括:节名、节大小、节偏移量等关键信息。重定位表部分包括了需要举行重定位的地点和符号信息,以及重定位的类型和偏移量等。
.rela.text是一个.text节中位置的列表,包含.text节中需要举行重定位的信息。由上图可知,在hello.o的重定位节中包含了main函数调用的puts、exit、printf、sleep、getchar函数以及全局变量,还有只读区域.rodata节存的两个字符串常量。表格纪录了它们的偏移量、信息、类型、符号值、符号名称及加数。另用rela.eh_frame单独纪录.text的信息。
表头信息含义为:
偏移量:需要重定位的信息的字节偏移位置(代码节/数据节)
信息:重定位目标在.symtab中的偏移量和重定位类型
类型:表现差别的重定位类型
符号值:符号的数值
符号名称:被重定位时指向的符号
加数:偏移
若重定义类型为R_X86_64_PC32,重定位一个使用32位PC相对地点的引用。若若重定义类型为R_X86_64_32,重定位一个使用32位绝对地点的引用。根据重定位条目和重定位算法即可得到相应的重定位位置。
4.3.4 符号表
ELF文件格式中的符号表用于存放步伐中定义和引用的函数和全局变量的信息。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image062.png&pos_id=uz5R1rdb
4.4 Hello.o的效果解析

objdump -d -r hello.o > hello.o .asm
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image064.png&pos_id=jHDupSt6
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image065.png&pos_id=efTdxdjG

通过对比hello.s和hello.o .asm发现差别之处:
4.4.1 包含内容
       hello.s中包含.type ,.rodata,.file,.section ,.align(对齐) 等信息,反汇编文件hello.o .asm中只有代码段.text的相关内容。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image067.png&pos_id=LECfn751
4.4.2 数字进制
       如下图,在汇编过程中,数字的进制发生了改变,从十进制转换为了十六进制,对应呆板的二进制数。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image069.png&pos_id=wnrn53dZ
4.4.3 引用地点区别
       例如,在汇编过程中对于字符串常量的引用时,基准地点差别:
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image070.png&pos_id=jBqwq91X
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image071.png&pos_id=8OAYLuS8
       hello.s中是用的内部代码全局变量所在.LC0段的名称加上%rip的值,而重定位目标文件(汇编后)hello.o中用的是0加%rip的值。
4.4.3 分支转移
       hello.s通过段名举行分支转移,跳转指令后用对应的段的名称表现跳转位置,而在hello.o的反汇编代码中每个段都有明确的地点,跳转指令后用相应的绝对大概相对地点表现跳转位置。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image070.png&pos_id=hIqYnt5z
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image072.png&pos_id=1gCreo0W
4.4.4 函数调用
可以看到,hello.s中直接调用函数的名称,而hello.o .asm中使用下一条地点相对函数起始地点的偏移量(R_X86_64_PC32),链接重定位后才能确定地点。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image073.png&pos_id=BL9KIUhl
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image074.png&pos_id=tLZBQgZO
4.5 本章小结

       在完本钱章内容的过程中,我对汇编语言的紧张性有了更深刻的熟悉。汇编语言固然底层且复杂,但它直接操作硬件的本领和对计算机运行机制的深入理解,使其在性能优化、嵌入式体系开辟和逆向工程等领域发挥着紧张作用。通太过析可重定位目标 ELF 格式文件的结构和特性,我对汇编步伐的编译、链接和重定位过程有了更清晰的熟悉,这将对我以后的软件开辟和调试工作产生积极影响。同时,对比原始汇编文件和反汇编后的目标文件,我熟悉到了编译器和链接器对代码的处置惩罚方式,这对我理解编译原理和代码优化提供了有益启示。




第5章 链接

5.1 链接的概念与作用

链接的概念:
链接是软件开辟中的关键步骤,它指的是将多个目标文件(Object Files)或库文件合并成一个可实行文件或共享库的过程。在编译阶段,源代码被编译成目标文件,每个目标文件包含了编译后的呆板代码以及所需的符号信息。链接器负责将这些目标文件中的符号举行解析和重定位,并将它们组合在一起,形成最终的可实行文件或共享库。
链接的作用:
符号解析: 链接器负责解析目标文件中的符号,即变量、函数等的声明和定义。它确保所有的符号引用都能够与其定义相匹配,以便步伐在运行时能够正确地访问和调用。
符号重定位: 在链接过程中,链接器还需要对符号举行重定位,即确定每个符号在最终可实行文件或共享库中的地点。这涉及到调整符号的引用地点,以确保步伐在运行时能够正确地访问和实行。
库链接: 链接器负责将步伐所需的外部库链接到可实行文件或共享库中。这些外部库可以是尺度库、第三方库等,它们提供了丰富的函数和服务,可以被步伐调用和使用。
       生成可实行文件: 最终,链接器将所有目标文件及其依赖的库文件链接在一起,生成一个完备的可实行文件或共享库。这个文件包含了步伐的所有代码和数据,可以直接在操作体系上运行。
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://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image076.png&pos_id=tiTgkEvg
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image078.png&pos_id=j1HOex0X
5.3 可实行目标文件hello的格式

       通过指令readelf -a hello>hello.elf检察目标文件hello的ELF格式。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image080.png&pos_id=eAhTESMI
以一个16字节的Magic序列开始,描述了生成该文件的体系的字大小和字节 序次。ELF头剩下的部分包含资助链接器语法分析和解释目标文件的信息,此中包 含ELF头的大小,步伐头部表的大小,目标文件的类型,呆板类型,节头部表的文件偏移,以及节头部表中条目标大小和数量。与链接前的ELF Header 比较,number of section headers,number of program headers 增加,入口地点不再是0,阐明重定位工作已完成。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image082.png&pos_id=1I4Tj1vN
       节头表对hello中所有的节的信息举行了声明,包括大小,偏移量等。hello中的节头表条目数多于hello.o。hello中每一节都有实际地点,而hello.o中每一节地点值都为0,阐明重定位工作已完成。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image084.png&pos_id=KtJlO5vr
根据下图可知,步伐头包含了以下信息:
PHDR:步伐头表
INTERP:步伐实行前需要调用的解释器
LOAD:步伐目标代码和常量信息
DYNAMIC:动态链接器所使用的信息
NOTE::辅助信息
GNU_STACK:使用体系栈所需要的权限信息
GNU_RELRO:保存在重定位之后只读信息的位置
       别的的节的内容是存放在0x00400fff后面。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image086.png&pos_id=0kwjMb4L
       由图,可实行文件内容初始化为两个内存段:只读内存段(代码段.text),读写数据段(.data)
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image088.png&pos_id=3ub2KBPv
       目标文件的符号表包含定位和重定位步伐的符号定义和符号引用所需的信息
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image090.png&pos_id=gDbtZBCS
       重定位后的偏移量与未重定位的hello.o的不一样
5.4 hello的虚拟地点空间

       根据5.3.2节头表,可知ELF表头地点为0x400000
       edb通过Data Dump与stack验证: 
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image092.png&pos_id=uwTdwr7f
       根据5.3.2节头表,可知步伐的入口地点为0x4010f0,对应ELF中.text节的起始地点
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image094.png&pos_id=UsOS4iay
根据5.3.2节头表,可知步伐的入口地点为0x4002e0,对应ELF中.interp节的起始地点
       由edb通过Data Dump与stack检察存储的内容可知:/lib64/ld-linux-x86-64.so.2为动态毗连器(dynamic linker)的路径
根据图5.3.4 步伐头部表知.rodata节的起始虚拟地点为0x402000
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image096.png&pos_id=FXlKTNqZ
根据图5.3.4 步伐头部表知.data节的起始虚拟地点为0x404030
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image098.png&pos_id=W6NLlTyP
5.5 链接的重定位过程分析

       通过指令objdump -d -r hello > asm_2.txt将可实行文件hello反汇编到文本文件hello.asm中。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image100.png&pos_id=pZM86QSK
5.5.1 代码量
       可以看出,可实行文件反汇编生成的代码量远大于可重定位目标文件反汇编生成的代码量。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image102.png&pos_id=I5p1Kg5l
5.5.2 起始地点
       hello.o反汇编代码地点从0开始,hello反汇编代码地点从  0x400000开始,阐明hello.0未实现重定位,每个符号没有确定的地点,hello已实现,每个符号有确定的地点。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image103.png&pos_id=mbA3aiXL
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image104.png&pos_id=GjKjs2Qp
5.5.3 函数
    在hello.o的反汇编步伐中,只有main函数,没有调用的函数段;颠末链接过程后,原来调用的C尺度库中的代码都被插入了代码中,而且每个函数都被分配了各自的虚拟地点
       别的,对比两个反汇编文件,可以看出,在hello.o的反汇编步伐中,由于当时函数未被分配地点,以是调用函数的位置都用call加下一条指令地点来表现,而在hello的反汇编步伐中,由于各函数已拥有了各自的虚拟地点,以是在call后加其虚拟地点来实现函数调用。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image106.png&pos_id=48kETN6W
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image108.png&pos_id=QgyXeUr5
5.5.4 CPU分配虚拟地点
       从图中可以看出在hello.o的反汇编步伐中, main函数中的所有语句前面的地点都是从main函数开始从0开始依次递增的,而颠末链接后,每一条语句都被分配了虚拟地点。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image110.png&pos_id=WlkONPzg
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image112.png&pos_id=IDfj9hRL
       同样,对比两个反汇编文件的跳转指令,在hello.o的反汇编步伐中,对于跳转指令,在其后加上目标地点,为main从0开始对每条指令分配的地点,而在hello的反汇编步伐中,由于各语句拥有了各自的虚拟地点,以是同样加上目标地点,但这里是每条指令的虚拟地点。
5.5.5 字符常量的引用
       从图中可以看到,在hello.o的反汇编步伐中,字符串常量的位置是用0加%rip的值来表现的,这是由于当时字符串常量并未分配虚拟内存,而在hello的反汇编步伐中,因为字符串常量都有了相应的位置,以是用实际的相对下一条语句的相对地点加%rip即PC的值来描述其位置。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image114.png&pos_id=TzrXF5kP
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image116.png&pos_id=z3ksCYgL
5.5.6 总结
链接的过程紧张分为两个过程:
1. 符号解析:符号解析解析目标文件定义和引用符号,并将每个符号引用和一个符号定义相关联。
2. 重定位:编译器和汇编器生成从0开始的代码和数据节。而链接器通过把每个符号定义与一个虚拟内存地点相关联,从而将这些代码和数据节重定位,然后链接器会修改对所有这些符号的引用,使得它们指向这个虚拟内存地点。
从上述对比图可以看出hello中每条指令都对应了一个虚拟地点,而且对每个函数,全局变量也都它关联到了一个虚拟地点,在函数调用,全局变量的引用,以及跳转等操作时都通过虚拟地点来举行,从而实行这些指令。
5.6 hello的实行流程

1.   edb第一个调用的步伐:_dl_start,地点:0x7f27b9e2da60
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image118.png&pos_id=QDUybL9V
2.   Step over运行后下一个调用的步伐为_dl_init,地点:0x7f27b9e15390
 
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image120.png&pos_id=Ir0iP1Ip
3.   Step over运行后步伐通过jmp  进入,地点为0x4010f0,则步伐进入函数入口
 
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image122.png&pos_id=ajKeo8Np
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image124.png&pos_id=4WO4XLmr
4.   继续Step over,看到_start函数中通过调用_libc_start_main函数,地点:
0x7f1fe6623ac0
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image126.png&pos_id=MSOxciQb
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image128.png&pos_id=IcteGh38
5.   继续Step over,看到_libc_start_main函数中调用_cxa_atexit函数,地点:0x7f1fe663e3e0
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image130.png&pos_id=B8D87YET
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image132.png&pos_id=39jQXFcg
6.   step out后继续Step over,看到_libc_start_main函数中通过%rcx跳转至hello_init函数,地点:0x401000
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image134.png&pos_id=hGcW6w9N
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image136.png&pos_id=q2aaDZ0f
7.   step out后继续Step over看到_libc_start_main函数中通过%rbx跳转至setjump函数非本地跳转。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image138.png&pos_id=8FGNgCQw
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image140.png&pos_id=TsAi3fNc
8.   继续运行,可以看到步伐进入main函数,地点:0x401125
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image142.png&pos_id=RX0UUTvp
9.   继续Step over,可看到main函数调用puts@plt函数(优化),地点:0x401030
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image144.png&pos_id=CmbOzJbW
然后调用0x401060处的atoi@plt函数,接着调用0x401080处的sleep@plt函数,循环8次后调用位于0x401050处的getchar@plt函数
10. 最后调用exit@plt函数退出,地点:0x401070
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image146.png&pos_id=iMCmmCj6
在exit@plt函数中调用libc-2.31.so!exit函数退出步伐
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image148.png&pos_id=lg0VRd8W
5.7 Hello的动态链接分析

在步伐中动态链接采用延迟绑定的策略实现。延迟绑定通过全局偏移量表 GOT、过程链接表PLT实现。GOT是数据段的一部分,PLT是代码段的一部分。  GOT中存放函数自标地点,PLT使用GOT中地点跳转到目标函数。  PLI:数组,每个条自者都是16学节代码。每个库函数者都有直已的PL条自,  PLT是一个特殊的条目,跳转到动态链接器中。从PLT和GOT包含动态链接器在解析函数地点时会使用  的信息。GOT是动态链接在ld-linux.so模块的入口点,别的条目对应于被调用  的函数,其地点在运行时被解析。
检察hello.elf中的节头表可知:  
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image150.png&pos_id=PYGFhU6X
       .got.plt数据从0x403fe8开始
       调用_dlt_init之前GOT表内容:
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image152.png&pos_id=St2iwoQ9
       调用_dlt_init之后GOT表内容:
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image154.png&pos_id=UXNujUYv
       通过两幅图的比较可以看出调用dlinit后GOT表后字节数据发生了变化,颠末初始化后,PLT和GOT表可以和谐工作,一同延迟解析库函数的地点。
5.8 本章小结

       本章详细介绍了链接在软件开辟中的概念和作用,并通过命令在 Linux 体系中举行了实际链接操作。同时,对可实行目标文件 `hello` 的格式举行了详细阐明,并分析了可实行目标文件与可重定位目标文件之间的区别。此外,还对 `hello` 的虚拟地点空间举行了分析,解释了步伐的实行过程,并详细阐述了动态链接的实现原理。

第6章 hello进程管理

6.1 进程的概念与作用

进程的概念:
进程是计算机中正在实行的步伐的实例。它是操作体系中的基本概念,代表了体系中正在运行的活动。每个进程都有自己独立的内存空间、资源和状态,而且可以独立地运行和管理。操作体系通过进程来实现任务的分配、调理和管理,以及多任务的并发实行。
进程的作用:
并发实行: 进程使得多个步伐能够同时实行,从而提高了体系资源的使用率和整体的相应速度。通过轮番分配处置惩罚器时间片,操作体系可以实现进程之间的并发实行。
资源管理: 每个进程都有自己独立的内存空间和资源管理机制,使得它们可以独立地分配和管理体系资源,如内存、文件、装备等。如许可以避免进程之间相互干扰或访问其他进程的数据。
任务调理: 进程调理是操作体系的核心功能之一。操作体系根据肯定的调理算法,动态地分配处置惩罚器时间片给差别的进程,以实现多任务之间的公平竞争和优先级管理。
进程间通讯: 进程可以通过进程间通讯(IPC)机制来举行数据互换和协作,实现差别进程之间的数据共享和通讯。常见的 IPC 机制包括管道、消息队列、信号量、共享内存等。
       错误隔离: 每个进程都运行在自己独立的地点空间中,一个进程的错误或瓦解不会影响到其他进程,提高了体系的稳定性和可靠性。
6.2 简述壳Shell-bash的作用与处置惩罚流程

壳(Shell)的作用:
壳(Shell)是用户与操作体系内核之间的接口,它吸收用户输入的命令,并将其转换成相应的体系调用或步伐运行。壳可以解释并实行用户输入的命令,同时提供了许多功能强盛的工具和功能,如脚本编程、管道、重定向、变量赋值等。最常见的壳之一是 Bash(Bourne Again Shell),它是许多 Linux 和 Unix 体系默认的命令行解释器。
Bash 的处置惩罚流程:
提示符显示: Bash 在等待用户输入命令时,通常会显示一个提示符,用于指示用户可以输入命令了。提示符的形式通常是一个字符或字符串,如 $ 大概 username@hostname:~$。
用户输入命令: 用户输入命令后,Bash 会读取并解析用户输入的内容,识别出命令和参数,并根据需要举行变量更换、通配符展开等操作。
命令实行: Bash 根据用户输入的命令,调用相应的步伐或体系调用来实行命令。如果命令是内置命令(如 cd、echo 等),则 Bash 会直接实行该命令;如果命令是外部步伐,Bash 则会搜索 PATH 环境变量指定的目录,找到并实行对应的步伐。
输出显示: 实行命令后,Bash 会将命令的输出显示在终端上,供用户检察。如果命令产生了尺度输出(stdout)或尺度错误输出(stderr),Bash 会将它们显示在终端上。
等待下一条命令: 实行完命令后,Bash 会继续等待用户输入下一条命令,直到用户退出或关闭终端。
总的来说,Bash 作为壳步伐充当了用户与操作体系之间的桥梁,负责解释和实行用户输入的命令,并将效果输出到终端上,为用户提供了一个强盛而灵活的命令行环境。
6.3 Hello的fork进程创建过程

https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image156.png&pos_id=s6O2dO9t
shell判定输入的指令不是内置指令,则调用fork函数创建一个子进程,子进  程会获得与父进程虚拟地点空间雷同的一段数据结构的副本。
调用fork()函数创建子进程,fork()函数最终调用fork体系调用,实行体系调用处置惩罚函数,存放体系调用号的寄存器(EAX)中为常数SYS_fork(在IA-32+Linux平台中为2),调用相应的体系调用服务例程sys_fork()实行,sys_fork()最终将创建一个子进程,其存储器映射与其父进程的完全雷同,即子进程完全复制父进程的mm_struct、vm_area_struct数据结构和页表,并将两者中每一个私有页的访问权限都设置成只读,最后将两者的vm_area_struct中描述的私有区域中的页都设置为私有的写时拷贝页。假设父进程先被调理返回实行,在子进程结束后返回到fork()函数的调用点。

6.4 Hello的execve过程

       创建进程后,加载和实行hello进程,子进程调用execve()体系调用封装函数在函数参数中指定加载并实行用户在命令行输入的hello步伐,execve()函数最终调用execve体系调用,实行体系调用处置惩罚函数,存放体系调用号的寄存器(EAX)中为常数SYS_wait4(在IA-32+Linux平台中为11),调用操作体系的加载器,将hello步伐加载到当进步程的虚拟地点空间,加载器删除子进程现有的虚拟内存段,并创建一组新的代码、数据、堆和栈段。新的栈和堆段被初始化为零,为用户栈分配页框并映射到当进步程的虚拟地点空间,将参数argv和环境变量envp放入栈中,遍历hello可实行文件(ELF格式)的步伐头表,找到动态加载器的路径,再次遍历hello的步伐头表,获取可加载段的信息,再通过do_mmap()内核函数将动态加载器文件(ELF格式)中的可加载段映射到当进步程的虚拟地点空间中,在此过程中填写相应的vm_area_struct数据结构,纪录可加载段对应的区域和属性标记,新的代码和数据段被初始化为可实行文件中的内容。将动态加载器的入口地点作为当进步程实行的入口。在加载并实行了一系列动态加载器的指令后,动态加载器举行加载时动态链接。最后加载器设置 PC (步伐计数器)指向_start 地点,_start 最终调用 hello 中的 main 函数。execve 函数加载并运行可实行目标文件 filename, 且带参数列表 argv 和环境变量列表 envp 。只有当出现错误时,例如找不到 filename, execve 才会返回到调用步伐。

https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image158.png&pos_id=2O0R8uf0
6.5 Hello的进程实行

上下文信息:上下文就是内核重新启动一个被抢占的进程所需要的状态,它由通用寄存器、浮点寄存器、步伐计数器、用户栈、状态寄存器、内核栈和各种内核数据结构等对象的值构成。
进程时间片:一个进程实行它的控制流的一部分的每一时间段叫做时间片(time slice)。因此,多任务也叫做时间分片(timeslicing)。
当开始运行hello时,内存为hello分配时间片,如一个体系运行着多个进程,
处置惩罚器的一个物理控制流就被分成了多个逻辑控制流并发实行。然后在用户态下实行并保存上下文。如果在此期间内发生了异常或体系停止,如发生TLB的缺页故障,则内核会壅闭该进程,并在核心态中举行上下文切换,通过schedule()函数调用调理器,选择体系中别的一个用户进程Q举行上下文切换
当hello 实行到 sleep时,hello 会休眠,再次上下文切换,控制交付给其他进程,一段时间后再次上下文切换,恢复hello在休眠前的上下文信息,控制权回到 hello 继续实行。
接着hello在循环结束后,步伐调用getchar(),hello又从用户模式进入内核模式,并再次上下文切换,控制交付给其他进程。最终,内核从其他进程回到 hello进程,在return后进程结束。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image160.png&pos_id=6M9wcd7f
6.6 hello的异常与信号处置惩罚

hello实行过程中会产生的异常:

[*]命令行参数异常:如果命令行参数不是5个,步伐会输出错误信息并退出,为陷阱异常
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image161.png&pos_id=TKN5bUJf
2. 体系调用异常:步伐使用了sleep函数,如果该函数调用失败,会产生SIGALRM信号,步伐会退出,为终止异常。
3. 用户输入异常:如果用户在步伐运行过程中按下Ctrl-C,会产生SIGINT信号,步伐会退出。如果用户按下Ctrl-Z,步伐会被挂起,此时可以使用fg命令将步伐恢复到前台运行,大概使用kill命令杀死步伐,为停止。
在步伐中,对于SIGINT和SIGALRM信号,步伐使用了默认的信号处置惩罚方式,即直接退出步伐。对于Ctrl-Z产生的SIGTSTP信号,步伐没有显式处置惩罚,而是被挂起,可以使用fg命令将其恢复到前台运行。
       如果在实行过程中不绝乱按(不包括回车),输出效果如下:
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image163.png&pos_id=wWvknys3
       在步伐实行过程中不停乱按,会将乱按的字符打印在屏幕上,对步伐没有其它影响。循环结束后让getchar()读入回车结束运行。
如果在实行过程中不绝乱按(包括回车),输出效果如下:
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image165.png&pos_id=SoyzDr7B
       由图,用户依次输入一个回车,乱按,一个回车,而getchar()只会读走第一个回车,后面的字符就会先存在输入缓冲区中,等待步伐运行结束后被终端读走再输出在屏幕上。
如果在步伐实行过程中按下ctrl+z,效果如下:
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image167.png&pos_id=19Js0mVZ
       由图,在步伐运行过程中键入Ctrl+Z会让步伐产生停止,向前台步伐发送信号SIGSTP,这时hello会吸收到信号SIGSTP并运行信号处置惩罚步伐让hello进程暂时停止,并打印相关信息。
在shell中输入ps命令,效果如下。
       在此中可以找到被挂起的hello步伐。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image169.png&pos_id=TA7ySJJX
在shell中输入jobs命令,效果如下。
       打印出被挂起的hello的相关信息。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image171.png&pos_id=EbZSPWGw
在shell中输入pstree命令,效果如下。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image172.png&pos_id=gMB9Z5hj
输入fg命令,效果如下:
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image174.png&pos_id=GXxrhnUo
       fg命令让被挂起的hello进程继续运行,在终端打印剩下未打印的6个Hello 2022110890 吴柏楠 19903663968,接着getchar()读入回车结束进程。

在步伐实行过程中按下ctrl+c,效果如下:
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image175.png&pos_id=AOlBV91c
       在步伐运行过程中键入Ctrl+C会让步伐产生停止异常,向前台步伐发送信号SIGINT。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image177.png&pos_id=hdi6Fyd9
       发现进程hello已经不存在了,阐明hello进程在SIGINT信号的作用下强行被终止,并被父进程shell接纳了。与键入Ctrl+Z效果差别

在shell中输入kill命令,效果如下。
       运行hello步伐,先键入ctrl+z停止步伐
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image179.png&pos_id=wNKW0Jhv
       在shell中输入ps检察进程hello的PID
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image180.png&pos_id=4eTVZzEf
       接着输入kill -9 6098来发送信号SIGKILL给进程6098,从而杀死该进程。接着再输入ps检察当进步程,发现hello进程已被杀死。
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%2FUsers%2FWBN%2FAppData%2FLocal%2FTemp%2Fmsohtmlclip1%2F01%2Fclip_image182.png&pos_id=FT9mYWD4
6.7本章小结

本章综合介绍了进程的概念、Shell-bash 的作用与处置惩罚流程,以及 hello 进程的创建过程和 execve 过程。同时,结合了进程的上下文信息、进程时间片、用户态与核心态转换等概念,详细阐述了 hello 进程怎样在 Shell 中作为一个子进程实行。
起首,相识了进程的概念和作用,进一步熟悉了进程在操作体系中的紧张性。然后,扼要介绍了 Shell-bash 在操作体系中的作用及其处置惩罚流程,包括吸收用户输入命令、解析实行命令等过程。接着,通过 fork 进程创建一个子进程,以及子进程通过 execve 体系调用加载并实行步伐的过程。
       在分析进程的实行过程中,深入讨论了进程的上下文信息、进程时间片、用户态与核心态转换等概念,以资助理解进程的实行机制。特殊地,在异常与信号处置惩罚方面,运用了一系列命令如 ps、jobs、pstree、fg、kill 等来测试进程实行过程中大概出现的异常和产生的信号,以加深对信号与异常处置惩罚的理解。

第7章 hello的存储管理

7.1 hello的存储器地点空间

逻辑地点: 逻辑地点是进程中使用的地点空间,通常由步伐员编写的步伐中使用。在 hello 步伐中,逻辑地点用于访问步伐中的变量、函数和指令等。逻辑地点是步伐的抽象表现,不依赖于实际的硬件。
线性地点: 线性地点是逻辑地点通过地点映射机制转换后的地点。在虚拟内存体系中,线性地点是由操作体系管理的地点空间,它提供了一种统一的地点空间给每个进程使用。在 hello 步伐中,操作体系将逻辑地点映射到线性地点上,以便举行虚拟内存管理和地点转换。
虚拟地点: 虚拟地点是进程在运行时使用的地点空间,它是线性地点的别名。在 hello 步伐中,虚拟地点用于访问进程所需的内存区域,包括代码段、数据段、堆和栈等。虚拟地点是由操作体系动态分配和管理的,它不直接映射到物理内存,而是通过地点映射机制转换成物理地点。
物理地点: 物理地点是实际存储器中的地点,它对应着体系中的物理内存空间。在 hello 步伐实行过程中,操作体系将虚拟地点映射到物理地点上,以便步伐可以访问实际的内存区域。物理地点是硬件层面的概念,它与具体的内存芯片和地点线有关。
综上所述,hello 步伐的存储器地点空间涉及了逻辑地点、线性地点、虚拟地点和物理地点的概念。逻辑地点是步伐中使用的地点空间,线性地点是逻辑地点通过地点映射转换后的地点,虚拟地点是进程在运行时使用的地点空间,而物理地点则对应着实际的存储器地点空间。操作体系通过地点映射机制将虚拟地点映射到物理地点上,以实现虚拟内存管理和地点转换。
7.2 Intel逻辑地点到线性地点的变更-段式管理

在 Intel x86 架构中,逻辑地点到线性地点的变更采用了段式管理机制。这个过程紧张涉及到段选择子、段描述符和段寄存器,以及基于段描述符的地点变更过程。
段选择子(Segment Selector): 段选择子是一个16位的数据结构,包含了段选择器和段表索引。段选择器是一个指向段描述符表中段描述符的索引,而段表索引则指示了该段描述符的起始位置。段选择子保存在段寄存器(如 CS、DS、ES、SS 等)中,用于在段描述符表中定位相应的段描述符。
段描述符(Segment Descriptor): 段描述符是一个8字节的数据结构,存储了一个段的属性信息和基地点。它包括了段的起始地点、段的长度、访问权限等信息。段描述符被存储在全局描述符表(GDT)或局部描述符表(LDT)中。
地点变更过程:
当CPU实行指令时,会根据指令中的段选择子(如 CS 寄存器)去索引全局描述符表(GDT)或局部描述符表(LDT),找到相应的段描述符。
然后,CPU会使用段描述符中的基地点和逻辑地点中的偏移量举行地点变更。逻辑地点中的偏移量作为段内的偏移量,加上段描述符中的基地点,得到线性地点。
如果开启了分页机制,线性地点再颠末页表的转换,最终得到物理地点。
通过这种段式管理机制,CPU能够根据段选择子和段描述符实现逻辑地点到线性地点的转换,同时通过页表实现线性地点到物理地点的转换,从而实现了对地点空间的管理和保护。
7.3 Hello的线性地点到物理地点的变更-页式管理

在 Intel x86 架构中,线性地点到物理地点的变更通常采用页式管理机制。这个过程涉及到页表、页目录、页目录表寄存器(CR3)、页表项等关键概念。
页表(Page Table): 页表是一种数据结构,用于将线性地点映射到物理地点。它是由操作体系管理的,存储在内存中。每个进程都有自己的页表,用于将其线性地点映射到物理地点。
页目录(Page Directory): 页目录是一个存储页表地点的数据结构,用于构建多级页表。在 Intel x86 架构中,页目录共有1024个条目,每个条目指向一个页表。
页表项(Page Table Entry): 页表项是页表中的一个条目,用于存储线性地点与物理地点的映射关系,以及一些相关的控制信息,如读/写权限、存在位等。
页目录表寄存器(CR3): 页目录表寄存器存储了当进步程的页目录的物理地点。当 CPU 实行访存指令时,会根据 CR3 寄存器中的内容来查找当进步程的页表。
地点变更过程:
当 CPU 实行指令时,会生成一个线性地点。
CPU 使用线性地点的高10位作为索引,在当进步程的页目录中找到相应的页表的物理地点。
接着,CPU 使用线性地点的中间10位作为索引,在找到的页表中找到对应的页表项。
最后,CPU 使用线性地点的低12位作为页内偏移量,加上页表项中存储的物理页框号,得到最终的物理地点。
通过这种页式管理机制,操作体系可以将逻辑地点空间划分成大小相等的页面,并将页面映射到物理内存中的页框上,实现了对内存的有效管理和保护。同时,页式管理还支持虚拟内存机制,允许操作体系在物理内存不足时,将部分页面存储到硬盘上,以实现更大的地点空间。
7.4 TLB与四级页表支持下的VA到PA的变更

在使用四级页表支持下的虚拟地点(VA)到物理地点(PA)的变更过程中,TLB(Translation Lookaside Buffer)饰演着紧张的脚色。TLB是一个高速缓存,用于存储最近访问过的虚拟地点到物理地点的映射关系,以加速地点转换的速度。
TLB(Translation Lookaside Buffer): TLB是一个硬件缓存,用于存储最近的一些虚拟地点到物理地点的映射关系。TLB的大小通常比较有限,但是由于它位于 CPU 内部,访问速度非常快。当 CPU 需要将虚拟地点转换为物理地点时,起首会在 TLB 中查找是否存在对应的映射关系,如果存在,则直接从 TLB 中获取物理地点,从而加速地点转换的过程。
四级页表(Four-Level Page Table): 四级页表是一种多级页表的实现方式,在 Intel x86 架构中常用。它将整个虚拟地点空间划分为多级结构,每一级对应一个页表,通过多级结构可以有效地减少页表的大小。通常情况下,四级页表的结构包括页目录表、页表、页表项等数据结构。
地点变更过程:
当 CPU 实行访存指令时,会生成一个虚拟地点。
CPU 起首使用虚拟地点的高位来索引 TLB,查找是否存在对应的物理地点。如果 TLB 中存在对应的映射关系,则直接从 TLB 中获取物理地点,地点转换完成。
如果 TLB 中未找到对应的映射关系,则 CPU 需要举行页表查找。
CPU 使用虚拟地点的高位来索引第一级页表(页目录表),根据页目录表中的条目找到第二级页表的地点。
接着,CPU 使用虚拟地点的中间位来索引第二级页表,依次找到第三级页表和第四级页表的地点。
最后,CPU 使用虚拟地点的低位来索引最后一级页表中的页表项,从中获取物理页框号,并将页内偏移量加上物理页框号,得到最终的物理地点。
通过 TLB 和四级页表的支持,CPU 可以快速高效地将虚拟地点转换为物理地点,从而实现了虚拟内存管理和地点空间的保护。TLB 的存在加速了地点转换的速度,而多级页表的结构有效地减少了页表的大小,提高了地点转换的效率。
7.5 三级Cache支持下的物理内存访问

在三级缓存(L3 Cache)支持下的物理内存访问过程中,缓存体系通过多级缓存结构提供了快速的数据访问路径,以减少对主存(RAM)的访问延迟和提高数据访问速度。
三级缓存(L3 Cache): L3 缓存是位于 CPU 芯片内部的高速缓存,通常是多个 CPU 核心共享的。L3 缓存的容量较大,速度相对较快,但仍远远低于 CPU 核心内部的一级缓存(L1 Cache)和二级缓存(L2 Cache)。
地点变更过程:
当 CPU 需要访问内存中的数据时,起首会查找 L1 Cache。如果数据在 L1 Cache 中找到(命中),则直接从 L1 Cache 中读取数据,访问完成。
如果数据未在 L1 Cache 中找到,则继续查找 L2 Cache。如果数据在 L2 Cache 中找到,则从 L2 Cache 中读取数据,访问完成。
如果数据未在 L2 Cache 中找到,则继续查找 L3 Cache。如果数据在 L3 Cache 中找到,则从 L3 Cache 中读取数据,访问完成。
如果数据未在 L3 Cache 中找到,则继续访问主存(RAM)。CPU 会向主存发起读取请求,并将数据加载到 L3 Cache、L2 Cache 和 L1 Cache 中,同时返回数据给 CPU,完成访问。
缓存更换策略: 在多级缓存中,通常采用的是 Least Recently Used(LRU)更换策略。当缓存满时,需要更换缓存中的数据。LRU 策略会选择最近最少被使用的缓存行举行更换,以保留最常被使用的数据。
       通过 L3 缓存的支持,CPU 在访问内存数据时能够先在 L3 Cache 中举行查找,从而加速数据访问的速度。L3 Cache 的存在减少了对主存的访问频率,低落了访问延迟,提高了体系的整体性能。
7.6 hello进程fork时的内存映射

在 hello 进程调用 fork() 函数创建子进程时,子进程会继续父进程的地点空间。这意味着子进程将获得与父进程雷同的内存映射,包括代码段、数据段、堆和栈等。
具体来说,在 fork() 调用后,操作体系会创建一个新的进程控制块(PCB)和页表,但是子进程的页表会与父进程的页表共享雷同的物理页面。这意味着子进程将看到与父进程雷同的内存映射关系,即雷同的虚拟地点将映射到雷同的物理地点上。
在典型的情况下,fork() 调用后,子进程的内存映射与父进程的内存映射是完全雷同的,包括:
代码段:子进程将实行与父进程雷同的步伐代码。
数据段:子进程将拥有与父进程雷同的全局变量和静态变量。
堆:子进程将继续父进程的堆空间,包括动态分配的内存。
栈:子进程将拥有一个新的栈,但是栈中的内容与父进程雷同。
需要留意的是,固然子进程与父进程共享雷同的物理页面,但是它们各自拥有独立的页表。这意味着对于雷同的虚拟地点,在父进程和子进程中大概会映射到差别的物理页面上。此外,子进程的页表大概会通过写时复制(Copy-on-Write,COW)机制举行优化,以减少内存开销。
       总之,在 hello 进程调用 fork() 创建子进程时,子进程将继续父进程的内存映射,但是它们各自拥有独立的页表,从而实现了地点空间的隔离和保护。
7.7 hello进程execve时的内存映射

当 hello 进程调用 execve() 函数时,它将加载一个新的可实行文件到当进步程的地点空间,代替原来的步伐映像。这意味着原来的步伐代码、数据和堆栈等内容将被新的可实行文件更换,进程的地点空间将被重新映射。
具体来说,在 execve() 调用后,操作体系会将新的可实行文件加载到当进步程的地点空间,并举行相应的内存映射。这个过程包括以下几个步骤:
清理原有的内存映射: 起首,操作体系会清理原有的步伐代码、数据和堆栈等内存映射,开释相关资源。
加载新的可实行文件: 然后,操作体系会将新的可实行文件加载到进程的地点空间中。这包括步伐的代码段、数据段和其他相关的内存区域。
创建新的内存映射: 操作体系会根据新的可实行文件的要求,在进程的地点空间中创建新的内存映射。这包括步伐的代码段、数据段、堆、栈以及其他需要的内存区域。
更新页表: 最后,操作体系会更新进程的页表,以便正确地将虚拟地点映射到物理地点。这确保了步伐能够正常实行,而且能够正确地访问内存中的数据。
       在 execve() 调用后,进程的地点空间将被重新映射为新的可实行文件的内存布局。这意味着原来的步伐状态将被完全更换,进程将以新的步伐状态开始实行。
7.8 缺页故障与缺页停止处置惩罚

缺页故障(Page Fault)是指当步伐访问的页面不在内存中,而是在外部存储装备(通常是硬盘)上时发生的情况。缺页停止(Page Fault Interrupt)是处置惩罚缺页故障的一种停止类型,它触发了操作体系的相应机制,以便将所需的页面加载到内存中。
下面是缺页故障与缺页停止处置惩罚的一样平常步骤:
发生缺页故障: 当步伐访问的页面不在内存中时,CPU 将会触发一个缺页故障,即发出缺页停止。
操作体系相应: 当操作体系收到缺页停止时,它会根据缺页故障的具体情况实行相应的处置惩罚步伐。
页面调理: 操作体系起首会查抄访问的页面是否在外部存储装备上,如果是的话,就需要将该页面加载到内存中。这个过程通常称为页面调理(Page Scheduling)。
页面加载: 操作体系根据页面调理算法选择要更换的页面(如果内存已满),将需要的页面从外部存储装备加载到内存中,并将其映射到正确的虚拟地点上。
更新页表: 操作体系将更新进程的页表,以便将访问的虚拟地点正确映射到物理地点。这确保了步伐能够继续实行,而且能够正确地访问所需的页面。
恢复实行: 最后,操作体系将恢复步伐的实行,使其继续实行被停止的指令。通常,CPU 会重新实行导致缺页故障的指令,这次指令可以乐成实行,因为所需的页面已经加载到了内存中。
       总的来说,缺页故障和缺页停止处置惩罚机制确保了步伐在访问不在内存中的页面时能够正常实行,而且能够正确地将所需的页面加载到内存中,以满足步伐的运行需求。
7.9动态存储分配管理

动态内存管理的基本方法:使用动态内存分配器维护堆,分配器将堆视为一组差别大小的块的集合来维护。每个块就是一个连续的虚拟内存片,要么是已分配的,要么是空闲的。空闲块可用来分配。需要时选择一个符合的空闲块举行内存分配。
       策略:(1)纪录空闲块:显示空闲链表,隐式空闲链表,分离空闲链表,红黑树;(2)放置策略:初次适配、下一次适配、最佳适配;(3)合并策略:立刻合并、延迟合并
7.10本章小结

       本章综合了第六章和第九章的内容,重点介绍了存储器的地点空间。起首,讨论了虚拟地点、物理地点、线性地点和逻辑地点的概念,以及它们之间的关系。随后,详细描述了逻辑地点到线性地点和线性地点到物理地点的转换过程,夸大了地点空间映射的紧张性。接着,介绍了在进程 `fork` 和 `execve` 时发生的内存映射过程,包括新步伐的加载和旧步伐的更换。最后,详细解释了体系怎样处置惩罚缺页异常,即当步伐试图访问未加载到内存中的页面时的情况。这些内容加深了对虚拟内存和存储器层次结构的理解,为进一步探索操作体系的内存管理机制打下了底子。


第8章 hello的IO管理

8.1 Linux的IO装备管理方法

装备的模型化:文件
一个 Linux 文件就是一个 m 个字节的序列,所有的 I/O 装备(例如网络、磁盘和终端)都被模型化为文件,而所有的输入和输出都被当尴尬刁难相应文件的读和写来实行。这种将装备优雅地映射为文件的方式,允许 Linux 内核引出一个简单、低级的应用接口,称为 Unix I/O,这使得所有的输入和输出都能以一种统一且同等的方式来实行:
Unix文件类型:
1.平凡文件(regular file)包含恣意数据。应用步伐常常要区分文本文件(text file)和二进制文件(binary file),文本文件是只含有 ASCII 或 Unicode 字符的平凡文件;二进制文件是所有其他的文件。
2.目录(directory)是包含一组链接(link)的文件,此中每个链接都将一个文件名(filename)映射到一个文件,这个文件大概是另一个目录。每个目录至少含有两个条目:是到该目录自身的链接,以及是到目录层次结构(见下文)中父目录(parent directory)的链接。
3.套接字(socket)是用来与另一个进程举行跨网络通讯的文件
4.命名通道(named pipe)
5.符号链接(symbolic link)
6.字符和块装备(character and block device)终端(Terminals特殊字符)和磁盘(disk特殊块)
7.FIFO(管道)用于进程内部通讯的文件类型
装备管理:unix io接口
1.   打开文件。一个应用步伐通过要求内核打开相应的文件,来宣告它想要访问一个I/O 装备,内核返回一个小的非负整数,叫做描述符,它在后续对此文件的所有操作中标识这个文件,内核纪录有关这个打开文件的所有信息。
2.   shell 创建的每个进程开始时都有三个打开的文件:标淮输入(描述符为0)、尺度输出 (描述符为1)和尺度错误 (描述符为2)。
3.   改变当前文件的位置。对于每个打开的文件,内核保持着一个文件位置k
初始为0。
4.读写文件。一个读操作就是从文件复制n>0个字符到内存,从当前文件
位置k开始,然后k+=n对给定一个大小为m字节的文件,当k>=m时实行读
操作会出发一个称为 EOF 的尔件,应用步伐能检测到这个条件。
5.关闭文件。当应用完成了对文件的访问之后,它就通知内核关闭这个文件。
无论一个进程因为何种缘故原由终止时,内核都会关闭所有打开的文件并开释它们的内存资源。
8.2 简述Unix IO接口及其函数

(1)Opening Files 打开文件
打开文件是通知内核你预备好访问该文件
Open(char *filename,int flags,mode_t mode);
返回一个小的描述符数字---- 文件描述符。返回的描述符总是在进程中当前没有打开的最小描述符。
Linux内核创建的每个进程都以与一个终端相关联的三个打开的文件开始:
0: 尺度输入 (stdin)
1: 尺度输出 (stdout)
2: 尺度错误 (stderr)
(2)改变当前的文件位置  (seek)
指示文件要读写位置的偏移量
lseek()函数用于在指定的文件描述符中将将文件指针定位到相应位置。
(3)Reading Files 读文件
读文件从当前文件位置复制字节到内存位置,然后更新文件位置
read(fd, buf, sizeof(buf))
(4)Writing Files 写文件
写文件从内存复制字节到当前文件位置,然后更新文件位置
write(fd, buf, sizeof(buf))
返回值表现的是从内存向文件fd实际传送的字节数量
如:printf()函数最终将调用体系级I/O函数write(1, "Hello world!\n",13)
(5)Closing Files 关闭文件
关闭文件是通知内核你要结束访问一个文件
close(fd)
返回:若乐成则为 0,若出错则为 -1。
       关闭一个已关闭的描述符会出错。
8.3 printf的实现分析

1.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 
va_list arg = (va_list)((char*)(&fmt)+ 4)中(char*)(&fmt) + 4)为..:中第一个参数。 
2.从vsprintf生成显示信息
调用vsprintf 函数。vsprintf 的作用是格式化。它接受确定输特殊式的格式字符串fmt。用格式字符串对个数变化的参数举行格式化,产生格式化输出,返回要打印出来的字符串的长度i。 
3.调用体系级I/O函数 write
 write把 buf 中的前i个字符,也就是要输出的格式串打印到
屏幕上。检察write反汇编代码可知write通过实行int INT VECTOR SYS CALL指令,导致一个到异常处置惩罚步伐的陷阱,体系调用内核步伐sys_call函数  write:
mov eax, _NR_write
mov ebx,
mov ecx,
4.   调用sys_call 函数。
可以找到INT_VECTOR_SYS_CALL的实现:
init_idt_desc(INT_VECTOR_SYS_CALL,DA_386IGate,sys_call,PRIVILEGE_USER);
    sys_call:
     call save
     push dword
     sti
     push ecx
     push ebx
     call
     add esp, 4 * 3
     mov , eax
     cli
     ret
功能:显示格式化的字符串
5.字符显示驱动子步伐:从ASCII到字模库到显示vram(存储每一个点的RGB颜色信息)
6.显示芯片按照革新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量)。
8.4 getchar的实现分析

1.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>=O) ? (unsigned char)*bb++ : EOF;
2.调用read函数:
异步异常-键盘停止的处置惩罚:键盘停止处置惩罚子步伐。接受按键扫描码转成ascii码,保存到体系的键盘缓冲区。
getchar等调用Unix I/O read体系函数,通过体系调用读取缓冲区中按键ascii码,直到接受到回车键才返回。
8.5本章小结

       本章着重介绍了Linux体系中的I/O装备管理方法,以及Unix体系中用于开启、关闭、读取、写入和转移文件的接口及相应的函数。特殊详细地分析了 printf 和 getchar 函数的具体实现方式。通过对这些函数的分析,我们深入理解了它们在步伐中的作用和实现原理。至此,我们对步伐 hello 的整个生命周期举行了全面的分析和解读,从开启、运行、直至结束,理解了它的运行过程中涉及的各种操作和机制。































结论

在"hello"的一生中,经历了多个关键阶段,展现了计算机体系的各个方面:
1. 源代码编写:步伐员使用高级语言在编辑器中编写了hello.c文件,并将其存储在内存中。
2. 预处置惩罚:通过预处置惩罚器对hello.c文件举行处置惩罚,生成了修改后的文本文件hello.i,此中删除了注释并举行了一些宏更换。
3. 编译:编译器将hello.i翻译成汇编语言,生成了hello.s文件。
4. 汇编:汇编器处置惩罚hello.s,生成了可重定位目标文件hello.o。
5. 链接:链接器将hello.o与其他可重定位目标文件链接,生成了可实行目标文件hello。
6. 步伐实行:在shell中运行hello步伐,创建子进程,实行execve,将步伐酿成一个独立的进程。
7. 进程实行:hello步伐获得时间片,实行自身的逻辑控制流,通过三级缓存访问内存,将虚拟地点映射成物理地点。
8. 信号处置惩罚:hello对差别的信号有差别的处置惩罚方式,体现了对异常控制流的处置惩罚。
9. 步伐终止:通过kill命令终止hello进程,接纳子进程资源。
       这一过程使我们深入相识了计算机体系中步伐的创建、编译、链接、实行、终止等紧张过程。通过对这一生命周期的分析和实践,我们加深了对计算机体系内部工作原理的理解,从而能够编写更高效、可靠的代码,而且拓展了我们对计算机体系的认知。


附件

hello.c         C语言源文件
hello.i          预处置惩罚产生的文件
hello.s         编译产生的汇编代码文件
hello.o               汇编产生的可重定位目标文件
hello.o.elf    hello.o文件的ELF格式
hello.o.asm hello.o反汇编生成的文本文件
hello            链接产生的可实行目标文件
hello.elf              hello文件的ELF格式
hello.asm    hello反汇编生成的文本文件

参考文献


[*]Linux常用命令大全(非常全!!!) - fcyh - 博客园 (cnblogs.com)
[*]  Linux内核停止顶半部和底半部的理解-CSDN博客.
[*] 段、页、页框、页表、页表项_页框号-CSDN博客
  进程的上下文切换_进程上下文切换-CSDN博客
逻辑地点、物理地点、线性地点、虚拟地点、段基地点偏移地点的接洽和区别_逻辑地点和物理地点的区别和接洽-CSDN博客
  C语言尺度IO函数整理-CSDN博客
ELF魔数-CSDN博客
objdump(Linux)反汇编命令使用指南_反汇编objdump-CSDN博客
全局变量、局部变量、const、static、内存管理和开释_rusyq全局静态需要手动开释吗-CSDN博客
动态内存管理(内存的分配与接纳)-知乎


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 步伐人生-Hello’s P2P