计统大作业

正在上传…重新上传取消

计算机系统

大作业

题     目  程序人生-Hello’s P2P   

专       业             信息安全          

学     号             2021110809   

班     级         2103201              

学       生          周钊宇           

指 导 教 师              刘宏伟         

计算机科学与技术学院

2022年5月

摘  要

本文讲述了hello.c从程序的编写到预处理,到编译,汇编等过程介绍了程序的出生到死亡的过程。

关键词:hello.c;P2P;O20;                           

目  录

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

P2P(From Program to Process)过程:

首先经过预处理器cpp进行预处理,生成文本文件hello.i,然后经过编译器ccl生成hello.s汇编程序,接着经过汇编器as生成hello.o文件,最后经过链接器ld将其与引用到的库函数链接,生成可执行文件hello。再通过系统创建一个新进程并且把程序内容加载,实现有程序到进程的转化。

O2O(From Zero-0 to Zero-0)过程:

shell调用execve函数将hello程序加载到相应的上下文中,将程序内容载入物理内存。然后调用main函数。程序运行结束后,父进程回收进程,释放虚拟内存空间,删除相关内容。

1.2 环境与工具

软件环境:Windows7 64位以上;VirtualBox/Vmware 11以上;Ubuntu 16.04 LTS 64位/优麒麟 64位

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

开发/调试工具:Visual Studio 2010 64位以上;CodeBlocks 64位;vi/vim/gedit+gcc

1.3 中间结果

hello.c:源代码文件

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

hello.s:编译后的汇编文件

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

elf.txt:hello.o的ELF格式文件

hello 链接产生的可执行目标文件

elf2.txt:hello的ELF格式文件

asm.txt:hello反汇编的代码文件

1.4 本章小结

   本章根据hello的自白,概括介绍了P2P020。此外,还介绍了本实验用到的硬软件环境和开发调试工具。

第2章 预处理

2.1 预处理的概念与作用

当对一个源文件进行编译时,系统将自动引用预处理程序对源程序中的预处理部分作处理,处理完毕自动进入对源程序的编译。

预处理的主要作用包括:

宏定义:预处理器可以使用#define指令定义宏,宏可以代表一段代码或常量,在编译过程中会被相应地替换。

文件包含:使用#include指令,预处理器可以将其他源代码文件包含到当前文件中,使得在编译时可以一起处理这些文件的内容。

条件编译:通过使用条件编译指令,如#ifdef、#ifndef、#ifdef等,预处理器可以根据条件来选择性地编译或排除某些代码块,以实现在不同情况下的代码分支。

2.2在Ubuntu下预处理的命令

gcc –E hello.c –o hello.i cpp hello.c > hello.i

2.3 Hello的预处理结果解析

正在上传…重新上传取消

打开hello.i我们可以发现文件被拓展到3091行这是因为预处理器会根据默认的环境变量依次搜索我们指定的文件,并将其内容替换到相应的位置。此外,预处理器还会根据我们使用#define指令定义的宏,将宏的实际值替换到代码中。从图中我们也可以看到最后会出现main函数及其所含代码。

2.4 本章小结

本章主要介绍了预处理的概念与作用,并对hello.c预处理后的结果进行分析,通过与源程序的文本对比,解释预处理的相关细节。

第3章 编译

3.1 编译的概念与作用

3.1.1 编译的概念

编译就是把高级语言变成计算机可以识别的2进制语言,计算机只认识1和0,编译程序把人们熟悉的语言换成2进制的。

3.1.2 编译的作用

代码正确性检测:在编译过程中,包括词法分析、语法分析和语义分析等步骤,会对源代码进行严格的检查和验证,确保代码符合语言规范和语义逻辑,避免出现常见的编程错误。

语言转换:编译器将高级语言(如C、C++等)的源代码转化为等效的汇编语言表示。汇编语言是一种较低级别的表示方式,更接近底层的机器指令,可以更直接地操作计算机硬件。

优化:在编译过程中,编译器会对生成的中间代码进行各种优化,以提高程序的执行效率和资源利用率。这些优化包括消除冗余代码、提取循环、内联函数等技术,使得生成的汇编代码更加高效。

3.2 在Ubuntu下编译的命令

cc1 hello.i -o hello.s 或 gcc -S hello.c -o hello.s

正在上传…重新上传取消

3.3 Hello的编译结果解析

.s文件内容:
正在上传…重新上传取消3.3.1 文件说明:

正在上传…重新上传取消

.file 指明源文件名

.text 代码段:用来存放程序代码的区域

.section 指示将代码分成若干个段

.rodata 用于维护只读数据

.align 8 地址对齐伪指令,用来指定符号的对齐方式

.string 字符串的存储位置

.global 用来让一个符号对链接器可见,可以供其他链接对象模块使用,告诉编译器后续跟的是一个全局可见的名字

.type 指定是对象类型或者函数类型

3.3.2   数据:

一.整型:

(1):main的参数argc:

正在上传…重新上传取消

一个参数argc被存储在寄存器%edi中,并且随后被转移到栈中。当需要使用这个参数时,它将从栈中取值。

(2):函数内部的局部变量int i

正在上传…重新上传取消

局部变量存储在栈中,当进入函数main的时候,会根据局部变量的需求,在栈上申请一段空间供局部变量使用。当局部变量的生命周期结束后,会在栈上释放。

在hello.c中i是局部变量,在hello.s中可以看到,首先跳转到了.L3的位置,然后将栈指针减少4,即存储局部变量i,然后跳转到.L4进行接下来的操作。

  • 字符串:

正在上传…重新上传取消

从图中我们可以看到字符串存储在.LC0和.LC1的段中。

  • 指针数组:

在命令行中输入的字符串被存储在argv[]数组中。在hello.s文件中,argv数组的首地址被保存在%rsi寄存器中,这是参数传递顺序中的第二个寄存器。接下来,为了方便调用其他函数,将argv的地址从%rsi寄存器中移动到堆栈中,并清空该寄存器以便其他用途。

3.3.3.运算与操作:

(1):赋值

通过mov语句通和lea语句实现

(2):for循环

        正在上传…重新上传取消

i存储在-4(%rbp)中,先赋予0,进入.L4(for循环)循环代码结束后,-4(%rbp)加1,之后进入.L4进行i的判断,若i小于8则进入.L4,否则结束循环。

  

3.3.4函数操作

     函数的功能实现通常涉及到跳转到特定的代码段执行,并在执行完后返回。函数一般在栈中进行操作。函数调用的过程可以分为以下几个步骤:

  1. 传递参数给被调用者: 在64位系统中,参数传递通过寄存器和内存的组合方式进行。按照"%rdi,%rsi,%rdx,%rcx,%r8,%r9"的顺序传递参数,从第七个参数开始则放在调用者的栈结构中。
  2. 使用call调用函数: call指令将返回地址压入栈中,并将rip寄存器的值指向所调用函数的地址。在函数执行完毕后,使用ret指令弹出原始的rip值,并恢复栈帧结构。
  3. 函数内部进行操作: 函数在自己的栈帧内执行操作。返回值通常存储在RAX寄存器中。

4,函数返回

在函数返回时,如果有返回值,通常会将返回值存储在%rax寄存器中,然后使用leave指令和ret指令来返回控制权给调用函数。

在hello.c文件中调用的函数包括:

  1. main()函数:这是程序的入口函数,在程序开始执行时被调用。
  2. printf()函数:用于格式化输出信息到标准输出。
  3. exit()函数:用于正常终止程序的执行,并返回一个指定的退出状态码。
  4. sleep()函数:使程序暂停执行指定的时间。
  5. atoi()函数:将字符串转换为相应的整数。
  6. getchar()函数:从标准输入获取一个字符。

函数:

puts:将传入的参数输出在屏幕上。

正在上传…重新上传取消

exit:从函数中退出。

正在上传…重新上传取消

sleep:实现程序的休眠。

正在上传…重新上传取消

getchar:从缓冲区中读取字符。

正在上传…重新上传取消

3.4 本章小结

编译器在Ubuntu环境下的示例中使用了名为hello.s的汇编语言文件。通过分析该文件,可以深入理解编译器在处理各种数据类型和操作时的工作过程。编译是将高级语言程序转化为可执行文件的关键步骤,而编译器则负责执行这一过程,包括词法分析、语法分析、语义分析、优化和代码生成等环节,以确保生成的汇编代码或机器代码能够正确且高效地执行。

第4章 汇编

4.1 汇编的概念与作用

作用:汇编语言的主要作用是允许程序员直接控制和操作计算机硬件。通过使用汇编语言,程序员可以编写更加高效和底层的代码,对硬件资源进行更精确的控制,以及针对特定的计算机架构进行优化。

概念:汇编语言使用助记符(Mnemonics)代表特定的机器指令。这些助记符比机器语言更易于阅读和理解,但仍然与底层机器指令一一对应。

汇编语言提供了对寄存器、内存、指令和数据等底层概念的直接访问和操作。程序员可以通过汇编语言指令直接读取和写入寄存器值、操作内存、执行算术和逻辑运算,以及控制程序流程。

4.2 在Ubuntu下汇编的命令

命令:gcc -c hello.s -o hello.o

正在上传…重新上传取消

4.3 可重定位目标elf格式

4.3.1  ELF头:

ELF头部是一个16字节的序列,用于描述生成目标文件的系统的字大小和字节顺序。它包含了帮助链接器进行语法分析和解释目标文件的信息。下面是ELF头部中包含的关键信息:ELF头大小(e_ident[EI_CLASS]):指定ELF头部本身的大小,以字节为单位;目标文件类型(e_type):表示目标文件的类型,可以是可执行文件(ET_EXEC)、共享库(ET_DYN)或目标文件(ET_REL)等;目标系统的字节顺序(e_ident[EI_DATA]):描述生成该文件的系统所使用的字节顺序,可以是小端字节序(ELFDATA2LSB)或大端字节序(ELFDATA2MSB);节头部表的文件偏移(e_shoff):指定节头部表在文件中的偏移量,节头部表包含了对目标文件中各个节的描述信息;节头部表中条目的大小(e_shentsize)和数量(e_shnum):描述节头部表中每个条目的大小和总共的条目数量;ELF头部是目标文件中的一个重要部分,它提供了关于目标文件本身的基本信息,如大小、类型、字节顺序和节头部表的位置等。这些信息帮助链接器进行目标文件的解析和处理,以正确地加载和链接目标文件。

正在上传…重新上传取消 

4.3.2 节头表:节头部表的条目提供了关于每个节的详细信息,包括名称、类型、地址、偏移量和大小等。链接器和加载器可以根据这些信息正确地定位和处理目标文件中的各个节,以便执行程序时能够正确地加载和访问节的内容。

正在上传…重新上传取消

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

正在上传…重新上传取消

4.3.4 重定位条目:重定位是指将符号的定义与对该符号的引用进行匹配的过程。在可重定位文件中,必须包含描述如何修改各个节(section)内容的信息,以便可执行文件或共享目标文件能够正确地保存程序的映像。可重定位条目(relocation entries)记录了需要进行重定位的节和相应的符号引用信息。这些条目指导链接器在连接或加载过程中对目标文件进行修改,以便正确解析和定位符号引用。

正在上传…重新上传取消

4.4 Hello.o的结果解析

objdump -d -r hello.o 

正在上传…重新上传取消

通过对比反汇编代码和 hello.s 文件,可以观察到它们的相似性和差异性。汇编指令代码几乎相同,但反汇编代码除了显示汇编指令外,还以16进制表示的机器代码。最左侧列出了相对地址。

在反汇编代码中,跳转指令和函数调用等操作在目标地址上显示为偏移量的形式,而在 hello.s 文件中直接使用函数名或定义的符号来表示。此外,在反汇编代码中,立即数以16进制显示,而在 hello.s 文件中以十进制显示。

总的来说,反汇编代码提供了更底层的视角,显示了汇编指令对应的机器指令,以及使用相对偏移量的跳转指令和函数调用。而 hello.s 文件更接近高级语言的视角,使用符号和直观的立即数表示。

这些差异是由于反汇编器和汇编器的不同行为造成的。反汇编器将机器代码还原为汇编指令,显示了更底层的细节。而汇编器则将汇编代码转换为机器指令,使用符号和直观的表示来提高可读性。

4.5 本章小结

本章首先介绍了汇编语言的概念和作用,然后通过实际操作演示了如何将 hello.s 文件进行汇编,生成可重定位目标文件 hello.o。接下来使用 readelf 工具,并通过设置不同的参数,查看了 hello.o 文件的 ELF 头部、节头表、可重定位信  息和符号表等内容。通过分析和理解这些信息,对可重定位目标文件的内容有了更深入的认识。

最后,对比了 hello.o 文件和 hello.s 文件,分析了它们之间的差异。同时强调了机器语言与汇编语言的一一对应关系,即机器指令和汇编指令是相互对应的,汇编语言是一种将高级语言转换为机器语言的中间层,便于程序员理解和编写底层代码。

5章 链接

5.1 链接的概念与作用

概念:链接是将多个目标文件或库文件合并成一个可执行文件或共享库的过程。它是编译过程中的最后一步,旨在解决符号引用、地址重定位和代码共享等问题。

  1. 作用:符号解析和引用:在编译过程中,每个源文件中的符号引用可能来自其他源文件或库文件中的定义。链接器通过符号解析的过程,将这些引用与正确的定义进行匹配,确保所有的符号都能被正确解析。
  2. 地址重定位:当目标文件或库文件被合并时,它们的代码和数据可能在内存中的不同位置。链接器负责修改目标文件中的地址引用,以使其能够正确地映射到最终加载位置。
  3. 符号重复消除:当多个目标文件或库文件中存在相同的符号定义时,链接器负责消除重复的定义,以避免重复定义的冲突和错误。
  4. 代码共享:链接器可以将多个目标文件中的相同代码合并成一个共享代码段,以减少最终可执行文件的大小。这种代码共享能够提高程序的内存利用率和运行效率。
  5. 导入和导出符号:链接器提供了符号的导入和导出机制,允许目标文件或库文件中的符号在链接过程中被引用或被其他模块引用。

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.3 可执行目标文件hello的格式

5.3.1  elf头:

正在上传…重新上传取消

5.3.2 节头表:

正在上传…重新上传取消

5.3.3 程序头

正在上传…重新上传取消

5.3.4 重定位节

正在上传…重新上传取消

5.3.5. 符号表:

正在上传…重新上传取消

5.4 hello的虚拟地址空间

正在上传…重新上传取消

 .init:size:0x1b,address:0x00401000

正在上传…重新上传取消

.text:size:0x145,address:0x004010f0。

正在上传…重新上传取消

5.5 链接的重定位过程分析

正在上传…重新上传取消

正在上传…重新上传取消

hello是经过链接和重定位之后的最终可执行文件,其中包含了更完整的功能和能够正确执行的能力。在链接过程中,hello与其他的目标文件进行了合并,解析了符号引用,并进行了地址分配和重定位操作,最终生成了一个具有固定地址的可执行文件。

相比之下,hello.o是一个可重定位目标文件,它只包含了编译和汇编阶段生成的机器代码,没有经过链接和重定位。在hello.o中,地址是相对于该目标文件自身的相对地址,跳转和调用指令使用的是相对于函数或地址的偏移量来确定目标地址。

通过链接和重定位的过程,hello.o中的相对地址被转换为具有固定绝对地址的hello可执行文件,这使得hello能够直接指定目标函数和地址的具体绝对位置,从而正确访问和调用各个函数。

因此,hello和hello.o之间的主要差异在于功能的完整性、地址的表示方式和能够访问和调用其他函数的能力。

5.6 hello的执行流程

0000000000401000 <_init>:

0000000000401020 <.plt>:

0000000000401090 <puts@plt>:

00000000004010a0 <printf@plt>:

00000000004010b0 <getchar@plt>:

00000000004010c0 <atoi@plt>:

00000000004010d0 <exit@plt>:

00000000004010e0 <sleep@plt>:

00000000004010f0 <_start>:

0000000000401120 <_dl_relocate_static_pie>:

0000000000401125 <main>:

00000000004011c0 <__libc_csu_init>:

0000000000401230 <__libc_csu_fini>:

0000000000401238 <_fini>:

正在上传…重新上传取消

5.7 Hello的动态链接分析

   首先在elf文件中找到.got的地址,0x403ff0

正在上传…重新上传取消

在edb找到相应地址处,分析在dl_init前后该地址附近变化:由此可以发现,动态链接库的地址为:0x7fca43070fc0。

正在上传…重新上传取消

5.8 本章小结

  本章介绍了链接的概念和作用,比对了hello和hello.o在地址空间的分布不同。

6章 hello进程管理

6.1 进程的概念与作用

概念:进程是操作系统中的一个基本概念,它代表了正在执行的一个程序实例。每个进程都是一个独立的执行单元,具有自己的内存空间、程序计数器、寄存器集合和其他执行状态。

  1. 作用:执行程序:进程是程序在操作系统中的实体,它负责执行程序的指令和处理数据。通过进程,操作系统能够管理和调度程序的执行,以提供计算和服务。
  2. 资源分配和管理:每个进程拥有自己的内存空间和其他资源,如文件、网络连接和设备。操作系统通过进程管理,为每个进程分配和管理资源,确保它们能够正常运行并相互隔离。
  3. 并发执行:多个进程可以同时在操作系统中执行,实现并发执行的能力。操作系统通过进程调度算法决定哪些进程应该执行,并按照一定的时间片或优先级进行切换,从而实现多任务和并发处理。
  4. 进程间通信:不同进程之间可能需要进行通信和数据交换。操作系统提供了进程间通信的机制,如管道、共享内存、消息队列和套接字等,使进程能够相互协作和共享信息。
  5. 安全和隔离:每个进程都运行在独立的地址空间中,相互之间不会直接访问彼此的内存。这提供了安全和隔离的环境,防止进程之间的干扰和恶意访问。

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

Shell(壳)是一种命令行解释器,它作为用户与操作系统内核之间的接口,提供了交互式的命令行环境。Bash(Bourne Again SHell)是其中最常用和广泛支持的一种Shell。

Bash的主要作用包括:

  1. 命令解释与执行:Bash接收用户输入的命令,并解释执行这些命令。它可以调用系统内置的命令、外部的可执行程序,还支持用户自定义的脚本。Bash可以执行各种操作,如文件操作、进程管理、网络通信等。
  2. 环境变量和参数处理:Bash维护着一组环境变量,用于保存系统和用户的配置信息。它还可以处理命令行参数,使得命令可以接受不同的选项和参数。
  3. 脚本编写和执行:Bash支持脚本编写,用户可以使用Bash脚本编写一系列命令和控制结构,实现复杂的操作逻辑和自动化任务。Bash可以解释执行这些脚本,并提供脚本调试和错误处理的功能。
  4. 输入输出重定向和管道:Bash支持输入输出重定向,可以将命令的输入和输出重定向到文件或设备中。它还支持管道操作,可以将多个命令连接起来,实现数据的流水线处理。

Bash的处理流程一般如下:

提示符显示:Bash等待用户输入命令,并在命令行上显示一个提示符,表示Bash已经准备好接收命令。

命令解析:Bash接收用户输入的命令行,并进行语法解析,将命令行拆分成命令、参数和选项等部分。

命令执行:Bash根据解析后的命令,调用对应的内置命令、外部程序或脚本进行执行。如果是外部程序或脚本,Bash会通过系统调用创建子进程,并执行相应的程序或脚本。

环境变量和参数处理:Bash在命令执行过程中会读取和修改环境变量,还会处理命令行参数,并将它们传递给命令或程序。

输入输出重定向和管道:Bash根据命令中的输入输出重定向符号和管道符号,将输入和输出重定向到指定的文件或设备,或将多个命令连接起来进行数据流转。

命令结果显示:Bash将命令执行的结果显示在终端上,包括输出的文本、错误消息和返回状态码等信息。

循环处理:Bash可以通过循环结构实现重复执行一组命令,或根据条件进行判断和分支。

6.3 Hello的fork进程创建过程

进程的创建通常使用fork()函数进行,其函数名为pid_t fork(void)。通过调用fork()函数,创建一个新的子进程,该子进程获得与父进程相同的用户级虚拟地址空间的副本,包括代码段、数据段、堆、共享库以及用户栈。此外,子进程还会获得与父进程中打开的文件描述符相同的副本,这意味着子进程可以读取父进程打开的任何文件。

父进程和子进程之间最显著的区别是它们拥有不同的进程ID(PID)。在子进程中,fork()函数的返回值为0。因为子进程的PID始终为非零值,通过返回值可以明确地区分程序是在父进程还是在子进程中执行。

在具体应用中,通常由Shell作为父进程。当我们在Shell中输入类似./hello的命令时,Shell首先解析该命令。由于Shell认为需要执行当前目录下的可执行文件"hello",因此Shell会调用fork()函数创建一个新的子进程。

6.4 Hello的execve过程

execve函数用于在当前进程的上下文中加载并执行一个新的程序。它接受三个参数:filename表示要加载的可执行目标文件,argv表示参数列表,envp表示环境变量。调用execve函数时,当前进程的上下文将被替换为新程序的上下文。新程序的可执行目标文件将被加载到内存中,并开始执行。如果execve函数成功执行,它将直接开始执行新程序,不会返回到调用程序。只有在发生错误时,例如找不到指定的filename文件,execve函数才会返回到调用程序。调用者可以根据返回值来判断是否出现错误,并采取相应的处理措施。

与fork函数不同,fork函数会在一次调用中返回两次,分别在父进程和子进程中返回。而execve函数只有一次调用,它不会返回到调用程序,而是直接执行新程序。

6.5 Hello的进程执行

上下文信息在操作系统中起着重要的作用,它包含了进程的虚拟地址空间以及与之相关的状态和数据。每个进程都有自己的上下文,包括用户级上下文和系统级上下文,与进程一一对应(通常与进程的PID一一对应)。上下文切换是操作系统实现多任务的一种机制,它允许处理器在多个进程之间进行切换,以实现并发执行。

当系统中有多个进程需要运行时,处理器在一段时间内执行一个进程的控制流,即一个时间片。然后,它将切换到另一个进程,执行其控制流,以此类推。这样,各个进程交替执行,实现了多任务的效果。

为了实现进程间的相互切换,处理器通常使用一个特殊的寄存器来区分不同的模式,该寄存器描述了当前进程所具有的特权级别。当模式位未设置时,进程处于用户模式,此时进程只能运行非特权指令,不能直接访问内核区域的代码和数据。当模式位设置为内核模式时,进程可以运行任何指令,包括特权指令,并可以访问内核区域。

通过上下文切换,操作系统能够实现进程的并发执行和资源的合理分配,提高系统的利用率和响应性能。上下文切换过程中需要保存和恢复进程的状态,包括寄存器的值、程序计数器、栈指针等,以确保切换后的进程能够正确地继续执行。上下文切换的开销较大,因此在设计系统时需要考虑减少上下文切换的频率,以提高系统的效率。

 6.6 hello的异常与信号处理

ello执行过程中会出现哪几类异常,会产生哪些信号,又怎么处理的。

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

运行过程中可能出现的异常种类由四种:中断、陷阱、故障、终止。

中断:来自I/O设备的信号,异步发生。硬件中断的异常处理程序被称为中断处理程序。

陷阱:是执行一条指令的结果。调用后返回到下一条指令。

故障:由错误情况引起,可能能被修正。修正成功则返回到引起故障的指令,否则终止程序。

终止:不可恢复,通常是硬件错误,这个程序会被终止

6.6.1 运行时输入回车:

正在上传…重新上传取消

6.6.2 运行时输入Ctrl+C

正在上传…重新上传取消

6.6.3 运行时输入Ctrl+Z

正在上传…重新上传取消

输入ps监视后台程序:

正在上传…重新上传取消

输入jobs,显示当前暂停的进程:

正在上传…重新上传取消

输入fg,使停止的进程收到SIGCONT信号,重新在前台运行:

正在上传…重新上传取消

输入kill,-9表示给进程13261发送9号信号,即SIGKILL,杀死进程。

正在上传…重新上传取消

6.6.4 运行时输入pstree以树状图形式显示所有进程

正在上传…重新上传取消

正在上传…重新上传取消

6.7本章小结

本章的重点是探讨了程序从可执行文件到进程的过程。我们了解了shell的作用和处理流程,它作为用户与操作系统之间的接口,负责解析用户输入的命令并执行相应的操作。

我们还学习了两个重要的函数:fork函数和execve函数。fork函数用于创建一个新的进程,该子进程与父进程共享代码和数据,但拥有独立的地址空间和文件描述符。而execve函数则用于在当前进程的上下文中加载并运行一个新的程序,替 换当前进程的上下文为新程序的上下文。

此外,我们也了解了上下文切换机制,它是操作系统实现多任务的一种机制。当有多个进程需要运行时,处理器会在不同进程之间进行切换,以实现并发执行。上下文切换涉及保存和恢复进程的状态,包括寄存器的值、程序计数器和栈指针等。

通过学习这些概念和机制,我们能够更好地理解程序的执行过程和进程的创建与管理。这对于编写高效、可靠的程序和系统的设计与优化非常重要。

7章 hello的存储管理

7.1 hello的存储器地址空间

逻辑地址是指程序在编译后出现在汇编代码中的地址。它是相对于程序自身的地址空间的逻辑位置。

线性地址是逻辑地址向物理地址转换过程中的一步。在段机制中,逻辑地址通过段描述符和偏移量的组合形式转换为线性地址。线性地址作为页表机制的输入,用于实现虚拟内存管理。

虚拟地址是指在虚拟内存系统中使用的地址,也可以用作线性地址的同义词。它是程序在虚拟内存空间中的地址,与物理内存的映射关系由操作系统进行管理和调度。

物理地址是通过CPU通过地址总线进行寻址,找到真实的物理内存对应的地址。物理地址是内存中实际存储数据的物理位置。

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

逻辑地址由两部分组成:段标识符和段内偏移量。段标识符(段选择符)是一个16位的字段,用于定位段描述符。通过段标识符的前13位,可以直接在段描述符表(全局段描述符表或局部段描述符表)中找到对应的段描述符,每个段描述符由8个字节组成。

在Linux系统中,采用分段机制将逻辑地址转换为线性地址。给定一个完整的逻辑地址[段选择符:段内偏移地址],首先根据段选择符的T1位(位 2)来确定是在全局段描述符表(GDT)还是局部段描述符表(LDT)中进行转换。根据相应的寄存器,可以获取到对应表的基地址和大小。然后通过段选择符中的前13位,在描述符表中找到对应的段描述符,进而获取到基地址。最后,将基地址与段内偏移量相加,就得到了线性地址。

这样,通过逻辑地址到线性地址的转换,操作系统可以实现对程序的地址空间的管理和保护。分段机制允许程序拥有不同的段,每个段有不同的权限和大小,通过段描述符表的组织和访问,可以实现对不同段的灵活控制和管理,提高内存的利用率和安全性。

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

在计算机系统中,将虚拟地址(VA)转换为物理地址(PA)的过程通过分页机制来完成。分页机制是对虚拟地址空间进行分页的一种方式。

在内存中,除了存储实际的数据和指令外,还额外存储了一个称为页表的数据结构,用作地址的索引。每个进程都有自己的页表,页表中的每一项记录着虚拟页与物理页的映射关系,包括对应的物理地址、有效位和其他相关信息。

然而,由于虚拟地址空间很大,而每个页的大小通常较小,导致页表项的数量过大,占用了大量的内存空间。为了解决这个问题,系统采用了多级页表的结构来进行索引。

系统将虚拟地址空间划分为虚拟页,而物理内存被划分为物理页。内存管理单元(Memory Management Unit,MMU)负责地址翻译,使用页表来进行虚拟地址到物理地址的映射。

每次进行地址转换时,MMU会查询页表来确定虚拟页是否已经缓存在物理内存中。如果虚拟页已经缓存在物理内存中,就可以直接通过查询页表项获取对应的物理页的起始地址,并将虚拟地址的偏移量与物理页的起始地址进行组合,得到相应的物理地址。

虚拟地址通常由虚拟页号(VPN)和虚拟页面偏移量(VPO)组成。MMU根据VPN选择适当的页表项,从中获取虚拟页的信息。如果虚拟页已经缓存在物理内存中,可以直接将页表项中的物理页号与虚拟页面偏移量进行组合,得到物理地址。

如果虚拟页未缓存在物理内存中,将触发一个缺页故障(Page Fault)。此时会调用一个缺页处理子程序,将磁盘上的虚拟页重新加载到内存中,然后再执行导致缺页的指令。

通过分页机制,计算机系统可以实现虚拟内存的管理和地址空间的隔离,提供更大的地址空间给每个进程使用,并且在物理内存不足时,可以将部分虚拟页交换到磁盘上,从而实现对内存的有效利用和管理。

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

1. CPU生成虚拟地址(VA)并发送给内存管理单元(MMU)进行转换。

2. MMU使用虚拟页号(VPN)的高位作为索引,在翻译后备缓冲(TLB)中查找匹配的项。

3. 如果TLB命中,即在TLB中找到了与VPN匹配的项,可以直接得到物理地址(PA)。

4. 如果TLB未命中,MMU将使用控制寄存器CR3中存储的页表基址(CR3)作为第一级页表的起始地址。

5. 使用VPN的高位作为索引,在第一级页表中查找对应的页表条目(PTE)。

6. 在第一级页表的PTE中,找到第二级页表的起始地址。

7. 使用VPN的中间位作为索引,在第二级页表中查找对应的PTE。

8. 依次进行类似的步骤,直到第四级页表,最终得到物理页号(PPN)。

9. 将物理页号(PPN)与虚拟页偏移量(VPO)组合,得到物理地址(PA)。

10. 将物理地址添加到页表中,以便CPU可以访问对应的物理内存单元。

这种四级页表的层次结构可以提高地址转换的效率,通过多级索引的方式,可以减少对整个页表的访问。TLB作为一个高速缓存,用于存储最近访问的页表条目,以加速地址转换过程。

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

与TLB(Translation Lookaside Buffer)类似,缓存(Cache)也是利用局部性原理来提高数据访问效率的一种硬件优化机制。

在缓存中,采用了组相联(Set-Associative)的方式来存储最近一段时间内加载的地址附近的数据内容。缓存被划分为多个组(Sets),每个组内有多个缓存行(Cache Line),每个缓存行可以存储一块数据。

当进行内存访问时,先从最高级别的缓存,即L1缓存(一级缓存)开始查找数据。如果数据在L1缓存中命中(Hit),即所需数据位于缓存行中,那么可以直接从缓存中获取数据,无需访问更慢的主存。如果数据不在L1缓存中未命中(Miss),则需要从下一级缓存,即L2缓存(二级缓存)中进行查找。

如果在L2缓存中命中,那么可以将数据从L2缓存传递给L1缓存,并提供给CPU使用。如果在L2缓存中未命中,则继续在更低级别的缓存,如L3缓存(三级缓存)或更低级别的缓存中查找。最后,如果在所有缓存中都未命中,则需要从主存中获取数据,并将其加载到适当的缓存层次中,以便将来的访问可以更快地命中缓存。

缓存的目的是减少对较慢的主存访问的需求,通过在高速缓存中存储最常访问的数据,加速CPU对数据的访问速度。缓存利用了数据的局部性原理,即近期访问的数据和其附近的数据很有可能在短时间内再次被访问到,因此将这些数据存储在缓存中可以提高访问效率。

总的来说,缓存层次结构(如L1、L2、L3缓存)与TLB一起工作,以提供更快的数据访问速度和更高的性能。当需要访问数据时,首先会检查TLB以获取物理地址,然后在缓存层次结构中进行数据查找,以减少对主存的访问。这种层次化的存储结构能够提供更快速的数据访问,并在内存访问的过程中利用局部性原理,从而提高整体系统性能。

7.6 hello进程fork时的内存映射

shell中输入命令./hello后,内核调用fork函数创建子进程,为hello程序的运行创建上下文,并分配一个与父进程不同的唯一的PID。为了给子进程创建虚拟内存,创建了当前进程的 mm_struct、区域结构和页表的原样副本。将这两个进程的每个页面都标记为只 读,并将两个进程中的每个区域结构都标记为私有的写时复制。

7.7 hello进程execve时的内存映射

execve函数调用驻留在内核区域的启动加载器代码,在当前进程中加载并运行包含在可执行目标文件hello中的程序,用hello程序有效地替代了当前程序。

加载并运行 hello 需要以下几个步骤:

当调用execve函数时,以下是大致的执行过程:

首先,操作系统将删除当前进程虚拟地址空间中已存在的用户区域,以清除当前程序的代码、数据和堆栈。

接下来,操作系统将为新程序的代码、数据、bss(未初始化的数据)和栈创建新的私有区域结构。这些区域是私有的,意味着它们只能被当前进程访问,并且在需要修改时才会进行实际的复制操作(写时复制)。

此时,操作系统会将可执行目标文件 "hello" 加载到内存中。它会将该文件的代码段映射到新创建的代码区域中,数据段映射到数据区域中,bss段映射到bss区域中。这样,新程序的代码和数据就可以在进程的虚拟地址空间中访问。

此外,如果可执行目标文件 "hello" 需要与动态链接库(如 libc.so)进行动态链接,操作系统会将该动态链接库映射到共享区域。共享区域允许多个进程共享同一段内存,以减少内存占用和提高性能。

最后,操作系统会设置当前进程的上下文,将程序计数器(PC)指向新程序的入口点,以便开始执行新程序的代码。一旦执行成功,新程序将取代当前程序运行,并且不会返回到调用 execve 的地方。

需要注意的是,如果调用execve函数失败(例如找不到指定的可执行目标文件),则函数会返回到调用程序,并根据返回值来判断发生的错误情况,并采取相应的处理措施。但通常情况下,execve函数成功执行后不会返回到调用程序,而是直接开始执行新程序。

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

缺页是指在虚拟内存管理中,当程序访问的页面不在主存中(即缺页),就会触发缺页异常,需要操作系统介入进行处理。

当发生缺页时,操作系统会暂停进程的执行,并执行以下操作:

检查缺页是否合法:操作系统会验证访问的虚拟地址是否在合法的地址范围内,以及对应的访问权限是否正确。如果地址非法或权限不足,则会终止进程。

选择牺牲页面:如果缺页是合法的,操作系统需要选择一个牺牲页面来腾出空间给新页面使用。牺牲页面可以是当前进程的其他页面,也可以是其他进程的页面,具体选择策略可以是根据页面的访问频率、最近使用时间等进行评估。

页面调入:操作系统将缺失的页面从辅存(如硬盘)加载到主存中的空闲页面中,并更新页表,将缺失页面的页表项更新为有效,同时更新对应的物理地址信息。

恢复进程执行:一旦缺页处理完成,操作系统会更新页表并恢复进程的执行状态。进程重新执行之前的指令,此时由于页面已经加载到主存中,MMU可以正常翻译虚拟地址,并完成内存访问操作。

7.9本章小结

在本章中,我们主要了解了hello程序在存储器中的地址空间,并深入了解了逻辑地址到线性地址、线性地址到物理地址的转换过程。同时,我们还介绍了四级页表下的线性地址到物理地址的转换过程,以及hello程序的内存映射。

此外,我们还探讨了缺页故障和缺页中断处理的机制。当程序访问一个未加载到主存中的页面时,会触发缺页故障,操作系统会选择一个牺牲页面,将缺失的页面加载到主存中,并更新页表。最后,我们还涉及了动态存储分配管理,这是操作系统负责管理和分配内存资源的重要任务。

通过这些内容,我们可以了解到程序在内存中的存储方式以及操作系统是如何管理和处理内存访问的。这对于理解计算机系统的内存管理机制和性能优化非常重要。

结论

用计算机系统的语言,逐条总结hello所经历的过程。

你对计算机系统的设计与实现的深切感悟,你的创新理念,如新的设计与实现方法。

从代码编辑器到程序执行的各个阶段。具体步骤如下:

预处理:使用预处理器cpp对源代码进行处理,包括展开宏定义和头文件,生成hello.i文件。

编译:编译器ccl对hello.i文件进行词法分析、语法分析和语义分析,并进行优化,最终生成汇编代码hello.s文件。

汇编:汇编器as将hello.s文件翻译成机器语言,生成可重定位目标文件hello.o。

链接:链接器ld对可重定位目标文件进行动态链接,生成可执行文件hello。

加载:通过Shell打开终端,输入"./hello"命令,Shell会创建一个新的进程并调用execve函数将可执行文件hello加载到虚拟内存空间中,程序开始执行。

执行过程:在程序运行过程中,受到内核的信号处理程序和异常处理程序的控制。程序执行完毕后,父进程通过回收子进程来完成清理工作,删除与该进程相关的所有数据结构。

通过对hello程序整个生命周期的描述,可以深入了解程序的开发过程和不同阶段的处理。这样的学习可以加深对计算机软件和硬件体系结构的理解,并强调了底层代码和体系构建的重要性。这对于计算机学习是一项关键的要点,能够帮助我们全面理解计算机系统和软件开发的细节。

附件

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

hello.c:源代码文件

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

hello.s:编译后的汇编文件

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

elf.txt:hello.o的ELF格式文件

hello 链接产生的可执行目标文件

elf2.txt:hello的ELF格式文件

asm.txt: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.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值