程序人生-Hello’s P2P

计算机系统

大作业

题     目  程序人生-Hellos P2P  

专       业   未来技术学院           

学     号   2022111008             

班   级   WL023

学       生   林家鑫               

指 导 教 师   刘宏伟                 

计算机科学与技术学院

20245

摘  要

本文通过追踪hello小程序在Linux系统的一生,探讨hello程序从hello.c经过预处理、编译、汇编、链接生成可执行文件,并由操作系统进行进程管理、存储管理和I/O管理的全过程。以此将计算机系统课程中的内容进行全面地总结和梳理,加深对计算机系统的理解。

关键词:计算机系统、预处理、编译、汇编、进程、链接                            

目  录

第1章 概述

1.1 Hello简介

1.2 环境与工具

1.3 中间结果

1.4 本章小结

第2章 预处理

2.1 预处理的概念与作用

2.2在Ubuntu下预处理的命令

2.3 Hello的预处理结果解析

2.4 本章小结

第3章 编译

3.1 编译的概念与作用

3.2 在Ubuntu下编译的命令

3.3 Hello的编译结果解析

3.4 本章小结

第4章 汇编

4.1 汇编的概念与作用

4.2 在Ubuntu下汇编的命令

4.3 可重定位目标elf格式

4.4 Hello.o的结果解析

4.5 本章小结

第5章 链接

5.1 链接的概念与作用

5.2 在Ubuntu下链接的命令

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

5.4 hello的虚拟地址空间

5.5 链接的重定位过程分析

5.6 hello的执行流程

5.7 Hello的动态链接分析

5.8 本章小结

第6章 hello进程管理

6.1 进程的概念与作用

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

6.3 Hello的fork进程创建过程

6.4 Hello的execve过程

6.5 Hello的进程执行

6.6 hello的异常与信号处理

6.7本章小结

第7章 hello的存储管理

7.1 hello的存储器地址空间

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

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

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

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

7.6 hello进程fork时的内存映射

7.7 hello进程execve时的内存映射

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

7.9动态存储分配管理

7.10本章小结

第8章 hello的IO管理

8.1 Linux的IO设备管理方法

8.2 简述Unix IO接口及其函数

8.3 printf的实现分析

8.4 getchar的实现分析

8.5本章小结

结论

附件

参考文献


第1章 概述

1.1 Hello简介

P2P:

Hello诞生于一个C程序,即hello.c。首先经过的是预处理过程,它处理了宏、#开头的库文件等等,将.c文件转换成预处理文件hello.i;而后编译器完成常量表达式计算等工作,将hello.i文件转为文本文件hello.s(汇编语言),这个过程被称作编译;接下来是汇编过程,在这里汇编语言被转换成二进制代码,生成二进制文件hello.o(可重定位文件);最后是链接阶段,在这里将进行符号解析和重定位,经过动态链接的过程就生成了最后的可执行文件hello。

020:

用户在shell中输入./hello命令后,第一步会调用Fork函数生成一个只有pid与父进程不同的子进程,并在子进程中调用evecve函数。evecve函数首先启动加载器loader,它将原来的上下文等内容全部丢弃,并新建出task_struct及其目录下包括mm_struct等的数据结构,映射私有区域和共享区域,然后设置程序计数器到代码区域的入口点,使程序开始运行(这其中会发生缺页故障、根据时间片的分配切换上下文等过程)。经过一系列的函数的调用、代码的执行,程序运行结束,成为僵死子进程,等待被父进程回收。

1.2 环境与工具

硬件环境:X64 CPU;2GHz;2G RAM;256GHD Disk

软件环境:Windows11;VirtualBox/Vmware 11以上;Ubuntu 20.04 LTS 64位

开发工具:VScode 2019 ;GDB;EDB等

1.3 中间结果

hello.c:源程序

hello.i:经过预处理得到的结果,是文本文件

hello.s:经过编译得到的结果,指令以汇编语言的形式出现,是文本文件

hello.o:经过汇编得到的结果,是可重定向文件,是二进制文件

hello:经过链接得到的结果,是可执行文件

1.4 本章小结

本章简要介绍了hello.c的P2P与O2O,然后对本次实验环境、实验工具、中间结果进行初步列举,最后大致地简介了hello程序从hello.c到可执行目标文件hello的历程。


第2章 预处理

2.1 预处理的概念与作用

1.预处理的概念:

预处理是在编译之前进行的处理,一般指在程序源代码被翻译为目标代码的过程中,生成二进制代码之前的过程,预处理中会展开以#起始的行,试图解释为预处理指令。

预处理过程扫描源代码,对其进行初步的转换,产生新的源代码提供给编译器。预处理过程读入源代码,检查包含预处理指令的语句和宏定义,并对源代码进行响应的转换。预处理过程还会删除程序中的注释和多余的空白字符。

2.预处理阶段作用:

处理宏定义指令预处理器根据#if和#ifdef等编译命令及其后的条件,将源程序中的某部分包含进来或排除在外,通常把排除在外的语句转换成空行。

处理条件编译指令。条件编译指令如#ifdef,#ifndef,#else,#elif,#endif等。 这些伪指令的引入使得程序员可以通过定义不同的宏来决定编译程序对哪些代码进行处理。预编译程序将根据有关的文件,将那些不必要的代码过滤掉。

处理头文件包含指令头文件包含指令如#include "FileName"或者#include 等。 该指令将头文件中的定义统统都加入到它所产生的输出文件中,以供编译程序对之进行处理。

处理特殊符号。预编译程序可以识别一些特殊的符号。 例如在源程序中出现的LINE标识将被解释为当前行号,FILE则被解释为当前被编译的C源程序的名称。预编译程序对于在源程序中出现的这些串将用合适的值进行替换。

2.2在Ubuntu下预处理的命令

预处理命令:gcc hello.c -E -o hello.i

图1.预处理结果1

图2.预处理结果2

2.3 Hello的预处理结果解析

由图可知,经过预处理后,hello.c的代码被扩展为3061行,其中main函数占第3048~3061行,main函数前为hello.c引用的stdio.h等头文件的内容。同时,注释内容被去除。

2.4 本章小结

本章主要介绍了预处理的相关概念和应用功能。分析hello.c预处理得到hello.i文本文件的过程,发现了预处理阶段的行为:头文件的展开、宏替换、去掉注释、条件编译。


第3章 编译

3.1 编译的概念与作用

1.编译的概念:

编译就是将源语言经过词法分析、语法分析、语义分析以及经过一系列优化后生成汇编代码的过程。其以高级程序设计语言书写的源程序作为输入,而以汇编语言或机器语言表示的目标程序作为输出。编译器将文本文件 hello.i 翻译成文本文件 hello.s,它包含一个汇编语言程序。

2.编译的作用:

将高级语言程序转化为机器可直接识别处理执行的的机器码的中间步骤。除了基本作用之外,编译程序还具备语法检查、调试措施、修改手段、覆盖处理、目标程序优化、不同语言合用以及人际联系等重要功能。

3.2 在Ubuntu下编译的命令

指令:gcc -S hello.i -o hello.s

图3.编译结果

3.3 Hello的编译结果解析

图4.编译结果

main前的部分伪指令代码

源文件名                    .file

代码段                      .text

只读代码段                  .section .rodata

对齐要求 对指令和数据地址   .align

字符串类型数据              .string

符号类型,包括函数和对象    .type

全局变量                    .global

3.3.1 数据

1.字符串

(1)"\347\224\250\346\263\225:Hello\345\255\246\345\217\267\345\247\223\345\220\215\347\247\222\346\225\260\357\274\201"对应.c文件中"用法: Hello 学号 姓名 秒数!\n",其中中文已被编码为UTF-8 格式,一个汉字占3个字节。

(2)“Hello %s %s\n” 对应原c文件中"Hello %s %s\n"第二个printf中的格式化参数,其中后两个字符串已在.rodata中声明。

2.整数

(1)int i(局部变量)

图5.int i编译结果

根据31行movl $0, -4(%rbp) 可以看出编译器将i存到了-4(%rbp) 中,且占4个字节。

(2)int argc

图6.int argc编译结果

作为第一个参数被压栈pushq %rbp,传入main函数

(3)立即数

程序中其他整型都是以立即数的形式出现

(4)数组 char *argv[ ]

图7.数组编译结果

这是一个指针数组,由addq $, %rax可以看出,一个内容占8个字节,说明linux中一个地址的大小是8个字节。

3.3.2赋值

(1) i=0

movl $0, -4(%rbp)  通过movl指令将0赋给了i

3.3.3算术操作

(1)i++   addl $1, -4(%rbp)

3.3.4 关系判断

(1)argc!=5

图8.编译argc!=5

(2)i<10

图9.编译i<10

3.3.5控制转移

(1)argc!=5,跳至L2

图10.编译argc!=5,跳至L2

(2)for(i=0;i<10;i++)

图11.编译for(i=0;i<10;i++)

3.3.6数组操作

argv[1],argv[2]

图12.编译argv[1],argv[2]

3.3.7函数调用

函数的调用需要有以下过程:传递控制、数据传递、分配空间

(1)main函数

main函数由系统启动的函数__libc_start_main调用call指令将main函数的地址分配给%rip,后跟main函数。主函数argc *argv[]的两个参数分别存储在%rdi和%rsi中。通常,该函数将返回0作为出口,并将%eax设置为 0。

(2)printf函数

图13.printf函数

当第一次调用 printf 时,字符串是固定的,只有一个参数,因此调用put@PLT。第二个调用具有三个参数,调用printf@PLT。

3.4 本章小结

本章主要讲述了编译的概念与作用,编译器如何处理各种数据和操作,以及c语言中各种类型和操作所对应的的汇编代码。


第4章 汇编

4.1 汇编的概念与作用

汇编是把汇编语言书写的程序翻译成与之等价的机器语言程序的过程。它的主要作用是将汇编指令翻译成机器能够识别、执行的形式,例如将人习惯使用的十进制数转换为机器运算需要的二进制数,按指令集编码规则将汇编指令翻译成机器能读懂的二进制编码。

4.2 在Ubuntu下汇编的命令

汇编的命令为:gcc -c hello.s -o hello.o

图14.汇编结果

4.3 可重定位目标elf格式

4.3.1 elf头

以16字节的序列开始,这个序列描述了生成该文件的系统的字的大小和字节顺序。elf头剩下的部分包含帮助链接器语法分析和解释目标文件的信息,其中包括elf头的大小、目标文件的类型、机器类型、节头部表的文件偏移,以及节头部表中条目的大小和数量。不同节的位置和大小是由节头部表描述的,其中目标文件中每个节都有一个固定大小的条目。

图15.elf头

4.3.2 .text

已编译程序的机器代码。

4.3.3 .rodata

只读数据,如printf语句中的格式串和开关语句的跳转表。

4.3.4 .data

已初始化的全局和静态C变量。这里,局部C变量在运行时被保存在栈中。

4.3.5 .bss

未初始化的全局和静态C变量,以及所有被初始化为0的全局或静态C变量。

4.3.6 .symtab

存放在程序中定义和引用的函数和符号的符号表。。

4.3.7节头部表

包括节名称,节的类型,节的属性(读写权限),节在ELF文件中所占的长度以及节的对齐方式和偏移量。

图16.节头部表

4.4 Hello.o的结果解析

命令为:objdump -d -r hello.o

图17.objdump结果

分析对比hello.s与hello.o的不同之处:

(1)全局变量。

hello.s通过段地址+%rip定位, 而hello.o由于尚未重定位,会把寻址写成0+%rip,并为其在.rela.text节中添加重定位条目;

(2)分支转移。

hello.o通过地址进行跳转,而hello.s通过段名称;

(3)函数调用。

hello.s中的函数调用形式为call+函数名称;而在hello.o文件中,call后跟的是下一条指令,同时因为这些函数都是共享库函数,地址尚不确定,因此call指令将相对地址设置为0x0,并在.rela.text节中为其添加重定位条目。

4.5 本章小结

这一章主要对汇编后的可重定向文件hello.o进行了分析,分别使用了readelf和objdump工具查看了hello.o中的信息。通过上述分析,可以非常清楚地看到汇编阶段处理的一些痕迹:文本文件被改成了二进制文件,使得汇编指令被翻译成了二进制代码;因为有了二进制代码指令,所以地址都可以被确定,在这一基础上又对一些需要相对寻址的地方做了改动。


5链接

5.1 链接的概念与作用

 链接是将各种代码和数据片段收集并组合为单一文件的过程,这个文件可以被加载(复制)到内存并执行。链接可以执行于编译时,也就是源代码被翻译成机器代码时;也可以执行于加载时,即程序被加载器加载到内存并执行时;甚至执行于运行时,也就是由应用程序来执行。链接使得分离编成为可能。更便于我们维护管理,我们可以独立的修改和编译我们需要修改的小的模块。

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

图18.链接命令

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

hello的elf头:

图19.hello的elf头

与hello.o的ELF头相比,有以下几处不同:文件类型从可重定位更改为可执行。程序的入口点、程序开始点、节头表偏移发生改变。共有27个节头表,增加了10个。

节头部表:

图20.hello的节头部表

5.4 hello的虚拟地址空间

打开EDB运行hello,观察Data Dump窗口,虚拟地址空间由0x401000到0x401ff0。其中的节与每个节头表的声明一一对应。

图21.hello的虚拟地址空间

图22.EDB展示hello的虚拟地址空间

5.5 链接的重定位过程分析

图23.hello的objdump结果

不同:

(1)反汇编代码中地址为确定的虚拟地址,而hello中地址为地址偏移量

(2)Hello中含有许多除main外的函数,链接的过程中发生重定位,使得被用到其他库的函数加入,hello比hello.o多出了一些节和代码

重定位的分析:在符号解析完成后,可进行重定位工作,分为3步:

(1)合并相同的节:将集合E的所有目标模块中相同的节合并成新节。

(2)对定义符号进行重定位;确定新节中所有定义符号在虚拟地址空间中的地址。

(3)对引用符号进行重定位:修改.text和.data节中对每个符号的引用。

5.6 hello的执行流程

使用edb执行hello

图24.使用edb执行hello

加载hello到_start,到call main,以及程序终止的过程

图25.程序名称及对应地址

5.7 Hello的动态链接分析

在hello中动态链接通过延时绑定来实现,延时绑定依赖全局偏移量表GOT和过程连接表PLT实现。
查看与动态链接相关的.got.plt段

图26.got.plt段

未调用init时

图27.未调用init时got.plt段

调用init后

图28.调用init后got.plt段

我们看到00404000和00404010间数据发生变化,变化的原因是GOT加载了共享库的内容。

5.8 本章小结

本章介绍了链接的概念及作用,对hello的elf格式进行了详细的分析,介绍了hello的虚拟地址,分析了hello的重定位过程、执行流程、动态链接过程,详细阐述了hello.o链接成为一个可执行目标文件的过程。


6hello进程管理

6.1 进程的概念与作用

进程是计算机科学中最深刻,最成功的概念之一。在现代系统上运行一个程序时,我们会得到一个假象,就好像我们的程序是系统当中运行的唯一程序一样。我们的程序好像是独占使用处理器和内存。处理器就好像是无间断地一条接着一条的执行我们的指令。最后我们程序中的代码和数据好像是系统内存中的唯一的对象。这些假象都是通过进程的概念提供给我们的。

进程的经典定义就是一个执行中的程序的实例。系统的每一个程序都是运行在某一个进程上下文中。上下文是由程序正确运行所需要的状态构成的。这个状态包括存放在内存中的程序的代码和数据,它的栈、通用目的寄存器的内容、程序计数器、环境变量以及上下文描述符的集合。

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

shell是指“为使用者提供操作界面”的软件。它类似于DOS下的command.com和后来的cmd.exe。它接收用户命令,然后调用相应的应用程序。shell是一个交互性应用级程序,代表用户运行其他程序。

处理流程如下:

1.从脚本或终端或bash -c选项后的字符串中获取输入。

2.将获取的输入分解成词元,此步骤会执行别名展开。

3.将词解析为简单命令或复合命令。

4.执行各种shell展开。

5.执行必要的重定向。

6.执行命令。

7.等待命令结束获取命令执行状态。

6.3 Hello的fork进程创建过程

当fork被调用时,内核为新进程创建各种数据结构,并分配给它唯一PID。然后创建当前mm_struct、区域结构和页表的原样副本。将两个进程每个页面都标为只读,并将每个区域结构都标记为私有的写时复制。

6.4 Hello的execve过程

1.删除当前进程虚拟内存的用户部分中已存在的区域结构

2.映射私有区域,为新程序的代码、数据、.bss和栈区域创建新区域结构。

3.共享对象动态链接hello程序,将其映射至用户虚拟内存空间的共享区域中

4.设置程序的计数器,使之指向代码区域。

6.5 Hello的进程执行

上下文信息:进程上下文是表示进程信息的一系列东西,包括各种变量、寄存器以及进程的运行的环境。这样,当进程被切换后,下次再切换回来继续执行,能够知道原来的状态。

进程时间片:进程时间片是分时操作系统分配给每个正在运行的进程微观上的一段CPU时间。

进程调度:操作系统管理系统的资源,当多个进程要使用这些资源时,由于资源的有限,必须按照一定的原则选择进程来占用资源。当我们在运行程序时,进程会给我们一种假象:仿佛每个进程都在独占使用处理器。在进程执行时,内核可以抢占当前的资源,并重新开始一个被抢占了的进程,这便是进程调度的决策。我们使用上下文切换来控制转移到新的进程中去。时间片是进程调度的方法之一,在时间片内如果进程完成任务或者阻碍,则该进程让出cpu,当进程耗费完时间片尚未执行完毕,强迫其让出cpu。

用户态和核心态的转换:用户态就是执行在用户空间中,不能直接执行系统调用,必须先切换到内核态,也就是系统调用的相关数据信息必须存储在内核空间中,然后执行系统调用。系统执行程序时大部分时间运行在用户态下,在其需要操作系统帮助,完成用户态没有权限无法完成的工作时,转换到用户态,这种转换是一种特殊的上下文切换。

6.6 hello的异常与信号处理

正常运行:

图29.程序正常运行

程序完成被正常回收。

(1)乱按+回车

图30.程序运行时乱按

乱按字符直接打印在了屏幕上,回车空行也打印在屏幕上

(2)输入ctrl+z

图31.程序停止运行

这时输入命令PS查看进程,使用jobs指令查看,得到以下结果,可知此时hello进程没有结束,而是被暂时挂起,PID为2421。

图32.查看程序停止运行

(3)输入ctrl+c

图33.程序终止

jobs输出为空,可以判断进程直接被终止,被回收.

(4)输入kill

图34.杀死程序

当输入kill后进程被杀死,此时再输入ps指令后发现当前无进程执行。

6.7本章小结

本章阐述了进程的概念与作用,Shell的一般处理流程,分析了hello进程的执行过程,创建、加载和终止,以及hello的异常与信号处理。
第7章 hello的存储管理

7.1 hello的存储器地址空间

1.逻辑地址

逻辑地址是指由程序hello产生的与段相关的偏移地址部分。

2.线性地址

线性地址是逻辑地址到物理地址变换之间的中间层。程序hello的代码会产生逻辑地址,或者说是段中的偏移地址,它加上相应段的基地址就生成了一个线性地址。

3.虚拟地址

有时我们也把逻辑地址称为虚拟地址。因为与虚拟内存空间的概念类似,逻辑地址也是与实际物理内存容量无关的,是hello中的虚拟地址。

4.物理地址

物理地址是指出现在CPU外部地址总线上的寻址物理内存的地址信号,是地址变换的最终结果地址。如果启用了分页机制,那么hello的线性地址会使用页目录和页表中的项变换成hello的物理地址;如果没有启用分页机制,那么hello的线性地址就直接成为物理地址了。

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

每个段的首地址就会被储存在各自的段描述符里面,所以的段描述符都将会位于段全局描述符表中,通过段选择符我们可以快速寻找到某个段的段全局描述符。逻辑上段地址的偏移量结构就是段选择符+偏移量。

段选择符的索引位组成和定义如下,分别指的是索引位,ti,rpl,当索引位ti=0时,段描述符表在rpgdt中,ti=1时,段描述符表在rpldt中。而索引位index就类似一个数组,每个元素内都存放一个段的描述符,索引位首地址就是我们在查找段描述符时再这个元素数组当中的索引。一个段描述符的首地址是指含有8个元素的字节,我们通常可以在查找到段描述符之后获取段的首地址,再把它与线性逻辑地址的偏移量进行相加就可以得到段所需要的一个线性逻辑地址。

在分段保护模式下,分段有两种机制:段的选择符在段的描述符表->分段索引->目标段的段描述符条目->目标段的描述符基地址+偏移量=转换为线性段的基地址。由于现代的macosx86系统内核使用的描述符是基本扁平的逻辑模型,即目标段的逻辑地址=线性段的描述符=转换为线性段的基地址,等价于描述符转换为线性地址时关闭了偏移量和分段的功能。这样逻辑段的基地址与转换为线性段的基地址就合二为一了。

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

系统将每个段分割为被称为虚拟页的大小固定的块来作为进行数据传输的单元,在Linux下每个虚拟页大小为4KB,类似地,物理内存也被分割为物理页,虚拟内存系统中MMU负责地址翻译,MMU使用存放在物理内存中的被称为页表的数据结构将虚拟页到物理页的映射,即虚拟地址到物理地址的映射。

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

将VPN分成三段,对于TLBT和TLBI来说,可以在TLB中找到对应的PPN,但是有可能出现缺页的情况,这时候就需要到页表中去找。此时,VPN被分成了更多段,CR3是对应的L1PT的物理地址,然后一步步递进往下寻址,越往下一层每个条目对应的区域越小,寻址越细致,在经过4层寻址之后找到相应的PPN让你和和VPO拼接起来。

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

得到物理地址之后,先将物理地址拆分成标记+索引+偏移量,然后在一级cache内部找,如果未能寻找到标记位为有效的字节的话就去二级和三级cache中寻找对应的字节,找到之后返回结果。

7.6 hello进程fork时的内存映射

当fork被新进程hello调用,内核给hello创建各种数据结构,并分配唯一的pid。Fork为新进程创建虚拟内存,创建当前进程的的mm_struct, vm_area_struct和页表的原样副本,两个进程中的每个页面都标记为只读并且两个进程中的每个区域结构都标记为私有的写时复制。在新进程中返回时,新进程拥有与调用fork进程相同的虚拟内存,随后的写操作通过写时复制机制创建新页面。

7.7 hello进程execve时的内存映射

execve函数在当前进程中加载并运行新程序的步骤:

(1)删除已存在的用户区域

(2)创建新的区域结构:这些区域都是私有的、写时复制的。代码和数据,被映射为hello文件中的.text和.data区。

(3)映射共享的区域,将hello程序与共享对象链接,对象动态链接到hello程序,然后映射到用户虚拟地址空间。

(4)设置PC,设置程序计数器,指向代码区域的入口点

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

缺页故障:进程线性地址空间里的页面不必常驻内存,在执行一条指令时,如果发现他要访问的页没有在内存中(即存在位为0),那么停止该指令的执行,并产生一个页不存在的异常,对应的故障处理程序可通过从外存加载该页的方法来排除故障,之后,原先引起的异常的指令就可以继续执行,而不再产生异常。

缺页中断处理:处理器生成一个虚拟地址,并将它传送给MMU,MMU生PTE地址,并从高速缓存处请求得到它,高速缓存返回PTE,缺页处理程序确认出物理内存中的牺牲页,如果这个页已经被修改了,则把它换到磁盘,调入新的页面,更新PTE,最后返回原来的进程,重新执行导致缺页的命令,如果处理成功,就会命中。

7.9动态存储分配管理

分配器通过维护虚拟内存(堆)来实现动态存储分配管理,存在两种维护方式:

(1)隐式空闲链表:分配器检测一个已分配块何时不再被程序所使用,那么就释放这个块

(2)显式空闲链表:每次声明内存空间都保证至少分配size_t大小的内存,双字对齐,每次必须从空闲块中分配空间,在申请空间时将空闲的空间碎片合并,以尽量减少浪费。

7.10本章小结

本章主要介绍了hello存储器的地址空间;虚拟地址到物理地址的转换;cache的物理内存访问;进程 fork、execve 时的内存映射、缺页故障与缺页中断处理;动态存储分配管理。
第8章 hello的IO管理

8.1 Linux的IO设备管理方法

设备的模型化:文件

所有的I/O设备都被模型化为文件,甚至内核也被映射为文件

设备管理:unix io接口

这种将设备优雅地映射为文件的方式,允许Linux内核引出一个简单、低级的应用接口,称为Unix I/O。我们可以对文件的操作有:打开关闭操作open和close;读写操作read和write;改变当前文件位置lseek等。

8.2 简述Unix IO接口及其函数

Unix IO接口:

(1)打开:open(),打开或创建目标文件。

(2)关闭:close(),关闭文件。

(3)读取:read(),从当前文件位置读取字节到内存中。

(4)写入:write(),从内存复制字节到当前文件位置。

(5)更改文件位置:lseek(),将文件位置更改为目标位置。

Unix IO 函数:

(1)int open(char* filename , int flags , mode_t mode)将文件转为操作符

(2)int close(fd)关闭文件,并返回操作结果

(3)ssize_t read(int fd , void *buf , size_t n)从fd复制n个字节到buf

(4)ssize_t wirte(int fd , const void *buf , size_t n)从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;

}

Valist说明arg是一个字符指针,指向fmt的第一个参数。Vsprintf返回即将打印的字符串的长度。接下来调用了write函数,write中INT_VECTOR_SYS_CALL表示要通过系统来调用sys_call这个函数。

Sys_call作用是打印,显存存储ASCII字符码,字符显示驱动子程序通过ASCII码在字体库中查找点阵信息,将点阵信息存储在vram中。显示芯片按照刷新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量)。

8.4 getchar的实现分析

getchar有一个int型的返回值。当程序调用getchar时。程序就等着用户按键.用户输入的字符被存放在键盘缓冲区中。直到用户按回车为止,回车字符也放在缓冲区中。当用户键入回车之后,getchar才开始从stdin流中每次读入一个字符。getchar函数的返回值是用户输入的第一个字符的ASCII码,如出错返回-1,且将用户输入的字符回显到屏幕。如用户在按回车之前输入了不止一个字符,其他字符会保留在键盘缓存区中,等待后续getchar调用读取。也就是说,后续的getchar调用不会等待用户按键,而直接读取缓冲区中的字符,直到缓冲区中的字符读完为后,才等待用户按键。

8.5本章小结

本章介绍了 Linux 的 I/O 设备的基本概念和管理方法,Unix I/O 接口及其函数,printf 函数和 getchar 函数的工作过程。

结论

结论:

本文讲述了hello的一生。

二至五章主要讲述了hello生成的过程,分别对应了预处理、编译、汇编、链接过程。预处理过程中,处理了#开头的行,包括宏定义、文件包含和条件编译;编译过程中,经过与处理的文件被转换为汇编指令,将贴近人类语言的代码转换成了计算机更愿意处理的指令集的形式;汇编过程中,由汇编指令组成的文本文件被转换了二进制文件,即可重定向文件;链接过程中,可重定向文件经过符号解析、重定位两个过程,最终得到了完整的可执行文件。

后面三章分别结合hello程序,从进程管理、存储管理、I/O管理这三个方面进行了详细的分析。其中涉及到了cache、页表、虚拟内存、信号处理、动态内存分配等多个方面,包括fork创建子进程、execve加载并执行hello、在hello执行中按ctrl-c/ctrl-z等过程的探究的和结果的详细阐述。

感悟:

经过一学期的学习,结合深入理解计算机系统这本经典教材与CMU的课程实验,以及老师们的悉心讲解。对现代计算机系统的整体框架和底层原理有了大致的认识和深刻的理解,从计算机内信息的存储,再到处理器体系结构,基本的汇编语言,存储器结构,链接,异常控制,虚拟内存,系统级I/O。

从宏观的角度,对现代计算机系统的整体认识,对以后的学习和工作无疑有莫大的帮助,对继续在计算机科学领域深耕也打下了坚实的基础。而从现实的角度,本门课程也从一个程序员的角度为以后的程序编写提供了保障,例如编写缓存友好,CPU友好的代码。

作为哈工大的学生,不仅仅应该停留在写代码的表面,更应该对这样计算机系统的底层知识有更深入的理解,而这门课程正是为我们以后成为一个优秀的哈工大青年打下基础,培养我们的能力。


附件

列出所有的中间产物的文件名,并予以说明起作用。

中间结果文件及作用:

hello.i 预处理后的文本文件

hello.s 编译后的汇编文本

hello.o 汇编后可重定位目标文件

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.

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值