hit大作业hello的一生

 

计算机系统

大作业

题     目  程序人生-Hello’s P2P 

专       业   计算学部              

学     号     120L021215          

班     级    2003010              

学       生    闵柏馀               

指 导 教 师       郑贵滨             

计算机科学与技术学院

2021年5月

摘  要

本文就hello P2P的过程和O2O的过程以及伴随的各种机制进行了简单介绍,机制包括重定位,虚拟地址,多级缓存,多级页表等。通过撰写此大作业,使我更加深入理解了计算机系统

关键词:汇编;链接;储存管理;。。。                           

目  录

第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的整个过程。

 首先通过文档编辑器运用高级语言(c语言)写出hello.c,然后用gcc编译,经过hello.i,hello.s,hello.o阶段最终成为hello.o的可重定位可执行程序,再由ld链接静态或动态库,最后形成完整的程序(program)。当打开该program时,bash shell先fork一个子进程,然后通过execve()函数让子进程执行该程序,就形成了进程(process)。上述即为P2P。

变成进程,需要将程序装入虚拟地址空间后开始执行代码段的代码。此时,CPU为执行文件hello分配时间片,执行逻辑控制流,依次执行取指、译码、执行、内存操作,写回等操作。另外,存储管理与MMU在执行过程中通过L1、L2、L3三级缓存和多级页表从磁盘或者内存中取出需要的数据,通过I\O系统根据代码指令进行输出。当程序运行结束时bash 调用sigchld——handler回收子进程,释放内存,删除与执行程序相关的数据结构,从无中生有,到最终被回收,便为hello的O2O。

软件:virtualbox,vim文本编辑器,bashshell,edb

1.3 中间结果

Hello.i:预处理后的文件

Hello.s:编译后,汇编代码写成的文件

Hello.o:汇编后,机器代码写成的文件

Hello:链接后的可执行文件

1.4 本章小结

作为本文的开篇,简单介绍了hello的一生

第2章 预处理

2.1 预处理的概念与作用

预处理一般是指在程序源代码被翻译为目标代码的过程中,生成二进制代码之前的过程。典型地,由预处理器(preprocessor) 对程序源代码文本进行处理,得到的结果再由编译器核心进一步编译。这个过程并不对程序的源代码进行解析,但它把源代码分割或处理成为特定的单位——(用C/C++的术语来说是)预处理记号(preprocessing token)用来支持语言特性(如C/C++的宏调用)。

2.2在Ubuntu下预处理的命令

gcc -E hello.c -o hello.i

2.3 Hello的预处理结果解析

加入include的库:stdio.h  unistd.h  stdlib.h

略去了注释部分

2.4 本章小结

本章介绍了预处理的概念和作用,并将其重定向到hello.i中以便浏览

第3章 编译

3.1 编译的概念与作用

Hello.i仍然是c语言写成,计算机无法执行,因此应该转为更低级的语言,于是就要经过编译,将.i转为.s,变成更低一级的汇编语言

3.2 在Ubuntu下编译的命令

gcc -S hello.i -o hello.s

3.3 Hello的编译结果解析

3.3.1:关系操作

movl     %edi, -20(%rbp)

cmpl     $4, -20(%rbp)

这两步操作对应if(argc!=4),edi的值正是argc的值

3.3.2:函数

leaq       .LC0(%rip), %rdi

      call  puts@PLT

      movl      $1, %edi

      call  exit@PLT

      rdi作为puts()的参数,对应printf("用法: Hello 学号 姓名 秒数!\n");

      edi作为exit的参数,对应exit(1)

3.3.3:赋值

.L2:

      movl      $0, -4(%rbp)

      对应for(i=0;i<8;i++)中将i赋值为0的操作

3.3.4:关系操作,跳转

      .L3:

      cmpl      $7, -4(%rbp)

             对应for(i=0;i<8;i++)中将i和8比较的操作

3.3.5:函数

      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

              上述代码对应

      printf("Hello %s %s\n",argv[1],argv[2]);argv是char型指针数组,每一位占8个字节,第一次movq       -32(%rbp), %rax;addq   $16, %rax使rax的内容为argv[2]的地址,因此movq       (%rax), %rdx,即是把rax的内容取出送给rdx,此时rdx的内容即为argv[2],同理,rsi的内容是argv[1],而rdi的内容为"Hello %s %s\n",三者作为后面call  printf@PLT的参数执行

3.3.6:函数操作

      movq     -32(%rbp), %rax

      addq      $24, %rax

      movq     (%rax), %rax

      movq     %rax, %rdi

      call  atoi@PLT

      rdi是argv[3],作为参数传入atio(),转化为整型数后存入eax传出

3.3.7:函数

      movl      %eax, %edi

      call  sleep@PLT

      rdi作为输入,执行sleep();

3.3.8:算术操作

      addl $1, -4(%rbp)

      对应于i++;

3.3.9:函数

      call  getchar@PLT

      执行getchar();

3.3.10

      movl      $0, %eax

      即为return 0;

3.4 本章小结

为了能让计算机执行,hello.i进一步变成hello.s,转变为更低一级的汇编语言

第4章 汇编

4.1 汇编的概念与作用

概念:将汇编语言文件经过汇编,生成目标文件.o文件,每一个源文件都对应一个目标文件。即把汇编语言的代码转换成机器码,这是as汇编器完成的工作。

作用:生成计算机可以读懂的机器码

4.2 在Ubuntu下汇编的命令

gcc -c hello.s -o hello.o

4.3 可重定位目标elf格式

上图的.rela.text节储存的正是重定位信息,offset表示的是应该重定位距离代码段起始的偏移量,info的高4个字节表示该符号在.symtab中的index,低4字节表示重定位的类型,type表示重定位的类型,如上面R—X86_64_PC32就是相对寻址,addend为加数

4.4 Hello.o的结果解析

机器语言与汇编语言大多是一一对应的,只有变量距离rbp相对位置和函数的引用方式不同。

分支转移:机器语言中是直接跳转到确定的地址,而汇编语言中是跳转到如.L1

的助记符。

函数调用:机器语言是跳转到call的下一条指令(由于未经过链接,相对地址默认都设置为0,因此就是理应的rip),而汇编语言是直接跟函数名称

全局变量的使用:同函数调用一样,机器语言仍是采用rip+相对偏移地址,而汇编语言则是采用rip+段名称

4.5 本章小结

本章简单分析了未经链接的机器语言同汇编代码的关系与区别

5章 链接

5.1 链接的概念与作用

概念:链接器将每个符号引用与一个确定的符号定义关联起来,然后将多个单独的代码节(sections)和数据节合并为单个节。将符号从它们在.o文件中的相对位置重新定位到可执行文件中的最终绝对内存位置。用它们的新位置,更新所有对这些符号的引用。

作用:链接器(ld)hello的可重定位文件与标准C库里面的用到的函数如printf函数所在的预编译好了的单独的文件printf.o合并成一个文件,合并成的文件则为hello可执行文件

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的格式

Name列下面的即为该段的大小,address列即为起始地址

下图为Program Headers

5.4 hello的虚拟地址空间

Datadump中可以看到0x400000地址处,正好对应字符.ELF,与Program Headers中第一个LOAD段的起始地址对应,表明程序开始执行的地方

PHDR:程序头表

INTERP:程序执行前需要调用的解释器

LOAD:程序目标代码和常量信息

DYNAMIC:动态链接器所使用的信息

NOTE::辅助信息

GNU_EH_FRAME:保存异常信息

GNU_STACK:使用系统栈所需要的权限信息

GNU_RELRO:保存在重定位之后只读信息的位置

5.5 链接的重定位过程分析

objdump -d -r hello 分析hello与hello.o的不同,说明链接的过程。

结合hello.o的重定位项目,分析hello中对其怎么重定位的。

与hello.o相比,原来需要重定位的地方直接变成了虚拟地址。以下的hello.o代码是由objdump -d -r hello.o得来。

Hello:

Hello.o

显然,hello.o中1c处被标记了需要重定位,且未经过重定位的地址默认全为0,而在Hello中,由于已经经过链接,直接写的是虚拟地址。下面的puts()函数调用也是如此。

重定位过程:1c处的是绝对寻址,直接

Hello

Hello.o

类型为PLT表重定位,多次映射后PLT[0]即为exit()地址。而hello.o则未经过重定位的地址默认全为0

以后的重定位同上

5.6 hello的执行流程

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

  1. Jmpq *%r12(即_start的起始地址)
  2. Callq *0x2ed2(%rip)
  3. Call hello!.plt+0x70

注:3是在参数数量不为4时直接打印用法并退出的情况下发生的调用

4.callq 0x4010a0    此时打印了hello语句

5.callq 0x4010c0

6.callq 0x4010e0

7.callq 0x4010b0    即执行getchar()

8.callq libc-2.31.so!exit 即执行exit(0)

使用edb执行hello,说明从加载hello到_start,到call main,以及程序终止的所有过程。请列出其调用与跳转的各个子程序名或程序地址。

5.7 Hello的动态链接分析

当程序调用一个由共享库定义的函数时,由于编译器无法预测这时候函数的地址是什么,因此这时,编译系统提供了延迟绑定的方法,将过程地址的绑定推迟到第一次调用该过程时。通过GOT和过程链接表PLT的协作来解析函数的地址。在加载时,动态链接器会重定位GOT中的每个条目,使它包含正确的绝对地址,而PLT中的每个函数负责调用不同函数。那么,通过观察edb,便可发现dl_init后.got.plt节发生的变化。
首先可以观察elf中.got.plt节的内容(图中标白处即为plt表首地址)

执行. dl_init前:

执行dl_init后;

可知,经过初始化后,原来为00。。的地方重定位为动态链接库中的函数地址

5.8 本章小结

对hello程序进行链接,完成符号解析与重定位,使之成为可执行程序

6章 hello进程管理

6.1 进程的概念与作用

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

作用:在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。

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

作用:Shell-bash是命令语言解释器,是用户与linux内核之间的接口程序,我们可以在shell中输入命令然后传给linux内核

处理流程:首先bash会判断我们输入的命令是不是内部命令,如果是,立即执行,否则先fork一个子进程,让子进程到指定的目录打开程序文件,执行该程序

6.3 Hello的fork进程创建过程

shell通过使用fork函数来创建子进程,新创建的子进程几乎但不完全与父进程相同。子进程得到父进程用户级的虚拟地址空间相同的一份副本,包括代码和数据段、堆、共享栈及用户栈。子进程还获得与父进程任何打开文件描述符相同的副本,但是它们的PID不同。在输入运行hello程序的命令后,shell开始对命令行进行解析,判断出hello不是内置命令后,shell调用fork函数创建子进程来运行hello程序。

6.4 Hello的execve过程

shell在使用fork创建子进程之后,(用setpgid(0,0)将其放在一个不同于父进程的进程组中)然后在子进程中使用execve函数。execve函数在当前进程中加载并运行包含在可执行文件hello中的程序,用hello程序替代了当前程序。加载并运行hello需要以下几个步骤:

1.删除已存在的用户区域。删除当前进程虚拟地址的用户部分中已存在的区域结构。

2.映射私有区域。为新程序的代码、数据、bss和栈区域创建新的区域结构。所有这些新的区域都是私有的、写时复制的(这些是第九章虚拟内存的内容)。代码和数据区被映射为hello文件中的.text和.data区。bss区域是请求二进制零的,映射到匿名文件,其大小包含在hello中。栈和堆区域也是请求二进制零的,初始长度为零。

3.映射共享区域。如果hello程序与共享对象链接,那么这些对象都是动态链接到这个程序的,然后再映射到用户虚拟地址空间中的共享区域内。

4.设置程序计数器。设置当前进程上下文中的程序计数器,使之指向代码区域的入口点。下一次调度这个进程时,它将从这个入口点开始执行。

execve只在加载失败时返回-1,否则不返回。

6.5 Hello的进程执行

结合进程上下文信息、进程时间片,阐述进程调度的过程,用户态与核心态转换等等。

控制流通过上下文切换从一个进程到另一个进程。一个进程执行它的控制流的一部分的每一时间段叫做进程时间片。当进入hello的时间片,则开始执行hello中的代码,该时段的时间用完后hello进程不再占用cpu等资源,而是把此时的进程信息(如此时的寄存器值)存入主存中,控制权交还给内核,内核再去执行其他进程,又到了hello的时间片时,再把寄存器值从内存中取出来,恢复到上一次执行后的状态,继续执行,这就是上下文转换。

同时,考虑到异常存在,如用户手动输入ctrl-z,则hello进程接受到sigtstp信号,控制权也会交还给内核执行异常处理函数

6.6 hello的异常与信号处理

当按下ctrl-z时,进程接收到sigtstp信号,控制权交还给内核,调用异常处理程序,默认会使hello进程暂停,此时bashshell进程waitfg()停止,故可以继续输入其他命令,当输入fg命令时,bash给子进程发送sigcont信号,且bash进程执行waitfg(),因此在前台执行hello进程

6.7本章小结

本章的hello实现了从program到process质的飞跃,分析了这一过程以及伴随的异常处理操作

7章 hello的存储管理

7.1 hello的存储器地址空间

逻辑地址是指由程序产生的与段相关的偏移地址部分,又称为绝对地址,在hello中就是各部分在段内的偏移地址。

线性地址:逻辑地址到物理地址变换之间的中间层。CPU在保护模式下,在分段部件中逻辑地址是段中的偏移地址,然后加上段的基址就称为了线性地址。即hello里面的虚拟内存地址。

虚拟地址:CPU没有分页机制时,线性地址就被当做最终的物理地址来用;若具有分页机制,则线性地址就叫作虚拟地址。而本次大作业的hello运行在个人笔记本的硬件环境下,显然有分页机制,因此hello程序的虚拟地址与线性地址等价

物理地址就是内存单元的绝对地址。在hello程序中就是虚拟内存地址经过翻译后获得的地址。

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

逻辑地址由段选择符和偏移量组成,线性地址为段首地址与逻辑地址中的偏移量组成。其中,段首地址存放在段描述符中。而段描述符存放在描述符表中,也就是GDT(全局描述符表)或LDT(局部描述符表)中。变换时,先在GDT中找到hello的LDT的基址,基址加偏移量即为线性地址

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

       线性地址,一般即为虚拟地址,可分为VPN与VPO两部分,VPN又包含PTEI与PTET两部分,PTEI可在PTE中索引到对应的条目组,然后再用PTET比对找到对应的条目,条目中包含了内存引用的限制信息和物理页号,物理页号与VPO组合即可形成物理地址,完成变换

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

       MMU(储存管理单元)先在TLB中寻找VPN对应的PTE,如果找到,则可以直接获得PPN,与VPO组合形成物理地址。如果没有找到,则通过PTBR(页表基址寄存器)获得PTEA,在内存中找到对应PTE后返回,一方面和VPO结合获得物理地址,一方面更新TLB表

      

上图为二级页表示例,四级页表同理

虚拟地址的VPN部分包含了在各级页表中的偏移地址,逐级寻址,直到在第四级页表中得到PPN,最终得到PA

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

从MMU得到物理地址后,首先先在L1缓存中寻找,将物理地址分成组索引,标记,和偏移量,以此在缓存中查找,如果找到,直接将值传递给cpu,否则继续从下一级缓存找,直至到主存

7.6 hello进程fork时的内存映射

首先创建当前进程的mm_struct、vm_area_struct和页表的原样副本。两个进程中的每个页面都标记为只读两个进程中的每个区域结构(vm_area_struct)都标记为私有的写时复制(COW)。在新进程中返回时,新进程拥有与调用fork进程相同的虚拟内存随后的写操作通过写时复制机制创建新页面。

7.7 hello进程execve时的内存映射

删除已存在的用户区域

创建新的区域结构

代码和初始化数据映射到.text和.data区(目标文件提供)

.bss和栈映射到匿名文件

设置PC,指向代码区域的入口点

Linux根据需要换入代码和数据页面

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

       故障:在hello进程的页表中如果条目的有效位为0,则发生缺页故障,即虚拟地址对应的数据没有被载入到内存中。

       处理:进程抛出缺页故障,控制权交还内核,内核将内存中的某一页作为牺牲页,替换成要读取的数据,让某一PTE指向替换后的内存所在位置,然后继续执行hello进程

7.9动态存储分配管理

Printf会调用malloc,请简述动态内存管理的基本方法与策略。

分配器将堆视为一组不同大小的块 (blocks)的集合来维护,每个块要么是已分配的,要么是空闲的。分配器主要分为显式分配器和隐式分配器。

策略:显式空闲链表和隐式空闲链表。

隐式空闲链表:通过头部的大小字段隐式的连接。分配器可以通过遍历堆中的所有块,从而间接地遍历整个空闲块地集合。可以通过添加脚部的方式实现隐式双向链表。寻找空闲块时可使用首次适配、下一次适配、最佳适配和分离适配等分配策略;分配空闲块时,如果块较大且找不到更合适的,则可以进行分割;释放块时需要按照四种情况合并相邻空闲块。

显式空闲链表:通过某种数据结构来管理、分配空闲块,而不去管理已分配的块。

7.10本章小结

       本章着重分析对于hello进程的存储管理的过程。

8章 hello的IO管理

8.1 Linux的IO设备管理方法

设备的模型化:文件

1、普通文件:包含任意数据的文件。

2、目录(directory):包含一组链接的文件,每个链接都将一个文件名映射到一个文件

3、套接字(socket):用来与另一个进程进行跨网络通信的文件

4、命名通道

5、符号链接

6、字符和块设备

设备管理:unix io接口

1.打开和关闭文件

2.读取和写入文件

3.改变当前文件的位置

8.2 简述Unix IO接口及其函数

Linux将设备映射为文件的方式,允许Unix内核引出一个简单、低级的应用接口。

正如以下的函数,这些都是系统调用。

1、打开文件 int open(char *filename, int flags, mode_t mode);

返回一个小的非负整数,即描述符。用描述符来标识文件。每个进程都有三个打开的文件:标准输入(0)、标准输出(1)、标准错误(2)。返回:若成功则为新文件描述符,若出错为-1

flags:进程打算如何访问文件

包含以下选项

O_RDONLY:只读    O_WRONLY:只写    O_RDWR:可读可写

O_CREAT:如文件不存在,则创建

O_TRUNC:如果文件已存在,则截断

O_APPEND:每次写操作,设置k到文件结尾

注:也可以是一个或更多位掩码的或

mode:指定新文件的访问权限位

2、改变当前文件位置。从文件开头起始的字节偏移量。系统内核保持一个文件位置k,对于每个打开的文件,起始值为0。应用程序执行seek,设置当前位置k,通过调用lseek函数,显示地修改当前文件位置。

3、读写文件。

读操作:从文件拷贝n个字节到存储器,从当前文件位置k开始,将k增加到k+n,对于一个大小为m字节的文件,当k>=m时,读操作触发一个EOF的条件。

写操作:从存储器拷贝n个字节到文件,k更新为k+n

ssize_t read(int fd, void *buf, size_t n);

返回:若成功则为读的字节数,若EOF则为0,若出错为-1.

ssize_t write(int fd, const void *buf, size_t n);

返回:若成功则为写的字节数,若出错则为-1

4、关闭文件:内核释放文件打开时创建的数据结构,并恢复描述符到描述符池中,进程通过调用close函数关闭一个打开的文件。关闭一个已关闭的描述符会出错。

int close(int fd);返回:若成功则为0,若出错则为-1.

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;

}

举个例子,就printf”hello %c”,a)而讲

Buf储存即将要打印的字符串,fmt”hello %c”字符串的首地址,arg在本例中是a的指针

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

   }

逐个字符读取fmt中的内容,如果没有遇到%,则将fmt的字符复制到以buf为首地址的数据段(以p作为指针跟随进度移动)中,fmt指针向前移动;如果遇到了%,则说明要输出特定格式的变量,就在当前p指针指向的地方从arg复制内容,fmt继续先前移动。循环上面的操作,直到遇到了\0,表示字符串读完了,此时p即指向要输出的字符串末尾,而buf在开头,因此相减返回的i就是字符串长度。最后将以buf为首地址的字符串write到标准输出区i个字符。在write函数中,设置陷阱:syscall,控制权交给系统。字符显示驱动子程序:从ASCII到字模库到显示vram(存储每一个点的RGB颜色信息)。

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

8.4 getchar的实现分析

异步异常-键盘中断的处理:键盘中断处理子程序。接受按键扫描码转成ascii码,保存到系统的键盘缓冲区。用bb指针取一个char型数据,让bb的指针直接指向buf的首地址,最后对read的返回值进行检查,如果read错误,则返回n=-1,最后return EOF;否则说明成功,返回bb指向的字符

8.5本章小结

       对于hello中的io操作有了更深一步的探索,初步涉及到系统调用

结论

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

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

Hello最先由c语言写成,经过预处理,编译,汇编,变成01串形式的机器码,调用其他库中的函数(如printf)不知道确切的虚拟地址,还无法执行。因此再链接,就变成了可执行的程序。

在bash shell中打开hello文件,bash先fork了一个子进程,再去exec该文件,于是hello变成了一个进程。

执行hello程序所需要的代码和数据都要经手储存管理单元,精妙的多级缓存,多级页表,虚拟地址机制以及TLB相互协调,使数据读取既快又准,还节省空间!

附件

Hello.i:预处理后的文件

Hello.s:编译后,汇编代码写成的文件

Hello.o:汇编后,机器代码写成的文件

Hello:链接后的可执行文件

参考文献

[1] Randal E. Bryant, David R. O'Hallaron. 深入理解计算机系统 .机械工业出版社

[2] ch06-02存储器层次系统.哈尔滨.哈尔滨工业大学

[3] ch09-1虚拟内存.哈尔滨.哈尔滨工业大学

[4] 落崖惊风.Linux动态链接之GOT与PLT https://www.cnblogs.com/xingyun/archive/2011/12/10/2283149.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值