哈工大计算机系统大作业 程序人生-Hello’s P2P
计算机系统
大作业
题 目 程序人生-Hello’s P2P
专 业 计算机与电子通信
学 号 2023111772
班 级 23L0503
学 生 张哲瑞
指 导 教 师 刘宏伟
计算机科学与技术学院
2024年5月
本文以“程序人生-Hello's P2P”为主题,详细描述了从C语言程序hello.c到可执行文件hello的完整生命周期,涵盖了预处理、编译、汇编、链接、进程管理、存储管理及I/O管理等计算机系统的核心环节。通过具体实验步骤和理论分析,展示了程序如何在Linux环境下被转化为可执行文件,并最终由操作系统加载执行。文章还探讨了进程创建、动态链接、地址转换、异常处理等关键技术,并结合实验以及截图进行了验证。此外,还对printf和getchar等函数的实现机制进行了深入分析。
关键词:计算机系统;程序生命周期;进程管理;存储管理;动态链接;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的P2P指的是From Program to Process,即将hello.c(program)经过预处理(hello.i)、编译(hello.s)、汇编(hello.o)、链接变为可执行文件hello,然后可以在shell中执行,shell通过fork函数为hello创建进程,并使用execve函数执行hello。
Hello的020指的是From Zero-0 to Zero-0,即指在hello程序未运行时,内存中并无hello的相关信息,即开始是Zero。等到hello开始执行后,内存加载hello的相关信息并开始运行,等到hello运行结束,计算机将hello的信息从内存中删除,又变回Zero,达成了From Zero-0 to Zero-0。
1.2 环境与工具
处理器:12th Gen Intel(R) Core(TM) i9-12900HX 2.30 GHz;
内存:32.0 GB;
系统类型:64 位操作系统, 基于 x64 的处理器;
软件环境:VMware;Windows 11;
开发和调试工具:Visual Studio 2022; gdb;gcc;
1.3 中间结果
Hello.i:预处理后的hello代码,是修改了的原程序
Hello.s:编译后的hello代码,是汇编程序
Hello.o:汇编后的hello代码,可重定位目标程序
Hello:链接后的可执行目标程序
1.4 本章小结
本章首先介绍了hello的P2P和020的含义和整个过程,然后介绍了使用的软硬件环境,以及开发与调试工具,最后列出了由hello生成的中间结果文件的名字,文件的作用等。
(第1章0.5分)
第2章 预处理
2.1 预处理的概念与作用
概念:预处理器cpp根据以字符#开头的命令,修改原始的C程序得到另一个C程序,以.i作为文件扩展名。
作用:将#include后面的文件直接插入程序文本中,根据宏定义#define直接在源程序中进行替换,实现了对源代码的转化。
2.2在Ubuntu下预处理的命令
图1.预处理的指令
2.3 Hello的预处理结果解析
使用vim查看hello.c与hello.i,可以发现hello.i较hello.c在main函数前多了许多内容,这些多的内容就是预处理时将#include后面的文件直接插入程序文本的内容
图2.hello.c
图3.hello.i
2.4 本章小结
本章先介绍了预处理的概念和作用,即预处理是指预处理器cpp根据以字符#开头的命令,修改原始的C程序得到另一个C程序,以.i作为文件扩展名的过程;接着在linux系统下对hello.c进行了预处理,得到了hello.i,为下一步编译做好了准备。
(第2章0.5分)
第3章 编译
3.1 编译的概念与作用
概念:编译是指编译器ccl将文本文件hello.i翻译成文本文件hello.s,它包含了一个汇编语言程序。
作用:编译器将产生汇编语言文件,并且会检测代码中的语法错误和语义错误,并报错。
3.2 在Ubuntu下编译的命令
(以下格式自行编排,编辑时删除)
应截图,展示编译过程!
图4.编译指令
3.3 Hello的编译结果解析
3.3.1 hello.s的内容
图5 6 7.hello.s
3.3.2 文件说明
图8.文件说明
.file说明了文件名称,.text段保存代码,.section指示把代码划分成若干段,.rodata为只读数据,.align 8用于确保指令或数据的存放地址对齐,此处是8字节对齐,.string声明字符串,.globl声明全局变量main,.type声明main为函数类型。
3.3.3 局部变量,立即数和字符串常量处理
图9.局部变量处理
在第21行对%rsp减32,为局部变量i申请空间
此外看第21行中对于立即数32,在它的前面加上$用以代表它为立即数
图10.字符串常量处理
在第41行,程序使用在3.3.2中已说明的.LC1找到字符串常量并使用
3.3.4 赋值操作
图11.赋值
使用movl指令,此处是将0赋给i
3.3.5 算术操作
图12.加法操作
加法,用addl指令,此处是将i+1
图13.减法操作
此处是减法,将栈减32
3.3.6 关系操作和控制转移
图14.跳转
将cmpl和jle连用,指i<=9时跳转
图15.跳转
将cmpl和je连用,指相等时跳转
图16 17.for循环
上图为for循环,.L2是为i赋初值,.L3是判断条件,.L4是循环主体
3.3.7 数组操作
图18 19.数组操作
对数组的操作就是利用数组首地址加偏移量,并且每次调用数组中的的数时都从头开始操作
3.3.8 函数操作
1.main函数
参数传递:
图20.main函数
将argv数组存在%rbp-20,argc存在%rbp-32
局部变量:i
2.puts函数
图21.puts函数
参数传递:将.LC0中的字符串传递给puts函数
3.printf函数
图22.printf函数
参数传递:将.LC1中的字符串传递给printf函数
4.atoi函数
图23.atoi函数
参数传递:将argv[3]传递给atoi函数
5.exit函数
图24.exit函数
6.sleep函数
图25.sleep函数
参数传递:将atoi函数的返回值传递给sleep函数
7.getchar函数
图26.getchar函数
3.4 本章小结
本章首先解释了编译的概念和作用,然后再linux系统中编译了hello.i程序,并展示和解释了编译后的代码
(第3章2分)
第4章 汇编
4.1 汇编的概念与作用
概念:汇编器as将hello.s翻译成机器语言指令,把这些指令打包成可重定位目标程序的格式,并把结果保存在hello.o中。
作用:汇编将程序转化可重定位目标程序的格式,便于后续进行链接
4.2 在Ubuntu下汇编的命令
应截图,展示汇编过程!
图27.汇编指令
4.3 可重定位目标elf格式
分析hello.o的ELF格式,用readelf等列出其各节的基本信息,特别是重定位项目分析。
Elf头:
图28.elf头
Elf头开始的序列描述了生成该文件的系统的字的大小和字节顺序,剩下的部分包含帮助链接器语法分析和解释目标文件的信息,其中包括elf头的大小、目标文件的类型、机器类型、节头部表的文件偏移以及节头部表中条目的大小和数量
节头:
图29.节头
符号表:
图30.节头
.rel.text:
图31.rel.text
4.4 Hello.o的结果解析
objdump -d -r hello.o 分析hello.o的反汇编,并请与第3章的 hello.s进行对照分析。
说明机器语言的构成,与汇编语言的映射关系。特别是机器语言中的操作数与汇编语言不一致,特别是分支转移函数调用等。
图32.hello.o的反汇编代码
代码与hello.s基本一致,区别在于
1.开头的部分消失了
2.跳转直接给出地址
图33.跳转举例
3.调用函数时call的目标地址为当前PC的值,需根据重定位才能跳转到正确位置
图34.调用函数举例
4.立即数转化为十六进制
图35.立即数举例
4.5 本章小结
本章首先介绍了汇编的概念和作用,接着在linux系统下对hello.s汇编生成hello.o,然后分析了hello.o的elf文件,并将hello.o的反汇编代码与hello.s进行比较。
(第4章1分)
第5章 链接
5.1 链接的概念与作用
概念:链接是编译过程的最后阶段,由链接器Linker完成。它的主要任务包括:将目标文件中的符号引用(如函数名、变量名)与定义关联起来和将不同目标文件中的代码和数据段合并,并分配最终的内存地址。
作用:将hello.o变为可执行文件
5.2 在Ubuntu下链接的命令
使用ld的链接命令,应截图,展示汇编过程! 注意不只连接hello.o文件
图36.使用ld的链接命令
5.3 可执行目标文件hello的格式
分析hello的ELF格式,用readelf等列出其各段的基本信息,包括各段的起始地址,大小等信息。
图37.elf头
可以看到,hello的类型为可执行文件
图38.节头
5.4 hello的虚拟地址空间
使用edb加载hello,查看本进程的虚拟地址空间各段信息,并与5.3对照分析说明。
图39.edb中显示的虚拟地址空间
根据edb可以看到程序的起始虚拟地址为0x400000,终止地址为0x405000
根据5.3节可查到各段信息。
.interp的地址:
图40..interp的地址
.text段的地址:
图41..text段的地址
5.5 链接的重定位过程分析
objdump -d -r hello 分析hello与hello.o的不同,说明链接的过程。
结合hello.o的重定位项目,分析hello中对其怎么重定位的。
图42 43 44 45.hello的反汇编代码
可以看到hello的反汇编代码与hello.o的反汇编代码较为不同
- 地址不同,地址以401000开始,不同于hello.o中从0开始。
- 内容不同,加入了各种所需函数的汇编代码。
- 跳转不同,跳转指令直接给出了跳转位置的绝对地址
5.6 hello的执行流程
使用gdb/edb执行hello,说明从加载hello到_start,到call main,以及程序终止的所有过程(主要函数)。请列出其调用与跳转的各个子程序名或程序地址。
过程如下
_start的地址:0x401190
_libc_start_main的地址:0x7f4f83587f90
_libc_csu_init的地址:0x4011d0
_init的地址:0x401000
Main的地址:0x4010f0
Puts的地址:0x401090
Exit的地址:0x4010d0
Printf的地址:0x4010a0
Sleep的地址:0x4010e0
Atoi的地址:0x4010c0
Getchar的地址:0x4010b0
5.7 Hello的动态链接分析
分析hello程序的动态链接项目,通过edb/gdb调试,分析在动态链接前后,这些项目的内容变化。要截图标识说明。
GOT(全局偏移表)是ELF格式可执行文件中用于动态链接的关键数据结构,主要解决位置无关代码在加载时确定全局变量和函数地址的问题,与PLT配合使用。
动态链接前,GOT表中函数地址项指向PLT中的跳转指令;动态链接后,GOT表项被动态链接器重写为真实的函数地址,后续调用直接跳转到真实函数。这样避免了启动时解析所有函数,加快程序启动速度
Got表的地址:
图46.GOT表的地址
动态链接前got内容:
图47. 动态链接前got内容
动态链接后got内容:
图48. 动态链接前got内容
可见,在动态链接前后,got中的内容发生改变
5.8 本章小结
本章首先介绍了链接的概念和作用,接着将hello.o进行链接,得到可执行程序hello,随后详细说明了hello的各种信息,包括格式,虚拟地址,执行流程等,还解析了链接的重定位过程以及hello的动态链接分析。
(第5章1分)
第6章 hello进程管理
6.1 进程的概念与作用
概念:进程是一个执行中程序的实例
作用:使我们的程序仿佛是系统中唯一运行的程序,我们的程序好像独占地使用处理器和内存,实现多任务并发执行,使操作系统能够高效管理处理器、内存等资源
6.2 简述壳Shell-bash的作用与处理流程
Shell是用户与操作系统内核之间的命令行接口,其作用是接收用户输入的命令并解释执行
处理流程:首先读取用户输入,然后进行解析,接着判断是否为内置命令(直接执行)或外部程序(通过系统调用创建子进程运行),最后将执行结果返回给用户,从而完成交互式操作
6.3 Hello的fork进程创建过程
在shell中输入./hello执行hello,shell调用fork创建一个子进程,即hello进程,hello进程在前台执行,所以父进程shell挂起等待子进程hello执行完毕
6.4 Hello的execve过程
子进程hello调用execve函数执行程序,这个函数调用一次从不返回,并覆盖当前进程的代码数据和栈,在execve加载了hello后,调用启动代码,启动代码设置栈,将控制传递给新程序的主函数,hello开始执行
6.5 Hello的进程执行
结合进程上下文信息、进程时间片,阐述进程调度的过程,用户态与核心态转换等等。
每个进程的上下文信息保存在进程控制块中,当调度发生时,当前进程的上下文被保存,待调度进程的上下文被恢复,确保执行连续性。操作系统为每个进程分配一个CPU时间片,若进程用完时间片或主动让出CPU,则触发调度器从就绪队列选取下一个进程运行。调度过程依赖于用户态和核心态的转换,当进程执行系统调用或发生中断时,CPU从用户态切换至核心态,由内核接管并执行调度逻辑;待新进程被选中后,内核完成上下文切换并返回用户态,使目标进程继续执行。
6.6 hello的异常与信号处理
hello执行过程中会出现哪几类异常,会产生哪些信号,又怎么处理的。
异常种类:
中断:是来自处理器外部的I/O设备的信号的结果
陷阱和系统调用:是执行一条指令的结果
故障:由错误情况引起
终止:是不可恢复的致命错误造成的结果
产生的信号:
SIGINT:输入ctrl+c时发送,程序中断
SIGTSTP:输入ctrl+z时发送,程序暂停
程序运行过程中可以按键盘,如不停乱按,包括回车,Ctrl-Z,Ctrl-C等,Ctrl-z后可以运行ps jobs pstree fg kill 等命令,请分别给出各命令及运行结截屏,说明异常与信号的处理。
乱按加回车不会影响程序的运行:
图49. 乱按加回车
Ctrl+z:
图50.ctrl+z后ps,jobs指令
图51 52.pstree命令
图53.fg命令
Ctrl+c:
图54.ctrl+c命令
6.7本章小结
本章介绍了进程的概念和作用,并简述了hello的执行过程,并在hello运行时输入各种信号观察hello程序的反应
(第6章1分)
第7章 hello的存储管理
7.1 hello的存储器地址空间
结合hello说明逻辑地址、线性地址、虚拟地址、物理地址的概念。
逻辑地址:程序在汇编代码中的地址
线性地址:一个由连续非负整数地址组成的有序集合称为线性地址空间
虚拟地址:在一个带虚拟内存的系统中,CPU从一个N=2^n个地址的地址空间中生成虚拟地址,这个地址空间称为虚拟地址空间
物理地址:计算机系统的主存被组织为一个由M个连续的字节大小的单元组成的数组。每字节都有为一个物理地址。第一个字节的地址为0,接下来的字节地址为1,在下一个为2,以此类推。
7.2 Intel逻辑地址到线性地址的变换-段式管理
在 Intel 平台下,逻辑地址是 selector:offset (即段选择符:偏移量)这种形式。用 selector(段选择符) 去 GDT(全局描述符表) 里拿到 segment base address(段基址) 然后加上 offset(段内偏移),这就得到了线性地址,整个过程就称为段式管理。
图55.逻辑地址转为线性地址示意图
7.3 Hello的线性地址到物理地址的变换-页式管理
线性地址分为三部分:页目录索引,页表索引,页内偏移,用页目录索引作为索引,找到页目录项,其中包含页表的物理基地址,通过页表基地址,结合页表索引找到页表项,那里面的值就是一个物理内存块的起始地址(其实就是是物理内存编号),把它加上线性地址中的页内偏移就得到了最终的物理地址。我们把这个过程称作页式内存管理。
图56.线性地址到物理地址的转换
7.4 TLB与四级页表支持下的VA到PA的变换
TLB(快表)是一个小的,虚拟寻址的缓存,其中每一行都保存着一个由单个PTE组成的块。下面是TLB命中时所需要的步骤,首先CPU产生一个虚拟地址,接着,MMU从TLB中取出相应的PTE,然后,MMU将这个虚拟地址翻译成一个物理地址,并且将它发送给高速缓存/主存,最后,高速缓存/主存将所请求的数据字返回给CPU。若TLB不命中,MMU必须从L1缓存中取出相应的PTE。
图57.用于访问TLB的组成部分
图58.TLB命中与未命中的操作图
四级页表是一种多级页表,在地址翻译过程中,虚拟地址页号VPN被分为了4个,每一个VPN都是一个指向某级页表的索引。最后一级页表中的每个PTE包含某个物理页面的PPN,或者一个磁盘块的地址。为构造物理地址,在能够确定PPN之前,MMU需要访问4个PTE,首先由VPN1作为偏移量在第一级页表中找到对应的PTE,它包含了某个第二级页表的首地址,由VPN2提供到这个页表中某个PTE的偏移量,以此类推,最后得到的第四级页表中VPN4对应的 PTE包含了需要的物理页号,和虚拟地址中的VPO连接起来就得到相应的物理地址。
图59.k级页表示意图
7.5 三级Cache支持下的物理内存访问
内存地址中有缓存组索引和缓存标记,将L1对应组中的每一行的标记位进行对比,如果相同并且有效位为1则命中,获得偏移量,取出相应字节,否则不命中,向下一级cache寻找,最后向内存中寻找。
7.6 hello进程fork时的内存映射
当fork函数被调用时,内核为新进程创建各种数据结构,并分配给它一个唯一的PID。为了给这个新进程创建虚拟内存,它创建了当前进程的mm_struct、区域结构和页表的原样副本,并将两个进程中的每个界面都标记为只读,将两个进程中的每个区域结构都标记为私有的写时复制。
当fork在新进程中返回时,新进程现在的虚拟内存搞好和调用fork时存在的虚拟内存相同。这两个进程中的任意一个后来进行写操作时,写时复制机制就会创建新页面,因此,也就为每个进程保持了私有地址空间的抽象概念。
7.7 hello进程execve时的内存映射
execve在当前进程中加载并运行包含在可执行目标文件 hello中的程序,用 hello 程序有效地替代了当前程序。加载并运行 hello需要以下几个步骤:
1.删除已存在的用户区域。删除当前进程虚拟地址的用户部分中的已存在的区域结构。
2.映射私有区域。为新程序的代码、数据、bss和栈区域创建新的区域结构,所有这些新的区域都是私有的、写时复制的。代码和数据区域被映射为 hello 文件中的.text 和.data区,bss区域是请求二进制零的,映射到匿名文件,其大小包含在hello中,栈和堆地址也是请求二进制零的,初始长度为零。
3.映射共享区域。hello程序与共享对象链接,那么这些对象都是动态链接到这个程序的,然后再映射到用户虚拟地址空间中的共享区域内。
4.设置程序计数器(PC)。execve 做的最后一件事情就是设置当前进程上下文的程序计数器,使之指向代码区域的入口点。
7.8 缺页故障与缺页中断处理
处理缺页要求硬件和操作系统内核协作完成。
- 处理器生成一个虚拟地址,并把它传送给MMU
- MMU生成PTE地址,并从高速缓存/主存请求得到它
- 高速缓存/主存向MMU返回PTE
- PTE中的有效位是0,所以MMU触发了一次异常,传递CPU中的控制到操作系统内核中的缺页异常处理程序
- 缺页处理程序确定出物理内存中的牺牲页,如果这个页面已经被修改了,则把它换出到磁盘
- 缺页处理程序调入新的页面,更新内存中的PTE
- 缺页处理程序返回到原来的进程,再次执行导致缺页的指令。CPU将引起缺页的虚拟地址重新发送给MMU。因为虚拟页面现在缓存在物理内存中,所以就会命中。
图60.缺页操作图
7.9动态存储分配管理
Printf会调用malloc,请简述动态内存管理的基本方法与策略。
动态内存分配器维护着一个进程的虚拟内存区域,称为堆,分配器将堆视为一组不同大小的块的集合来维护。每个块是一个连续的虚拟内存片,要么是已分配的,要么是空闲的。已分配的块显式的保留为供应用程序使用。空闲块可用来分配。空闲块保持空闲,直到它显式的被应用所分配。一个已分配的块保持已分配状态,直到它被释放,这种释放要么是应用程序显式执行的,要么是内存分配器自身隐式执行的。
分配器有两种基本风格。两种风格都要求应用显式的分配块。不同之处在于由哪个实体来负责释放已分配的块,分别是显式分配器和隐式分配器。Malloc就属于显式分配器,程序通过调用malloc来从堆中分配块。
7.10本章小结
本章首先区分了hello的各种地址,接着介绍了各种地址间的变换,并介绍了TLB和cache支持下的物理内存访问,随后讲了fork和execve的内存映射机理,最后介绍了动态存储分配管理。
(第7章 2分)
第8章 hello的IO管理
8.1 Linux的IO设备管理方法
设备的模型化:文件
设备管理:unix io接口
一个Linux文件就是一个m个字节的序列,B0,B1…所有的I/O设备都被模型化为文件,而所有的输入和输出都被当作对相应文件的读和写来执行。这种将设备优雅的映射为文件的方式,允许Linux内核引出一个简单、低级的应用接口,称为Unix I/O,使得所有输入和输出都能以一种统一且一致的方式执行:
1.打开文件。一个应用程序通过要求内核打开相应的文件来宣告它想访问一个I/O设备。内核返回一个小的非负整数,叫做描述符,它在后续对此文件的所有操作中标识这个文件。内核记录有关这个打开文件的所有信息,应用程序只需要记住这个描述符。
2.Linux shell创建的每个进程开始时都有三个打开的文件:标准输入0、标准输出1、标准错误2。头文件<unistd.h>定义了常量STDIN_FILENO,STDOUT_FILENO和STDERR_FILENO,它们可用来代替显式的描述符值。
3.改变当前文件的位置。对于每个打开的文件,内核保持着一个文件位置k,初始为0,这个文件位置是从文件开头起始的字节偏移量,应用程序能够通过执行seek操作,显式的设置文件的当前位置为k。
4.读写文件。一个读操作就是从文件复制n>0个字节到内存,从当前文件位置k开始,然后将k增加为k + n。给定一个m字节的文件,当k大于等于m时,执行读操作会触发EOF条件,应用程序能检测到这个条件。写操作就是从内存复制n>0个字节到一个文件,从当前文件位置k开始,然后更新k。
5.关闭文件。应用在完成对文件的访问后,会通知内核关闭这个文件,内核将释放打开这个文件时创建的数据结构,并将这个描述符恢复到可用的描述符池中。
int open(const char *pathname, int flags, mode_t mode);
功能:打开文件或设备,返回文件描述符(fd)。
参数:
flags:控制打开方式(如 O_RDONLY、O_WRONLY、O_CREAT、O_TRUNC)。mode:创建文件时的权限(如 0644)。
int close(int fd);
功能:关闭文件
参数:fd是目标文件的描述符
ssize_t read(int fd, void *buf, size_t count);
功能:从 fd 读取最多 count 字节到 buf。
返回值:实际读取的字节数(0 表示 EOF,-1 表示错误)。
ssize_t write(int fd, const void *buf, size_t count);
功能:将 buf 中的 count 字节写入 fd。
返回值:实际写入的字节数(-1 表示错误)。
off_t lseek(int fd, off_t offset, int whence);
功能:移动文件指针。
参数:whence包括SEEK_SET(文件头)、SEEK_CUR(当前位置)、SEEK_END(文件尾)。
8.3 printf的实现分析
[转]printf 函数实现的深入剖析 - Pianistx - 博客园
字符显示驱动子程序:从ASCII到字模库到显示vram(存储每一个点的RGB颜色信息)。
显示芯片按照刷新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量)。
图61.printf程序图
vsprintf的作用就是格式化。它接受确定输出格式的格式字符串fmt。用格式字符串对个数变化的参数进行格式化,产生格式化输出,返回值由i接受,作为要打印的字符串的长度,从vsprintf生成显示信息,到write系统函数,到陷阱-系统调用 int 0x80或syscall等。字符显示驱动子程序:从ASCII到字模库到显示vram(存储每一个点的RGB颜色信息)。
显示芯片按照刷新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量)。
8.4 getchar的实现分析
异步异常-键盘中断的处理:键盘中断处理子程序。接受按键扫描码转成ascii码,保存到系统的键盘缓冲区。getchar等调用read系统函数,通过系统调用读取按键ascii码,直到接受到回车键才返回。
8.5本章小结
本章介绍Linux设备的I/O设备管理方法和Unix IO接口及其函数,并介绍了printf和getchar的实现方法。
(第8章1分)
结论
用计算机系统的语言,逐条总结hello所经历的过程。
你对计算机系统的设计与实现的深切感悟,你的创新理念,如新的设计与实现方法。
Hello从执行前到执行结束总共经历了以下几个过程:
- 预处理:hello.c通过预处理器cpp根据以字符#开头的命令,修改原始的C程序得到另一个C程序,以.i作为文件扩展名,得到hello.i。
- 编译:hello.i通过编译器ccl将文本文件hello.i翻译成文本文件hello.s,它包含了一个汇编语言程序。
- 汇编:hello.s通过汇编器as将hello.s翻译成机器语言指令,把这些指令打包成可重定位目标程序的格式,并把结果保存在hello.o中。
- 链接:将hello.o变为可执行文件hello
- 准备运行:在shell中输入对应指令./hello 2023111772 zzr 13284965988 3
- 创建进程:shell通过fork函数为hello创建一个新进程
- 执行程序:hello调用execve函数执行程序。
- 加载数据:处理器经过一系列的地址转换,在内存中访问到执行hello所需的数据
- 接收、处理信号:当hello程序发生异常时,hello接收到信号,并作出相应反应,例如接收到SIGINT时程序中断
- 回收进程:当hello程序执行结束时,shell回收该进程
感悟:通过本次大作业,我了解到计算机真的是一个精密的系统,一个简单的hello.c程序的执行,需要软硬件结合才能有条不紊的运行,更何况在现代计算机中,无时无刻不在同时运行着成百上千个比hello更复杂的进程,而它依然游刃有余,这都要多亏了计算机领域的前人,是他们一个个不眠的夜晚,一个个精妙的巧思,才构成了我们如今如此庞大,蓬勃发展的计算机领域
(结论0分,缺失 -1分,根据内容酌情加分)
附件
列出所有的中间产物的文件名,并予以说明起作用。
Hello.i:预处理后的hello代码,是修改了的原程序
Hello.s:编译后的hello代码,是汇编程序
Hello.o:汇编后的hello代码,可重定位目标程序
Hello:链接后的可执行目标程序
(附件0分,缺失 -1分)
参考文献
为完成本次大作业你翻阅的书籍与网站等
[1] linux内核中 逻辑地址、虚拟地址、线性地址和物理地址大扫盲 - 知乎
[2] 深入理解计算机系统,兰德尔 E. 布莱恩特,大卫 R. 奥哈拉论著
(参考文献0分,缺失 -1分)
相关文章:

哈工大计算机系统大作业 程序人生-Hello’s P2P
计算机系统 大作业 题 目 程序人生-Hello’s P2P 专 业 计算机与电子通信 学 号 2023111772 班 级 23L0503 学 生 张哲瑞 指 导 教 师 …...

计算机一次取数过程分析
计算机一次取数过程分析 1 取址过程 CPU由运算器和控制器组成,其中控制器中的程序计数器(PC)保存的是下一条指令的虚拟地址,经过内存管理单元(MMU),将虚拟地址转换为物理地址,之后交给主存地址寄存器(MAR),从主存中取…...

Halcon联合QT ROI绘制
文章目录 Halcon 操纵界面代码窗口代码 Halcon 操纵界面代码 #pragma once#include <QLabel>#include <halconcpp/HalconCpp.h> #include <qtimer.h> #include <qevent.h> using namespace HalconCpp;#pragma execution_character_set("utf-8&qu…...

力扣面试150题--二叉树的右视图
Day 53 题目描述 思路 采取层序遍历,利用一个high的队列来保存每个节点的高度,highb和y记录上一个节点的高度和节点,在队列中,如果队列中顶部元素的高度大于上一个节点的高度,说明上一个节点就是上一层中最右边的元素…...
数据绑定页面的完整的原理、逻辑关系、实现路径是什么?页面、表格、字段、属性、值、按钮、事件、模型、脚本、服务编排、连接器等之间的关系又是什么?
目录 一、核心概念:什么是数据绑定页面? 二、涉及的组件及其逻辑关系 页面(Page): 表格(Table): 字段(Field): 属性(Property): 值(Value): 按钮(Button): 事件(Event): 模型(Model): 脚本(Script): 服务(Service): 服务编排(Se…...

江西某石灰石矿边坡自动化监测
1. 项目简介 该矿为露天矿山,开采矿种为水泥用石灰岩,许可生产规模200万t/a,矿区面积为1.2264km2,许可开采深度为422m~250m。矿区地形为东西一北东东向带状分布,北高南低,北部为由浅变质岩系组…...
《Python 应用中的蓝绿部署与滚动更新:持续集成中的实践与优化》
《Python 应用中的蓝绿部署与滚动更新:持续集成中的实践与优化》 引言 在现代软件开发中,持续集成与持续部署(CI/CD)已成为标准实践。面对频繁发布与升级需求,蓝绿部署和滚动更新两种策略为 Python 应用提供了稳定、安全的发布方式。本文将深入探讨这两种策略的原理、适…...

C# 类和继承(所有类都派生自object类)
所有类都派生自object类 除了特殊的类object,所有的类都是派生类,即使它们没有基类规格说明。类object是唯 一的非派生类,因为它是继承层次结构的基础。 没有基类规格说明的类隐式地直接派生自类object。不加基类规格说明只是指定object为 基…...

02业务流程的定义
1.要想用好业务流程,首先必须得了解流程与认识流程,什么是业务流程。在认识流程之前,首先要理清两个基本概念,业务和流程。 业务指的是:个人的或者摸个机构的专业工作。流程,原本指的是水的路程࿰…...

cursor rules设置:让cursor按执行步骤处理(分析需求和上下文、方案对比、确定方案、执行、总结)
写在前面的话: 直接在cursor rules中设置一下内容: RIPER-5 MULTIDIMENSIONAL THINKING AGENT EXECUTION PROTOCOL 目录 RIPER-5 MULTIDIMENSIONAL THINKING AGENT EXECUTION PROTOCOL 目录 上下文与设置 核心思维原则 模式详解 模式1: RESEARCH…...

Linux操作系统之进程(四):命令行参数与环境变量
目录 前言: 什么是命令行参数 什么是环境变量 认识环境变量 PATH环境变量 HOME USER OLDPWD 本地变量 本地变量与环境变量的差异 核心要点回顾 结语: 前言: 大家好,今天给大家带来的是一个非常简单,但也十…...

Typora-macOS 风格代码块
效果: 替换 Typora安装目录中 themes 文件夹下的 base.user.css 文件,直接替换即可,建议先备份。 css: /* 语法高亮配色 */ .CodeMirror-line .cm-number { color: #b5cea8; } /* 数字 - 浅绿色 */ .CodeMirror-line .…...
如何迁移SOS数据库和修改sos服务的端口号
一. 迁移SOS数据库。 1. 对SOS整个库进行拷贝。压缩拷贝等都可以 2. 找到SOS安装目录下的这个目录 /SOS7/SERVERS7/LOCAL/ 在此目录下会发现,有SOS服务库的文件夹。拷贝你要迁移的SOS数据库 3. 进入该文件夹,找到:serverdb.cfg 打开后&…...

ansible自动化playbook简单实践
方法一:部分使用ansible 基于现有的nginx配置文件,定制部署nginx软件,将我们的知识进行整合 定制要求: 启动用户:nginx-test,uid是82,系统用户,不能登录 启动端口82 web项目根目录/…...

20250526惠普HP锐14 AMD锐龙 14英寸轻薄笔记本电脑(八核R7-7730U)的显卡驱动下载
20250526惠普HP锐14 AMD锐龙 14英寸轻薄笔记本电脑(八核R7-7730U)的显卡驱动下载 2025/5/26 14:44 百度:AMD 7700 显卡驱动 amd APU 显卡驱动 https://item.jd.com/100054819707.html 惠普HP【国家补贴20%】锐14 AMD锐龙 14英寸轻薄笔记本电脑(八核R7-7730U 16G 1T…...
WIN11使用vscode搭建c语言开发环境
安装 VS Code 下载地址: Visual Studio Code - Code Editing. Redefined 安装时勾选 "添加到 PATH"(方便在终端中调用 code 命令 下载 MSYS2 官网:MSYS2 下载 msys2-x86_64-xxxx.exe(64位版本)并安装。 默认安装路径…...

2025年5月蓝桥杯stema省赛真题——象棋移动
上方题目可点下方去处,支持在线编程~ 象棋移动_scratch_少儿编程题库学习中心-嗨信奥 程序演示可点下方,支持源码和素材获取~ 象棋移动-scratch作品-少儿编程题库学习中心-嗨信奥 题库收集了历届各白名单赛事真题和权威机构考级…...

AI重构SEO关键词精准定位
内容概要 随着AI技术深度渗透数字营销领域,传统SEO关键词定位模式正经历系统性重构。基于自然语言处理(NLP)的智能语义分析引擎,可突破传统关键词工具的局限性,通过解析长尾搜索词中的隐含意图与语境关联,…...
C++ 模板元编程语法大全
C 模板元编程语法大全 模板元编程(Template Metaprogramming, TMP)是C中利用模板在编译期进行计算和代码生成的强大技术。以下是C模板元编程的核心语法和概念总结: 1. 基础模板语法 类模板 template <typename T> class MyClass {// 类定义 };函数模板 t…...

SPSS跨域分类:自监督知识+软模板优化
1. 图1:SPSS方法流程图 作用:展示了SPSS方法的整体流程,从数据预处理到模型预测的关键步骤。核心内容: 领域知识提取:使用三种词性标注工具(NLTK、spaCy、TextBlob)从源域和目标域提取名词或形容词(如例句中提取“excellent”“good”等形容词)。词汇交集与聚类:对提…...
【术语扫盲】BSP与MSP
专业解释版: MSP(Microcontroller Support Package) 定义:MSP 是微控制器支持包,包含 MCU 的启动代码、寄存器配置、驱动库等,主要针对 芯片本身。 作用:提供通用的底层硬件抽象,方…...

vscode的Embedded IDE创建keil项目找不到源函数或者无法跳转
创建完Embedded IDE项目后跳转索引很容易找不到源函数或者无法跳转,原因是vscode工作区被eide覆盖了,需要手动往当前目录下的.vscode/c_cpp_properties.json里添加路径 打开eide.json ,找到folders, 里面的name是keil里工程的虚拟…...
HTTP/2与HTTP/3特性详解:为你的Nginx/Apache服务器开启下一代Web协议
更多服务器知识,尽在hostol.com 嘿,各位站长和服务器管理员朋友们!咱们天天跟网站打交道,都希望自己的网站能像火箭一样快,用户体验“嗖嗖”的。但你知道吗?除了服务器硬件配置、代码优化、CDN加速这些“常…...

构建高效智能客服系统的8大体验设计要点
构建一流的客户服务中心体验,企业需要以用户需求为核心,将智能化流程、前沿科技与人文关怀有机结合,打造流畅、高效且富有温度的服务生态。在客户需求日益多元化的今天,单纯的问题解决能力已无法满足期待,关键在于通过…...

CppCon 2014 学习:Making C++ Code Beautiful
你说的完全正确,也很好地总结了 C 这门语言在社区中的两种典型看法: C 的优点(Praise) 优点含义Powerful允许底层控制、系统编程、高性能计算、模板元编程、并发等多种用途Fast无运行时开销,接近汇编级别性能&#x…...
副本(Replica)在Elasticsearch中扮演什么角色?
在Elasticsearch(ES)中,副本(Replica)是主分片(Primary Shard)的镜像拷贝,与主分片共同构成分布式索引的高可用性和高性能架构。副本的设计目标是解决数据冗余、负载均衡和故障恢复等核心问题,其具体作用和原理如下: 一、副本的核心角色与功能 1. 数据冗余与故障恢…...

据传苹果将在WWDC上发布iOS 26 而不是iOS 19
苹果可能会对其操作系统的编号方式做出重大改变,基于年份的新版系统会将iOS 19重新命名为 iOS 26,同时 macOS 也会以同样的方式命名。 苹果的编号系统相当简单,版本号每年都会像钟表一样定期更新。然而,今年秋天情况可能有所不同&…...
整理了Windows(7—11)官方镜像下载链接和各版本区别介绍
原文《整理了Windows(7—11)官方镜像下载链接和各版本区别介绍》 引言 在安装或重装Windows系统时,使用微软官网提供的正版ISO镜像可以保证系统完整性和安全更新,避免使用第三方盗版镜像带来的恶意软件、广告风险。 本期汇总了微…...
数据库主键与索引详解
目录 主键核心特性 主键必要性问题 索引核心解析 基本定义 优劣分析 索引类型对比 数据结构实现 工作原理 主键与索引核心区别 主键核心特性 唯一标识:确保字段数据不重复且不为空数量限制:每表仅允许存在一个主键存储类型:通常采用…...
RTOS:启动调度器的作用(含源码逐行解读)
文章目录 前言一、启动调度器二、详细逻辑分析三、逐行分析3.1、traceENTER_vTaskStartScheduler3.2、configASSERT( ( sizeof( UBaseType_t ) * taskBITS_PER_BYTE ) > configNUMBER_OF_CORES );3.3、xReturn prvCreateIdleTasks();3.4、xTimerCreateTimerTask();3.5、fre…...