计算机系统大作业

本文详细阐述了hello程序从源代码到可执行文件的全过程,包括预处理、编译、汇编、链接的步骤,以及程序执行时的进程管理、存储管理和IO管理。文章深入探讨了硬件、操作系统如何管理资源,以及在不同阶段的内存映射和网络通信概念。
摘要由CSDN通过智能技术生成

计算机系统

大作业

题     目  程序人生-Hello’s P2P   

专       业   

学     号             

班     级               

学       生              

指 导 教 师              

计算机科学与技术学院

2023年4月

摘  要

本文从程序员创建代码开始,经过编译、链接等步骤,将C代码转换为可执行的hello程序,介绍hello程序的整个生命周期。同时,还介绍了指令系统和内存存储体系结构等硬件方面的知识,以及操作系统如何管理硬件、进程线程和虚拟内存等软件方面的知识。此外,还介绍了系统之间的网络通信和并发并行等概念。

关键词:hello程序;计算机系统;汇编;编译

目  录

第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简介

1.1.1 P2P

P2P即From Program to Process。Program指的是hello.c源文件,它是经过我们通过键盘输入后读入内存的文件。Process指通过对hello.c文件进行预处理(cpp)、编译(ccl)、汇编(as)、链接(ld)等一系列操作之后生成的可执行文件hello。当我们在shell中输入./hello 学号 姓名 秒数时,shell会创建一个子进程。

020即From Zero-0 to Zero-0。在execve将hello程序加载到相应的上下文中,从main函数开始执行代码,CPU为运行的hello分配时间片并执行其逻辑控制流。当程序运行结束后,shell父进程负责回收hello进程,内核删除相关数据结构。

1.2 环境与工具

硬件:X64CPU

软件:Windows10 64位 Vmware Ubuntu 22.04

开发工具:GCC EDB VisualStudio2019 Codeblocks

1.3 中间结果

文件名    文件作用

hello.c    源文件

hello.i     hello.c经过预处理(cpp)后的文本文件

hello.s    hello.i经过编译(ccl)得到的汇编文件

hello.o    hello.s经过汇编(as)得到的可重定位目标文件

hello       hello.o与其他目标文件链接后得到的可执行目标文件

1.4 本章小结

本章主要介绍了hello的程序人生, 简要概括了hello程序的P2P和020的过程,同时列出了本次实验所需的环境和结果。

(第1章0.5分)

第2章 预处理

2.1 预处理的概念与作用

2.1.1 概念:在编译C程序之前,需要进行预处理工作。预处理器(cpp)会对源文件进行修改,识别以#开头的代码行作为预处理指令,并进行相应的处理,例如宏定义(#define)、文件包含(include)、条件编译(#if)等。

2.1.2作用:处理宏定义指令、条件编译指令、头文件、特殊符号,得到便于编译器工作的.i文件

2.2在Ubuntu下预处理的命令

命令:gcc hello.c -E -o hello.i

2.3 Hello的预处理结果解析

预处理之后,hello.c被转换为hello.i文件。文件内容扩展为3091行,其中注释已经被删除,但仍然是C语言程序。在预处理过程中,原始代码中的宏被展开,#include<stdio.h>、#include<stdlib.h>、#include<unistd.h>文件已经被预处理。

2.4 本章小结

本章主要介绍了预处理的概念和作用,并对hello.c源文件进行了预处理,对预处理结果进行了分析。

(第2章0.5分)

第3章 编译

3.1 编译的概念与作用

3.1.1概念:编译器将以高级程序设计语言书写的源程序作为输入,以汇编语言或机器语言表示的目标程序作为输出

3.1.2功能:源程序翻译成目标程序。除了基本功能之外,编译程序还具备语法检查、调试功能、修改手段、覆盖处理、目标程序优化、不同语言合用以及人际联系等重要功能。

3.2 在Ubuntu下编译的命令

命令:gcc -S hello.i

3.3 Hello的编译结果解析

3.3.1 数据

3.3.1.1 字符串

两个字符串被用作printf的参数

3.3.1.2局部变量i

main函数声明了一个局部变量i,放在栈上-4(%rbp)的位置。

       3.3.1.3数组

        

在hello.c中,数组作为main函数的第二个参数传递,其中数组的每个元素都是指向字符类型的指针。该数组的起始地址存储在栈的-32(%rbp)的位置。

3.3.2.全局函数

经过编译之后,main函数中使用的字符串常量也被存放在数据区。

3.3.3赋值操作

通过mov指令来实现

      

       3.3.4算术操作

i++的实现:在for循环中i每次循环加1,addl指令将%rbp-4地址对应内存处的值加一。

3.3.5条件判断和exit函数调用

je跳转的含义:如果i等于3,则不执行if语句,否则执行if语句

cmpl指令将%rbp-20地址处保存的argc与立即数4比较,若相等,跳转到L2,若不相等将. LC0保存的字符串打印,并调用exit函数。

jmp跳转的含义:i赋初值0,然后无条件跳转至判断条件的代码中,即.L3.

3.3.6 函数调用和数组操作

在for循环内部调用了printf函数,sleep函数,atoi函数

调用printf函数时,LC1保存在%edi中, argv[1]保存在%rsi中, argv[2]保存在%rdx中,通过栈指针%rax从栈中赋值。

3.4 本章小结

本章介绍了编译的概念和作用,并对hello.i源文件进行了编译,将编译结果对照源文件分析数据储存,变量保存,函数调用,控制转移,数组操作等操作的在汇编语言上的实现

(第3章2分)

第4章 汇编

4.1 汇编的概念与作用

4.1.1概念:汇编器将.s文件翻译成机器语言指令,并将这些指令打包成可重定位目标文件的格式,可重定位目标文件包括二进制的代码和数据。

4.1.2作用:将汇编语句翻译成二进制机器指令,便于后续链接

4.2 在Ubuntu下汇编的命令

4.3 可重定位目标elf格式

       ELF Header: 命令:readelf -h hello.o

   

ELF头描述了生成该文件的系统的字大小和字节顺序。ELF头的剩余部分包括ELF头的大小、目标文件类型、机器类型、字节头部表的文件偏移,以及节头部表中条目的大小和数量。

 Section Headers:命令:readelf -S hello.o

Section Headers:节头部表,包含了文件中出现的各个节的语义,包括节 的类型、位置和大小等信息。

       重定位节:是一个test节中位置的列表,确定每个符号定义的运行时内存地址,并修改对这些符号的引用,使之指向符号定义的运行时内存地址。

符号表:存放程序中定义和引用的函数和全局变量的信息

4.4 Hello.o的结果解析

命令:objdump -d -r hello.o 反汇编代码

4.4.1进制改变

在汇编文件中栈指针减16,在反汇编文件中栈指针减0x10。

反汇编文件采用十六进制

4.4.2分支转移

 

在汇编文件中跳转需要L2,在反汇编文件中jmp指令用十六进制相对地址进行跳转。

4.4.3函数调用

汇编文件中call指令使用的是函数名称,在反汇编文件中使用相对偏移地址

4.5 本章小结

本章介绍了汇编的概念和作用,并对hello.s文件进行了汇编,生成了hello.o可重定位目标文件,并且分析了可重定位文件的ELF头、节头部表、符号表和可重定位节,将hello.o文件和反汇编文件进行了对比,分析异同点。

(第4章1分)

第5章 链接

5.1 链接的概念与作用

5.1.1 概念: 在计算机编程中,链接器(linker)是一个将各种代码和数据片段组合成为一个单一可执行文件的程序。链接的结果是一个可被加载到内存并执行的文件。

5.1.2 作用: 链接器的主要作用是将各个目标文件以及相关的库文件连接成一个可执行文件。这使得分离编译成为可能,也就是将一个大型的应用程序分解为更小、更好管理的模块,可以独立地修改和编译这些模块。当我们改变这些模块中的一个时,只需简单地重新编译它,并重新链接应用,而不必重新编译其他文件。因此,链接器在软件开发中起到了非常重要的作用

注意:这儿的链接是指从 hello.o 到hello生成过程。

5.2 在Ubuntu下链接的命令

(以下格式自行编排,编辑时删除)

使用ld的链接命令,应截图,展示汇编过程! 注意不只连接hello.o文件

5.3 可执行目标文件hello的格式

命令:readelf -h hello

hello是一个可执行目标文件,Type类型为EXEC,有27个节.

节头部表声明了hello中所有节的信息,其中包括大小(Size)以及在程序中的偏移量。

重定位节

重定位节:包含需要进行重定位的信息

符号表:

符号表中,程序源代码中的每个标识符都和它的声明或使用信息绑定在一起

5.4 hello的虚拟地址空间

   

init显示在40100地址位置

在虚拟内存中对应:

同理可得其他节头在虚拟内存中的位置

5.5 链接的重定位过程分析

objdump -d -r hello

hello反汇编的代码有确定的虚拟地址,已经完成了重定位

hello的反汇编文件中,多了一些节和函数,如.init节

重定位过程中

 分析可得,hello.o与main函数的偏移地址为1f, 调用后偏移量为-0x4

所以调用puts函数指令字是 (unsigned)(0x401090 + (-0x4) - (0x401125 + 0x1f))=0xff ff ff 48,转换为小端法即为48 ff ff ff

5.6 hello的执行流程

使用edb执行hello,执行流程如下

地址       子程序名

0x4010f0 _start

0x401000       _init

0x401125       main

0x401090       puts@plt

0x4010d0       exit@plt

0x4011b4       _fini

0x4010e0       sleep@plt

0x4010c0       atoi@plt

0x4010a0       printf@plt

0x4010b0       getchar@plt

0x401120       _dl_relocate_static_pie

0x401020       .plt

5.7 Hello的动态链接分析

动态链接指的是主程序对动态共享库或对象中符号的引用,是等到程序运行后再加载并进行重定位操作。程序的主体部分也称为主程序还是静态链接的,这部分链接是不会将依赖的动态共享库或对象链接进主程序的。

GOT表中存放着函数的目标地址,PLT表则使用GOT中的地址来跳转到目标函数.

.GOT地址

GOT表是0x404000为首地址,大小为0x48的表

运行dl_init之前

运行dl_init之后

5.8 本章小结

本章分析了hello的ELF格式,用readelf等列出其各段的基本信息,对比了hello与hello.o的不同,说明链接的过程,结合hello.o的重定位项目,分析hello的重定位过程和动态链接过程。

(第5章1分)

第6章 hello进程管理

6.1 进程的概念与作用

6.1.1概念

进程是一个执行中的程序的实例,每一个进程都有它自己的地址空间,一般情况下,包括文本区域、数据区域、和堆栈。进程之间是相对独立的,一个进程无法直接访问另一个进程的数据

6.1.2作用

有效管理和调度进入计算机系统主存储器运行的程序

6.2 简述壳Shell-bash的作用与处理流程

6.2.1作用:

shell是一个交互型应用级程序,代表用户运行其他程序,用户通过其提供的界面访问操作系统内核的服务,是用户使用 Linux 的桥梁。shell接收用户命令,然后调用相应的应用程序。

6.2.2处理流程:

1.    终端进程从键盘读取用户输入的命令行。

2.    对命令行字符串进行解析,提取出命令行参数,并构造一个argv向量以供传递给execve函数。

3.    检查命令行的第一个参数是否是内置的shell命令。

4.    如果不是内置命令,使用fork函数创建一个新的进程或子进程。

5.    在子进程中,使用步骤2中提取的参数,调用execve函数来执行指定的程序。

6.    如果用户没有要求在后台运行(即命令行末尾没有加上&符号),则shell进程使用waitpid函数等待子进程执行完毕。

7.    如果用户要求在后台运行(即命令行末尾有&符号),则shell进程立即返回。

6.3 Hello的fork进程创建过程

父进程可以通过调用fork函数来创建一个子进程。fork函数会返回两次,一次是在父进程中,另一次是在新创建的子进程中。新创建的子进程与父进程几乎相同,,区别在于:子进程拥有与父进程用户级虚拟地址空间相同但独立的副本,包括代码段、数据段、堆、共享库和用户栈。子进程能获得与父进程中任何打开文件描述符相同的副本,可以读写父进程打开的任何文件,同时,父进程和新创建的子进程具有不同的PID。

6.4 Hello的execve过程

execve函数用于在当前进程的上下文中加载并运行一个新程序。

当调用execve函数时,它将加载并运行可执行文件filename,并带有参数列表argv和环境变量列表envp。只有当出现错误时,execve函数才会返回到调用程序。因此,execve函数只需调用一次且不会返回。加载filename后,execve函数调用启动代码,设置新程序的栈,并将控制转移传递给新程序的主函数。

子进程通过调用execve系统调用启动加载器。加载器删除子进程现有的虚拟内存段并创建一组新的代码、数据、堆和栈段。新的堆和栈段被初始化为零。加载器将虚拟地址空间中的页面映射到可执行文件的页面大小的片,以将新的代码和数据段初始化为可执行文件的内容。最后,加载器调用_start函数并最终调用应用程序的main函数。

6.5 Hello的进程执行

(1) 上下文信息:操作系统中的进程,除了CPU寄存器之外,还需要维护许多额外的信息,如内存分配状态、打开的文件列表等。这些信息称为进程的上下文信息,它包含了进程的运行环境和状态信息。当操作系统需要切换到另一个进程时,需要保存当前进程的上下文信息,然后再加载下一个进程的上下文信息。这个过程就是上下文切换。

(2) 进程时间片:为了实现多任务调度,操作系统将CPU的运行时间划分为若干个时间片段,每个进程分配一个时间片段,当时间片用完时,操作系统将会切换到下一个进程。这个时间段就是进程时间片。

当处理器刚开始运行时,处于用户模式中,只能访问用户空间的地址,不能执行特权指令或访问内核空间。当发生异常或中断时,处理器会自动切换到内核模式,并执行对应的异常处理程序,这样就可以执行特权指令或访问内核空间。当处理器从内核模式返回到用户模式时,会再次切换回用户模式。上下文切换的目的是在多任务环境中实现进程之间的切换,而进程时间片则是保证进程能够公平地获取CPU时间,避免某些进程长时间占用CPU,导致其他进程无法运行的情况。

6.6 hello的异常与信号处理

程序运行过程中可以按键盘,如不停乱按,包括回车,Ctrl-Z,Ctrl-C等,Ctrl-z后可以运行ps  jobs  pstree  fg  kill 等命令,请分别给出各命令及运行结截屏,说明异常与信号的处理。

hello程序出现的异常可能有:

中断:在hello程序执行的过程中可能会出现外部I/O设备引起的异常。

陷阱:陷阱是有意的异常,是执行一条指令的结果,hello执行sleep函数的时候会出现这个异常。

故障:在执行hello程序的时候,可能会发生缺页故障。

终止:终止时不可恢复的错误,在hello执行过程可能会出现DRAM或者SRAM位损坏的奇偶错误。

(1)不停乱按和回车

无影响,正常输出字符、回车和原文。

(2)Ctrl-Z

进程收到SIGSTP信号,hello进程挂起

       (3)Ctrl-C

收到SIGINT信号,hello被终止。

(4)Ctrl-z后运行ps  jobs  pstree  fg  kill 等命令

 

输入ps查看当前进程的状态包括PID

输入jobs查看被挂起的进程hello

输入fg 1 重启hello进程

输入 kill -9 和PID终止进程

再输入ps发现hello已经被杀死

6.7本章小结

本章介绍了进程的定义和作用,以及Shell-bash的职能和工作流程。还详细介绍了hello程序中的fork进程创建流程、execve过程和进程执行过程,讨论了异常和信号处理的过程,以及如何通过命令行查看进程状态等相关内容。

(第6章1分)

第7章 hello的存储管理

7.1 hello的存储器地址空间

1. 逻辑地址是由CPU生成的地址。逻辑地址是在程序运行时生成的,是相对于程序的起始位置的偏移量。

2. 线性地址是由MMU(内存管理单元)生成的地址。线性地址是逻辑地址经过段基址和段限长寄存器的限制之后所得到的地址。

3. 虚拟地址是由操作系统或MMU创建的,不一定代表实际的物理内存地址,而只是被应用程序使用的地址。

4. 物理地址是指CPU访问内存时真正要访问的地址,是指存储器模块中实际存储数据的地址。物理地址是通过将虚拟地址映射到物理内存上获得的。

7.2 Intel逻辑地址到线性地址的变换-段式管理

在Intel平台下,逻辑地址的格式为“段选择符:段内偏移量”。其中,段选择符由一个16位长的字段组成,其中前13位是索引号,后3位包含硬件细节。分段机制将逻辑地址转换为线性地址的过程如下:

1.使用段选择符中的索引号在GDT或LDT表中定位相应的段描述符。

2.检查该段的访问权限和范围,以确保它可以被访问。

3.将段描述符中的段基地址加上段内偏移量,得到线性地址

7.3 Hello的线性地址到物理地址的变换-页式管理

在Intel架构中,缓存的访问是通过物理地址实现的,一个物理地址可以分成三个部分:标记位、组索引和块偏移。

在Intel i7芯片中,缓存采用组相联的结构构成,即将缓存划分为多个块,并将块进一步分为多个组,每个组内有多行数据。在访问缓存时,首先通过组索引找到目标地址在缓存中对应的组号,然后通过标记和缓存的有效位来判断所需内容是否在缓存中。如果命中,则通过块偏移量读取需要的数据;如果不命中,则从下一级缓存中查找

7.4 TLB与四级页表支持下的VA到PA的变换

页表是一个由页表条目(PTE)组成的数组,它用于将虚拟页映射到物理页。每个PTE包含一个有效位和一个n位的地址字段。有效位用于指示虚拟页是否被缓存在DRAM中。虚拟地址由虚拟页号(VPN)和虚拟页面偏移量(VPO)两部分组成。虚拟页号需要在PTE中进行查询以获取对应的物理页号,而虚拟页面偏移量则直接对应物理地址偏移(PPO)。

7.5   三级Cache支持下的物理内存访问

PA访问内存的过程可以分为以下几个步骤:

1.根据物理地址(PA)、L1高速缓存的组数和块大小,计算出高速缓存块的偏移量(CO)、组索引(CI)和高速缓存标记(CT)。使用组索引查找相应组中的每一行,将其标记与高速缓存标记进行匹配。如果匹配成功,且块的标志位为1,则命中。此时,根据偏移量CO,从高速缓存中读取数据并返回给CPU。

2.如果在L1高速缓存中未找到相匹配的行,或者块的有效位为0,则需要继续在L2高速缓存和L3高速缓存中进行类似的查找。如果三级高速缓存都未命中,则需要从主存或硬盘中获取数据。

3.如果至少有一级高速缓存未命中,则需要在将数据返回给CPU之前,将未命中的高速缓存中的块进行更新。首先检查是否有空闲块可用,如果有,则直接将数据写入该块;否则,需要根据缓存替换策略(如LRU、LFU策略等)驱逐一个块,再将数据写入该块。

4.如果未命中的数据需要从主存或硬盘中获取,则需要将物理地址发送到内存控制器或硬盘控制器,以进行数据读取或写入操作。读取或写入操作完成后,内存控制器或硬盘控制器会将数据传输到高速缓存中,供后续访问使用。

7.6 hello进程fork时的内存映射

当CPU需要访问内存时,首先会在高速缓存中查找对应的数据,如果命中则直接从高速缓存中读取数据并返回给CPU,否则需要从更低一级的高速缓存或主存中获取数据,同时还需要将未命中的数据写入高速缓存,以供后续访问使用。在高速缓存中查找数据时,会将物理地址映射到高速缓存中的块偏移、组索引和标记上,并通过比较标记和有效位来确定是否命中。若未命中,则需要进行替换操作,驱逐掉一个块,再将新的数据写入。

7.7 hello进程execve时的内存映射

当Shell调用fork函数创建新进程时,内核会为新进程hello创建数据结构并分配一个唯一的PID。为了让hello进程拥有自己的虚拟内存,内核会创建hello进程的mm_struct、区域结构和页表的原样副本。此时,新旧进程中的每个页面都被标记为只读,每个区域结构都被标记为私有的写时复制。子进程通过fork函数得到的区域结构、页表等和父进程相同,同时子进程也能访问父进程已打开的文件。当这两个进程中的任意一个进程进行写操作时,写时复制机制会创建新的页面,从而保持每个进程的私有地址空间。在新进程中返回时,新进程的虚拟内存刚好与调用fork函数时父进程的虚拟内存相同。

7.8 缺页故障与缺页中断处理

当发生缺页时,处理器会生成一个虚拟地址,并将其传递给MMU,MMU根据这个虚拟地址生成PTE地址(PTEA),并从高速缓存或主存请求得到PTE。如果PTE的有效位为0,那么MMU就会触发缺页异常。

此时,操作系统的缺页处理程序会被调用,它会根据当前进程的内存需求,从物理内存中找到一个牺牲页(若页面被修改,则先将其换出到磁盘),并将新的页面调入内存。接着,缺页处理程序会更新当前进程的页表,并将控制返回到原来的进程,使其重新执行导致缺页的指令。

7.9动态存储分配管理

printf会调用malloc,只有在malloc函数调用时才分配内存。

malloc函数可以通过使用mmap和munmap函数,显式地分配和释放堆内存。

malloc函数通过sbrk或mmap系统调用来申请内存,sbrk系统调用可以增加当前进程数据段大小,mmap系统调用则可以将一块物理内存映射到虚拟内存空间中,一般用于大块内存的分配。在实际使用中,malloc函数会根据内存分配情况灵活选择sbrk和mmap方式,以达到更高效的内存管理。

7.10本章小结

本章介绍了hello程序的存储管理方案,其中包括地址空间的转换、段式管理、页式管理等内容。还介绍了VA到PA的转换过程和物理内存的访问方式。此外,还介绍了调用fork函数和execve函数时的内存映射,以及如何处理缺页故障以及如何管理动态内存分配。

(第7章 2分)

第8章 hello的IO管理

8.1 Linux的IO设备管理方法

设备的模型化:文件

设备管理:unix io接口

Linux将所有的I/O设备都看作是文件,这种将设备模型化的方式使得所有的输入和输出都能被当做相应文件的读和写来执行。这种方式被称为Unix I/O,允许Linux内核引出一个简单、低级的应用接口,使得设备的管理变得简单而统一。

8.2 简述Unix IO接口及其函数

Unix I/O 接口:

(1)打开文件。一个应用程序通过要求内核打开相应的文件,来宣告它想 要访问一个 I/O 设备,内核返回一个小的非负整数,叫做描述符,它在 后续对此文件的所有操作中标识这个文件,内核记录有关这个打开文 件的所有信息。

(2)Shell 创建的每个进程都有三个打开的文件:标准输入,标准输出,标 准错误。

(3)改变当前的文件位置:对于每个打开的文件,内核保持着一个文件位 置 k,初始为 0,这个文件位置是从文件开头起始的字节偏移量,应用 程序能够通过执行 seek,显式地将改变当前文件位置 k。

(4)读写文件:一个读操作就是从文件复制 n>0 个字节到内存,从当前文 件位置 k 开始,然后将 k 增加到 k+n,给定一个大小为 m 字节的而文 件,当 k>=m 时,触发 EOF。类似一个写操作就是从内存中复制 n>0 个字节到一个文件,从当前文件位置 k 开始,然后更新 k。

(5)关闭文件,内核释放文件打开时创建的数据结构,并将这个描述符恢 复到可用的描述符池中去。

Unix I/O 函数:

(1)int open(char* filename,int flags,mode_t mode) ,进程通过调用 open 函 数来打开一个存在的文件或是创建一个新文件的。 open函数将filename 转换为一个文件描述符,并且返回描述符数字,返回的描述符总是在 进程中当前没有打开的最小描述符,flags 参数指明了进程打算如何访 问这个文件,mode 参数指定了新文件的访问权限位。

(2)int close(fd),fd 是需要关闭的文件的描述符,close 返回操作结果。

(3) ssize_t read(int fd,void *buf,size_t n),read 函数从描述符为 fd 的当前文 件位置赋值最多 n 个字节到内存位置 buf。返回值-1 表示一个错误,0 表示 EOF,否则返回值表示的是实际传送的字节数量。

(4) ssize_t wirte(int fd,const void *buf,size_t n),write 函数从内存位置 buf 复制至多 n 个字节到描述符为 fd 的当前文件位置。

8.3 printf的实现分析

printf的函数体:

int printf(const char *fmt, ...)

{

int i;

char buf[256];

  

     va_list arg = (va_list)((char*)(&fmt) + 4);

     i = vsprintf(buf, fmt, arg);

     write(buf, i);

    return i;

}

va_list arg = (va_list)((char*)(&fmt) + 4)的作用是让指针arg指向传入的参数中的第一个字符串。函数vsprintf会根据指定的格式化字符串fmt,将参数列表中的值转换成相应的字符串,并将结果存储到缓冲区buf中。函数返回值i是转换后字符串的长度。而函数write会将缓冲区buf中的i个字符写入到终端中,使其显示在屏幕上。

在实现过程中,系统函数write会调用系统调用函数syscall,将buf中的字符从寄存器中复制到显卡的显存中,其中显存中存储的是字符的ASCII码。字符显示驱动子程序将根据ASCII码在字模库中查找对应的点阵信息,并将点阵信息存储到vram中。显示芯片会按照一定的刷新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量)。最终,需要打印的字符串就会显示在屏幕上。

从vsprintf生成显示信息,到write系统函数,到陷阱-系统调用 int 0x80或syscall等.

字符显示驱动子程序:从ASCII到字模库到显示vram(存储每一个点的RGB颜色信息)。

显示芯片按照刷新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量)。

8.4 getchar的实现分析

getchar等调用read系统函数,通过系统调用读取按键ascii码,直到接受到回车键才返回。

异步异常-键盘中断的处理是指当用户敲击键盘时,操作系统通过中断处理程序来接收和处理键盘输入。当键盘产生中断时,CPU暂停正在执行的程序并跳转到中断处理程序。中断处理程序接受按键扫描码并将其转换为ASCII码,并将它们保存到系统的键盘缓冲区中。然后,用户可以使用类似于getchar的函数来读取缓冲区中的输入。如果输入有误,则会返回-1。如果输入正确,则可以继续读取更多的字符,直到用户按下回车键。在读取所有的字符后,操作系统会等待用户按下回车键,然后继续执行程序。

8.5本章小结

本章介绍了Linux的IO设备管理方法,了解了IO接口及其函数,分析了printf和getchar函数的实现

(第8章1分)

结论

hello.c文件首先通过预处理器(cpp)变成了hello.i,再经过编译器(cc1)变成了hello.s,再经过汇编器(as)生成hello.o,最后通过链接器(ld)生成了可执行目标程序hello. 在运行程序的过程中,shell通过fork创建子进程,通过execve加载程序,实现了P2P

计算机系统的设计思想和实现都是基于抽象实现的。从最底层的信息的表示用二进制表示抽象开始,到实现操作系统管理硬件的抽象:进程是对处理器、主存和I/O设备的抽象。虚拟内存是对主存和磁盘设备的抽象。文件是对I/O设备的抽象。

在计算机系统中,存储速度和存储容量之间存在平衡问题。为了解决这个问题,设计者引入了高速缓存这样的存储设备作为更底层存储设备的缓存,这样CPU就可以更快地访问主存,提高了系统的性能。

(结论0分,缺失 -1分,根据内容酌情加分)

附件

文件名    文件作用

hello.c    源文件

hello.i     hello.c经过预处理(cpp)后的文本文件

hello.s    hello.i经过编译(ccl)得到的汇编文件

hello.o    hello.s经过汇编(as)得到的可重定位目标文件

hello       hello.o与其他目标文件链接后得到的可执行目标文件

hello_elf.txt    hello.o的elf文件

hello_elf_.txt  hello的elf文件

(附件0分,缺失 -1分)

参考文献

为完成本次大作业你翻阅的书籍与网站等

[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分)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值