【无标题】

计算机系统

大作业

题     目  程序人生-Hellos P2P  

专       业     计算机科学与技术     

学     号       2021111897         

班   级        21W0311          

学       生          王世泽        

指 导 教 师           史先俊         

计算机科学与技术学院

2022年5月

摘  要

Hello是每一位编程初学者的起点,它看似简单,但其背后是计算机无数严谨的工序。从Hello开始,我们正式向计算机世界say Hello。

本文将从hello.c开始,讲述计算机通过预处理、编译、汇编与链接得到可执行文件的流程,了解整个程序的运行过程,并讲述可执行文件执行过程中的进程管理、存储管理和I/O管理的原理。

关键词:预处理、编译、汇编、链接、进程管理、存储管理、IO管理。

目  录

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

Hello是每位编程者的起点。它的成功执行,看似简单,实则需要计算机进行多步严谨的工序。小小的Hello就是一个完整的P2P。

P2P:全称为From Program to Progress,从项程序到进程。这个过程需要经过预处理(cpp)、编译(ccl)、汇编(as)、链接(ld)等一系列操作后才可以生成一个可执行目标文件。

图1.1.1 hello.c的编译运行过程

020: shell运行hello程序,首先通过fork产生子进程,再通过execve等函数,进行进程的执行并进行进程回收。Hello进程创建之前后都不占用任何资源。创建Hello进程之时是CPU为其分配内存、时间片,而Hello结束之后,其内部的数据被删除。这就是所谓的“从0到0”。

1.2 环境与工具

硬件环境:Intel CORE i7 10th GEN.

软件环境:Windows10 ;VMware Workstation pro2022;Ubuntu20.04.

开发与调试工具:gcc; vim; edb.

1.3 中间结果

hello.c:存储源代码。

hello.i:源代码hello.c经过预处理产生的文件。

hello.s:hello.i经过编译产生的文件。

hello.o:hello.s可重定位目标文件。

hello:链接后形成的可执行目标文件。

1.4 本章小结

本章对简单介绍了hello,介绍了P2P和020的含义,概述了Hello的生成需要的运行环境,列出了任务过程中出现的中间文件及其作用,后面的章节会进一步展开。


第2章 预处理

2.1 预处理的概念与作用

预处理简而言之就是对程序源代码文本中的预处理命令(#开头)进行处理。

在程序代码被翻译为目标代码的过程中,预处理器根据以#开头的命令对直观的C程序进行修改,并将其所引用的库进行合并,比如包含头文件、宏定义等。

2.2在Ubuntu下预处理的命令

使用如下命令:gcc hello.c -E -o hello.i

图2.2.1 预处理指令

2.3 Hello的预处理结果解析

打开后发现文本大量增加,变为3060行。大多语句是对宏进行展开,并引入头文件(stdio.h、unistd.h和stdlib.h)内容,其中包含一些对类型和函数的声明。main函数的长度差别不太大。

图2.3.1 hello.i

2.4 本章小结

本章探索了预处理的操作和命令语句,并对生成的hello.i进行了分析,对预处理有了更深的认识。


第3章 编译

3.1 编译的概念与作用

概念:将程序由C语言(hello.i)转为汇编语言(hello.s)的过程。

作用:帮助计算机识别原本不能识别的高级程序语言,即先将C语言转换为汇编语言。将程序改为汇编语言还有助于通过词法分析和句法分析查找程序可能的错误。

3.2 在Ubuntu下编译的命令

使用如下命令:gcc hello.i -S -o hello.s

图3.2.1 编译指令

3.3 Hello的编译结果解析

首先看以下hello.i文件:

图3.3.1 hello.i

3.3.1 常量分析

1.整数常量:通常用于比较和一些简单运算,从而我们找到下图的整数常量。

图3.3.2 整数常量

2.字符串常量:找到源代码中的“hello”,而中文则被换成了其它表示形式。

图3.3.3 字符串常量

3.3.2 变量分析

整数变量:代码中只有argc是整形变量,它在一开始就被赋到-20(%rbp)上。

图3.3.4 整数变量

3.3.3 数组分析

该代码仅涉及argv[],它的位置如下

图3.3.5 数组

3.3.4 算术操作分析

该代码涉及++操作,如图:

图3.3.6 算数操作

3.3.5关系操作分析

该代码涉及<和!=,分别如图:

图3.3.7 关系操作

3.3.6函数操作分析

该代码涉及函数返回值,如图:

图3.3.8 函数操作操作

3.3.7 控制转移分析

跳转指令会根据条件码当前的值来进行相应的跳转,可用于改变一组机器代码指令的执行顺序。

该代码涉及if和for。汇编语言中,一些指令会改变条件码,如cmpl和setl指令,如图:

图3.3.9 控制转移

3.4 本章小结

本章较为细致地分析了编译的结果,对汇编指令进行了简单的介绍,,发现汇编代码与C语言代码的关联,理解语句背后的逻辑。

对汇编程序的具体执行过程做的深入的分析,包括常量、变量、数组、算术操作、关系操作、函数操作、控制转移的汇编代码和C语言中的语句做了详细对比,


第4章 汇编

4.1 汇编的概念与作用

概念:把汇编语言书写的程序翻译成与之等价的机器语言程序的翻译程序,并且形成.o文件,它叫做可重定位目标程序文件。

作用:生成计算机可以理解的语言,即实现了文本文件到二进制文件的转化,为之后的链接操作做了准备工作。

4.2 在Ubuntu下汇编的命令

使用如下命令:gcc hello.s -c -o hello.o

图4.2.1 汇编

4.3 可重定位目标elf格式

使用如下命令:readelf -a hello.o,查看hello.o文件的ELF头信息,可见,信息大概分为4部分。

1.ELF头以一个16字节的序列(Magic)开始,这个序列描述了生成文件的系统的字的大小和字节顺序。ELF头剩下部分的信息包含帮助连接器语法分析和解释目标文件的信息。其中包括ELF头的大小、目标文件的类型和机器类型等。

图4.3.1 ELF头信息

2.节头:程序中所有节的信息,包括每个节的名称、大小等。

图4.3.2 节头信息

3.重定位部分:重定位部分的相关信息,如偏移量、类型、系统名称等等。

图4.3.3 重定位信息

4.符号表:展示程序中可能会使用的符号,如函数名称。

图4.3.4 符号表信息

4.4 Hello.o的结果解析

输入objdump -d -r hello.o,得到hello.o的反汇编如图:

图4.4.1反汇编结果

反汇编文件的字里行间中,也混杂着一些机器代码,每一条机器代码都对应一条机器指令,是机器能识别的语言。

机器代码与汇编代码不同的地方有两点:

1.分支跳转:汇编语言中分支跳转语句使用的标识符来跳转,机器语言直接使用对应的地址跳转。

2.函数调用:在原.s文件中,函数调用直接写上函数名。而在.o反汇编文件中,函数调用是直接指向下一条指令地址。

4.5 本章小结

本章概述了汇编的概念与作用,生成了可重定位目标文件。对elf文件进行了分析,比较了反汇编代码和汇编代码的关系。对汇编过程三者关系内容有了一定了解。
第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

图5.2.1 链接命令

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

分析hello的ELF格式,用readelf等列出其各段的基本信息,包括各段的起始地址,大小等信息。

输入命令:readelf -a hello.

5.3.1ELF头信息

图5.3.1 ELF头信息

与之前对比,文件类型改变了,从REL变成了EXEC,hello的ELF格式还添加了程序头的分段,节头部数量变为了27个。

5.3.2 Section头信息

图5.3.2  Section头信息

节头部表对hello中信息进行声明。根据始地址和大小,我们就可以得到每个节的区域。与hello.oELF程序相比,helloELF程序有所不同,比如节的个数、大小和地址的偏移。

5.3.3符号表

图5.3.3 符号表

可以发现该表中符号数有了显著的增长。

5.3.4重定位信息表

图5.3.4重定位信息表

偏移量是被修改引用的节偏移,加数是一个有符号常数,一些重定位要使用它对引用的值做调整。

5.4 hello的虚拟地址空间

使用edb加载hello,查看本进程的虚拟地址空间各段信息,如下(部分):

图5.4.1 hello的虚拟地址空间

虚拟地址空间,其起始地址为00401000,结束地址为00401ff0.各节头中节的位置与5.3中的相同。

5.5 链接的重定位过程分析

输入指令:objdump -d -r hello,反汇编结果如下:

图5.5.1 hello文件反汇编结果

hello与hello.o的不同:hello反汇编代码中新增了很多节;函数调用时已经完成了重定位,函数有明确的地址;添加了许多系统与操作函数。

重定位分为:

1.重定位节和符号定义:连接器将所有相同类型的节合并成为同一类型的新节。例如,所有.data节被合并成一个输出的可执行目标文件的.data节。

2.重定位节中的符号引用:依赖于可重定位条目,连接器修改代码节和符号引用,及5.3节中的数据。

5.6 hello的执行流程

程序调用流程地址:

_init:0x401000

__GI___cxa_atexit:0x7ffff7e05de0

_start:0x4010f0

libc_start_main:0x7ffff7de2f90

libc_csu_init:0x4011c0

main:0x401125

_sigsetjump:0x7ffff7e01bb0

__new_exitfn:0x7ffff7e05b80

strcmp:0x7ffff7fee600

do_lookup_x:0x7ffff7fda4c9

dl_runtime_resolve_xsavec:0x7ffff7fe7bc0

_dl_fixup:0x7ffff7fe00c0

_dl_lookup_symbol_x:0x7ffff7fdb0d0

check_match:0x7ffff7fda318

5.7 Hello的动态链接分析

共享库函数的共享模块在运行时可以加载到任意位置,编译器不能预测,应该生成重定位记录,在程序加载的时候解析它。

动态链接器使用过程链接表PLT+GOT实现函数的动态链接,GOT中存放函数目标地址,PLT使用GOT中地址跳转到目标函数。

5.8 本章小结

本章主要了解链接过程中,可重定位文件如何转变为可运行文件,还运用了edb来查看hello的虚拟地址空间,还分析了反汇编指令和hello.o的不同,最后,对hello的动态链接进行了分析。链接是生成可执行文件的最后一步,是对各个库进行链接的环节。


6hello进程管理

6.1 进程的概念与作用

概念:进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。

作用:使得我们的程序独占系统资源。

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

Shell是一个应用程序,它链接了用户和Linux内核,作为操作系统和用户交互的一个接口,可以代替用户执行各种命令以及执行它内置的命令。

Shell执行一系列的读/求值步骤,然后终止。读步骤读取来自用户的一个命令行。求值步骤解析命令行,并代表用户运行程序。

Shell处理流程:

1.打印提示信息

2.等待用户输入

3.接受命令

4.解释命令

5.执行命令

6.执行完成,返回第一步

6.3 Hello的fork进程创建过程

用户在shell输入指令./hello,shell读取后,发现hello不是内置的shell指令,随后调用相应程序,找到hello。父进程通过调用fork函数创建一个新的运行的子进程,子进程得到与父进程虚拟地址空间相同的副本,但子进程与父进程的PID不同。

6.4 Hello的execve过程

在子进程中,执行shell执行execve系统调用,将hello.out装载入内存,覆盖了原先的内存信息,此时,hello正式成为进程,下一步开始执行。

在输入命令的时候,将文件名放入argv[0],相关的环境变量装载在envp中。调用这个时,会保持相同PID不变,但是通过上文中存数各个变量的地方读取相关的值,覆盖原来的进程中值。

6.5 Hello的进程执行

Shell接收到可执行文件,利用fork创建一个子进程,该子进程调用execve函数运行此可执行文件。加载器删除子进程现有的虚拟内存,创建空间并初始化为0。然后将虚拟地址空间中的页映射到可执行文件的页,代码段和数据段被设置为可执行文件的内容。

6.6 hello的异常与信号处理

异常:中断、陷阱、故障和终止。Hello中常见的异常是缺页故障。

信号:SIGINT、SIGSEGV、SIGKILL、SIALARM、SIGCHLD。

1.按下Ctrl+C: 内核发送一个SIGINT信号到前台进程组的每个进程,终止前台作业。

图6.6.1 按下Ctrl+C

  1. 按下Ctrl+Z:内核会发送SIGSTP信号,SIGSTP默认挂起前台hello作业,但 hello进程并没有回收,而是运行在后台下。输入ps后可以进行查看。

    

图6.6.2 键入ps

3.键入jobs查看进程仍在后台。

         

图6.6.3 键入jobs

4.键入pstree后

图6.6.4 键入pstree(部分)

  1. 键入fg程序继续进行

           

图6.6.5 键入fg

  1. 键入kill,发送SIGKILL,杀死程序

         

图6.6.6 键入kill

  1. 经验证,乱按没效果。

6.7本章小结

    本章介绍了进程的概念与作用、shell的作用与处理流程;以hello进程为例,论述了fork进程创建过程、execve过程、进程执行、异常与信号处理等内容。


7hello的存储管理

7.1 hello的存储器地址空间

逻辑地址:程序角度的内存单元、存储单元、网络主机的地址。即hello.o里面的相对偏移地址。

线性地址:逻辑地址转化为线性地址,地址空间是一个非负整数集合。即hello里面的虚拟内存地址。

虚拟地址:与线性地址等价。

物理地址:在地址总线上,以电子形式存在,找到真实的物理内存对应地址就可以访问某个特定存储单元。

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

逻辑地址由段标识符和段内偏移量组成。段内偏移量共16位长,前13位是序列号,后面3位包含一些硬件细节。根据一个段描述符可以找到一个段的首地址,而需要的时候根据这个索引值取内存中找,找到后,基地址+偏移量便得到了线性地址。

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

程序在加载时在磁盘上建立虚拟内存,按照页交换的方式加载进入内存中。

虚拟内存被组织为一个由存放在磁盘上的N个连续字节大小的单元组成的数组。每字节都有唯一的虚拟地址,作为到数组的索引。这些页块被划分为三种状态:未分配、为缓存、已缓存。

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

页表将虚拟页映射到物理页,MMU利用页表来实现这种映射。每个 PTE 都有一个有效位和一个 n 位地址字段,有效位表明该虚拟页是否被缓存在 DRAM 中。虚拟地址又包含两个部分,(n-p)位虚拟页号,p位的虚拟页面偏移量。VPN需要在PTE中查询对应,VPO对应物理地址偏移。

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

CPU访问内存先去CacheL1中找内存是否已被缓存如果命中,直接就对其进行读写,如果Cache L1未命中,就去L2中寻找,如果还是未命中就去L3中寻找。如果还未命中,就会访问内存,并把需要访问的内存存进Cache L1,L2,L3中,进行下一步操作。

7.6 hello进程fork时的内存映射

调用fork被shell调用时,系统为该hello进程创建了各种数据结构,将其分配给它PID。Fork创立进程的mm_struct、所有区域结构和页表的原样拷贝。这两个标识符的存在保证了父进程和子进程共用相同的地址空间和存储结构。当fork返回,新进程与调用fork的进程中的任一项完成写操作时,也会生成新的页面,给各个进程都保留了私有地址空间。

7.7 hello进程execve时的内存映射

execve函数在当前进程中运行新程序,在本程序表现为:

1.删除已存在的地址的程序然后运行hello
2.先后映射到私有或共享区域

3.最后要利用程序计数器,调整进程下一步的入口点,从hello程序开始的位置执行程序。

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

缺页故障:虚拟内存中的字不在物理内存中

缺页中断处理:缺页故障程序选择牺牲一个内存页,然后把物理页复制到内存中。处理结束后跳转到引发缺页故障的那条指令重新执行。

7.9动态存储分配管理

调用malloc申请内存,被分配的内存会用另一块空间用来记录该内存的大小,根据大小表示申请空闲空间。调用free后根据记录的大小删除原来的空间。

printf从前往后扫描字符,扫描时会查看输出的多少,若太多则会用malloc申请内存。

7.10本章小结

本章简述了逻辑地址、虚拟地址、线性地址、物理地址的相关概念;分析了Hello的线性地址到物理地址的变换-页式管理、TLB与页表支持下的地址变换、三级cache支持下的物理内存访问;对fork与execve时的内存映射和缺页故障及其缺页中断处理进行了分析,讨论了动态存储分配管理的原理。

结论

1.Hello开始于程序员对源程序hello.c的编写。

2.键入gcc hello.c -E -o hello.i后,对hello.c进行预处理,可以得到hello.i。

3.键入gcc hello.i -S -o hello.s后,对hello.i进行编译,可以得到hello.s。

4.键入gcc hello.i -c -o hello.s后,对hello.s进行汇编,可以得到hello.o。

5.与动态库进行链接,得到可执行目标文件hello。

6.运行hello遇到异常信号,shell调用fork创建一个进程。shell调用exerve函数会把新创建的子进程的原数据删除,并把子进程映射到虚拟内存,设置程序计数器,使其指向hello。

7.hello运行于上下文中,在计算机存储器硬件的支持下进行运作。

8.最后,执行结束,Hello被回收,程序的人生告一段落。


附件

hello.c:存储源代码。

hello.i:源代码hello.c经过预处理产生的文件。

hello.s:hello.i经过编译产生的文件。

hello.o:hello.s可重定位目标文件。

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.

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值