目 录
2.2在Ubuntu下预处理的命令............................................................................. - 5 -
5.3 可执行目标文件hello的格式........................................................................ - 8 -
6.2 简述壳Shell-bash的作用与处理流程........................................................ - 10 -
6.3 Hello的fork进程创建过程......................................................................... - 10 -
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 -
8.2 简述Unix IO接口及其函数.......................................................................... - 13 -
第1章 概述
1.1 Hello简介
P2P,即Program to Process,这一过程为程序员编写的代码经过预处理、编译、汇编、链接得到可执行文件,再由shell为hello创建进程并加载可执行文件,变成一个运行中的hello进程。
020,即hello.c文件中的“from 0 to 0”,指程序开始并不在内存中,shell调用execve函数,OS会为其开辟空间,执行完毕后,开辟的空间会被回收。
1.2 环境与工具
硬件环境:CPU: AMD R75800H;RAM: 16GB;Disk:512G。
软件环境:windows11,Vmware 16,Ubuntu 20.04。
开发工具:Visual Studio Code; vi/vim/gpedit+gcc
1.3 中间结果
列出你为编写本论文,生成的中间结果文件的名字,文件的作用等。
文件名 | 作用 |
hello.i | 经过预处理的文件,可分析预处理过程 |
hello.s | 汇编语言文件,分析编译过程 |
hello.o | 可重定位目标执行文件,分析汇编过程 |
hello.elf | hello.o的elf格式文件,分析汇编和链接过程 |
hello.txt | helloo.o的反汇编文件,分析hello.o |
hello | 可执行文件,分析链接过程 |
helloo.elf | hello的elf文件,分析重定位过程 |
helloo.txt | hello的反汇编文件,分析重定位过程 |
1.4 本章小结
本章对hello进行了一个总体的概括,首先介绍了P2P、020的意义和过程,介绍了作业中的硬件环境、软件环境和开发工具,最后简述了从.c文件到可执行文件中间经历的过程。
(第1章0.5分)
第2章 预处理
2.1 预处理的概念与作用
概念:预处理器(cpp)根据以字符#开头的命令,修改原始的C程序。结果就得到了另一个C程序,通常是以.i作为文件扩展名。
作用:预处理的机制提高了源文件的灵活性,能适应不同的计算机和操作系统;而且通过预处理指令,可以使用已经封装好的库函数,极大地提高了编程效率。
2.2在Ubuntu下预处理的命令
命令:gcc -E hello.c -o hello.i
生成hello.i文件
2.3 Hello的预处理结果解析
打开hello.i文件,可以发现文件已被扩展至几千行,而在文件末尾,如下图,与源程序并无两样。再根据内容,可知.i文件是对源文件的宏进行了展开,即对stdio.h,unistd.h,stdlib.h的头文件展开。
2.4 本章小结
本章简要介绍了预处理的概念和作用,通过对生成的hello.i文件内容的解析,分析预处理的实际操作,得到结论:预处理生成的.i文件实际是对源程序的补充和扩展,是修改后的程序。
第3章 编译
3.1 编译的概念与作用
概念:编译器(ccl)将文本文件hello.i翻译成文本文件hello.s,它包含一个汇编语言程序。
作用:进行语法分析,对编译完成的程序的输入符号进行检查,不符合语法标准就会发生错误。同时还会进行优化,根据代码和硬件环境进行可选择的优化。
3.2 在Ubuntu下编译的命令
命令:gcc -S hello.i -o hello.s
3.3 Hello的编译结果解析
- 初始部分
在文件首部展示了节名称
.file | 说明源文件为hello.c |
.text | 表示代码节 |
.section .rodata | 表示只读数据段 |
.align | 表示对齐方式为8字节对齐 |
.string | 表示一个字符串 |
.globl | 表示全局变量 |
.type | 表示类型 |
- 数据
- 全局变量
main函数,如下图
- 字符串
输出的“hello 学号 姓名”这个字符串,如下图
- 局部变量
for循环中的i变量
- 常量
代码中for循环中i小于等于8
- 赋值操作
for循环中的i变量初始赋值为0,i是int型变量,使用movl指令。
- 算数操作
在for循环中,i变量自增加一时使用addl指令
- 关系操作
(1)if(argc != 4),这个语句比较参数argc的大小,设置了跳转
(2)for循环中i变量会与9进行比较,for(i =0; i<9;i++)
- 控制转移
与上一条一样,
(1)对比参数argc进行跳转,argc不为4,执行if语句,否则执行下一个语句。
(2)for循环比较i变量和9,决定循环继续与否。i小于9继续循环,否则跳出循环。
- 函数操作
- main函数
函数参数为int argc,char *argv[],分别在%rdi,%rsi寄存器里,之后传入%rbp中。
函数内部调用了printf,exit,atoi,sleep,getchar函数。下图只列出其中三种。
函数内部使用了局部变量i用来实现for循环,函数返回0。
- printf函数
该函数调用参数argv[1],argv[2]。
第一次调用:将下列字符串打印
第二次调用:将其设置为“Hello %s %s”的初始地质。
- exit函数
函数使用参数1,将%rdi设置为1,使用call指令调用,完成exit(1)。
- atoi函数
函数调用argv[3],将argv[3]传入%rdi寄存器作为参数
- sleep函数
使用atoi(argv[3])作为参数,将atoi函数返回值传入%edi,进行调用。
- getchar函数
无参数传递,直接使用指令调用。
3.4 本章小结
本章介绍了编译器将hello.i文件翻译为hello.s文件的过程,概括了编译的概念和作用。通过hello.i文件和hello.s文件,介绍了编译器如何处理各个数据类型以及各类操作,说明了大部分数据、操作在汇编代码中的实现。
第4章 汇编
4.1 汇编的概念与作用
概念:汇编器(assembler)将以.s结尾的汇编程序翻译成机器语言指令,把这些指令打包成可重定位目标程序的格式,并把结果保存在以.o结尾的目标文件中的过程。
作用:将汇编语言转换为机器能识别的机器语言,使文件被连接后能被机器识别并执行。
4.2 在Ubuntu下汇编的命令
命令:gcc -c hello.c -o hello.o
4.3 可重定位目标elf格式
- 命令
readelf -a hello.o > hello.elf
- 分析
- ELF头
以 16字节序列 Magic 开始,其描述了生成该文件的系统的字的大小和字节顺序,ELF 头剩下的部分包含帮助链接器语法分析和解释目标文件的信息,其中包括 ELF 头大小、目标文件类型、机器类型、节头部表的文件偏移,以及节头部表中条目的大小和数量等相关信息。如下图:
- 节头
记录各节名称、类型、地址、偏移量、大小、全体大小、旗标、链接、信息、对齐。如下图:
- 重定位节
表示引用的外部符号,通过重定位节对这些位置的地址进行修改。
- 符号表
存放一个程序定义和引用的全局变量和函数的信息。如下图:
4.4 Hello.o的结果解析
将反汇编结果生成txt文件,使用objdump -d -r hello.o > hello.txt。
对比分析:
- 操作数
hello.s中的操作数时十进制,反汇编代码中的操作数是十六进制。
- 分支转移
反汇编的跳转指令,跳转位置表示方法为主函数+段内偏移量,hello.s中为段名称,如L2
- 函数调用
在hello.s文件中,调用函数格式为 call+函数名称,反汇编文件中,call后是一条重定位指引的信息。
4.5 本章小结
本章简单概括了汇编的概念和作用,展示了elf文件的格式内容,对每个节进行简单介绍和分析。并通过比较hello.s文件和反汇编代码,展示汇编过程的细节和前后区别。
第5章 链接
5.1 链接的概念与作用
概念:链接是指通过链接器(Linker),将程序编码与数据块收集并整理成为一个单一文件,生成完全链接的可执行目标文件的过程。
作用:使分离编译成为可能,将大型程序分解为更小,更好管理的模块。
5.2 在Ubuntu下链接的命令
命令:
ld -o hello -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/crti.o hello.o /usr/lib/x86_64-linux-gnu/libc.so /usr/lib/x86_64-linux-gnu/crtn.o
5.3 可执行目标文件hello的格式
分析hello的ELF格式,用readelf等列出其各段的基本信息,包括各段的起始地址,大小等信息。
利用命令readelf -a hello > helloo.elf(是helloo,,不是hello)
分析:
- ELF头
与hello.elf基本相同,类型发生改变,这里是可执行文件类型
- 节头
描述了各个节的大小、偏移量和其他属性
- 程序头
程序头部分是一个结构数组,描述了系统准备程序执行所需的段或其他信息。
- 动态节
- 可重定位条目
- 符号表
5.4 hello的虚拟地址空间
使用edb打开hello程序,如下图
对比elf文件,可知起始地址为0x400000,逐一对照,可以找到每一节对应的信息,如:/.text 节起始位置为0x4010f0,可以找到下图
5.5 链接的重定位过程分析
- 使用命令 objdump -d -r hello > helloo.txt(是helloo,不是hello)生成反汇编文件。对比可以发现:
- 函数数量增加
新增许多函数部分,如init,.plt
- 地址位置改变
如上图init从0x401000开始,而hello.o地址是从0x0开始的,紧跟着,一些跳转指令,函数调用等等的地址都发生了变化。
- 重定位过程
由两步组成:
- 重定位节和符号定位:所以来自一个部分的合并为一个节
- 重定位节中的符号引用,在elf文件中,显示了每个符号的运行时的地址,这在运行时是链接的基本条件。
重定位过程地址计算方法:
5.6 hello的执行流程
401000 <_init>
401020 <.plt>
401030 <puts@plt>
401040 <printf@plt>
401050 <getchar@plt>
401060 <atoi@plt>
401070 <exit@plt>
401080 <sleep@plt>
401090 <_start>
4010c0 <_dl_relocate_static_pie>
4010c1 <main>
401150 <__libc_csu_init>
4011b0 <__libc_csu_fini>
4011b4 <_fini>
5.7 Hello的动态链接分析
查看elf文件,可知.got和.got.plt部分
进入edb查看为
运行init后
对于库函数而言,需要plt、got合作。plt初始存的是一批代码,它们跳转到got所指示的位置,然后调用链接器。初始时got里面存的都是plt的第二条指令,随后链接器修改got,下一次再调用plt时,指向的就是正确的内存地址。接下来执行程序的过程中,就可以使用过程链接表plt和全局偏移量表got进行动态链接。
5.8 本章小结
本章概括了链接的基本概念和作用,展示了使用使用命令链接生成可执行文件的过程,并通过对比其elf文件,和edb运行,分析了hello程序链接中重定位过程,执行过程和动态链接过程。
第6章 hello进程管理
6.1 进程的概念与作用
概念:进程是正在运行的程序的实例。
作用:进程提供给应用程序的关键抽象:一个独立的逻辑控制流;一个私有的地址空间。通过以上两个抽象,进程提供给用户一种假象:就好像我们的程序是系统中当前运行的唯一的程序一样。我们的程序好像是独占地使用处理器和内存。处理器就好像是无间断地一条接着一条地执行我们程序中的指令。最后,我们程序中的代码和数据好像是系统内存中唯一的对象。
6.2 简述壳Shell-bash的作用与处理流程
作用:Shell 是一个用C语言编写的交互型应用程序,代表用户运行其他程序。Shell 应用程序提供了一个界面,用户可以通过这个界面进行系统的基本操作,访问操作系统内核的服务。
处理流程:
① 从Shell终端读入输入的命令。
② 切分输入字符串,获得并识别所有的参数
③ 若输入参数为内置命令,则立即执行
④ 若输入参数并非内置命令,则调用相应的程序为其分配子进程并运行
⑤ 若输入参数非法,则返回错误信息
⑥ 处理完当前参数后继续处理下一参数,直到处理完毕
6.3 Hello的fork进程创建过程
在shell输入./hello 2021112380 任鼎 1。Shell会判断是不是内置命令,然后调用fork函数创建一个新的子进程,子进程获取了与父进程的上下文,包括栈、通用寄存器、程序计数器,环境变量和打开的文件相同的一份副本。
6.4 Hello的execve过程
execve函数在当前进程的上下文中加载并运行一个新程序。execve函数加载并运行可执行目标文件filename,且带参数列表argv和环境变量列表envp。与fork一次调用返回两次不同,execve调用一次,从不返回(除了出现错误)。
6.5 Hello的进程执行
- 进程调度
在进程执行的某些时刻,内核可以决定抢占当前进程,并重新开始一个先前被抢占了的进程,这种决策就叫做调度,是由内核中称为调度器的代码处理的。当内核选择一个新的进程运行,我们说内核调度了这个进程。在内核调度了一个新的进程运行了之后,它就抢占了当前进程,并使用上下文切换机制来将控制转移到新的进程。
- 用户态与核心态转换
为了能让处理器安全运行,不至于损坏操作系统,必然需要先知应用程序可执行指令所能访问的地址空间范围。因此,就存在了用户态与核心态的划分,核心态可以说是“创造模式”,拥有最高的访问权限,处理器以一个寄存器当做模式位来描述当前进程的特权。进程只有故障、中断或陷入系统调用时才会得到内核访问权限,其他情况下始终处于用户权限之中,保证了系统的安全性。
6.6 hello的异常与信号处理
(以下格式自行编排,编辑时删除)
hello执行过程中会出现哪几类异常,会产生哪些信号,又怎么处理的。
程序运行过程中可以按键盘,如不停乱按,包括回车,Ctrl-Z,Ctrl-C等,Ctrl-z后可以运行ps jobs pstree fg kill 等命令,请分别给出各命令及运行结截屏,说明异常与信号的处理。
- 正常运行
- 运行时按回车
回车符被缓存,等待程序结束后重新输出
- 运行时按ctrl+C
按下Ctrl + C,Shell进程收到SIGINT信号,Shell结束并回收hello进程。
- 运行时按ctrl+Z
Shell进程收到SIGSTP信号,Shell显示屏幕提示信息并挂起hello进程
- ps
- jobs
- pstree
- fg
- kill
6.7本章小结
本章概括了进程的概念和作用,以及shell-bash的概念和作用。并详细介绍了fork函数和execve函数的原理和进程执行过程。通过hello的运行过程,展示了异常和信号处理的细节。
第7章 hello的存储管理
7.1 hello的存储器地址空间
逻辑地址:程序hello产生的与段相关的偏移地址部分。
线性地址:程序hello的代码会产生逻辑地址,或者说是(即hello程序)段中的偏移地址,它加上相应段的基地址就生成了一个线性地址。
虚拟地址:程序hello访问存储器所使用的逻辑地址。
物理地址:现在CPU外部地址总线上的寻址物理内存的地址信号,是地址变换的最终结果地址。
7.2 Intel逻辑地址到线性地址的变换-段式管理
段式管理是指把一个程序分成若干个段进行存储,每个段都是一个逻辑实体。段式管理是通过段表进行的,包括段号(段名)、段起点、装入位、段的长度等。程序通过分段划分为多个块,如代码段、数据段、共享段等。
一个逻辑地址是两部分组成的,包括段标识符和段内偏移量。段标识符是由一个16位长的字段组成的,称为段选择符。其中前13位是一个索引号,后3位为一些硬件细节。索引号即是“段描述符”的索引,段描述符具体地址描述了一个段,很多个段描述符就组成了段描述符表。通过段标识符的前13位直接在段描述符表中找到一个具体的段描述符。
7.3 Hello的线性地址到物理地址的变换-页式管理
虚拟内存被组织为一个由存放在磁盘上的N个连续的宁节大小的单元组成的数组。VM系统将虚拟内存分割,称为虚拟页,类似地,物理内存也被分割成物理页。利用页表来管理虚拟页,页表就是一个页表条口(PTE)的数组,每个PI1由一个有效位和一个n位地址字段组成,有效位表明了该虚拟页当前是否被缓存在DRAM中,如果设置了有效位,那么地址字段就表示D)RAM中相应的物理页的起始位置,如果发生缺页,则从磁盘读取。
7.4 TLB与四级页表支持下的VA到PA的变换
CPU产生虚拟地址VA,虚拟地址VA传送给MMU,MMU使用VPN高位作为TLBT和TLBI,向TLB中寻找匹配。如果命中,则得到物理地址PA。如果 TLB中没有命中,MMU查询页表,CR3确定第一级页表的起始地址,VPN1确定在第一级页表中的偏移量,查询出PTE,以此类推,最终在第四级页表中找到PPN,与VPO组合成物理地址PA,添加到PLT。
7.5 三级Cache支持下的物理内存访问
由虚拟地址翻译得到物理地址之后,将物理地址分为缓存偏移CO、缓存组索引CI以及缓存标记CT。首先,利用组索引CI来寻找我们的地址是否在Cache中有对应的组;然后利用标记CT来判断我们的内容是否在Cache中。若命中,则访问我们的物理地址;若不命中,则进行下一层Cache的索引、访问,以此类推。
7.6 hello进程fork时的内存映射
当fork 函数被当前进程调用时,内核为新进程创建各种数据结构,并分配给它一个唯一的PID。为了给这个新进程创建虚拟内存,它创建了当前进程的mm_struct、区域结构和页表的原样副本。当fork 在新进程中返回时,新进程现在的虚拟内存刚好和调用fork时存在的虚拟内存相同。当这两个进程中的任何一个后来进行写操作时,写时复制机制就会创建新页面,因此,也就为每个进程保持了私有地址空间的抽象概念。
7.7 hello进程execve时的内存映射
execve函数加载并运行hello需要以下几个步骤:
1、删除已存在的用户区域
删除当前进程hello虚拟地址的用户部分中的已存在的区域结构。
2、映射私有区域
为新程序的代码、数据、bss和栈区域创建新的私有的、写时复制的区域结构。其中,代码和数据区域被映射为hello文件中的.text和.data区。bss区域是请求二进制零的,映射到匿名文件,其大小包含在hello中。栈和堆区域也是请求二进制零的,初始长度为零。
3、映射共享区域
若hello程序与共享对象或目标(如标准C库libc.so)链接,则将这些对象动态链接到hello程序,然后再映射到用户虚拟地址空间中的共享区域内。
4、设置程序计数器
最后,execve设置当前进程上下文中的程序计数器,使之指向代码区域的入口点。
7.8 缺页故障与缺页中断处理
如果程序执行过程中发生了缺页故障,则内核调用缺页处理程序。处理程序执行如下步骤:
1.检查虚拟地址是否合法,如果不合法则触发一个段错误,终止这个进程。
2.检查进程是否有读、写或执行该区域页面的权限,如果不具有则触发保护异常,程序终止。
3.两步检查都无误后,内核选择一个牺牲页面,如果该页面被修改过则将其交换出去,换入新的页面并更新页表。然后将控制转移给hello进程,再次执行触发缺页故障的指令。
7.9动态存储分配管理
基本方法和策略:
动态内存分配器维护着一个称为堆的进程的虚拟内存区域。分配器将堆视为一组不同大小的块的集合来维护。每个块就是一个连续的虚拟内存片,要么是已分配的,要么是空闲的。已分配的块显式地保留为供应用程序使用。空闲块可用来分配。空闲块保持空闲,直到它显式地被应用所分配。一个已分配的块保持已分配状态,直到它被释放,这种释放可以由应用程序显式执行或内存分配器自身隐式执行。
- 显式空闲链表
- 隐式空闲链表
- 带边界标记的合并
- 分离存储
7.10本章小结
本章详细介绍了hello 的存储器地址空间、intel 的段式管理、hello 的页式管理, 地址变换、物理内存访问,hello进程fork、execve 时的内存映射、缺页故障与缺页中断处理、动态存储分配管理的相关内容。
第8章 hello的IO管理
8.1 Linux的IO设备管理方法
(以下格式自行编排,编辑时删除)
设备的模型化:文件
设备管理:unix io接口
8.2 简述Unix IO接口及其函数
(以下格式自行编排,编辑时删除)
8.3 printf的实现分析
(以下格式自行编排,编辑时删除)
https://www.cnblogs.com/pianist/p/3315801.html
从vsprintf生成显示信息,到write系统函数,到陷阱-系统调用 int 0x80或syscall等.
字符显示驱动子程序:从ASCII到字模库到显示vram(存储每一个点的RGB颜色信息)。
显示芯片按照刷新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量)。
8.4 getchar的实现分析
(以下格式自行编排,编辑时删除)
异步异常-键盘中断的处理:键盘中断处理子程序。接受按键扫描码转成ascii码,保存到系统的键盘缓冲区。
getchar等调用read系统函数,通过系统调用读取按键ascii码,直到接受到回车键才返回。
8.5本章小结
(以下格式自行编排,编辑时删除)
(第8章1分)
结论
用计算机系统的语言,逐条总结hello所经历的过程。
你对计算机系统的设计与实现的深切感悟,你的创新理念,如新的设计与实现方法。
(结论0分,缺失 -1分,根据内容酌情加分)
附件
文件名 | 作用 |
hello.c | 源程序 |
hello.i | 经过预处理的文件,可分析预处理过程 |
hello.s | 汇编语言文件,分析编译过程 |
hello.o | 可重定位目标执行文件,分析汇编过程 |
hello.elf | hello.o的elf格式文件,分析汇编和链接过程 |
hello.txt | helloo.o的反汇编文件,分析hello.o |
hello | 可执行文件,分析链接过程 |
helloo.elf | hello的elf文件,分析重定位过程 |
helloo.txt | hello的反汇编文件,分析重定位过程 |
参考文献
为完成本次大作业你翻阅的书籍与网站等
[1] 林来兴. 空间控制技术[M]. 北京:中国宇航出版社,1992:25-42.
[2] 辛希孟. 信息技术与信息服务国际研讨会论文集:A集[C]. 北京:中国科学出版社,1999.
[3] 赵耀东. 新时代的工业工程师[M/OL]. 台北:天下文化出版社,1998 [1998-09-26]. http://www.ie.nthu.edu.tw/info/ie.newie.htm(Big5).
[4] 谌颖. 空间交会控制理论与方法研究[D]. 哈尔滨:哈尔滨工业大学,1992:8-13.
[5] KANAMORI H. Shaking Without Quaking[J]. Science,1998,279(5359):2063-2064.
[6] CHRISTINE M. Plant Physiology: Plant Biology in the Genome Era[J/OL]. Science,1998,281:331-332[1998-09-23]. http://www.sciencemag.org/cgi/ collection/anatmorp.
(参考文献0分,缺失 -1分)