摘 要
编辑好的word转存图片总是失败,就先不上传图片了。
本文主要利用计算机系统课程学习的知识,分析hello.c程序在Linux下从从产生到死亡的全过程,回顾Linux系统下的程序从代码到运行再到最后终止过程的底层实现,涉及gcc、objdump、gdb、edb等工具对一段程序代码预处理、编译、汇编、链接与反汇编的过程。目标通过此次大作业加深对课程知识的掌握。
关键词:计算机系统 程序的生命周期 汇编 反汇编 linux
(摘要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 -
P2P:
020:
1.shell为hello进程映射虚拟内存,在开始运行进程的时候分配并载入物理内存
2.进入main函数执行目标代码,CPU为运行的hello分配时间并执行
3.当程序运行结束后,回收进程,内核删除相关数据结构。
硬件环境:
X64CPU; 8GHz; 16GRAM; 1TB HD
软件环境:
Windows10 64位;VMware14.12; Ubuntu 18.04 LTS 64位
使用工具:
codeblocks,objdump,gdb,edb,gcc
列出你为编写本论文,生成的中间结果文件的名字,文件的作用等。
文件名 文件功能
hello.i 预处理之后的文本文件
hello.s 编译之后的汇编文件
hello.o 汇编之后可重定位目标执行文件
hello 链接之后的可执行目标文件
helloo.objdmp hello.o的反汇编文件
hello.elf hello的ELF格式
hello.objdmp hello的反汇编文件
介绍了完成作业中软硬件使用情况,和产生的各种文件。
(第1章0.5分)
1.概念
程序设计领域中,预处理一般是指在程序源代码被翻译为目标代码的过程中,生成二进制代码之前的过程。典型地,由预处理器(preprocessor) 对程序源代码文本进行处理,得到的结果再由编译器核心进一步编译。
2.作用:
预处理是C语言的一个重要功能, 它由预处理程序负责完成。当对一个源文件进行编译时, 系统将自动引用预处理程序对源程序中的预处理部分作处理, 处理完毕自动进入对源程序的编译。
在集成开发环境中,编译,链接是同时完成的。其实,C语言编译器在对源代码编译之前,还需要进一步的处理:预编译。预编译的主要作用如下:
●将源文件中以”include”格式包含的文件复制到编译的源文件中。
●用实际值替换用“#define”定义的字符串。
●根据“#if”后面的条件决定需要编译的代码。
应截图,展示预处理过程!
图2.1
cpp hello.c > hello.i
图2.2
可以看到预处理后形成很多行代码,而hello程序在最后面。
经过预处理之后,hello.c文件转化为hello.i文件。查看hello.i文件可以看到,在原有代码的基础上,将头文件stdio.h的内容引入,例如声明函数、定义结构体、定义变量、定义宏等内容。
Hello.i仍为可以阅读的C语言程序文本文件。
介绍了预处理知识;对hello程序进行预处理,生成.i文件。
(第2章0.5分)
编译:将某一种程序设计语言写的程序翻译成等价的另一种语言的程序的程序, 称之为编译。在本程序中即指编译器将文本文件hello.i翻译成文本文件hello.s,它包含一个汇编语言程序。这是编译的功能。
编译器的基本功能是把源程序(高级语言)翻译成目标程序。除了基本功能之外,编译程序还具备语法检查、调试措施、修改手段、覆盖处理、目标程序优化、不同语言合用以及人机联系等重要功能。
注意:这儿的编译是指从 .i 到 .s 即预处理后的文件到生成汇编语言程序
编译命令:gcc-S hello.i-o hello.s
图3.1
应截图,展示编译过程!
编译结果截图如下:
图3.2
3.3.1、Hello.c 里一共有三种数据类型:整数,字符串型,数组
a. 整数
1.int sleepsecs hello.c中 int sleepsecs是全局变量,编译器进行处理,把 sleepsecs声明为 globl全局变量,存放在 .data节里
2. int I i是循环时候的计数变量,初始值 0,从0变到9。编译器将局部变量
图3.3
存储在寄存器或者栈空间中
3. 立即数在程序中直接出现的整数,都是以立即数的形式$xxxx出现的,直接硬编码在汇编代码中
4. int argc:作为第一个参数传入。
b.字符串
1. Hello 1183300515 曹沛祯 !!\n”,第一个 printf 传入的输出格式化参数,在 hello.s 中声明 ,字符串被编码成 UTF-8 格式
2.Hello %s %s\n”,第二个 printf 传入的输出格式化参数,在 hello.s 中
c.组
程序中涉及数组的是:char *argv[]和 int argv。 前者是 main函数执行
时输入的命令行 ;后者作为存放char指针的数组同时是第二个参数传入。在寄存器 %rsi中,argv指针指向已经分配好的、一片存放着字符指针的连续空间,起始地址为argv
图3.4
3.3.2、赋值
程序中涉及的赋值操作有:
1. int sleepsecs=2.5 :sleepsecs是全局变量,所以直接在 .data节中将sleepsecs声明为值 2的 long类型数据。
2. i=0:整型数据的赋值使用 mov指令完成,根据数据的大小不同使用不同
图3.5
3.3.3、类型转换
将float类型的2.5赋值给int类型的sleepsecs时发生了强制类型转换。2.5被向下取整为2.
3.3.4、算术操作
汇编语言中算数和逻辑操作指令如下:
Hello.c中算数操作是 for循环里每次i++
图3.5
图3.6
3.3.5、关系操作
C语言中关系操作的种类有 关系操作: :== 、 != 、 > 、 < 、 >= 、 <=。
在hello.c中有两个关系操作,分别是 argc!=3和 i<10,截图如下:
图3.7
图3.8
3.3.6、数组/指针/结构操作
Hello程序中main函数的第二个参数 argv[],访问数组的地址,在这个地址基础上加上数据元素的大小,到下一位,就是argv[2]和 argv[1]。
图3.9
3.3.7控制转移
C语言中在跳转指令汇编语言中主要有 jmp命令来实现
图3.10
Hello.c里一共有两个控制转移 : if(argc!=3),编译器判断argc是否等于3;for循环中i<10,判断i是否小于10
图3.11
3.3.8函数操作
Hello.c中总共有五个函数: main(),printf(),exit(),sleep()和 getchar()。
1. main函数。
main函数 ,又称主函数 ,是程序执行的起点。有两个参数 argc和 argv[],由命令行输入,存储在 %rdi和 %rsi中。
图3.12
图3.13
2.printf函数
printf(“Usage: Hello 学号 姓名!\n”):
图3.14
printf(“Hello %s %s\n”,argv[1],argv[2]):
图3.15
3 .exit函数
exit()通常是用在 子程序 中用来终结程序用的,使用后程序自动结束,跳回操作系统。exit(0) 表示程序正常退出 ,exit⑴ /exit(-1)表示程序异常退出。
图3.16
4 .sleep函数
执行挂起一段时间的函数
图3.17
5. getchar函数
getchar函数没有任何参数,在执行完循环后直接用 call getchar指令调用函数。
图3.18
了编译器是如何处理C语言的各个数据类型以及各类操作以便计算机可以读懂并执行。
(第3章2分)
概念:
汇编大多是指汇编语言。把汇编语言翻译成机器语言的过程称为汇编 。
作用:
将.s汇编程序翻译成机器语言指令,同时把这些指令打包成可重定位目标程序的格式,并将结果保存在二进制文件 .o中。
(注意:这儿的汇编是指从 .s 到 .o 即编译后的文件到生成机器语言二进制程序的过程。)
命令 as hello.s -o hello.o
图4.1
readelf -a hello.o > hello.elf指令获得hello.o文件的ELF格式。
图4.2
1. ELF头 (ELF feader)以 一 个 16字节的序列开始,这个序列描述了生成该文件的系统的字的大小和字节顺序。 ELF头剩下 的部分包含帮助链接器语法分析和解释目标文件的信息。其中包括 ELF头的大小、目标文件的类型 (如可重定位、可执行或者共享的 )、机器类型、节头部表的文件偏移,以及节头部表中条目的大小和数量。不同节的位置和大小是由节头部表描述的,其中目标文件中每个节都有一个固定大小的条目。如图所示:
图4.3
2.节头部。节头部表描述了hello.o文件各个节的类型、位置和大小等信息
图4.4.
3.重定位节 .rela.text ,一个.text 节中位置的列表,包含 .text 节中需要进行重
计算机系统课程报告定位的信息,当链接器把这个目标文定位的信息,当链接器把这个目标文件和其他文件组合时,需要修改这些件和其他文件组合时,需要修改这些位置位置。
8条重定位信息分别是对条重定位信息分别是对.L0(第一个(第一个 printf 中的字符串)、中的字符串)、puts 函函数、数、exit 函数、函数、.L1(第二个(第二个 printf 中的字符串)、中的字符串)、printf 函数、函数、sleepsecs、、sleep 函数、函数、getchar 函数进行重定位声明
图4.5
4. 符号表 symtab:符 号表中包含用于重定位的信息,符号名称、符号是全
局还是局部,同时标识了符号的对应类型
图4.6
图4.7
对照截图如上:
a.分支转移:反汇编代码跳转指令的操作数使用的不是段名称如.L3,而是确定的地址。
b.函数调用:在.s文件中,函数调用之后直接跟着函数名称,反汇编代码中函数调用的目标地址是当前的下一条指令,然后在 .rela.text 节中为其添加重定位条目,等待静态链接 的进一步确定。
objdump -d -r hello.o 分析hello.o的反汇编,并请与第3章的 hello.s进行对照分析。说明机器语言的构成,与汇编语言的映射关系。特别是机器语言中的操作数与汇编语言不一致,特别是分支转移函数调用等。
本章介绍了汇编过程,由.s变到 .o文件。通过查看文件 ELF头,得到文件的基本信息。
(第4章1分)
概念:链接是将各种代码和数据片段收集并组合成为一个单一文件的过程。链接可以执行于编译时也就是在源代码被翻译成机器代码时 也可以执行于加载时,也就是在程序被加载器加载到内存并执行时 甚至执行于运行时 (也就是由应用程序来执行)
作用:链接在软件开发中扮演着一个关键的角色,它将一个大型的应用程序(巨大的源文件)分解为更小、更好管理的模块,也可以独立地修改和编译这些模块。实际应用中当我们需要改变部分模块时,只需简单地重新编译它,而不是所有的文件 。
注意:这儿的链接是指从 hello.o 到hello生成过程。
命令:
ld -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 /usr/lib/gcc/x86_64-linux-gnu/5/crtbegin.o hello.o -lc /usr/lib/gcc/x86_64-linux-gnu/5/crtend.o /usr/lib/x86_64-linux-gnu/crtn.o -z relro -o hello
图5.1
应截图,展示汇编过程! 注意不只连接hello.o文件
分析hello的ELF格式,用readelf等列出其各段的基本信息,包括各段的起始地址,大小等信息。
图5.2
ELF头中主要介绍了程序 节表大小、节表数量、数据存储方式(这 里是小端)、文件类型(可执行文件)、程序入口点( 0x400510)等等与文件整体框架相关的信息。节头表中列举了程序所有的节头,每一个节头都包含了它的节名称、节大小、节类型、节的开始地址、节的偏移量(向地址最高位对齐的相对偏移量)等等
使用edb加载hello,查看本进程的虚拟地址空间各段信息
5.5 链接的重定位过程分析
图5.3
图5.4
objdump -d -r hello 分析hello与hello.o的不同,说明链接的过程。
结合hello.o的重定位项目,分析hello中对其怎么重定位的。
(以下格式自行编排,编辑时删除)
使用edb执行hello,说明从加载hello到_start,到call main,以及程序终止的所有过程。请列出其调用与跳转的各个子程序名或程序地址。
(以下格式自行编排,编辑时删除)
分析hello程序的动态链接项目,通过edb调试,分析在dl_init前后,这些项目的内容变化。要截图标识说明。
介绍了链接的概念与作用、hello的 ELF格式,分析了 hello的虚拟地址空间、重定位过程、执行流程、动态链接过程。
(第5章1分)
对数据集合进行操作所运行的一次活动,是系统进行资源分配和调度的基本单位
1.删除已存在的用户区域。
2.映射私有区域。为新程序的代码、数据、bss和栈区域创建新的区域结构。所有这些新的区域都是私有的、写时复制的。
3.映射共享区域。如果hello程序与共享对象链接,那么这些对象都是动态链接到这个程序的,然后再映射到用户虚拟地址空间中的共享区域内。
4.设置程序计数器。下一次调度这个进程时,它将从这个入口点开始执行。
逻辑控制流:一系列程序计数器 PC 的值的序列叫做逻辑控制流,在同一个处理器核心中,每个进程执行它的流的一部分后被抢占(暂时挂起),然后轮到其他进程,进程轮流使用处理器,。
时间片:一个进程执行它的控制流的一部分的每一时间段叫做时间片。
用户模式和内核模式:处理器通常使用一个寄存器描述了进程当前享有的特权, 对两种模式区分。设置模式位时,进程处于内核模式,该进程可以访问系统中的任何内存位置,可以执行指令集中的任何命令;当没有设置模式位时,进程就处于 用户模式中,用户模式的进程不允许执行特权指令,也不允许直接引用地址空间中内核区内的代码和数据。
上下文信息:上下文就是内核重新启动一个被抢占的进程所需要的状态 。它由通用寄存器、浮点寄存器、程序计数器、用户栈、状态寄存器、内核栈和各种内核数据结构等对象的值构成。
调度:当进程执行的某些时刻内核可以决定抢占当前进程,并重新开始一个先前被抢占的进程,称为调度。
调度的过程:进程收到一个信号,进程A挂起,进入内核模式(发生了一次上下文切换)运行另外一个进程B,当运行过程中进程B收到一个信号,停止运行进程B,进入用户模式(又发生一次上下文切换)
图6.1
具体对于hello中sleep函数的进程调度,在运行到sleep之前,程序未收到信号保持执行的状态,运行到sleep函数之后,进程收到挂起信号,挂起当前进程切换进入其他进程。2s后sleep调用截止,当前运行的进程又收到一个信号,此时再次发生上下文切换,返回hello程序的运行。(返回这个进程时会恢复寄存器,堆栈的状态)具体流程图如图所示:
结合进程上下文信息、进程时间片,阐述进程调度的过程,用户态与核心态转换等等。
异常的类别:
图6.2
信号:
图6.3
hello执行过程中会出现哪几类异常,会产生哪些信号,又怎么处理的。
程序运行过程中可以按键盘,如不停乱按,包括回车,Ctrl-Z,Ctrl-C等,Ctrl-z后可以运行ps jobs pstree fg kill 等命令,请分别给出各命令及运行结截屏,说明异常与信号的处理。
介绍了进程的定义与作用,Shell的处理流程,fork调用创建进程, execve调用执行,hello hello的进程执行,以及进程异常与信号处理。
(第6章1分)
(1) 逻辑地址:程序代码经过编译后出现在汇编程序中地址。逻辑地址由选择符和偏移量组成。
(2) 线性地址:地址空间是一个非负整数地址的有序集合,而如果此时地址空间中的整数是连续的,则我们称这个地址空间为线性地址空间。
(3) 虚拟地址:由逻辑地址翻译得到的线性地址
(4) 物理地址: CPU 通过地址总线的寻址,找到真实的物理内存对应地址。
图7.1
结合hello说明逻辑地址、线性地址、虚拟地址、物理地址的概念。
1.基本原理:在段式存储管理中,将程序的地址空间划分为若干个段(segment),这样每个进程有一个二维的地址空间。在段式存储管理系统中,为每个段分配一个连续的分区,而进程中的各个段可以不连续地存放在内存的不同分区中。程序加载时,操作系统为所有段分配其所需内存,这些段不必连续,物理内存的管理采用动态分区的管理方法。在为某个段分配物理内存时,可以采用首先适配法、下次适配法、最佳适配法等方法在回收某个段所占用的空间时,要注意将收回的空间与其相邻的空间合并。段式存储管理也需要硬件支持,实现逻辑地址到物理地址的映射。程序通过分段划分为多个模块,如代码段、数据段、共享段。
2.管理:为了进行段式管理,除了系统需要为每道程序分别设置段映象表外,还得由操作系统为整个主存系统建立一个实主存管理表,它包括占用区域表和可用区域表两部分。占用区域表的每一项(行)用来指明主存中哪些区域已被占用,被哪道程序的哪个段占用以及该段在主存的起点和长度。此外,还可以设置诸如该段是否进入主存后被改写过的字段,以便该段由主存中释放时,决定是否还要将其写回到辅存中原先的位置来减少辅助操作。可用区域表的每一项(行)则指明每一个未被占用的基地址和区域大小。当一个段从辅存装入主存时,操作系统就在占用区域表中增加一项,并修改可用区域表。而当一个段从主存中退出时,就将其在占用区域表的项(行)移入可用区域表中,并进行有关它是否可与其它可用区归并的处理,修改可用区域表。当某道程序全部执行结束或者是被优先级更高的程序所取代时,也应将该道程序的全部段的项从占用区域表移入可用区域表并作相应的处理。
图7.2
图7.3
图7.5
图7.6
图7.7
当fork 函数被 shell 进程调用时,内核为新进程创建各种数据结构,并分配给它一个唯一的 PID,为了给这个新进程创建虚拟内存,它创建了当前进程的mm_struct、区域结构和页表的原样副本。它将这两个进程的每个页面都标记为只读,并将两个进程中的每个区域结构都标记为私有的写时复制。当fork在新进程中返回时,新进程现在的虚拟内存刚好和调用fork时存在的虚拟内存相同。当这两个进程中的任一个后来进行写操作时,写时复制机制就会创建新页面。
execve 函数调用加载器代码,在当前进程中加载并运行hello 需要以下几个步骤:
(1) 删除已存在的用户区域,删除当前进程虚拟地址的用户部分中的已存在的区域结构。
(2) 映射私有区域,为新程序的代码、数据、 bss和栈区域创建新的区域结构,所有这些新的区域都是私有的、写时复制的。
(3) 共享对象由动态链接映射到本进程共享区域
(4) 设置程序计数器使之指向代码区域的入口点。
缺页故障是一种常见的故障,当指令引用一个虚拟地址,在 MMU中查找页表时发现与该地址相对应的物理地址不在内存中,因此必须从磁盘中取出的时候就会发生故障。 即缓存不命中。
缺页中断处理:缺页处理程序是系统内核中的代码,选择一个牺牲页面,如果这个牺牲页面被修改过,那么就将它交换出去,换入新的页面并更新页表。当缺页处理程序返回时, CPU重新启动引起缺页的指令,这条指令再次发送 VA到 MMU这次 MMU就能 正常翻译 VA了。
程序运行时使用动态内存分配器(比如malloc)获得虚拟内存。动态内存分配器维护着一个进程的虚拟内存区域,称为堆。
对于每个进程,内核维护着一个变量 brk,它指向堆的顶部。分配器将堆视为一组不同大小的块的结合来维护。每个块就是一个连续的拟内存片,要么是已分配的,要么是空闲的。已分配的块显式地保留为供应用程序使用。空闲块可用来分配。一个已分配的块保持已分配状态,直到它被释放,这种释放要么是应用程序显式执行的,要么是内存分配器自身隐式执行的。
分配器有两种基本风格,两种风格都要求应用显式地分配块,不同在于由哪个实体来负责释放。
显式分配器:要求应用显式地释放任何已分配的块。隐式分配器:要求分配器检测一个已分配块何时不再使用,那么就释放这个块,自动释放未使用的已经分配的块的过程叫做垃圾收集。
隐式空闲链表:空闲块通过头部中的大小字段隐含地连接着。分配器可以通过遍历堆中所有的块,从而间接地遍历整个空闲块的集合。显式空闲链表:每个空闲块中,都包含一个前驱和后继指针。使用双向链表使首次适配的时间减少到空闲块数量的线性时间。
内存块合并方式:立即合并,在每次一个块被释放就合并所有的相邻块。对于某些情况会产生抖动,产生不必要的分割和合并。
Printf会调用malloc,请简述动态内存管理的基本方法与策略。
本章主要介绍了hello的存储器地址空间、 intel的段式管理、 hello 的页式管理, 以 intel Core7在指定环境下介绍了 VA 到 PA 的变换、物理内存访问,还介绍 hello进程 fork时的内存映射、 execve时的内存映射、缺页故障与缺页中断处理、动态存储分配管理。
(第7章 2分)
所有的I/O设备(例如网络、磁盘和终端)都被模型化为文件,而所有的输入和输出都被当做对相应文件的读和写来执行。这种将设备映射为文件的方式,允许linux内核引出一个简单、低级的应用接口,称为 Unix I/O,这使得所有的输入和输出都能以一种统一且一致的方式来执行。
设备的模型化:文件设备管理:unix io接口
写文件:ssize_t write(int fd, const void *buf, size_t n);
8.3 printf的实现分析
https://www.cnblogs.com/pianist/p/3315801.html
图8.1
看printf函数的函数体可知
printf函数的执行过程是:从vsprintf生成显示信息,到write系统函数
再看vsprintf函数的函数体
图8.2
vsprintf的作用是格式化。vsprintf 程序按照格式 fmt 结合参数 args 生成格式化之后的字符串,并返回字串的长度。
看write函数的函数体
图8.3
Write函数:写操作,把buf中的i个元素的值写到终端。
8.4 getchar的实现分析
getchar函数调用了系统函数read,读入BUFSIZE字节到buf,然后返回buf的首地址,注意到只有当n = 0时才会调用read函数,如果n = 0还会返回EOF文件终止符。异步异常-键盘中断的处理:键盘中断处理子程序。接受按键扫描码转成ascii码,保存到系统的键盘缓冲区。getchar等调用read系统函数,通过系统调用读取按键ascii码,直到接受到回车键才返回
异步异常-键盘中断的处理:键盘中断处理子程序。接受按键扫描码转成ascii码,保存到系统的键盘缓冲区。
getchar等调用read系统函数,通过系统调用读取按键ascii码,直到接受到回
车键才返回。
图8.4
Getchar函数函数体:
本章主要介绍了Linux 的IO 设备管理方法、Unix IO 接口及其函数,分析了printf函数和getchar 函数。
(第8章1分)
Hello.c程序全生命周期过程:
1.编辑器创建hello.c。
2.预处理器修改hello.c得到另一个C程序hello.i。
3.编译器将hello.i翻译成文本文件hello.s
4.汇编器将hello.s翻译成机器语言指令,将结果保存在hello.o中。
5.链接器对hello.o处理得到可执行目标文件hello。
6. shell会fork一个子进程;在这个子进程中调用execve函数加载hello。
7.然后程序会跳转到_start地址,最终调用hello的main函数。
8.hello通过调用sleep getchar exit等系统函数运行程序。
9.当hello收到异常信号时,它会自动挂起等待shell的下一步命令
10.进程结束后被shell回收。
复习了课程所学内容。通过这次实验我了解到任何一个程序的运行都要经过重重“关卡”,才能修成正果。繁如星海的程序软件背后是同样的运行逻辑,通过这个环环相扣的框架实现人机交互,简单但周密,稳定而强大。在学习中,也要善于抓住事物背后的内在逻辑,构建知识体系,不然一环丢失就要数倍努力弥补
用计算机系统的语言,逐条总结hello所经历的过程。你对计算机系统的设计与实现的深切感悟,你的创新理念,如新的设计与实现方法。
(结论0分,缺失 -1分,根据内容酌情加分)
列出所有的中间产物的文件名,并予以说明起作用。
hello.i 预处理之后的文本文件
hello.s 编译之后的汇编文件
hello.o 汇编之后可重定位目标执行文件
hello 链接之后的可执行目标文件
helloo.objdmp hello.o的反汇编文件
hello.elf hello的ELF格式
hello.objdmp hello的反汇编文件
(附件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.
[7] 百度百科相关词条
[8] Bryant,R.E 深入理解计算机系统 第三版
[9] CSDN相关博客
[10] 维基百科 virtua memory https://en.wikipedia.org/wiki/Virtual_memory
(参考文献0分,缺失 -1分)