CSAPP 大作业

计算机系统

大作业

题     目  程序人生-Hello’s P2P 

专       业     计算机科学与技术  

学     号       1190202402       

班     级         1936602       

学       生         李培意      

指 导 教 师          刘宏伟       

计算机科学与技术学院

2021年6月

摘  要

从hello这一文件看到一个程序背后的故事。围绕我们每个程序员最先写下的能正常运行的程序hello,透过其整个生命的流程,分析出其背后的种种过程以及各种系统中的管理,来反馈出计算机系统这一复杂系统的理解。也了解硬件,操作系统,程序之间的配合关系。也让hello从编程软件中脱离出来,经历预处理、编译、汇编、再到链接。成为一个系统可运行的程序。也从系统的进程管理,存储管理,IO的管理角度进行分析。以及最后被系统回收。从hello的一生,来看计算机系统的运行。

关键词:hello的一生;计算机系统;存储管理;进程管理;预处理、编译、汇编、链接;                            

(摘要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 -

第1章 概述

1.1 Hello简介

根据Hello的自白,利用计算机系统的术语,简述Hello的P2P,020的整个过程。

P2P:From Program to process:

Hello刚开始只是一段C语言代码,存于内存当中,也就是最初的hello.c程序,也就是最初的program。编译器驱动程序。然后编译器驱动程序在需要时候调用预处理器、编译器、汇编器和链接器。首先是预处理器(cpp)将C语言源程序hello.c预处理为一个中间文件;编译器(ccl)将该中间文件翻译为一个汇编语言文件;汇编器(as)将汇编语言文件翻译为可重定位目标文件;最后链接器(ld)创建一个可执行目标文件。可以通过shell创建一个子进程运行该可执行目标文件。

020:From Zero-0 to Zero-0

运行可执行目标文件,调用程序wxecve,一次进行对于虚拟内存的映射,物理内存载入,进入主程序运行代码,调用系统函数

1.2 环境与工具

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

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

开发与调试工具:gcc,vim,edb,readelf,HexEdit

1.3 中间结果

hello.c   (C语言源程序)

hello.i   (hello.c预处理之后的中间文件)

hello.s   (hello.i编译成汇编语言之后的汇编语言文件)

hello.o   (hello.s生成的二进制文件,也就是可重定位目标文件)

hello    (可执行目标文件)

1.4 本章小结

介绍了Hello的基本信息,介绍了实验的基本环境工具,以及可能生成的实验的中间结果。

(第1章0.5分)

第2章 预处理

2.1 预处理的概念与作用

以下格式自行编排,编辑时删除

预处理的概念:预处理器根据字符#开头的命令,修改原始程序,将引用的库合并成完整文件。

C语言的预处理主要有三个方面的内容:

1.宏定义(#define);

2.文件包含(#include);

3.条件编译(#ifdef/#ifndef/#if/#else/#elseif/#endif);

C预处理器是C语言、C++语言的预处理器。用于在编译器处理程序之前预扫描源代码,完成头文件的包含, 宏扩展, 条件编译, 行控制(line control)等操作。

这样做的目的是使得编译器在对程序进行翻译的时候更加方便。

2.2在Ubuntu下预处理的命令

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

应截图,展示预处理过程!

2.3 Hello的预处理结果解析

原本只有几行的源代码扩展到了3000多行并且在在原有的代码基础上加入了系统库中包含的typedef,结构体,以及外部引用符号。另外还添加了以#开头的语句,这些都是用来辅助表示代码是源自哪个文件以及行号的。

typedef

结构体,#语句

2.4 本章小结

本章介绍了C预处理的概念和作用。展示了用linux虚拟机进行预处理的过程以及结果,还有对该结果的分析

以下格式自行编排,编辑时删除

(第2章0.5分)

第3章 编译

3.1 编译的概念与作用

将某种高级程序设计语言翻译为低一级的汇编语言并生成汇编语言文件

是高级语言和机器语言之间的媒介,方便程序进一步转换为机器可读的语言。

注意:这儿的编译是指从 .i 到 .s 即预处理后的文件到生成汇编语言程序

       

3.2 在Ubuntu下编译的命令

编译命令:gcc -S hello.i -o hello.s

应截图,展示编译过程!

3.3 Hello的编译结果解析

编译结果:

      .file "hello.c"

      .text

      .globl     sleepsecs

      .data

      .align 4

      .type      sleepsecs, @object

      .size       sleepsecs, 4

sleepsecs:

      .long      2

      .section .rodata

      .align 8

.LC0:

      .string    "Usage: Hello 1190202402 \346\235\216\345\237\271\346\204\217\357\274\201"

.LC1:

      .string    "Hello %s %s\n"

      .text

      .globl     main

      .type      main, @function

main:

.LFB6:

      .cfi_startproc

      endbr64

      pushq    %rbp

      .cfi_def_cfa_offset 16

      .cfi_offset 6, -16

      movq     %rsp, %rbp

      .cfi_def_cfa_register 6

      subq      $32, %rsp

      movl      %edi, -20(%rbp)

      movq     %rsi, -32(%rbp)

      cmpl      $3, -20(%rbp)

      je    .L2

      leaq .LC0(%rip), %rdi

      call puts@PLT

      movl      $1, %edi

      call exit@PLT

.L2:

      movl      $0, -4(%rbp)

      jmp .L3

.L4:

      movq     -32(%rbp), %rax

      addq      $16, %rax

      movq     (%rax), %rdx

      movq     -32(%rbp), %rax

      addq      $8, %rax

      movq     (%rax), %rax

      movq     %rax, %rsi

      leaq .LC1(%rip), %rdi

      movl      $0, %eax

      call printf@PLT

      movl      sleepsecs(%rip), %eax

      movl      %eax, %edi

      call sleep@PLT

      addl $1, -4(%rbp)

.L3:

      cmpl      $9, -4(%rbp)

      jle   .L4

      call getchar@PLT

      movl      $0, %eax

      leave

      .cfi_def_cfa 7, 8

      ret

      .cfi_endproc

.LFE6:

      .size       main, .-main

      .ident     "GCC: (Ubuntu 10.3.0-1ubuntu1~20.10) 10.3.0"

      .section .note.GNU-stack,"",@progbits

      .section .note.gnu.property,"a"

      .align 8

      .long      1f - 0f

      .long      4f - 1f

      .long      5

0:

      .string    "GNU"

1:

      .align 8

      .long      0xc0000002

      .long      3f - 2f

2:

      .long      0x3

3:

      .align 8

4:

  1. 全局变量:全局变量在data节中定义它,并且解释了它。

.globl     sleepsecs

  1. 局部变量:局部变量会在栈中储存它,给他分配一个大小符合的字节大小。

argc/argv 调用main函数里传入的参数,存放在%rdi中

主函数:

main:

.LFB6:

       .cfi_startproc

       endbr64

       pushq    %rbp

       .cfi_def_cfa_offset 16

       .cfi_offset 6, -16

       movq     %rsp, %rbp

       .cfi_def_cfa_register 6

       subq      $32, %rsp

       movl      %edi, -20(%rbp)

       movq     %rsi, -32(%rbp)

       cmpl      $3, -20(%rbp)

       je    .L2

       leaq .LC0(%rip), %rdi

       call puts@PLT

       movl      $1, %edi

       call exit@PLT

其余略,

rdi和rsi均为从堆栈中调用数据

   i 局部变量,在循环中出现,作为每次循环更新的变量 保存在%ebx中

  1. 赋值

.long      2(全局变量赋值)

movl      $0, -4(%rbp) (局部变量赋值)

4.类型转换

   .type      sleepsecs, @object

      .size       sleepsecs, 4

sleepsecs:

      .long      2

  

movl    sleepsecs(%rip), %eax

      movl      %eax, %edi

  1. 算数操作

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

addq $16, %rax

addq $8, %rax

subq $32, %rsp

  1. 关系操作

cmpl      $9, -4(%rbp)(循环中的<操作

cmpl      $3, -20(%rbp) (if语句)

  1. 控制转移

je    .L2 根据条件进行跳转

jmp .L3

ret 返回

  1. 函数操作

call puts@PLT

call exit@PLT

call sleep@PLT

call getchar@PLT

  1. 头部

.file:    说明文件名字为从hello.c编译而来

.text              代码段

.globl     全局变量:说明sleepsecs是全局变量

.data      数据段

.align     对齐方式,.align 4说明是按四个字节对齐

.type    sleepsec,说明这个变量是对象类型

.size       大小,说明这个变量占用的大小为4字节

.long      说明sleepsec的类型是long

.section 说明sleepsecs的节在于只读数据段

注意 main为全局符号在.text段中

3.4 本章小结

介绍了编译的概念及其作用,利用汇编文件解析了汇编文件中各部分的作用,并与源程序对比,看汇编文件有哪些方面不同,从汇编文件中看源程序。

(第32分)

第4章 汇编

4.1 汇编的概念与作用

通过汇编器,将汇编语言翻译成机器语言,并生成机器语言的二进制程序

转化为了机器能够理解的二进制文本,方便程序的执行。

4.2 在Ubuntu下汇编的命令

汇编命令:as hello.s -o hello.o

应截图,展示汇编过程!

4.3 可重定位目标elf格式

分析hello.o的ELF格式,用readelf等列出其各节的基本信息,特别是重定位项目分析。

由图可知,ELF头以一个16字节的序列开始,这个序列描述了生成该文件的系统的字的大小和字节顺序。ELF头剩下的部分包含帮助链接器语法分析和解释目标文件的信息。其中包括ELF头的大小、目标文件的类型(如可重定位、可执行或共享的)、机器类型(如x86-64)、节头部表(section header table)的文件偏移,以及节头部表中条目的大小和数量。不同节的位置和大小是由节头部表描述的,其中目标文件中每个节都有一个固定大小的头目(entry

节头部表,描述了每个节的名字,种类,地址偏移,大小,全体大小,flag,链接,信息,对齐。

但没有这些头:

重定位节:有静态链接内容pc也有动态链接内容plt,也存在一个异常处理单元

符号表

4.4 Hello.o的结果解析

hello.o:     文件格式 elf64-x86-64

Disassembly of section .text:

0000000000000000 <main>:

   0:    f3 0f 1e fa               endbr64

   4:    55                          push   %rbp

   5:    48 89 e5               mov    %rsp,%rbp

   8:    48 83 ec 20             sub    $0x20,%rsp

   c:    89 7d ec               mov    %edi,-0x14(%rbp)

   f:    48 89 75 e0             mov    %rsi,-0x20(%rbp)

  13:    83 7d ec 03             cmpl   $0x3,-0x14(%rbp)

  17:    74 16                je     2f <main+0x2f>

  19:    48 8d 3d 00 00 00 00       lea    0x0(%rip),%rdi        # 20 <main+0x20>

                    1c: R_X86_64_PC32 .rodata-0x4

  20:    e8 00 00 00 00           callq  25 <main+0x25>

                    21: R_X86_64_PLT32      puts-0x4

  25:    bf 01 00 00 00            mov    $0x1,%edi

  2a:    e8 00 00 00 00           callq  2f <main+0x2f>

                    2b: R_X86_64_PLT32      exit-0x4

  2f:    c7 45 fc 00 00 00 00 movl   $0x0,-0x4(%rbp)

  36:    eb 3b                jmp    73 <main+0x73>

  38:    48 8b 45 e0             mov    -0x20(%rbp),%rax

  3c:    48 83 c0 10             add    $0x10,%rax

  40:    48 8b 10               mov    (%rax),%rdx

  43:    48 8b 45 e0             mov    -0x20(%rbp),%rax

  47:    48 83 c0 08             add    $0x8,%rax

  4b:    48 8b 00               mov    (%rax),%rax

  4e:    48 89 c6               mov    %rax,%rsi

  51:    48 8d 3d 00 00 00 00       lea    0x0(%rip),%rdi        # 58 <main+0x58>

                    54: R_X86_64_PC32 .rodata+0x21

  58:    b8 00 00 00 00           mov    $0x0,%eax

  5d:    e8 00 00 00 00           callq  62 <main+0x62>

                    5e: R_X86_64_PLT32      printf-0x4

  62:    8b 05 00 00 00 00         mov    0x0(%rip),%eax        # 68 <main+0x68>

                    64: R_X86_64_PC32 sleepsecs-0x4

  68:    89 c7                mov    %eax,%edi

  6a:    e8 00 00 00 00           callq  6f <main+0x6f>

                    6b: R_X86_64_PLT32      sleep-0x4

  6f:    83 45 fc 01              addl   $0x1,-0x4(%rbp)

  73:    83 7d fc 09              cmpl   $0x9,-0x4(%rbp)

  77:    7e bf                  jle    38 <main+0x38>

  79:    e8 00 00 00 00           callq  7e <main+0x7e>

                    7a: R_X86_64_PLT32      getchar-0x4

  7e:    b8 00 00 00 00           mov    $0x0,%eax

  83:    c9                   leaveq

  84:    c3                   retq  

  1. 十进制数被翻译为了16进制数
  2. 一些符号信息已经被放入了表中,特别是引用函数中的符号的重定位信息
  3. 堆栈申请大小不同
  4. 没有再细分便于理解的各种段
  5. 地址由相对偏移量转变为了可由cpu直接访问的虚拟地址
  6. 跳转指令的变化

4.5 本章小结

对汇编的概念以及作用的叙述,并且在linux虚拟机中进行了演示,并探究了重定位前和重定位后反汇编的汇编程序的差异。分析了ELF格式文件的组成。

(第41分)

5章 链接

5.1 链接的概念与作用

链接是将各种代码和数据片段收集并组合成一个单一文件的过程,将一个或多个由编译器或汇编器生成的目标文件外加库,链接为一个可执行文件。这个文件可以被加载到内存并执行。链接可以在编译时实现,也就是在源代码被翻译成机器代码时,也可以在加载时实现,也就是在程序被加载器加载到内存并执行时,甚至可以在运行时实现,也就是由应用程序来执行。

产生一个可以直接被加载到内存并执行的文件。

5.2 在Ubuntu下链接的命令

链接命令:gcc hello.o -o hello

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

   

5.4 hello的虚拟地址空间

   

前四行为堆栈分配的虚拟空间。

5.5 链接的重定位过程分析

以下格式自行编排,编辑时删除

hello:     文件格式 elf64-x86-64

Disassembly of section .init:

0000000000001000 <_init>:

    1000:   f3 0f 1e fa               endbr64

    1004:   48 83 ec 08             sub    $0x8,%rsp

    1008:   48 8b 05 d9 2f 00 00        mov    0x2fd9(%rip),%rax        # 3fe8 <__gmon_start__>

    100f:   48 85 c0               test   %rax,%rax

    1012:   74 02                je     1016 <_init+0x16>

    1014:   ff d0                  callq  *%rax

    1016:   48 83 c4 08             add    $0x8,%rsp

    101a:   c3                   retq  

Disassembly of section .plt:

0000000000001020 <.plt>:

    1020:   ff 35 7a 2f 00 00    pushq  0x2f7a(%rip)        # 3fa0 <_GLOBAL_OFFSET_TABLE_+0x8>

    1026:   f2 ff 25 7b 2f 00 00   bnd jmpq *0x2f7b(%rip)        # 3fa8 <_GLOBAL_OFFSET_TABLE_+0x10>

    102d:   0f 1f 00                nopl   (%rax)

    1030:   f3 0f 1e fa               endbr64

    1034:   68 00 00 00 00           pushq  $0x0

    1039:   f2 e9 e1 ff ff ff       bnd jmpq 1020 <.plt>

    103f:   90                          nop

    1040:   f3 0f 1e fa               endbr64

    1044:   68 01 00 00 00           pushq  $0x1

    1049:   f2 e9 d1 ff ff ff       bnd jmpq 1020 <.plt>

    104f:   90                          nop

    1050:   f3 0f 1e fa               endbr64

    1054:   68 02 00 00 00           pushq  $0x2

    1059:   f2 e9 c1 ff ff ff       bnd jmpq 1020 <.plt>

    105f:   90                          nop

    1060:   f3 0f 1e fa               endbr64

    1064:   68 03 00 00 00           pushq  $0x3

    1069:   f2 e9 b1 ff ff ff       bnd jmpq 1020 <.plt>

    106f:   90                          nop

    1070:   f3 0f 1e fa               endbr64

    1074:   68 04 00 00 00           pushq  $0x4

    1079:   f2 e9 a1 ff ff ff       bnd jmpq 1020 <.plt>

    107f:   90                          nop

Disassembly of section .plt.got:

0000000000001080 <__cxa_finalize@plt>:

    1080:   f3 0f 1e fa               endbr64

    1084:   f2 ff 25 6d 2f 00 00   bnd jmpq *0x2f6d(%rip)        # 3ff8 <__cxa_finalize@GLIBC_2.2.5>

    108b:   0f 1f 44 00 00            nopl   0x0(%rax,%rax,1)

Disassembly of section .plt.sec:

0000000000001090 <puts@plt>:

    1090:   f3 0f 1e fa               endbr64

    1094:   f2 ff 25 15 2f 00 00   bnd jmpq *0x2f15(%rip)        # 3fb0 <puts@GLIBC_2.2.5>

    109b:   0f 1f 44 00 00            nopl   0x0(%rax,%rax,1)

00000000000010a0 <printf@plt>:

    10a0:   f3 0f 1e fa               endbr64

    10a4:   f2 ff 25 0d 2f 00 00   bnd jmpq *0x2f0d(%rip)        # 3fb8 <printf@GLIBC_2.2.5>

    10ab:   0f 1f 44 00 00            nopl   0x0(%rax,%rax,1)

00000000000010b0 <getchar@plt>:

    10b0:   f3 0f 1e fa               endbr64

    10b4:   f2 ff 25 05 2f 00 00   bnd jmpq *0x2f05(%rip)        # 3fc0 <getchar@GLIBC_2.2.5>

    10bb:   0f 1f 44 00 00            nopl   0x0(%rax,%rax,1)

00000000000010c0 <exit@plt>:

    10c0:   f3 0f 1e fa               endbr64

    10c4:   f2 ff 25 fd 2e 00 00   bnd jmpq *0x2efd(%rip)        # 3fc8 <exit@GLIBC_2.2.5>

    10cb:   0f 1f 44 00 00            nopl   0x0(%rax,%rax,1)

00000000000010d0 <sleep@plt>:

    10d0:   f3 0f 1e fa               endbr64

    10d4:   f2 ff 25 f5 2e 00 00   bnd jmpq *0x2ef5(%rip)        # 3fd0 <sleep@GLIBC_2.2.5>

    10db:   0f 1f 44 00 00            nopl   0x0(%rax,%rax,1)

Disassembly of section .text:

00000000000010e0 <_start>:

    10e0:   f3 0f 1e fa               endbr64

    10e4:   31 ed                xor    %ebp,%ebp

    10e6:   49 89 d1               mov    %rdx,%r9

    10e9:   5e                   pop    %rsi

    10ea:   48 89 e2               mov    %rsp,%rdx

    10ed:   48 83 e4 f0              and    $0xfffffffffffffff0,%rsp

    10f1:   50                          push   %rax

    10f2:   54                          push   %rsp

    10f3:   4c 8d 05 c6 01 00 00       lea    0x1c6(%rip),%r8        # 12c0 <__libc_csu_fini>

    10fa:    48 8d 0d 4f 01 00 00        lea    0x14f(%rip),%rcx        # 1250 <__libc_csu_init>

    1101:   48 8d 3d c1 00 00 00       lea    0xc1(%rip),%rdi        # 11c9 <main>

    1108:   ff 15 d2 2e 00 00           callq  *0x2ed2(%rip)        # 3fe0 <__libc_start_main@GLIBC_2.2.5>

    110e:   f4                   hlt   

    110f:    90                          nop

0000000000001110 <deregister_tm_clones>:

    1110:   48 8d 3d 01 2f 00 00        lea    0x2f01(%rip),%rdi        # 4018 <__TMC_END__>

    1117:   48 8d 05 fa 2e 00 00 lea    0x2efa(%rip),%rax        # 4018 <__TMC_END__>

    111e:   48 39 f8                cmp    %rdi,%rax

    1121:   74 15                je     1138 <deregister_tm_clones+0x28>

    1123:   48 8b 05 ae 2e 00 00        mov    0x2eae(%rip),%rax        # 3fd8 <_ITM_deregisterTMCloneTable>

    112a:   48 85 c0               test   %rax,%rax

    112d:   74 09                je     1138 <deregister_tm_clones+0x28>

    112f:    ff e0                   jmpq   *%rax

    1131:   0f 1f 80 00 00 00 00 nopl   0x0(%rax)

    1138:   c3                   retq  

    1139:   0f 1f 80 00 00 00 00 nopl   0x0(%rax)

0000000000001140 <register_tm_clones>:

    1140:   48 8d 3d d1 2e 00 00       lea    0x2ed1(%rip),%rdi        # 4018 <__TMC_END__>

    1147:   48 8d 35 ca 2e 00 00        lea    0x2eca(%rip),%rsi        # 4018 <__TMC_END__>

    114e:   48 29 fe                sub    %rdi,%rsi

    1151:   48 89 f0                mov    %rsi,%rax

    1154:   48 c1 ee 3f              shr    $0x3f,%rsi

    1158:   48 c1 f8 03              sar    $0x3,%rax

    115c:   48 01 c6               add    %rax,%rsi

    115f:    48 d1 fe                sar    %rsi

    1162:   74 14                je     1178 <register_tm_clones+0x38>

    1164:   48 8b 05 85 2e 00 00       mov    0x2e85(%rip),%rax        # 3ff0 <_ITM_registerTMCloneTable>

    116b:   48 85 c0               test   %rax,%rax

    116e:   74 08                je     1178 <register_tm_clones+0x38>

    1170:   ff e0                   jmpq   *%rax

    1172:   66 0f 1f 44 00 00          nopw   0x0(%rax,%rax,1)

    1178:   c3                   retq   

    1179:   0f 1f 80 00 00 00 00 nopl   0x0(%rax)

0000000000001180 <__do_global_dtors_aux>:

    1180:   f3 0f 1e fa               endbr64

    1184:   80 3d 89 2e 00 00 00       cmpb   $0x0,0x2e89(%rip)        # 4014 <completed.0>

    118b:   75 2b                jne    11b8 <__do_global_dtors_aux+0x38>

    118d:   55                          push   %rbp

    118e:   48 83 3d 62 2e 00 00       cmpq   $0x0,0x2e62(%rip)        # 3ff8 <__cxa_finalize@GLIBC_2.2.5>

    1195:   00

    1196:   48 89 e5               mov    %rsp,%rbp

    1199:   74 0c                je     11a7 <__do_global_dtors_aux+0x27>

    119b:   48 8b 3d 66 2e 00 00       mov    0x2e66(%rip),%rdi        # 4008 <__dso_handle>

    11a2:   e8 d9 fe ff ff       callq  1080 <__cxa_finalize@plt>

    11a7:   e8 64 ff ff ff       callq  1110 <deregister_tm_clones>

    11ac:   c6 05 61 2e 00 00 01       movb   $0x1,0x2e61(%rip)        # 4014 <completed.0>

    11b3:   5d                          pop    %rbp

    11b4:   c3                   retq  

    11b5:   0f 1f 00                nopl   (%rax)

    11b8:   c3                    retq  

    11b9:   0f 1f 80 00 00 00 00 nopl   0x0(%rax)

00000000000011c0 <frame_dummy>:

    11c0:   f3 0f 1e fa               endbr64

    11c4:   e9 77 ff ff ff       jmpq   1140 <register_tm_clones>

00000000000011c9 <main>:

    11c9:   f3 0f 1e fa               endbr64

    11cd:   55                          push   %rbp

    11ce:   48 89 e5               mov    %rsp,%rbp

    11d1:   48 83 ec 20             sub    $0x20,%rsp

    11d5:   89 7d ec               mov    %edi,-0x14(%rbp)

    11d8:   48 89 75 e0             mov    %rsi,-0x20(%rbp)

    11dc:   83 7d ec 03             cmpl   $0x3,-0x14(%rbp)

    11e0:   74 16                je     11f8 <main+0x2f>

    11e2:   48 8d 3d 1f 0e 00 00        lea    0xe1f(%rip),%rdi        # 2008 <_IO_stdin_used+0x8>

    11e9:   e8 a2 fe ff ff       callq  1090 <puts@plt>

    11ee:   bf 01 00 00 00            mov    $0x1,%edi

    11f3:    e8 c8 fe ff ff       callq  10c0 <exit@plt>

    11f8:    c7 45 fc 00 00 00 00 movl   $0x0,-0x4(%rbp)

    11ff:    eb 3b                jmp    123c <main+0x73>

    1201:   48 8b 45 e0             mov    -0x20(%rbp),%rax

    1205:   48 83 c0 10             add    $0x10,%rax

    1209:   48 8b 10               mov    (%rax),%rdx

    120c:   48 8b 45 e0             mov    -0x20(%rbp),%rax

    1210:   48 83 c0 08             add    $0x8,%rax

    1214:   48 8b 00               mov    (%rax),%rax

    1217:   48 89 c6               mov    %rax,%rsi

    121a:   48 8d 3d 0c 0e 00 00       lea    0xe0c(%rip),%rdi        # 202d <_IO_stdin_used+0x2d>

    1221:   b8 00 00 00 00           mov    $0x0,%eax

    1226:   e8 75 fe ff ff        callq  10a0 <printf@plt>

    122b:   8b 05 df 2d 00 00          mov    0x2ddf(%rip),%eax        # 4010 <sleepsecs>

    1231:   89 c7                mov    %eax,%edi

    1233:   e8 98 fe ff ff       callq  10d0 <sleep@plt>

    1238:   83 45 fc 01              addl   $0x1,-0x4(%rbp)

    123c:   83 7d fc 09              cmpl   $0x9,-0x4(%rbp)

    1240:   7e bf                  jle    1201 <main+0x38>

    1242:   e8 69 fe ff ff       callq  10b0 <getchar@plt>

    1247:   b8 00 00 00 00           mov    $0x0,%eax

    124c:   c9                    leaveq

    124d:   c3                   retq  

    124e:   66 90                xchg   %ax,%ax

0000000000001250 <__libc_csu_init>:

    1250:   f3 0f 1e fa               endbr64

    1254:   41 57                push   %r15

    1256:   4c 8d 3d 3b 2b 00 00       lea    0x2b3b(%rip),%r15        # 3d98 <__frame_dummy_init_array_entry>

    125d:   41 56                push   %r14

    125f:   49 89 d6               mov    %rdx,%r14

    1262:   41 55                push   %r13

    1264:   49 89 f5                mov    %rsi,%r13

    1267:   41 54                push   %r12

    1269:   41 89 fc                mov    %edi,%r12d

    126c:   55                          push   %rbp

    126d:   48 8d 2d 2c 2b 00 00       lea    0x2b2c(%rip),%rbp        # 3da0 <__do_global_dtors_aux_fini_array_entry>

    1274:   53                          push   %rbx

    1275:   4c 29 fd                sub    %r15,%rbp

    1278:   48 83 ec 08             sub    $0x8,%rsp

    127c:   e8 7f fd ff ff       callq  1000 <_init>

    1281:   48 c1 fd 03              sar    $0x3,%rbp

    1285:   74 1f                  je     12a6 <__libc_csu_init+0x56>

    1287:   31 db                xor    %ebx,%ebx

    1289:   0f 1f 80 00 00 00 00 nopl   0x0(%rax)

    1290:   4c 89 f2                mov    %r14,%rdx

    1293:   4c 89 ee                mov    %r13,%rsi

    1296:   44 89 e7               mov    %r12d,%edi

    1299:   41 ff 14 df               callq  *(%r15,%rbx,8)

    129d:   48 83 c3 01             add    $0x1,%rbx

    12a1:   48 39 dd               cmp    %rbx,%rbp

    12a4:   75 ea                jne    1290 <__libc_csu_init+0x40>

    12a6:   48 83 c4 08             add    $0x8,%rsp

    12aa:   5b                          pop    %rbx

    12ab:   5d                          pop    %rbp

    12ac:   41 5c                pop    %r12

    12ae:   41 5d                pop    %r13

    12b0:   41 5e                pop    %r14

    12b2:   41 5f                  pop    %r15

    12b4:   c3                   retq  

    12b5:   66 66 2e 0f 1f 84 00 data16 nopw %cs:0x0(%rax,%rax,1)

    12bc:   00 00 00 00

00000000000012c0 <__libc_csu_fini>:

    12c0:   f3 0f 1e fa               endbr64

    12c4:   c3                   retq  

Disassembly of section .fini:

00000000000012c8 <_fini>:

    12c8:   f3 0f 1e fa               endbr64

    12cc:   48 83 ec 08             sub    $0x8,%rsp

    12d0:   48 83 c4 08             add    $0x8,%rsp

    12d4:   c3                   retq  

汇编代码段增加,增加了.init .plt .plt.sec .fini

.text段除了main增加了一些函数,如_start等

增加了外部的共享库函数

0000000000001090 <puts@plt>:

    1090:   f3 0f 1e fa               endbr64

    1094:   f2 ff 25 15 2f 00 00   bnd jmpq *0x2f15(%rip)        # 3fb0 <puts@GLIBC_2.2.5>

    109b:   0f 1f 44 00 00            nopl   0x0(%rax,%rax,1)

00000000000010a0 <printf@plt>:

    10a0:   f3 0f 1e fa               endbr64

    10a4:   f2 ff 25 0d 2f 00 00   bnd jmpq *0x2f0d(%rip)        # 3fb8 <printf@GLIBC_2.2.5>

    10ab:   0f 1f 44 00 00            nopl   0x0(%rax,%rax,1)

00000000000010b0 <getchar@plt>:

    10b0:   f3 0f 1e fa               endbr64

    10b4:   f2 ff 25 05 2f 00 00   bnd jmpq *0x2f05(%rip)        # 3fc0 <getchar@GLIBC_2.2.5>

    10bb:   0f 1f 44 00 00            nopl   0x0(%rax,%rax,1)

00000000000010c0 <exit@plt>:

    10c0:   f3 0f 1e fa               endbr64

    10c4:   f2 ff 25 fd 2e 00 00   bnd jmpq *0x2efd(%rip)        # 3fc8 <exit@GLIBC_2.2.5>

    10cb:   0f 1f 44 00 00            nopl   0x0(%rax,%rax,1)

00000000000010d0 <sleep@plt>:

    10d0:   f3 0f 1e fa               endbr64

    10d4:   f2 ff 25 f5 2e 00 00   bnd jmpq *0x2ef5(%rip)        # 3fd0 <sleep@GLIBC_2.2.5>

    10db:   0f 1f 44 00 00            nopl   0x0(%rax,%rax,1)

重定位

重定位节和符号:将所有类型相同的节合并在一起后,这个节就作为可执行目标文件的节。然后链接器把运行时的内存地址赋给新的聚合节,赋给输入模块定义的每个节,以及赋给输入模块定义的每个符号,当这一步完成时,程序中每条指令和全局变量都有唯一运行时的地址。也就是.text段中增加的一些新的函数,这些函数最终合并为同一聚合结。

重定位节中的符号引用:链接器修改代码节和数据节中对每个符号的引用,使得他们指向正确的运行地址。

5.6 hello的执行流程

 _start 0x00000000004010fe

 _libc_start_main 0x00007fffff5d70b3

main 0x0000000000401105

printf@plt 0x0000000000401090

sleep@plt  0x4010c0

getchar 0x7fffff63e6e0

_rtld_global_ro 0x7fffff7dd620

5.7 Hello的动态链接分析

 

地址在dl_init后被改写了

进入改写地址后发现进入了一个新的函数,并且实现了GOT的动态链接。PLT使用GOT中的地址跳转到目标函数。

5.8 本章小结

介绍了链接器的概念和作用,探讨了程序运行时的虚拟地址空间,分析了可执行文件的ELF,研究了重定位以及动态链接的过程。

(第51分)

6章 hello进程管理

6.1 进程的概念与作用

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

通过进程,我们会得到一种假象,好像我们的程序是当前唯一运行的程序,我们的程序独占处理器和内存,我们程序的代码和数据好像是系统内存中唯一的对象。

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

shell俗称壳,它是指UNIX系统下的一个命令解析器;主要用于用户和系统的交互。UNIX系统上有很多种Shell。首个shell,即Bourne Shell,于1978年在V7(AT&T的第7版)UNIX上推出。后来,又演变出C shell、bash等不同版本的shell。

Shell接受用户的命令并解释该命令然后将其送入内核执行。

处理流程::打印一个提示符,等待用户输入命令行,从终端读入输入的命令。将输入的命令行切分得出参数,如果是内置命令则立即执行,否则调用相应的程序为其分配子进程并运行,.shell应该接受键盘输入信号,并对这些信号进行相应处理。并最终回收。

6.3 Hello的fork进程创建过程

Shell调用fork函数创建子进程,形成自身的一个拷贝,为运行hello做准备

6.4 Hello的execve过程

Shell 调用execve 函数在当前进程的上下文中加载并运行一个新的程序,即hello程序

6.5 Hello的进程执行

逻辑控制流:即为一系列程序计数器PC的值序列进程是轮流使用处理器的,在同一个处理器核心中,每个进程执行它的流的一部分后被抢占(暂时挂起),然后轮到其他进程。

时间片:进程执行它的控制流的部分时间段。

用户模式和内核模式:用户模式即为未设置模式位,不允许执行特权指令直接引用地址空间中内核区内的代码和数据;内核模式为设置模式位时,该进程执行所有命令访问所有数据。

上下文信息:上下文就是内核重启被抢占的进程所需要的状态,它由通用寄存器等各种内核数据构成。分别三个步骤:

保存当前进程的上下文

恢复某个先前被抢占的进程被保存的上下文

将控制传递给这个新恢复的进程。

6.6 hello的异常与信号处理

正常运行:

乱按

回车

Ctrl+c

Ctrl+z

Ps:

Jobs:

Pstree:

Fg:

Kill

6.7本章小结

讨论了进程的概念和作用,简单介绍了shell以及其重要功能函数,最后进行了异常信号的处理。

(第61分)

7章 hello的存储管理

7.1 hello的存储器地址空间

逻辑地址:汇编程序中地址。逻辑地址由选择符和偏移量组成。是经过编译后出现在汇编程序中的地址。

线性地址:逻辑地址经过段机制后转化为线性地址,以描述符:偏移量的组合形式存在。分页机制中线性地址作为输入。

虚拟地址:类似于线性地址

物理地址:真实的物理内存对应地址。 CPU对内存的访问是通过连接着CPU和北桥芯片的前端总线来完成的。在前端总线上传输的内存地址都是物理内存地址

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

最初8086处理器的寄存器是16位的,为了能够访问更多的地址空间但不改变寄存器和指令的位宽,所以引入段寄存器,8086共设计了20位宽的地址总线,通过将段寄存器左移4位加上偏移地址得到20位地址,这个地址就是逻辑地址。将内存分为不同的段,段有段寄存器对应,段寄存器有一个栈、一个代码、两个数据寄存器。

分段功能在实模式和保护模式下有所不同。

实模式,即不设防,也就是说逻辑地址=线性地址=实际的物理地址。段寄存器存放真实段基址,同时给出32位地址偏移量,则可以访问真实物理内存。

在保护模式下,线性地址还需要经过分页机制才能够得到物理地址,线性地址也需要逻辑地址通过段机制来得到。段寄存器无法放下32位段基址,所以它们被称作选择符,用于引用段描述符表中的表项来获得描述符。描述符表中的一个条目描述一个段,构造如下:

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

线性地址到物理地址之间的转换通过分页机制完成。而分页机制是对虚拟地址内存空间进行分页。

首先Linux系统有自己的虚拟内存系统,Linux将虚拟内存组织成一些段的集合,段之外的虚拟内存不存在因此不需要记录。内核为hello进程维护一个段的任务结构即图中的task_struct,其中条目mm指向一个mm_struct,它描述了虚拟内存的当前状态,pgd指向第一级页表的基地址(结合一个进程一串页表),mmap指向一个vm_area_struct的链表,一个链表条目对应一个段,所以链表相连指出了hello进程虚拟内存中的所有段。

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

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

36位的虚拟地址被分割成4个9位的片。CR3寄存器包含L1页表的物理地址。VPN1有一个到L1 PTE的偏移量,找到这个PTE以后又会包含到L2页表的基础地址;VPN2包含一个到L2PTE的偏移量,找到这个PTE以后又会包含到L3页表的基础地址;VPN3包含一个到L3PTE的偏移量,找到这个PTE以后又会包含到L4页表的基础地址;VPN4包含一个到L4PTE的偏移量,找到这个PTE以后就是相应的PPN(物理页号)。

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

cache:高速缓存,从上图就可以看出高速缓存的高效和高昂,三级cache是为了能在达到效率的前提下降低成本。

获得物理地址VA后,使用CI(后六位再后六位)进行组索引,每组8路,对8路的块分别匹配CT(前40位)如果匹配成功且块的valid标志位为1,则命中(hit),根据数据偏移量CO(后六位)取出数据返回。

如果没有匹配成功或者匹配成功但是标志位是1,则不命中(miss),向下一级缓存中查询数据(L2 Cache->L3 Cache->主存)。查询到数据之后,一种简单的放置策略如下:如果映射到的组内有空闲块,则直接放置,否则组内都是有效块,产生冲突(evict),则采用最近最少使用策略LFU进行替换

7.6 hello进程fork时的内存映射

fork的内存映射是使用特殊文件提供匿名内存映射,而这种内存映射,适用于具有亲缘关系的进程之间;由于父子进程特殊的亲缘关系,在父进程中先调用mmap(),然后调用fork()。那么在调用fork()之后,子进程继承父进程匿名映射后的地址空间,同样也继承mmap()返回的地址,这样,父子进程就可以通过映射区域进行通信了。注意,这里不是一般的继承关系。一般来说,子进程单独维护从父进程 继承下来的一些变量。而mmap()返回的地址,却由父子进程共同维护。

7.7 hello进程execve时的内存映射

exceve函数加载和执行程序hello的步骤为:首先删除已存在的用户区域。然后为hello的代码、数据、bss和栈区域创建新的区域结构,所有这些区域都是私有的、写时复制的。再映射共享区域。比如hello程序与标准C库libc.so链接,这些对象都是动态链接到hello,然后存储在用户虚拟地址空间中的共享区域内。最后设置程序计数器(PC)。

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

DRAM缓存的不命中被称为缺页。DRAM缓存的不命中触发一个缺页故障,缺页故障调用内核中的缺页异常处理程序,该程序会选择一个牺牲页,如果该牺牲页已经做了更改,那么内核会将它复制回磁盘,否则不会进行复制即写回,然后将牺牲页从DRAM中出去,更新该页的位置放入待取的页面。然后CPU重新执行造成缺页故障的命令此时将可以正常运行。

7.9动态存储分配管理

在程序运行时应使用动态内存分配器给引用程序分配内存,动态内存分配器的维护着一个进程的虚拟内存(堆)。分配器将堆视为一组不同大小的块的集合来进行维护,每个块就是一个连续的虚拟内存片,要么是已分配的,要么是空闲的。已分配的块显式地保留以供应用程序使用。空闲块可用来分配。空闲块保持空闲,直到它显式地被应用所分配。一个已分配的块保持已分配状态,直到它被释放,这种释放要么是应用程序显式执行的,要么是内存分配器自身隐式执行的。

分配器分为两种基本风格:显式分配器、隐式分配器。

显式分配器:要求应用显式地释放任何已分配的块。

隐式分配器:要求分配器检测一个已分配块何时不再使用,那么就释放这个块。

7.10本章小结

通过对虚拟内存的介绍了解,学习了TLB和四级页表支持下VAPA的转换,以及得到了PA后,三级cache下的物理内存的访问过程,掌握了各种函数与虚拟内存的关系。

(第7 2分)

8章 hello的IO管理

8.1 Linux的IO设备管理方法

设备的模型化:所有的IO设备都被模型化为文件,而所有的输入和输出都被当做对相应文件的读和写来执行,这种将设备优雅地映射为文件的方式,允许Linux内核引出一个简单低级的应用接口,称为Unix I/O

8.2 简述Unix IO接口及其函数

接口:

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

2. Shell创建的每个进程都有三个打开的文件:标准输入,标准输出,标准错误。

3. 改变当前的文件位置:对于每个打开的文件,内核保持着一个文件位置a,初始为0,这个文件位置是从文件开头起始的字节偏移量,应用程序能够通过执行seek,显式地将改变当前文件位置a。

4. 读写文件:一个读操作就是从文件复制n>0个字节到内存,从当前文件位置a开始,然后将a增加到a+n,给定一个大小为m字节的而文件,当a>=m时,触发EOF。类似一个写操作就是从内存中复制n>0个字节到一个文件,从当前文件位置a开始,然后更新a。

5. 关闭文件,内核释放文件打开时创建的数据结构,并将这个描述符恢复到可用的描述符池中去。

函数:

open()函数:这个函数回打开一个已经存在的文件或者创建一个新的文件。

close()函数:这个函数关闭一个已经打开的文件。

read()函数:从描述符为fd的当前文件位置复制最多n个字节到内存位置buf。返回值-1表示一个错误,返回值为0表示EOF。否则返回值表示的是实际传送的字节数量。

write()函数:从内存buf位置复制至多n个字节到描述符fd的当前文件位置。

8.3 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;

}

int vsprintf(char *buf, const char *fmt, va_list args)

{

    char* p;

    char tmp[256];

    va_list p_next_arg = args;

    for (p = buf; *fmt; fmt++)

    {

        if (*fmt != '%')

        {

            *p++ = *fmt;

            continue;

        }

        fmt++;

        switch (*fmt)

        {

            case 'x':  

                itoa(tmp, *((int*)p_next_arg));

                strcpy(p, tmp);

                p_next_arg += 4;

                p += strlen(tmp);

                break;

            case 's':

                break;

            default:

                break;

        }

    }

 

    return (p - buf);  

}

vsprintf程序按照格式fmt结合参数args生成格式化之后的字符串,并返回字串的长度。

在printf中调用系统函数write(buf,i)将长度为i的buf输出

Write:

write:

    mov eax, _NR_write

    mov ebx, [esp + 4]

    mov ecx, [esp + 8]

int INT_VECTOR_SYS_CALL

write函数中,将栈中参数放入寄存器,ecx是字符个数,ebx存放第一个字符地址,int INT_VECTOR_SYS_CALLA代表通过系统调用syscall

Sys_call:

call save

push dword [p_proc_ready]

sti

push ecx

push ebx

call [sys_call_table + eax * 4]

add esp, 4 * 3

mov [esi + EAXREG - P_STACKBASE], eax

cli

ret

syscall将字符串中的字节“Hello 1190202402 李培意”从寄存器中通过总线复制到显卡的显存中,显存中存储的是字符的ASCII码。

字符显示驱动子程序:从ASCII到字模库到显示vram(存储每一个点的RGB颜色信息)。

显示芯片按照刷新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量)。

8.4 getchar的实现分析

异步异常-键盘中断的处理:键盘中断处理子程序。接受按键扫描码转成ascii码,保存到系统的键盘缓冲区。

getchar等调用read系统函数,通过系统调用读取按键ascii码,直到接受到回车键才返回。

8.5本章小结

学习了linux中的I/O管理机制,以及其各类的函数的功能等。也对printf和getchar函数有了更多更新的研究。

(第81分)

结论

最终跟随着hello程序走完了它的一生,也从它的一生中,了解了计算机系统的种种内容。从开始,到结束,也是我们编写的代码的开始,到可能的将来的结束。但当下,一个hello结束了,我们还要有更多的程序,从编写,到交给系统,再到电脑硬件的执行,最后的结束回收,在这个过程中循环往复。赋能人类的生活。

1.预处理器将hello.c源代码经过初步的修改变成了hello.i文件。

2.编译器处理hello.i文件使之成为汇编代码并保存在hello.s文件中。

3.汇编器将hello.s文件处理成了可重定位的目标程序,也就是hello.o文件,这个时候,我们的程序离可以运行就只差一步了。

4.链接器将我们的hello.o与外部文件进行链接,终于我们得到了可以跑起来的hello文件了。

5.当我们在shell中运行hello程序时,内核会为我们分配好运行程序所需要的堆、用户栈、虚拟内存等一系列信息。使我们的hello程序能够正常的运行。

6.从外部对hello程序进行操控只需要在键盘上给一个相应的信号,hello程序就会按照我们的指令来执行。

7.在hello需要访问磁盘中的信息的时候,MMU会将程序中使用的虚拟内存地址通过页表映射成物理地址。

8.当hello执行结束,shell父进程回收子进程,内核删除为这个进程创建的所有数据结构,hello也就结束了它的一生。

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

附件

Hello.c  C语言源文件

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

Hello.o  汇编之后的可重定位目标执行文件

Hello.s  编译后的文本文件

Hello  链接之后的可执行的目标文件

Elf  hello.o的ELF

Elf2  hello的ELF

(附件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.

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值