哈工大计算机系统大作业2024

计算机系统

大作业

题     目  程序人生-Hello’s P2P 

专       业        网络空间安全      

学     号        2022111167       

班     级        2203901           

学       生        毕浩翔         

指 导 教 师        史先俊            

计算机科学与技术学院

2024年5月

摘  要

本文通过对Hello.c文件的预处理,编译,汇编,链接的单步执行与对反汇编代码,中间文件,I/O结果的查看,跟踪一个典型c语言程序的“一生”,分析该过程中软件与硬件的协同配合。

关键词:预处理;汇编;链接;反汇编;I/O                           

目  录

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

第3章 编译... - 7 -

3.1 编译的概念与作用... - 7 -

3.2 在Ubuntu下编译的命令... - 7 -

3.3 Hello的编译结果解析... - 7 -

3.4 本章小结... - 9 -

第4章 汇编... - 10 -

4.1 汇编的概念与作用... - 10 -

4.2 在Ubuntu下汇编的命令... - 10 -

4.3 可重定位目标elf格式... - 10 -

4.4 Hello.o的结果解析... - 13 -

4.5 本章小结... - 14 -

第5章 链接... - 15 -

5.1 链接的概念与作用... - 15 -

5.2 在Ubuntu下链接的命令... - 15 -

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

5.4 hello的虚拟地址空间... - 16 -

5.5 链接的重定位过程分析... - 16 -

5.6 hello的执行流程... - 22 -

5.7 Hello的动态链接分析... - 22 -

5.8 本章小结... - 24 -

第6章 hello进程管理... - 25 -

6.1 进程的概念与作用... - 25 -

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

bash的作用... - 25 -

bash的处理流程... - 25 -

6.3 Hello的fork进程创建过程... - 26 -

6.4 Hello的execve过程... - 26 -

6.5 Hello的进程执行... - 26 -

6.6 hello的异常与信号处理... - 26 -

6.7本章小结... - 29 -

第7章 hello的存储管理... - 30 -

7.1 hello的存储器地址空间... - 30 -

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

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

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

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

7.6 hello进程fork时的内存映射... - 31 -

7.7 hello进程execve时的内存映射... - 31 -

7.8 缺页故障与缺页中断处理... - 32 -

7.9动态存储分配管理... - 32 -

7.10本章小结... - 33 -

第8章 hello的IO管理... - 34 -

8.1 Linux的IO设备管理方法... - 34 -

8.2 简述Unix IO接口及其函数... - 34 -

8.3 printf的实现分析... - 34 -

8.4 getchar的实现分析... - 35 -

8.5本章小结... - 35 -

结论... - 35 -

附件... - 36 -

参考文献... - 37 -

第1章 概述

1.1 Hello简介

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

P2P:  hello.c-(cpp)->hello.i-(ccl)->hello.s-(as)->hello.o-(ld)->hello.out

020: 程序未运行时没有分配内存空间(0),在shell上输入./hello后OS为程序分配虚拟地址及逻辑控制流,让程序拥有独立的逻辑控制流和内存系统,在程序结束运行后再回收分配到的空间并由其父进程回收子进程,回到一无所有的状态(0)

1.2 环境与工具

环境:Ubuntu 64 位

工具:gedit/gdb

1.3 中间结果

hello.c 源文件

hello.i 预编译结果

hello.s 编译结果

hello.o 汇编结果

hello.exe 链接结果

hello_asm hello.exe的反汇编文件

1.4 本章小结

       本章概括性介绍了本文的运行环境,中间结果及整体思路,便于读者复现。

第2章 预处理

2.1 预处理的概念与作用

概念

预处理器(cpp)根据以字符#开头的命令,修改原始的C程序。结果就得到了另一个C程序,通常是以.i作为文件扩展名。

作用

预处理阶段根据已放置在文件中的预处理指令来修改源文件的内容。比如#include就是一个预处理指令,它把头文件的内容添加到.cpp文件中。这种预处理的机制提高了源文件的灵活性,能适应不同的计算机和操作系统;而且通过预处理指令,可以使用已经封装好的库函数,极大地提高了编程效率。

2.2在Ubuntu下预处理的命令

2.3 Hello的预处理结果解析

      我发现hello.i比hello.c多出了许多外部代码,这些外部代码应当是hello.c中include进来的库文件

2.4 本章小结

Hello.c到hello.i经历了预处理的过程,该过程处理了hello.c中的库引用(include)与宏定义(define),将引用的库代码拼接到源代码文件中。

第3章 编译

3.1 编译的概念与作用

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

   

概念

      编译器ccl将文件hello.i中的c语言代码编译为汇编语言存入hello.s

作用

      在编译阶段中,gcc首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,gcc把代码翻译成汇编语言。在编译阶段,编译器还能起到优化的作用,优化处理是编译系统中一项比较艰深的技术。它涉及到的问题不仅同编译技术本身有关,而且同机器的硬件环境也有很大的关系。

3.2 在Ubuntu下编译的命令

3.3 Hello的编译结果解析

3.3.1 汇编头部

.file 源文件名

.text 源代码

.rodata 只读数据

.string 对应hello.c文件中”用法: Hello 学号 姓名 手机号 秒数!\n”

.globl 全局变量main

.type 全局变量main是一个函数

3.3.2main函数

逻辑结构:

  1. 分支跳转(je .L2)对应源文件if语句,24行cmpl对应if语句的判断条件
  2. 26-30行对应源文件调用printf函数打印字符串并退出exit(0)
  3. .L3和.L4对应源文件for循环,.L4是循环体,.L3是循环终止条件
  4. .L4中执行打印字符串操作并通过寄存器传参调用sleep函数

3.4 本章小结

本章通过分析hello.c的汇编代码与源代码的语句对应关系剖析了汇编语言的头部,传参,函数调用,分支结构。

第4章 汇编

4.1 汇编的概念与作用

汇编器(as)hello.s翻译成机器语言指令,把这些指令打包成一种叫做可重定位目标程序的格式,并将结果保存在目标文件hello.o中。hello.o是一个二进制文件,它包含的17个字节是函数main的指令编码。

注意:这儿的汇编是指从 .s 到 .o 即编译后的文件到生成机器语言二进制程序的过程。

4.2 在Ubuntu下汇编的命令

4.3 可重定位目标elf格式

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

4.3.1 elf头部

可以看到许多程序有关信息,如该文件使用小端法编码的等等。

      1. elf各section

上图展示了elf的整体section结构,包括各section的大小,名称等

      1. 重定向(rela.text)

该section中包含了需要被重定位的变量的偏置值,在链接时会根据偏置值将局部变量重定向到对应已声明变量,将已声明变量对应到对应内存地址

4.4 Hello.o的结果解析

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

objdump -d -r hello.o  分析hello.o的反汇编,并请与第3章的 hello.s进行对照分析。

说明机器语言的构成,与汇编语言的映射关系。特别是机器语言中的操作数与汇编语言不一致,特别是分支转移函数调用等。

  1. 机器语言指令部分与汇编基本相同,但在每行指令的开头都多了一串十六进制数,表示该指令的内存地址;汇编语言每行指令没有分配地址
  2. 控制结构表示不同,汇编语言中jmp指令跟的.L1.LL3等在机器语言中被使用对应指令首地址表示,因此指令中的.L1.LL3也不存在了
  3. 函数调用表示不同,call后面跟的函数名变成了对应地址

4.5 本章小结

本章通过分析hello.o的elf结构和反汇编代码剖析了一个可执行程序的基本组成结构,对比分析了机器语言与汇编代码的异同。

5章 链接

5.1 链接的概念与作用

链接(linking)是将各种代码和数据部分收集并组合成为一个单一文件的过程,这个文件可被加载(复制)到内存并执行。

链接由链接器程序自动执行。链接器在软件开发中扮演着一个关键的角色,因为它们使得分离编译成为可能。我们不用将一个大型的应用程序组织为一个巨大的源文件,而是可以把它分解为更小、更好管理的模块,可以独立地修改和编译这些模块。当我们改变这些模块中的一个时,只需简单地重新编译它,并重新链接应用,而不必重新编译其他文件。

注意:这儿的链接是指从 hello.o 到hello生成过程。

5.2 在Ubuntu下链接的命令

使用ld的链接命令,应截图,展示汇编过程! 注意不只连接hello.o文件

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

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

5.4 hello的虚拟地址空间

使用edb加载hello,查看本进程的虚拟地址空间各段信息,并与5.3对照分析说明。

通过edb调试可以看出该程序地址从0x401000开始,我们可以通过elf的每个section的地址在Data Dump中找到相应数据。

5.5 链接的重定位过程分析

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

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

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

可以看出,重定向后的hello.out比hello.o的反汇编左侧多了一列虚拟地址序号VPN,因为经过重定向每条指令的VA-PA映射关系已经确定。

同时经过链接该文件比hello.o多了许多库函数的代码如exit()等,因为许多调用的外部函数以可重定向文件的格式存在,在链接这步加入了这些文件。

同时在链接过程中,各个可重定向文件的相同elf section会被聚合在一起形成聚合结,例如所有的.rodata,.text,.bss,.data等等。

5.6 hello的执行流程

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

在_start打断点并单步执行

函数

地址

main

0x4011e2

init

0x401000

_start

0x7ffff7fe3290

call_init

0x7ffff7c29e68

执行顺序

_start->init->call_init->main

5.7 Hello的动态链接分析

分析hello程序的动态链接项目,通过edb/gdb调试,分析在动态链接前后,这些项目的内容变化。要截图标识说明。

PLT和GOT是与动态链接最相关的两个节,观察他们所在地址段的变化即可反应动态链接的内容变化。

通过readelf找到他们的地址

在动态链接处打断点

发现程序没有正确停下,于是我在_start处与main处分别打断点,观察观察前后两变量变化,如下:

5.8 本章小结

       本章通过gdb调试剖析了链接这一过程进行了怎么样的工作,包括elf节的聚合,虚拟地址的映射,库函数代码的引入等等。

6章 hello进程管理

6.1 进程的概念与作用

进程,是一个执行中程序的实例。

进程提供给应用程序的关键抽象:一个独立的逻辑控制流;一个私有的地址空间。

通过以上两个抽象,进程提供给用户一种假象:就好像我们的程序是系统中当前运行的唯一的程序一样。我们的程序好像是独占地使用处理器和内存。处理器就好像是无间断地一条接着一条地执行我们程序中的指令。最后,我们程序中的代码和数据好像是系统内存中唯一的对象。

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

bashBourne Again Shell)是Linux和许多Unix系统上广泛使用的shell之一。作为用户与操作系统之间的接口,bash(以及其他shell)允许用户通过命令行与系统进行交互,并执行各种命令和脚本。以下是bash的作用和处理流程的简要概述:

bash的作用

  1. 命令解释器bash读取用户输入的命令,解析它们,并传递给相应的程序或函数执行。
  2. 脚本解释器bash还可以执行存储在文件中的命令序列,这些文件通常被称为shell脚本或bash脚本。
  3. 自动化:通过脚本,bash可以实现自动化任务,如系统维护、文件操作、数据处理等。
  4. 环境控制bash管理环境变量,这些变量定义了shell和程序的行为。
  5. 任务调度:结合其他工具(如cron),bash可以用于在特定时间或条件下自动执行任务。
  6. 交互式使用:用户可以直接在命令行界面与bash交互,执行命令和查看输出。

bash的处理流程

  1. 启动:当用户启动一个新的bash shell(例如,通过打开一个终端窗口或登录到系统)时,bash会读取其初始化文件(如.bashrc.bash_profile),这些文件定义了shell的环境和行为。
  2. 读取命令:bash等待用户输入命令。当用户键入一个命令并按下回车键时,bash会读取该命令。
  3. 解析命令:bash将输入的命令分解成各个部分,如命令名、选项和参数。它还会检查命令是否存在以及用户是否有权限执行该命令。
  4. 执行命令:bash会查找并执行与命令名对应的程序。这可能是一个内置的bash命令(如cdecho),一个外部程序(如/bin/ls),或者一个shell函数。
  5. 捕获输出:bash会捕获命令的输出(包括标准输出和标准错误输出),并可以选择性地将其显示给用户或重定向到文件。
  6. 循环等待:执行完命令后,bash会返回到等待状态,继续读取用户输入的下一个命令。这个过程会一直持续下去,直到用户退出shell(通过键入exit命令或关闭终端窗口)。

6.3 Hello的fork进程创建过程

       我们在shell中输入./hello,OS就会使用我们给的上下文(参数,状态信息等等)fork一个子进程来运行hello

6.4 Hello的execve过程

OS创建了子进程后,就会调用execve在当前上下文加载并运行hello可执行程序

6.5 Hello的进程执行

进程是程序的一个在特定上下文中的实例,进程的许多行为由上下文决定(如hello程序接收五个参数,接收参数不同打印的提示信息也不同),上下文包括程序接受的参数,运行状态等很多与程序运行相关的属性。

进程会在用户态与内核态不断切换,因为CPU采用非阻塞模式,当一个进程阻塞(如执行大规模磁盘读写),CPU会先执行其他进程,这一过程称为调度,由内核管理。进程在用户态下访问权限有限,如果要调用系统函数或磁盘信息等等,需要构造特定的异常进入异常处理子程序,从而进入内核态执行高权限操作,执行完毕再回到内核态。

6.6 hello的异常与信号处理

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

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

6.6.1 Ctrl-C

6.6.2 Crtl-Z

6.6.3 正常运行

6.7本章小结

本章通过运行hello程序剖析了OS与创建进程的交互,并探究了不同信号对进程的影响。

7章 hello的存储管理

7.1 hello的存储器地址空间

逻辑地址是程序直接使用的地址,一般用段偏移量索引;

线性地址和虚拟地址是虚拟内存空间中的地址,对应磁盘的相应位置;

物理地址是主存中的地址值,可以直接用来访问主存数据。

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

       逻辑地址由段基址和偏移量构成。

       首先检查TI字段,决定是使用GDT(TI=0)还是LDT(TI=1),再计算段描述符的地址,最后将逻辑地址中的偏移量与段描述符中的base相加得到线性地址。

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

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

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

7.6 hello进程fork时的内存映射

当shell使用fork创建子进程时,内核为新的子进程创建各种数据结构,并分配给子进程一个唯一的PID,为了给它创建虚拟内存空间,内核创建了当前进程的mm_struct、区域结构和页表的原样副本,将两个进程的页面都标记为只读,并将两个进程中的每个区域结构都标记为私有的写时复制。这样,在新进程里,最开始的时候它的虚拟内存和原进程的虚拟内存映射相同,但当这两个进程中的任意一个进行写操作时,写时复制机制就会创建新页面,这样两个进程的地址空间就在逻辑上私有了。

7.7 hello进程execve时的内存映射

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

7.9动态存储分配管理

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

动态内存管理分为显式内存管理和隐式内存管理,显式内存管理常用的由malloc,calloc等等;隐式的内存管理是垃圾回收,即找出堆中不可达(不能从堆外部访问)的节点并释放对应内存。

7.10本章小结

本章通过hello这一实例剖析了计算机系统是如何进行内存管理的,捋清了VA->PA->Data的转化流程,回顾了常见的动态内存管理机制。

8章 hello的IO管理

8.1 Linux的IO设备管理方法

设备的模型化:文件

设备管理:unix io接口

Linux将IO设备视为文件的一种,将Input视为读文件,将Output视为写文件

8.2 简述Unix IO接口及其函数

常见函数:

open 打开文件

close 关闭文件

read 将文件读到内存

write 将内存数据写入文件

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会接收一个格式串并根据格式串决定接收参数类型及个数。

从vsprintf生成显示信息,到write系统函数,到陷阱-系统调用 int 0x80或syscall等.

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

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

8.4 getchar的实现分析

       源代码

int getchar(void)

{

       static char buf[BUFSIZ];

       static char* bb=buf;

       static int n=0;

       if(n==0)

       {

              n=read(0,buf,BUFSIZ);

              bb=buf;

       }

       return(--n>=0)?(unsigned char)*bb++:EOF;

}

getchar是stdio.h中的库函数,它的作用是从stdin流中读入一个字。

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

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

8.5本章小结

本章通过分析c语言中的文件处理函数剖析了linux系统的I/O处理模式。

结论

  1. 程序员写出hello.c这一高级程序语言脚本
  2. hello.c-(cpp)->hello.i-(ccl)->hello.s-(as)->hello.o-(ld)->hello.out
  3. 在shell上运行./hello
  4. OS为hello程序fork一个子进程,在子进程中exceve可执行程序hello
  5. hello在运行时拥有“看起来”私有的地址空间与逻辑控制流
  6. hello在运行时可能接收各种信号,如键盘发出的crtl-C
  7. hello结束运行后,OS回收分配给hello的子进程及地址空间

附件

hello.c 源文件

hello.i 预编译结果

hello.s 编译结果

hello.o 汇编结果

hello.exe 链接结果

hello_asm hello.exe的反汇编文件

参考文献

[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.

[7] Randal E.Bryant / David O'Hallaron  Computer Systems: A Programmer's Perspective, 2016

[8] Linux readelf命令教程:深入理解ELF文件结构(附实例详解和注意事项)-Linux入门自学网 (bashcommandnotfound.cn)

[9] gdb给指定位置设置断点_gdb在指定的文件中新建断点-CSDN博客

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值