哈尔滨工业大学计算机系统大作业 程序人生-Hello‘s P2P ...

打印 上一主题 下一主题

主题 523|帖子 523|积分 1569







计算机系统


大作业



题     目  程序人生-Hellos P2P 

专       业        物联网工程                

学     号        2022111576                

班   级        2237301                

学       生        宋镇同          

指 导 教 师        吴锐             







计算机科学与技术学院

20245

摘  要

文章对hello程序的整个生命周期举行分析,将hello的人生分为7个阶段举行处理,对各个阶段举行分析和深度挖掘,并联系教材书本以求到达知行合一,熟练掌握。

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

(摘要0分,缺失-1分,根据内容出色称都酌情加分0-1分








目  录


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

1.通过编辑器编写hello.c文件,得到hello.c的源程序。
2.运行C预处理器(cpp)将hello.c举行预处理天生hello.i文件。
3.运行C编译器(ccl)将hello.i举行翻译天生汇编语言文件hello.s。
4.运行汇编器(as)将hello.s翻译成一个可重定位目标文件hello.o。
5.运行链接器ld将hello.o和系统目标文件组合起来,创建了一个可实行目标文件hello。(如图所示)
6.通过shell输入./hello,shell通过fork函数创建新的进程,然后调用了execve对假造内存举行映射,通过mmap为hello开辟一片空间。

7.中央处理器CPU从假造内存中的.text,.data截代替码和数据,调理器为进程规划时间片,在发生非常时触发非常处理子程序。
1.2 环境与工具

硬件环境:Intel(R) Core(TM) i7-10875H CPU 2.30 GHz;16GRAM;1024Disk
软件环境:Windows11 64位;Vmware 16;Ubuntu 20.04 LTS 64位
工具:codeblocks;gdb;Objdump;HexEdito
1.3 中心结果

1.4 本章小结


本章总体先容了hello程序“一生”的过程,以及举行实验时的软硬件环境及开发与调试工具等根本信息。


(第1章0.5分)



第2章 预处理

2.1 预处理的概念与作用


  • 概念:预处理器根据以字符”#”开头的下令,处理hello.c源程序。
  • 作用:根据源代码中的预处理指令修改源代码,预处理从系统头文件中将头文件的源码插入到目标文件中,最终天生hello.i文件。





2.2在Ubuntu下预处理的下令

Linux中预处理hello.c文件的下令是:gcc -E -o hello.i hello.c

2.3 Hello的预处理结果剖析

结果剖析:经过预处理后,hello.c被处理成为hello.i文件。打开文件后发现hello.i文件中文件内容大大增加,且仍为可阅读的c语言程序文本文件。hello.i文件对hello.c程序中的宏举行了宏睁开,该文件包罗了头文件中的内容。如果代码中有#define下令还会对相应符号举行替换。
2.4 本章小结

本章先容了预处理的相关概念和作用,举行实际操纵查看了hello.i文件,是对源程序举行增补和替换

(第2章0.5分)


第3章 编译


3.1 编译的概念与作用

1.概念:编辑器将文本文件hello.i翻译成文本文件hello.s,即一个汇编语言程序。
2.作用:把源程序翻译成目标程序,举行词法分析和语法分析,分析过程中发现有语法错误,给出提示信息
        

3.2 在Ubuntu下编译的下令

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




3.3 Hello的编译结果剖析

3.3.1汇编初始部门
节名称        作用
.file           声明源文件
.text           代码节
.section.rodata   只读数据段
.globl          声明全局变量
.type           声明一个符号是函数类型还是数据类型
.size           声明大小
.string          声明一个字符串
.align           声明对指令或者数据的存放所在举行对齐的方式
3.3.2 数据
1)字符串
程序中有两个字符串,这两个字符串都在只读数据段中,如图所示:

hello.c中唯一的数组是作为main函数的第二个参数,数组的每个元素都是一个指向字符类型的指针。数组的出发点存放在栈中-32(%rbp)的位置,被两次调用找参数传给printf函数。

如图所示,这两个字符串作为printf的参数。
2)局部变量
main函数声明了一个局部变量i,编译器举行编译的时候将局部变量i放入堆栈中。i被放置在栈中-4(%rbp)的位置,如下图所示。


3)参数argc

参数argc是作为用户传给main函数的参数。同样被放置到堆栈之中了。

4)数组char*argv[]

char*argv[]是main函数的第二个参数,数组的起始所在存放在-32(%rbp)的位置,数组中的每一个元素都是一个指向字符类型的指针,在内存中被两次调用穿给printf函数。

5)立刻数

立刻数直接体现在汇编代码中。

3.3.3全局函数

hello.c声明了一个函数int main(int argc,char *argv[]),通过阅读汇编代码我们发现此函数是一个全局函数,如图所示。

3.3.4赋值操纵

hello中的赋值操纵重要有:i=0,而这个操纵在.s文件中汇编代码重要使用mov指令来实现。mov指令根据操纵数的字节大小分为:

movb:一个字节赋值,movw:两个字节赋值,

movl:四个字节赋值,movq:八个字节赋值。

3.3.5算术操纵

hello.c中的算数操纵重要有i++,i是int类型,在汇编代码中用addl实现此操纵。

3.3.6关系操纵

1)hello.c中 “if(argc!=4)”,这是一个条件判断语句,在举行编译时,被编译为:cmpl$4, -20(%rbp)。比力后设置条件码,根据条件码判断是否需要跳转。

2)hello.c源程序中的for循环条件是for(i=0;i<8;i++),该条指令被编译为cmpl$7,-4(%rbp)。同样在判断后设置条件码,为下一步的jle使用条件码跳转做准备。    

3.3.7控制转移指令

汇编语言中设置了条件码,然后根据条件码来举行控制程序的跳转。通过阅读hello.c 的汇编代码,我们发现有如下控制转移指令。

1)判断argc是否即是4。如果即是4,则不实行if语句;反之if不即是4,则实行后续的语句,对应的汇编代码为:


  • for循环中,每次都要判断i是否小于8来决定是否继续循环。先对i举行赋初值,然后无条件跳转至判断条件的.L3中,然后判断i是否符合循环的条件,若符合则直接跳转到.L4中。这一部门的汇编代码为:


3.3.8函数操纵

hello.c中涉及的函数操纵重要有以下几个:main,printf,exit,sleep,和getchar函数。main函数的参数是argc和*argv,printf函数的参数是字符串,exit函数的参数是1,sleep函数的参数是atoi(argv[3])。所有函数的返回值都会存储在%eax寄存器中。函数的调用与传参的过程是给函数通报参数需要先设定一个寄存器,将参数传给这个设定的寄存器后,再通过call来跳转到调用的函数开头的所在。

3.3.9类型转换

hello.c中的atoi(argv[3])将字符串类型转换为整形。int、float、double、short、char之间可以举行相互转化。

3.4 本章小结

本章重要先容了编译器处理c语言程序的根本过程,编译器分别从c语言的数据,赋值语句,类型转换,算术操纵,逻辑/位操纵,关系操纵,控制转移与函数操纵这几点举行分析,hello程序从高级的c语言变成了低阶的汇编语言

(第3章2分)


第4章 汇编


4.1 汇编的概念与作用

1.概念:汇编是指从 .s 到 .o 即编译后的文件到天生机器语言二进制程序的过程,汇编器(as)将.s汇编程序翻译成机器语言并将这些指令打包成可重定目标程序的格式存放在.o目标文件中,.o 文件是一个二进制文件,它包罗程序的指令编码。
2.作用:将汇编语言翻译成机器语言,使其在链接后能够被机器辨认并实行。
4.2 在Ubuntu下汇编的下令

gcc -c -o hello.o hello.s





4.3 可重定位目标elf格式

典范的ELF可重定位目标文件

在linux下天生hello.o文件的elf格式下令:readelf -a hello.o > hello.elf


ELF 头:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  类别:                              ELF64
  数据:                              2 补码,小端序 (little endian)
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI 版本:                          0
  类型:                              REL (可重定位文件)
  系统架构:                          Advanced Micro Devices X86-64
  版本:                              0x1
  入口点所在:               0x0
  程序头出发点:          0 (bytes into file)
  Start of section headers:          1088 (bytes into file)
  标记:             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           64 (bytes)
  Number of section headers:         14
  Section header string table index: 13

节头:
  [号] 名称              类型             所在              偏移量
       大小              全体大小          旗标   链接   信息   对齐
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .text             PROGBITS         0000000000000000  00000040
       00000000000000a3  0000000000000000  AX       0     0     1
  [ 2] .rela.text        RELA             0000000000000000  000002f0
       00000000000000c0  0000000000000018   I      11     1     8
  [ 3] .data             PROGBITS         0000000000000000  000000e3
       0000000000000000  0000000000000000  WA       0     0     1
  [ 4] .bss              NOBITS           0000000000000000  000000e3
       0000000000000000  0000000000000000  WA       0     0     1
  [ 5] .rodata           PROGBITS         0000000000000000  000000e8
       0000000000000040  0000000000000000   A       0     0     8
  [ 6] .comment          PROGBITS         0000000000000000  00000128
       000000000000002c  0000000000000001  MS       0     0     1
  [ 7] .note.GNU-stack   PROGBITS         0000000000000000  00000154
       0000000000000000  0000000000000000           0     0     1
  [ 8] .note.gnu.pr[...] NOTE             0000000000000000  00000158
       0000000000000020  0000000000000000   A       0     0     8
  [ 9] .eh_frame         PROGBITS         0000000000000000  00000178
       0000000000000038  0000000000000000   A       0     0     8
  [10] .rela.eh_frame    RELA             0000000000000000  000003b0
       0000000000000018  0000000000000018   I      11     9     8
  [11] .symtab           SYMTAB           0000000000000000  000001b0
       0000000000000108  0000000000000018          12     4     8
  [12] .strtab           STRTAB           0000000000000000  000002b8
       0000000000000032  0000000000000000           0     0     1
  [13] .shstrtab         STRTAB           0000000000000000  000003c8
       0000000000000074  0000000000000000           0     0     1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  D (mbind), l (large), p (processor specific)

There are no section groups in this file.

本文件中没有程序头。

There is no dynamic section in this file.

重定位节 '.rela.text' at offset 0x2f0 contains 8 entries:
  偏移量          信息           类型           符号值        符号名称 + 加数
00000000001c  000300000002 R_X86_64_PC32     0000000000000000 .rodata - 4
000000000024  000500000004 R_X86_64_PLT32    0000000000000000 puts - 4
00000000002e  000600000004 R_X86_64_PLT32    0000000000000000 exit - 4
000000000062  000300000002 R_X86_64_PC32     0000000000000000 .rodata + 2c
00000000006f  000700000004 R_X86_64_PLT32    0000000000000000 printf - 4
000000000082  000800000004 R_X86_64_PLT32    0000000000000000 atoi - 4
000000000089  000900000004 R_X86_64_PLT32    0000000000000000 sleep - 4
000000000098  000a00000004 R_X86_64_PLT32    0000000000000000 getchar - 4

重定位节 '.rela.eh_frame' at offset 0x3b0 contains 1 entry:
  偏移量          信息           类型           符号值        符号名称 + 加数
000000000020  000200000002 R_X86_64_PC32     0000000000000000 .text + 0
No processor specific unwind information to decode

Symbol table '.symtab' contains 11 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS hello.c
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    1 .text
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    5 .rodata
     4: 0000000000000000   163 FUNC    GLOBAL DEFAULT    1 main
     5: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND puts
     6: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND exit
     7: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND printf
     8: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND atoi
     9: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND sleep
    10: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND getchar

No version information found in this file.

Displaying notes found in: .note.gnu.property
  所有者            Data size Description
  GNU                  0x00000010 NT_GNU_PROPERTY_TYPE_0
      Properties: x86 feature: IBT, SHSTK

1)ELF头 :ELF头(ELF header)以一个16字节的序列开始,这个序列形貌了天生该文件的系统的字的大小和字节次序。ELF头剩下的部门包罗了资助链接器语法分析息争释目标文件的信息,其中包罗ELF头的大小、目标文件的类型(如可重定位、可实行或者共享的)、机器类型(如x86-64)、节头部表(section header table)的文件偏移,以及节头部表中条目的大小和数目。不同节的位置和大小是有节头部表形貌的,其中目标文件中每个节都有一个固定大小的条目(entry)。
2)节头:记载各节名称、类型、所在、偏移量、大小、全体大小、旗标、链接、信息、对齐。
3)重定位节:重定位节生存的是.text节中需要被修正的信息(任何调用外部函数或者引用全局变量的指令都需要被修正),调用外部函数的指令和引用全局变量的指令需要重定位,调用局部函数的指令不需要重定位。Hello程序中需要被重定位的有printf、puts、exit、sleep、sleepseces、getchar和.rodata中的.L0和.L1。
.rela.eh_frame节是.eh_frame节的重定位信息。
4)符号表:.symtab,一个符号表,它存放在程序中定义和引用的函数和全局变量的信息,一些程序员错误地认为必须通过-g选项来编译一个程序,才气得到符号表信息。实际上每个可重定位目标文件在.symtab中都有一张符号表(除非程序员特意用STRIP下令去掉它)。然而,和编译器中的符号表不同,.symtab符号表不包罗局部变量的条目。

4.4 Hello.o的结果剖析

下令:objdump -d -r hello.o>hello.txt



结果剖析:与hello.s的差异

1)分支转移
hello.s

hello1.txt

反汇编代码跳转指令的操纵数使用的不是段名称,因为段名称只是在汇编语言中便于编写的助记符,以是在汇编成机器语言之后显然不存在,而是确定的所在。
2)对函数的调用与重定位条目对应
hello.s

hello1.txt

在可重定位文件中call背面不再是函数的详细名称,而是一条重定位条目指引的信息。而在反汇编文件中可以看到,call背面直接加的是偏移量。

3)立刻数变为十六进制格式

hello.s

hello1.txt

    在编译文件中,立刻数全部是以16进制表示的,因为16进制与2进制之间的转换比十进制更加方便,以是都转换成了16进制。

4.5 本章小结

  本章对应的重要是hello.s汇编到hello.o的过程。在本章中,我们查看了hello.o的可重定位目标文件的格式,使用反汇编查看hello.o经过反汇编过程生

成的代码而且把它与hello.s举行比力,分析和叙述了从汇编语言进一步翻译成
为机器语言的汇编过程。
(第4章1分)

5链接


5.1 链接的概念与作用

概念:链接是将各种代码和数据片段收集并合成为一个单一文件的过程,这个文件可被加载(复制)到内存并实行。链接可以实行于编译时,也就是在源代码被翻译成机器代码时;也可以实行于加载时,也就是在程序被加载器加载到内存并实行时;甚至实行于运行时,也就是由应用程序来实行。
作用:链接器在软件开发过程中饰演着一个关键的脚色,因为它们使得分离编译成为大概。我们不消将一个大型的应用程序组织为一个巨大的源文件,而是可以把它分解为更小、更好管理的模块,可以独立地修改和编译这些模块。当我们改变这些模块中的一个时,只需简单地重新编译它,并重新链接应用,而不必重新编译其它文件。
5.2 在Ubuntu下链接的下令



下令:ld -o hello.o -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/11/crtbegin.o hello.o -lc /usr/lib/gcc/x86_64-linux-gnu/11/crtend.o /usr/lib/x86_64-linux-gnu/crtn.o -z relro -o hello



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

下令:readelf -a hello > hello1.elf

ELF 头:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  类别:                              ELF64
  数据:                              2 补码,小端序 (little endian)
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI 版本:                          0
  类型:                              EXEC (可实行文件)
  系统架构:                          Advanced Micro Devices X86-64
  版本:                              0x1
  入口点所在:               0x4010f0
  程序头出发点:          64 (bytes into file)
  Start of section headers:          14080 (bytes into file)
  标记:             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         12
  Size of section headers:           64 (bytes)
  Number of section headers:         30
  Section header string table index: 29

节头:
  [号] 名称              类型             所在              偏移量
       大小              全体大小          旗标   链接   信息   对齐
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .interp           PROGBITS         00000000004002e0  000002e0
       000000000000001c  0000000000000000   A       0     0     1
  [ 2] .note.gnu.pr[...] NOTE             0000000000400300  00000300
       0000000000000030  0000000000000000   A       0     0     8
  [ 3] .note.ABI-tag     NOTE             0000000000400330  00000330
       0000000000000020  0000000000000000   A       0     0     4
  [ 4] .hash             HASH             0000000000400350  00000350
       0000000000000038  0000000000000004   A       6     0     8
  [ 5] .gnu.hash         GNU_HASH         0000000000400388  00000388
       000000000000001c  0000000000000000   A       6     0     8
  [ 6] .dynsym           DYNSYM           00000000004003a8  000003a8
       00000000000000d8  0000000000000018   A       7     1     8
  [ 7] .dynstr           STRTAB           0000000000400480  00000480
       0000000000000067  0000000000000000   A       0     0     1
  [ 8] .gnu.version      VERSYM           00000000004004e8  000004e8
       0000000000000012  0000000000000002   A       6     0     2
  [ 9] .gnu.version_r    VERNEED          0000000000400500  00000500
       0000000000000030  0000000000000000   A       7     1     8
  [10] .rela.dyn         RELA             0000000000400530  00000530
       0000000000000030  0000000000000018   A       6     0     8
  [11] .rela.plt         RELA             0000000000400560  00000560
       0000000000000090  0000000000000018  AI       6    23     8
  [12] .init             PROGBITS         0000000000401000  00001000
       000000000000001b  0000000000000000  AX       0     0     4
  [13] .plt              PROGBITS         0000000000401020  00001020
       0000000000000070  0000000000000010  AX       0     0     16
  [14] .plt.sec          PROGBITS         0000000000401090  00001090
       0000000000000060  0000000000000010  AX       0     0     16
  [15] .text             PROGBITS         00000000004010f0  000010f0
       0000000000000189  0000000000000000  AX       0     0     16
  [16] .fini             PROGBITS         000000000040127c  0000127c
       000000000000000d  0000000000000000  AX       0     0     4
  [17] .rodata           PROGBITS         0000000000402000  00002000
       0000000000000048  0000000000000000   A       0     0     8
  [18] .eh_frame         PROGBITS         0000000000402048  00002048
       00000000000000a4  0000000000000000   A       0     0     8
  [19] .init_array       INIT_ARRAY       0000000000403e00  00002e00
       0000000000000008  0000000000000008  WA       0     0     8
  [20] .fini_array       FINI_ARRAY       0000000000403e08  00002e08
       0000000000000008  0000000000000008  WA       0     0     8
  [21] .dynamic          DYNAMIC          0000000000403e10  00002e10
       00000000000001e0  0000000000000010  WA       7     0     8
  [22] .got              PROGBITS         0000000000403ff0  00002ff0
       0000000000000010  0000000000000008  WA       0     0     8
  [23] .got.plt          PROGBITS         0000000000404000  00003000
       0000000000000048  0000000000000008  WA       0     0     8
  [24] .data             PROGBITS         0000000000404048  00003048
       0000000000000010  0000000000000000  WA       0     0     8
  [25] .bss              NOBITS           0000000000404058  00003058
       0000000000000008  0000000000000000  WA       0     0     1
  [26] .comment          PROGBITS         0000000000000000  00003058
       000000000000002b  0000000000000001  MS       0     0     1
  [27] .symtab           SYMTAB           0000000000000000  00003088
       0000000000000390  0000000000000018          28    17     8
  [28] .strtab           STRTAB           0000000000000000  00003418
       00000000000001e9  0000000000000000           0     0     1
  [29] .shstrtab         STRTAB           0000000000000000  00003601
       00000000000000fe  0000000000000000           0     0     1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  D (mbind), l (large), p (processor specific)

There are no section groups in this file.

程序头:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000400040 0x0000000000400040
                 0x00000000000002a0 0x00000000000002a0  R      0x8
  INTERP         0x00000000000002e0 0x00000000004002e0 0x00000000004002e0
                 0x000000000000001c 0x000000000000001c  R      0x1
      [Requesting program interpreter: /lib64/ld-linux-x86_64.so.2]
  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
                 0x00000000000005f0 0x00000000000005f0  R      0x1000
  LOAD           0x0000000000001000 0x0000000000401000 0x0000000000401000
                 0x0000000000000289 0x0000000000000289  R E    0x1000
  LOAD           0x0000000000002000 0x0000000000402000 0x0000000000402000
                 0x00000000000000ec 0x00000000000000ec  R      0x1000
  LOAD           0x0000000000002e00 0x0000000000403e00 0x0000000000403e00
                 0x0000000000000258 0x0000000000000260  RW     0x1000
  DYNAMIC        0x0000000000002e10 0x0000000000403e10 0x0000000000403e10
                 0x00000000000001e0 0x00000000000001e0  RW     0x8
  NOTE           0x0000000000000300 0x0000000000400300 0x0000000000400300
                 0x0000000000000030 0x0000000000000030  R      0x8
  NOTE           0x0000000000000330 0x0000000000400330 0x0000000000400330
                 0x0000000000000020 0x0000000000000020  R      0x4
  GNU_PROPERTY   0x0000000000000300 0x0000000000400300 0x0000000000400300
                 0x0000000000000030 0x0000000000000030  R      0x8
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     0x10
  GNU_RELRO      0x0000000000002e00 0x0000000000403e00 0x0000000000403e00
                 0x0000000000000200 0x0000000000000200  R      0x1

 Section to Segment mapping:
  段节...
   00     
   01     .interp
   02     .interp .note.gnu.property .note.ABI-tag .hash .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt
   03     .init .plt .plt.sec .text .fini
   04     .rodata .eh_frame
   05     .init_array .fini_array .dynamic .got .got.plt .data .bss
   06     .dynamic
   07     .note.gnu.property
   08     .note.ABI-tag
   09     .note.gnu.property
   10     
   11     .init_array .fini_array .dynamic .got

Dynamic section at offset 0x2e10 contains 25 entries:
  标记        类型                         名称/值
 0x0000000000000001 (NEEDED)             共享库:[libc.so.6]
 0x000000000000000c (INIT)               0x401000
 0x000000000000000d (FINI)               0x40127c
 0x0000000000000019 (INIT_ARRAY)         0x403e00
 0x000000000000001b (INIT_ARRAYSZ)       8 (bytes)
 0x000000000000001a (FINI_ARRAY)         0x403e08
 0x000000000000001c (FINI_ARRAYSZ)       8 (bytes)
 0x0000000000000004 (HASH)               0x400350
 0x000000006ffffef5 (GNU_HASH)           0x400388
 0x0000000000000005 (STRTAB)             0x400480
 0x0000000000000006 (SYMTAB)             0x4003a8
 0x000000000000000a (STRSZ)              103 (bytes)
 0x000000000000000b (SYMENT)             24 (bytes)
 0x0000000000000015 (DEBUG)              0x0
 0x0000000000000003 (PLTGOT)             0x404000
 0x0000000000000002 (PLTRELSZ)           144 (bytes)
 0x0000000000000014 (PLTREL)             RELA
 0x0000000000000017 (JMPREL)             0x400560
 0x0000000000000007 (RELA)               0x400530
 0x0000000000000008 (RELASZ)             48 (bytes)
 0x0000000000000009 (RELAENT)            24 (bytes)
 0x000000006ffffffe (VERNEED)            0x400500
 0x000000006fffffff (VERNEEDNUM)         1
 0x000000006ffffff0 (VERSYM)             0x4004e8
 0x0000000000000000 (NULL)               0x0

重定位节 '.rela.dyn' at offset 0x530 contains 2 entries:
  偏移量          信息           类型           符号值        符号名称 + 加数
000000403ff0  000100000006 R_X86_64_GLOB_DAT 0000000000000000 __libc_start_main@GLIBC_2.34 + 0
000000403ff8  000500000006 R_X86_64_GLOB_DAT 0000000000000000 __gmon_start__ + 0

重定位节 '.rela.plt' at offset 0x560 contains 6 entries:
  偏移量          信息           类型           符号值        符号名称 + 加数
000000404018  000200000007 R_X86_64_JUMP_SLO 0000000000000000 puts@GLIBC_2.2.5 + 0
000000404020  000300000007 R_X86_64_JUMP_SLO 0000000000000000 printf@GLIBC_2.2.5 + 0
000000404028  000400000007 R_X86_64_JUMP_SLO 0000000000000000 getchar@GLIBC_2.2.5 + 0
000000404030  000600000007 R_X86_64_JUMP_SLO 0000000000000000 atoi@GLIBC_2.2.5 + 0
000000404038  000700000007 R_X86_64_JUMP_SLO 0000000000000000 exit@GLIBC_2.2.5 + 0
000000404040  000800000007 R_X86_64_JUMP_SLO 0000000000000000 sleep@GLIBC_2.2.5 + 0
No processor specific unwind information to decode

Symbol table '.dynsym' contains 9 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND _[...]@GLIBC_2.34 (2)
     2: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND puts@GLIBC_2.2.5 (3)
     3: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND [...]@GLIBC_2.2.5 (3)
     4: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND [...]@GLIBC_2.2.5 (3)
     5: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
     6: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND atoi@GLIBC_2.2.5 (3)
     7: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND exit@GLIBC_2.2.5 (3)
     8: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND sleep@GLIBC_2.2.5 (3)

Symbol table '.symtab' contains 38 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS crt1.o
     2: 0000000000400330    32 OBJECT  LOCAL  DEFAULT    3 __abi_tag
     3: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
     4: 0000000000401130     0 FUNC    LOCAL  DEFAULT   15 deregister_tm_clones
     5: 0000000000401160     0 FUNC    LOCAL  DEFAULT   15 register_tm_clones
     6: 00000000004011a0     0 FUNC    LOCAL  DEFAULT   15 __do_global_dtors_aux
     7: 0000000000404058     1 OBJECT  LOCAL  DEFAULT   25 completed.0
     8: 0000000000403e08     0 OBJECT  LOCAL  DEFAULT   20 __do_global_dtor[...]
     9: 00000000004011d0     0 FUNC    LOCAL  DEFAULT   15 frame_dummy
    10: 0000000000403e00     0 OBJECT  LOCAL  DEFAULT   19 __frame_dummy_in[...]
    11: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS hello.c
    12: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
    13: 00000000004020e8     0 OBJECT  LOCAL  DEFAULT   18 __FRAME_END__
    14: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS
    15: 0000000000403e10     0 OBJECT  LOCAL  DEFAULT   21 _DYNAMIC
    16: 0000000000404000     0 OBJECT  LOCAL  DEFAULT   23 _GLOBAL_OFFSET_TABLE_
    17: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_mai[...]
    18: 0000000000404048     0 NOTYPE  WEAK   DEFAULT   24 data_start
    19: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND puts@GLIBC_2.2.5
    20: 0000000000404058     0 NOTYPE  GLOBAL DEFAULT   24 _edata
    21: 000000000040127c     0 FUNC    GLOBAL HIDDEN    16 _fini
    22: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND printf@GLIBC_2.2.5
    23: 0000000000404048     0 NOTYPE  GLOBAL DEFAULT   24 __data_start
    24: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND getchar@GLIBC_2.2.5
    25: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
    26: 0000000000404050     0 OBJECT  GLOBAL HIDDEN    24 __dso_handle
    27: 0000000000402000     4 OBJECT  GLOBAL DEFAULT   17 _IO_stdin_used
    28: 0000000000404060     0 NOTYPE  GLOBAL DEFAULT   25 _end
    29: 0000000000401120     5 FUNC    GLOBAL HIDDEN    15 _dl_relocate_sta[...]
    30: 00000000004010f0    38 FUNC    GLOBAL DEFAULT   15 _start
    31: 0000000000404058     0 NOTYPE  GLOBAL DEFAULT   25 __bss_start
    32: 00000000004011d6   163 FUNC    GLOBAL DEFAULT   15 main
    33: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND atoi@GLIBC_2.2.5
    34: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND exit@GLIBC_2.2.5
    35: 0000000000404058     0 OBJECT  GLOBAL HIDDEN    24 __TMC_END__
    36: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND sleep@GLIBC_2.2.5
    37: 0000000000401000     0 FUNC    GLOBAL HIDDEN    12 _init

Histogram for bucket list length (total of 3 buckets):
 Length  Number     % of total  Coverage
      0  0          (  0.0%)
      1  0          (  0.0%)      0.0%
      2  1          ( 33.3%)     25.0%
      3  2          ( 66.7%)    100.0%

Version symbols section '.gnu.version' contains 9 entries:
 所在:0x00000000004004e8  Offset: 0x0004e8  Link: 6 (.dynsym)
  000:   0 (*当地*)       2 (GLIBC_2.34)    3 (GLIBC_2.2.5)   3 (GLIBC_2.2.5)
  004:   3 (GLIBC_2.2.5)   1 (*全局*)      3 (GLIBC_2.2.5)   3 (GLIBC_2.2.5)
  008:   3 (GLIBC_2.2.5)

Version needs section '.gnu.version_r' contains 1 entry:
 所在:0x0000000000400500  Offset: 0x000500  Link: 7 (.dynstr)
  000000: Version: 1  文件:libc.so.6  计数:2
  0x0010:   Name: GLIBC_2.2.5  标记:无  版本:3
  0x0020:   Name: GLIBC_2.34  标记:无  版本:2

Displaying notes found in: .note.gnu.property
  所有者            Data size Description
  GNU                  0x00000020 NT_GNU_PROPERTY_TYPE_0
      Properties: x86 feature: IBT, SHSTK
x86 ISA needed: x86-64-baseline

Displaying notes found in: .note.ABI-tag
  所有者            Data size Description
  GNU                  0x00000010 NT_GNU_ABI_TAG (ABI version tag)
    OS: Linux, ABI: 3.2.0

分析:
1)ELF头:hello的文件头和hello.o文件头的不同之处如下图标记所示,hello是一个可实行目标文件,有27个节。
2)节头:对 hello中所有的节信息举行了声明,包罗大小和偏移量。
3) 重定位节.rela.text:
4)符号表.symtab:

5.4 hello的假造所在空间

分析程序头LOAD可加载的程序段的所在为0x400000


通过edb加载hello程序,打开Data Dump查看hello加载到假造所在的状况,并
查看各段信息。


通过edb调试可以看出该程序所在从0x401000开始,我们可以通过elf的每个section的所在在Data Dump中找到相应数据
5.5 链接的重定位过程分析

下令: objdump -d -r hello > hello2.txt

与hello.o的反汇编文件对比发现,hello2.txt中多了很多节。hello1.txt中只有一个.text节,而且只有一个main函数,函数所在也是默认的0x000000。hello2.txt中有.init,.plt,.text三个节,而且每个节中有很多函数。库函数的代码都已经链接到了程序中,程序各个节变的更加完备,跳转的所在也具有参考性。

hello的重定位过程:

    1)重定位节和符号定义链接器将所有类型雷同的节合并在一起后,这个节就作为可实行目标文件的节。然后链接器把运行时的内存所在赋给新的聚合节,赋给输入模块定义的每个节,以及赋给输入模块定义的每个符号,当这一步完成时,程序中每条指令和全局变量都有唯一运行时的所在。

    2)重定位节中的符号引用这一步中,连接器修改代码节和数据节中对每个符号的引用,使他们指向正确的运行时所在。

    3)重定位条目当编译器碰到对最终位置未知的目标引用时,它会天生一个重定位条目。代码的重定位条目放在.rel.txt中。


5.6 hello的实行流程

实行次序:_start->init->call_init->main

函数      所在
main       0x4011e2
Init        0x401000
_start      0x7ffff7fe3290
Call_init   0x7ffff7c29e68



5.7 Hello的动态链接分析

共享库:共享库是一个目标模块,在加载或运行时,可以加载到任意的内存所在,并和一个在内存中的程序链接起来。这个过程被称为动态链接,是由一个叫做动态链接器的程序来实行的。共享库也称为共享目标。

动态链接的根本头脑:先把程序按照模块拆分成各个相对独立的部门,在程序运行时将这些相对独立的部门链接在一起形成一个完备的程序。

动态耽误绑定:动态的链接器在正常工作的时候链接器接纳了耽误绑定的连接器战略,由于静态的编译器本身无法正确的猜测变量和函数的绝对运行时的所在,动态的连接器需要等待编译器在程序开始加载时在对编译器举行耽误剖析,这样的耽误绑定战略叫做动态耽误绑定。

耽误绑定是通过got和plt实现的。Got是数据段的一部门,而plt是代码段的一部门。
通过readelf找到他们的所在

在动态链接处设置断点

接着在_start和main处设置断点

5.8 本章小结

本章研究了链接的过程。通过edb查看hello的假造所在空间,对比hello与hello.o的反汇编代码,深入研究了链接的过程中重定位的过程。
(第5章1分)



6hello进程管理


6.1 进程的概念与作用

(1)概念:进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统举行资源分配和调理的根本单元,是操纵系统布局的基础。在早期面向进程设计的计算机布局中,进程是程序的根本实行实体;在当代面向线程设计的计算机布局中,进程是线程的容器。程序是指令、数据及其组织情势的形貌,进程是程序的实体。

2)作用:进程作为一个实行中程序的实例,系统中每个程序都运行在某个进程的上下文中,上下文是由程序正确运行所需的状态构成的。这个状态包罗存放在内存中的程序的代码和数据,它的栈、通用目的寄存器的内容、程序计数器、环境变量以及打开文件形貌符的集合。
6.2 简述壳Shell-bash的作用与处理流程

(1)Shell-bash的作用:Linux系统中,Shell是一个交互型应用级程序,为使用者提供操纵界面,吸取用户下令,然后调用相应的应用程序。
(2)Shell-bash的处理流程:

① 在shell下令行中输入下令:$./hello
② shell下令行解释器构造argv和envp;
③ 调用fork()函数创建子进程,其所在空间与shell父进程完全雷同,包罗只读代码段、读写数据段、堆及用户栈等
④ 调用execve()函数在当前进程(新创建的子进程)的上下文中加载并运行hello程序。将hello中的.text节、.data节、.bss节等内容加载到当前进程的假造所在空间
⑤ 调用hello程序的main()函数,hello程序开始在一个进程的上下文中运行。




6.3 Hello的fork进程创建过程

在终端中输入./hello 学号 姓名 1下令后,shell会处理该下令,判断出不是内置下令,则会调用fork函数创建一个新的子进程,子进程险些但不完全与父进程雷同。通过fork函数,子进程得到与父进程用户级假造所在空间雷同的但是假造所在独立、PID也不雷同的一份副本。
6.4 Hello的execve过程

当创建了一个子进程之后,子进程调用exceve函数在当前子进程的上下文加载并运行一个新的程序,即hello程序,需要以下步调:

①删除已存在的用户地域。删除之前进程在用户部门中已存在的布局。

②创建新的代码、数据、堆和栈段。所有这些地域布局都是私有的,写时复制的。假造所在空间的代码和数据地域被映射为hello文件的.txt和.data区。bss地域是请求二进制零的,映射匿名文件,其大小包罗在hello文件中。栈和堆地域也是请求二进制零的,初始长度为零。

③映射共享地域。如果hello程序与共享对象链接,好比标准C库libc.so,那么这些对象都是动态链接到这个程序的,然后再映射到用户假造所在空间中的共享地域。

④设置程序计数器(PC)。exceve做的最后一件事就是设置当前进程的上下文中的程序计数器,使之指向代码地域的入口点。
6.5 Hello的进程实行

联合进程上下文信息、进程时间片,叙述进程调理的过程,用户态与焦点态转换等等。
6.5.1 逻辑控制流和时间片:

进程的运行本质上是CPU不断从程序计数器 PC 指示的所在处取出指令并实行,值的序列叫做逻辑控制流。操纵系统会对进程的运行举行调理,实行进程A->上下文切换->实行进程B->上下文切换->实行进程A->… 如此循环往复。 在进程实行的某些时候,内核可以决定抢占当前进程,并重新开始一个先前被抢占了的进程,这种决策就叫做调理,是由内核中称为调理器的代码处理的。当内核选择一个新的进程运行,我们说内核调理了这个进程。在内核调理了一个新的进程运行了之后,它就抢占了当前进程,并使用上下文切换机制来将控制转移到新的进程。在一个程序被调运行开始到被另一个进程打断,中心的时间就是运行的时间片。

   6.5.2用户模式和内核模式:

   Shell使得用户可以偶然机修改内核,以是需要设置一些防护步伐来保护内核,如限制指令的类型和可以作用的范围。

   6.5.3上下文切换

   如果系统调用因为等待某个事件发生而阻塞,那么内核可以让当前进程休眠,切换到另一个进程,上下文就是内核重新启动一个被抢占的进程所需要的状态,是一种比力高层次的非常控制流。

   6.5.4调理

   在对进程举行调理的过程,操纵系统重要做了两件事:加载生存的寄存器,切换假造所在空间。

   6.5.5用户态与焦点态转换

   为了能让处理器安全运行,需要限制应用程序可实行指令所能访问的所在范围。因此划分了用户态与焦点态。

   焦点态可以说是拥有最高的访问权限,处理器以一个寄存器当做模式位来形貌当前进程的特权。进程只有故障、停止或陷入系统调用时才会得到内核访问权限,其他环境下始终处于用户权限之中,保证了系统的安全性。




6.6 hello的非常与信号处理

6.6.1 hello的正常运行状态

6.6.2 按下CTRL-Z

输入ctrl-z默认结果是挂起前台的作业,hello进程并没有回收,而是运行在背景下,用ps下令可以看到,hello进程并没有被回收。此时他的背景 job 号是 1,调用 fg 1 将其调到前台,此时 shell 程序首先打印 hello 的下令行下令, hello 继续运行打印剩下的 8 条 info,之后输入字串,程序结束,同时进程被回收,如下图。




6.6.3按下CTRL-C

6.7本章小结

本章了解了hello进程的实行过程。在hello运行过程中,内核对其调理,非常处理程序为其将处理各种非常。每种信号都有不同的处理机制,对不同的shell下令,hello也有不同的相应结果。
(第6章1分)


7hello的存储管理


7.1 hello的存储器所在空间

1)逻辑所在:程序经过编译后出现在汇编代码中的所在。逻辑所在用来指定一个操纵数或者是一条指令的所在。是由一个段标识符加上一个指定段内相对所在的偏移量,表示为 段标识符:段内偏移量。
2)线性所在:逻辑所在向物理所在转化过程中的一步,逻辑所在经过段机制后转化为线性所在,为形貌符:偏移量的组合情势,分页机制中线性所在作为输入。
3)假造所在:就是线性所在。
4)物理所在:CPU通过所在总线的寻址,找到真实的物理内存对应所在。CPU对内存的访问是通过连接着CPU和北桥芯片的前端总线来完成的。在前端总线上传输的内存所在都是物理内存所在。


7.2 Intel逻辑所在到线性所在的变换-段式管理

在 Intel 平台下,逻辑所在(logical address)是 selectorffset 这种情势,selector 是 CS 寄存器的值,offset 是 EIP 寄存器的值。如果用 selector 去 GDT( 全局形貌符表 ) 里拿到 segment base address(段基址) 然后加上 offset(段内偏移),这就得到了 linear address。我们把这个过程称作段式内存管理。
    一个逻辑所在由段标识符和段内偏移量构成。段标识符是一个16位长的字段(段选择符)。可以通过段标识符的前13位,直接在段形貌符表中找到一个详细的段形貌符,这个形貌符就形貌了一个段。
    全局的段形貌符,放在“全局段形貌符表(GDT)”中,一些局部的段形貌符,放在“局部段形貌符表(LDT)”中。
    给定一个完备的逻辑所在段选择符+段内偏移所在,看段选择符的T1=0还是1,知道当前要转换是GDT中的段,还是LDT中的段,再根据相应寄存器,得到其所在和大小。拿出段选择符中前13位,可以在这个数组中,查找到对应的段形貌符,就得到了其基所在。Base + offset = 线性所在。




7.3 Hello的线性所在到物理所在的变换-页式管理

线性所在即假造所在(VA)到物理所在(PA)之间的转换通过分页机制完成,而分页机制是对假造所在内存空间举行分页。

系统将假造页作为举行数据传输的单元。Linux下每个假造页大小为4KB。物理内存也被分割为物理页, MMU(内存管理单元)负责所在翻译,MMU使用页表将假造页到物理页的映射,即假造所在到物理所在的映射。

n位的假造所在包罗两个部门:一个p位的假造页面偏移(VPO),一个n-p位的假造页号(VPN),MMU使用VPN选择得当的PTE,根据PTE,我们知道假造页的信息,如果假造页是已缓存的,那直接将页表条目的物理页号和假造所在的VPO串联起来就得到一个相应的物理所在。VPO和PPO是雷同的。如果假造页是未缓存的,会触发一个缺页故障。调用一个缺页处理子程序将磁盘的假造页重新加载到内存中,然后再实行这个导致缺页的指令
7.4 TLB与四级页表支持下的VA到PA的变换

 7.4.1 翻译后备缓冲器

   每次CPU产生一个假造所在,MMU(内存管理单元)就必须查阅一个PTE(页表条目),以便将假造所在翻译为物理所在。在最糟糕的环境下,这会从内存多取一次数据,代价是几十到几百个周期。如果PTE可巧缓存在L1中,那么开销就会下降1或2个周期。然而,很多系统都试图消除纵然是这样的开销,它们在MMU中包罗了一个关于PTE的小的缓存,称为翻译后备缓存器(TLB)。

    7.4.2 多级页表:

将假造所在的VPN划分为相等大小的不同的部门,每个部门用于寻找由上一级确定的页表基址对应的页表条目。

7.4.3 VA到PA的变换

处理器天生一个假造所在,并将其传送给MMU。MMU用VPN向TLB请求对应的PTE,如果命中,则跳过之后的几步。MMU天生PTE所在(PTEA).,并从高速缓存/主存请求得到PTE。如果请求不成功,MMU向主存请求PTE,高速缓存/主存向MMU返回PTE。PTE的有效位为零, 因此 MMU触发缺页非常,缺页处理程序确定物理内存中的牺牲页 (若页面被修改,则换出到磁盘——写回战略)。缺页处理程序调入新的页面,并更新内存中的PTE。缺页处理程序返回到原来进程,再次实行导致缺页的指令。在多级页表的环境下,无非就是不断通过索引 – 所在 – 索引 - 所在重复四次举行寻找。



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

获得物理所在之后,先取出组索引对应位,在L1中寻找对应组。如果存在,则比力标记位,相等后检查有效位是否为1.如果都满意则命中取出值传给CPU,否则按次序对L2cache、L3cache、内存举行雷同操纵,直到出现命中。然后再一级一级向上传,如果有空闲块则将目标块放置到空闲块中,否则将缓存中的某个块驱逐,将目标块放到被驱逐块的位置。
7.6 hello进程fork时的内存映射

在shell输入下令行后,内核调用fork创建子进程,为hello程序的运行创建上下文,并分配一个与父进程不同的PID。同时为这个新进程创建假造内存,创建当前进程的mm_struct、地域布局和页表的原样副本。它将两个进程中的每个页面都标记位只读,并将两个进程中的每个地域布局都标记为私有的写时复制。

当fork在新进程中返回时,新进程现在的假造内存刚好和调用fork时存在的假造内存雷同。当这两个进程中的任一个后来举行写操纵时,写时复制机制就会创建新页面。
7.7 hello进程execve时的内存映射

execve 函数调用驻留在内核地域的启动加载器代码,在当前进程中加载并运 行包罗在可实行目标文件 hello 中的程序,用 hello 程序有效地替代了当出息序。 它大概会主动覆盖当前进程中的所有假造所在和空间,删除当前进程假造所在的所有效户假造和部门空间中的已存在的代码共享地域和布局,但它不会主动创建一个新的代码共享进程。
加载并运行 hello 需要以下几个步调:
    删除当前进程假造所在中已存在的用户地域
    映射私有地域,为新程序的代码、数据、bss和栈创建新的地域布局。
    映射共享地域,将hello与libc.so动态链接,然后再映射到假造所在空间中的共享地域。
    设置当前进程上下文程序计数器(PC),使之指向代码地域的入口点。
7.8 缺页故障与缺页停止处理

页面命中完全是由硬件完成的,而处理缺页是由硬件和操纵系统内核协作完成的,在指令请求一个假造所在时,MMU中查找页表,如果这时对应得物理所在没有存在主存的内部,我们必须要从磁盘中读出数据。在假造内存的习惯说法中,DRAM缓存不命中成为缺页。在发生缺页后系统会调用内核中的一个缺页处理程序,选择一个页面作为牺牲页面。详细流程如下


  • 处理器天生一个假造所在,并将它传送给MMU
  • MMU天生PTE所在,并从高速缓存/主存请求得到它
  • 高速缓存/主存向MMU返回PTE
  • PTE中的有效位是0,以是MMU出发了一次非常,通报CPU中的控制到操纵系统内核中的缺页非常处理程序。
  • 缺页处理程序确认出物理内存中的牺牲页,如果这个页已经被修改了,则把它换到磁盘。
  • 缺页处理程序页面调入新的页面,并更新内存中的PTE。
  • 缺页处理程序返回到原来的进程,再次实行导致缺页的下令。CPU将引起缺页的假造所在重新发送给MMU。因为假造页面已经换存在物理内存中,以是就会命中。
7.9动态存储分配管理

动态内存管理的根本方法与战略:
动态内存分配器维护着一个进程的假造内存地域,称为堆,系统之间细节不同,但是不失通用性,假设堆是一个请求二进制零的地域,它紧接在未初始化的数据地域后开始,并向上生长(向更高所在)。对于每个进程,内核维护着一个变量brk,它指向对的顶部。
分配器将堆视为一组不同大小的块的集合来维护。每个块就是一个个连续的假造内存片,要么是已分配的,要么是空闲的。已分配的块显示地保留为供应用程序使用。空闲块可用来分配。空闲块保持空闲,直到它显示地被应用所分配。一个已分配的块保持已分配状态,直到它被释放,这种释放要么是应用程序显示实行的。要么是内存分配器自身隐式实行的。分配器有两种根本风格。两种风格都要求应用显示地分配块。他们的不同之处在于由哪个实体来负责释放已分配的块。
1.显示分配器:要求应用显示的释放任何已分配的块。比方C标准库提供一个叫做malloc程序包的显示分配器。
2.隐式分配器:要求分配器检测一个已分配块何时不再被程序使用,那么就释放这个块。隐式分配器也叫垃圾收集器。
①隐式空闲链表的堆块格式:

②隐式空闲链表的带边界标记的堆块格式:

使用边界标记的堆块的格式其中头部和脚部门别存放了当前内存块的大小与是否已分配的信息。通过这种布局,隐式动态内存分配器会对堆举行扫描,通过头部和脚部的布局实现查找。
使用双向链表而不是隐式空闲链表,使初次适配的分配时间从块总数的线性时间淘汰到了空闲块数目的线性时间。维护链表的次序有:后进先出(LIFO),将新释放的块放置在链表的开始处,使用LIFO的次序和初次适配的放置战略,分配器会最先检查最近使用过的块,在这种环境下,释放一个块可以在线性的时间内完成,如果使用了边界标记,那么合并也可以在常数时间内完成。按照所在次序来维护链表,其中链表中的每个块的所在都小于它的后继的所在,在这种环境下,释放一个块需要线性时间的搜索来定位合适的前驱。平衡点在于,按照所在排序初次适配比LIFO排序的初次适配有着更高的内存使用率,接近最佳适配的使用率。
7.10本章小结

本章先容了存储器所在空间、段式管理、页式管理,VA 到 PA 的变换、物理内存访问, hello 进程fork时和execve 时的内存映射、缺页故障与缺页停止处理、包罗隐式空闲链表和显式空闲链表的动态存储分配管理。
(第7章 2分)

8hello的IO管理


8.1 Linux的IO设备管理方法

设备的模子化: Linux将文件所有的I/O设备都模子化为文件,甚至内核也被映射为文件。这种将设备优雅地映射为文件的方式,允许Linux内核引出一个简单、低级的应用接口,称为Unix I/O。Linux就是基于Unix I/O实现对设备的管理。
设备的模子化:文件
设备管理:unix io接口
8.2 简述Unix IO接口及其函数

Unix IO接口:

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

    2.Linux Shell创建的每个进程都有三个打开的文件:标准输入(形貌符为0),标准输出(形貌符为1),标准错误(形貌符为2)。

    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)

    进程通过调用close函数关闭一个打开的文件,fd是需要关闭的文件的形貌符。


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




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

8.3 printf的实现分析

源代码:



从vsprintf天生显示信息,到write系统函数,到陷阱-系统调用 int 0x80或syscall等.
字符显示驱动子程序:从ASCII到字模库到显示vram(存储每一个点的RGB颜色信息)。
显示芯片按照刷新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量)。






8.4 getchar的实现分析

当程序调用getchar时,程序等待用户按键,用户输入的字符被存放在键盘缓冲区中直到用户按回车(回车也在缓冲区中)。

当用户键入回车之后,getchar才开始从stdio流中每次读入一个字符。getchar函数的返回值是用户输入的第一个字符的ascii码,如出错返回-1,且将用户输入的字符回显到屏幕。如用户在按回车之前输入了不止一个字符,其他字符会保留在键盘缓存区中,等待后续getchar调用读取。也就是说,后续的getchar调用不会等待用户按键,而直接读取缓冲区中的字符,直到缓冲区中的字符读完为后,才等待用户按键。
异步非常-键盘停止的处理:当用户按键时触发键盘终端,操纵系统将控制转移到键盘停止处理子程序,停止处理程序实行,继承按键扫描码转成ascii码,生存到系统的键盘缓冲区,显示在用户输入的终端内。当停止处理程序实行完毕后,返回到下一条指令运行。
8.5本章小结

本章先容了Linux的IO设备管理方法,Unix IO接口及其函数,分析了printf函数和getchar函数的实现。
(第8章1分)
















结论

用计算机系统的语言,总结hello的一生:
    
预处理
hello.c预处理到hello.i文本文件
编译
hello.i编译到hello.s汇编文件
汇编
hello.s汇编到二进制可重定位目标文件hello.o
链接
hello.o链接天生可实行文件hello
创建子进程
bash进程调用fork函数,天生子进程
加载程序
execve函数加载运行当前进程的上下文中加载并运行新程序hello
访问内存
hello的运行需要所在的概念,假造所在是计算机系统最伟大的抽象
交互
hello的输入输出与外界交互,与linux I/O痛痒相关
终止
hello最终被shell父进程回收,内核会收回为其创建的所有信息

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

附件

hello.c 源文件
hello.i 预编译结果
hello.s 编译结果
hello.o 汇编结果
hello.exe 链接结果
hello_txt  hello.exe的反汇编文件
hello.elf  hello.o的elf情势
(附件0分,缺失 -1分)


参考文献


为完资本次大作业你翻阅的册本与网站等


[1]  深入明确计算机系统原书第3版-笔墨版.pdf
[2]  https://www.cnblogs.com/diaohaiwei/p/5094959.html 内存管理
[3]  https://www.cnblogs.com/pianist/p/3315801.html printf函数的实现分析
[4]  内存所在转换与分段_内存的所在变幻-CSDN博客 内存所在的转换
[5]  fork()创建子进程步调、函数用法及常见考点(内附fork()过程图)_子进程创建时的第一个函数-CSDN博客 fork创建子进程

(参考文献0分,缺失 -1分)



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

伤心客

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表