HIT 2024 CSAPP大作业

计算机系统

大作业

题     目  程序人生-Hello’s P2P   

专       业        信息安全           

学     号        2022111192        

班     级         2203201          

学       生         李童溪         

指 导 教 师          史先俊           

计算机科学与技术学院

20245

 

hello从hello.c诞生以来经历了预处理、编译、汇编、链接的过程称为可执行文件hello,执行中又需要考虑内存、进程、异常、IO管理等问题,了解hello对我们理解计算机系统有重大意义,本文旨在通过阐述以上部分,总结hello从生成到运行的方方面面。

关键词:计算机系统,编译,进程,内存;                           

 

第1章 概述................................................... - 4 -

1.1 Hello简介............................................ - 4 -

1.2 环境与工具........................................... - 4 -

1.3 中间结果............................................... - 4 -

1.4 本章小结............................................... - 4 -

第2章 预处理............................................... - 6 -

2.1 预处理的概念与作用........................... - 6 -

2.2在Ubuntu下预处理的命令................ - 6 -

2.3 Hello的预处理结果解析.................... - 6 -

2.4 本章小结............................................... - 7 -

第3章 编译................................................... - 8 -

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

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

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

3.4 本章小结............................................. - 11 -

第4章 汇编................................................. - 12 -

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

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

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

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

4.5 本章小结............................................. - 15 -

第5章 链接................................................. - 16 -

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

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

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

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

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

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

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

5.8 本章小结............................................. - 19 -

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

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

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

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

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

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

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

6.7本章小结.............................................. - 21 -

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

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

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

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

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

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

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

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

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

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

7.10本章小结............................................ - 24 -

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

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

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

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

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

8.5本章小结.............................................. - 25 -

结论............................................................... - 26 -

附件............................................................... - 27 -

参考文献....................................................... - 28 -

1章 概述

1.1 Hello简介

hello.c经过预处理、编译、汇编、链接生成可执行文件hello,执行中又需要考虑内存、进程、异常、IO管理等问题,才能成功运行hello’

1.2 环境与工具

1.2.1 硬件环境

X64 CPU;2GHz;2G RAM;256GHD Disk 以上

1.2.2 软件环境

Windows11 64位;

Vmware 17;Ubuntu 16.04 LTS 64位;

1.2.3 开发工具

Visual Studio 2022 64位;CodeBlocks 64位;vi/vim/gedit+gcc

1.3 中间结果

hello.c :源文件

hello.s:预处理文件

hello.i:编译文件

hello.o:汇编文件

hello:链接后的可执行文件

asm.txt:反汇编文件

objdump_hello.txt:链接后反汇编文件

readelf.txt: elf文件

readelf_hello: 链接后的elf文件

1.4 本章小结

本章对文章目的进行介绍,并介绍了开发环境与必要附件

2章 预处理

2.1 预处理的概念与作用

概念:预处理是生成二进制程序过程的第一步,预处理由预处理器完成,预处理器是编译器的一部分。

作用:预处理在实际编译源代码之前对代码进行预处理,它会处理源代码中的预处理指令,主要作用有宏定义和替换、文件包含、条件编译、编译控制等。

2.2在Ubuntu下预处理的命令

gcc -o hello.i -E hello.c

2-1 Ubuntu下的预处理命令

2-2 源文件hello.c与结果文件hello.i

2.3 Hello的预处理结果解析

hello.c的长度为24行,而hello.i的长度达到了3092行,主要为预处理过程包括的头文件源码,即stdio.h , unistd.h , stdlib.h ,以及对一些函数的声明

2-3 hello.i的开头内容

hello.i末尾的内容为hello.c的主函数

2-4 hello.i的末尾内容

2.4 本章小结

本章总结了预处理的概念和作用,使用gcc -o hello.i -E hello.c在Ubuntu下进行了预处理,并分析了预处理结果hello.i的内容

3章 编译

3.1 编译的概念与作用

概念:编译是指将预处理后的代码转换为汇编语言代码的过程,即从.i.s的过程。       

作用:编译过程由编译器完成,主要作用有词法分析,语法分析,语义分析,代码优化,生成汇编代码等。

3.2 在Ubuntu下编译的命令

gcc -o hello.s -S hello.c

3-1 Ubuntu下的编译命令

3-2 hello.c的编译结果文件

3.3 Hello的编译结果解析

3.3.1 常量数据

      int型数值常量直接以立即数的形式表示

3-3 数值常量的存储

字符串常量,直接存储在汇编代码中

3-4 字符串常量的存储

3.3.2 局部变量

hello.c中的int i被保存在堆栈中,即-4(%rbp)

3-5 局部变量的存储

3.3.3 赋值

将0赋值给i, 对应hello.c中的i=0

3-6 赋值操作

3.3.4 算数操作

加法操作(+),将-4(%rbp)的值+1,对应hello.c的i++

3-7 加法算数操作

3.3.5 关系操作

判断是否相等(==),对应hello.c的if(argc!=5)

3-8 判断是否相等

判断是否小于(<),对应hello.c的i<10

3-9 判断是否小于

3.3.6 控制转移

主要对应hello.c的if判断与for循环,在汇编代码中通常表现为比较和跳转

3-10 控制转移

3.3.7 函数操作

调用函数时,需要将当前的基址寄存器压入栈中,保存调用者的基址,将栈指针寄存器的值赋给基址寄存器,然后通过寄存器传递参数,并把返回值存储在寄存器中,最后恢复栈帧并返回

3.4 本章小结

本章总结了编译的概念和作用,在Ubuntu下编译了hello.c得到hello.s,然后分析了汇编代码中的常量数据,局部变量,赋值操作,算术操作,关系操作,控制转移和函数调用

4章 汇编

4.1 汇编的概念与作用

概念:汇编是将汇编语言代码转换为机器语言二进制代码的过程,即从 .s 文件到 .o 文件。机器代码是计算机可以直接执行的二进制代码。

作用:主要由汇编器进行,主要作用为解析、符号解析、指令翻译、生成机器码、生成符号表

4.2 在Ubuntu下汇编的命令

as -o hello.o hello.s

4-1 Ubuntu下的汇编命令

4-2 结果文件hello.o

4.3 可重定位目标elf格式

4-3 Ubuntu下的readelf指令

ELF头:Magic表示文件字符类型,类别表示这是一个64位的ELF文件数据,表示数据编码方式为小端序,还表明了文件类型、系统架构、文件版本号、程序的入口点地址,程序头起点表示程序头表在文件中的偏移,标志表示ELF头的大小,程序头表中的条目数等

4-4 ELF

节头表:显示所有节的名称、类型、地址、偏移量、大小等

4-5节头表

重定位节:重定位节描述了各节的重定位信息和地址修正,主要包括对.rodata(存放只读数据)putsexitprintfatoisleepgetchar的重定位信息

4-6重定位节

符号表:符号表包含了程序中所有符号的信息,包括函数、变量和节等。每个符号表条目提供了符号的详细信息,如其在内存中的地址、大小、类型、绑定属性、可见性和关联的节等。

4-7 符号表

4.4 Hello.o的结果解析

objdump -d -r hello.o > asm.txt

4-8 Ubuntu下的反汇编命令

4-9 反汇编的内容(部分)

4-10 hello.s的内容(部分)

相比于hello.s的内容,反汇编多出了地址偏移量与16进制机器指令;反汇编代码中的数字为16进制,而hello.s中的数字为10进制;反汇编代码中的跳转地址使用相对地址表示,而hello.s中使用标签来表示,用于之后重定位。

汇编代码中使用符号和偏移量,而机器代码中使用的是相对地址或绝对地址, 机器代码中的操作数是相对于当前指令的偏移量;汇编代码中立即数通常是明确的数字,而在机器代码中,这些立即数被直接嵌入到指令中。汇编代码中使用符号标签来表示跳转目标,而机器代码中用相对偏移量表示跳转条目。

4.5 本章小结

本章总结了汇编的概念和作用,阐述了ELF文件各部分的内容和意义,解析了hello.o反汇编后的内容并作对比

5章 链接

5.1 链接的概念与作用

概念:链接是将一个或多个目标文件组合成一个可执行文件的过程,即将.o文件转化为可执行文件。

作用:链接主要由链接器完成,主要作用有符号解析、地址重定位、段合并和生成可执行文件

5.2 在Ubuntu下链接的命令

5-1 Ubuntu下的链接命令

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

hello的ELF分为主要分为ELF头、节头表、程序头、动态偏移表、重定位节、符号表等部分,其中各个段的信息主要在节头表中说明

5-2 节头表(部分)

5.4 hello的虚拟地址空间

使用edb加载hello,其中各段地址与节头表中标识一致:

5-3 edbhello的虚拟地址空间

  

5.5 链接的重定位过程分析

objdump -d -r hello > objdump_hello.txt

5-4 objdump_hello.txt(部分)

相比于链接前的hello.o,链接后的hello反汇编代码中出现了其他的库函数,并且将重定位标签改为了确定的地址,说明链接的过程将程序调用的各种函数组装在一起,并且将跳转标签全部替换为具体地址

5.6 hello的执行流程

执行流程:

_start 、_libc_start_main、main、puts、printf、exit、sleep、getchar

5-5 使用edb追踪hello的执行流程

5.7 Hello的动态链接分析

对于位置无关代码,需要添加重定向记录,因此动态链接器使用过程链接表与全局偏移量表,即PLT和GOT,在程序加载时在具体解析重定向位置

5-6 readelf_hello.txt中的地址记录

5-7 edb中的PLT表位置

调用动态链接器前后,PLT函数的调用地址都是改变

5.8 本章小结

本章总结了链接的概念和作用,描述了hello的elf表格式,阐述了hello的虚拟地址空间特性、重定位过程和执行流程,对动态链接前后进行分析对比,链接后,hello.c正式成为可执行文件hello

6章 hello进程管理

6.1 进程的概念与作用

概念:一个执行中程序的实例

作用:资源分配和保护、并发处理、简化编程模型

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

shell 是一个交互型应用级程序,代表用户运行其他程序。shell是信号处理的代表,负责各进程创建与程序加载运行及前后台控制,作业调用,信号发送与管理等。

处理流程:

1. 提示符,当用户打开终端或命令行界面时,Shell会显示一个提示符,等待用户输入命令。

2. 解析命令,一旦用户输入命令并按下回车键,Shell会解析这个命令,识别命令的名称、参数和选项。

3. 执行命令,Shell将解析后的命令传递给操作系统内核,内核根据命令的要求执行相应的操作,比如创建、删除、移动文件,启动程序等。

4. 输出结果,当命令执行完成后,Shell会将操作系统内核返回的结果显示在命令行界面上,让用户查看。

5. 循环等待,完成命令执行后,Shell会再次显示提示符,等待用户输入下一个命令,整个过程循环进行。

6.3 Hello的fork进程创建过程

调用fork会创建一个新的子进程。子进程是父进程的一个副本,几乎完全相同,包括代码、数据、堆和栈等。当fork被调用时,程序从用户模式切换到内核模式,进入内核的系统调用处理程序。复制父进程上下文和文件描述符,设置返回值,然后返回用户模式

6.4 Hello的execve过程

execve调用会将当前进程替换为hello程序,若未成功则返回-1。操作系统内核根据路径名加载 hello 程序的可执行文件,读取程序头,设置进程上下文、切换到并跳转到入口点,开始执行hello

6.6 hello的异常与信号处理

6-1 各命令运行结果

主要会出现四类异常,即中断、陷阱、故障和终止,会产生SIGCHLD,SIGSTP,SIGINT等信号。SIGSTP 信号会使hello进程挂起, SIGINT 信号会结束hello,Kill命令会将挂起的hello被终止,不停乱按会使程序正常运行但命令行中显示输入的乱码

6.7本章小结

本章总结了进程的概念和作用,Shell的作用和处理流程,分析了hello的fork和execve过程,分析了hello对于各种异常和信号的处理过程

7章 hello的存储管理

7.1 hello的存储器地址空间

逻辑地址:程序员在源代码中使用的地址。这些地址在编译时生成,是相对于某个段的偏移量。

线性地址:由段选择器和段内偏移量组合而成的平坦地址空间中的地址。线性地址是通过段寄存器和逻辑地址转换得到的。

虚拟地址:进程所看到的地址空间中的地址。虚拟地址空间是由操作系统提供的一种抽象,使每个进程都认为自己独占一个完整的内存空间。虚拟地址通过页表映射到物理内存中的实际地址。

物理地址:内存单元在物理内存中的实际位置。处理器通过内存管理单元将虚拟地址转换为物理地址。

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

Intel架构中,逻辑地址到线性地址的转换过程即为段式管理。其中逻辑地址由段选择子和段内偏移量组成。段选择子包括段描述符表中的索引、表指示位,和请求的特权级别。段描述符包含段的基址、限长和类型及访问权限等信息 段选择子从段寄存器中获取,用于在段描述符表中查找对应的段描述符。段描述符提供了该段的基址和限长,用于确定该段的内存范围。线性地址通过将段描述符中的基址与逻辑地址中的段内偏移量相加得到。

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

线性地址到物理地址的转换过程即为页式管理。这个过程通过页表将线性地址映射到物理地址。 页式管理将内存分为页和页框。线性地址由页目录、页表、和页内偏移量组成。页目录和页表用于逐级查找物理地址,页内偏移量用于定位具体物理内存中的地址。

主要流程:处理器使用线性地址中的页目录项,其包含页表的物理基址;使用线性地址中的中间部分索引页表中的页表项。页表项包含页框的物理基址;页框基址与线性地址中的低位部分相加,得到最终的物理地址。

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

四级页表支持下,虚拟地址到物理地址的变换过程依赖于多级页表和TLB的协作。当CPU需要转换一个虚拟地址时,首先查询TLB。如果TLB命中,直接返回对应的物理地址,避免访问页表,从而加快转换速度,否则CPU会执行四级页表遍历。四级页表由PGD、PUD、PMD和PT组成。

主要流程:使用PGD索引从页全局目录中查找页上级目录的地址;使用PUD索引从页上级目录中查找页中间目录的地址;使用PMD索引从页中间目录中查找页表的地址;使用PT索引从页表中查找页框的物理基址,并加上页内偏移量得到最终的物理地址。

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

三级Cache支持下,物理内存访问流程可以分为CPU缓存访问和主存访问

CPU缓存访问:CPU首先在最快的L1 Cache中查找所需数据。如果未命中,继续查询L2 和L3Cache。如果在某级缓存中命中,则将数据返回给CPU。

      主存访问:如果在所有Cache都找到数据,则CPU向主内存发起请求。内存控制器根据请求的物理地址从主内存中读取数据,并将其传输到CPU缓存中。

7.6 hello进程fork时的内存映射

调用fork函数创建子进程时,操作系统会复制父进程的地址空间,包括代码段、数据段、堆和栈,形成一个新的地址空间给子进程使用。fork()会复制父进程的页表,但并不会复制整个物理内存内容。而是将父进程的页表条目中的读/写权限改为只读,并标记为共享,即两个进程的页表指向同一块物理内存。

7.7 hello进程execve时的内存映射

调用execve时,操作系统会清除当前进程的地址空间,加载新程序的代码段和数据段,通常,代码段会被映射到进程的可执行内存区域,数据段会被映射到进程的数据段区域。然后操作系统会根据新程序的要求,在进程的地址空间中分配堆和栈,并更新页表和内存映射,设置栈指针。之后操作系统成功加载新程序并将进程的地址空间映射到新程序的内存布局,使得进程可以开始执行新程序的代码。

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

当一个进程访问的页面不在主存中时触发异常,即缺页故障。

       处理流程:触发缺页中断,保存上下文,查找缺页位置,选择牺牲页,加载缺页,更新页表并恢复上下文

7.9动态存储分配管理

动态内存管理是指在程序运行过程中,根据需要动态分配和释放内存的机制。常用方法包括:内存分配器,如malloc函数,其中分配器分为显式和隐式分配器,分配器需要分割和合并空闲块。

7.10本章小结

本章概括了逻辑地址、线性地址、虚拟地址、物理地址的概念,简述了段式管理、页式管理的流程,简述了四级页表支持下的VA到PA的变换与三级Cache支持下的物理内存访问,描述了hello的fork与execve内存映射,阐述了缺页中断处理与动态存储分配管理方法

8章 hello的IO管理

8.1 Linux的IO设备管理方法

设备的模型化:文件

设备管理:unix io接口

Linux的IO设备管理方法包括设备的模型化和设备管理。设备的模型化将所有设备抽象为文件,通过统一的文件接口进行操作。这种统一接口允许用户空间程序通过标准的文件操作函数来访问不同类型的硬件设备。

8.2 简述Unix IO接口及其函数

Unix IO接口提供了一组用于文件和设备操作的系统调用函数,包括open,read,write,close等

8.3 printf的实现分析

https://www.cnblogs.com/pianist/p/3315801.html

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

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

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

8.4 getchar的实现分析

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

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

8.5本章小结

本章关于hello的IO管理,包括Linux的IO设备管理方法,Unix IO接口及函数以及printf和getchar的实现分析

结论

              hello从hello.c诞生以来经历了预处理、编译、汇编、链接的过程称为可执行文件hello,执行中又需要考虑内存、进程、异常、IO管理等问题,hello的运行实属不易。对hello诞生于运行流程的了解可以促进我们对计算机系统的方方面面的理解,一个简单的程序却有着重大的启发作用。

附件

hello.c :源文件

hello.s:预处理文件

hello.i:编译文件

hello.o:汇编文件

hello:链接后的可执行文件

asm.txt:反汇编文件

objdump_hello.txt:链接后反汇编文件

readelf.txt: elf文件

readelf_hello: 链接后的elf文件

参考文献

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

[2]  苏小红, 赵玲玲, 孙志岗, 王宇颖. C语言程序设计. 高等教育出版社, 2022.

计算机系统

大作业

题     目  程序人生-Hello’s P2P   

专       业        信息安全           

学     号        2022111192        

班     级         2203201          

学       生         李童溪         

指 导 教 师          史先俊           

计算机科学与技术学院

20245

 

hello从hello.c诞生以来经历了预处理、编译、汇编、链接的过程称为可执行文件hello,执行中又需要考虑内存、进程、异常、IO管理等问题,了解hello对我们理解计算机系统有重大意义,本文旨在通过阐述以上部分,总结hello从生成到运行的方方面面。

关键词:计算机系统,编译,进程,内存;                           

 

第1章 概述................................................... - 4 -

1.1 Hello简介............................................ - 4 -

1.2 环境与工具........................................... - 4 -

1.3 中间结果............................................... - 4 -

1.4 本章小结............................................... - 4 -

第2章 预处理............................................... - 6 -

2.1 预处理的概念与作用........................... - 6 -

2.2在Ubuntu下预处理的命令................ - 6 -

2.3 Hello的预处理结果解析.................... - 6 -

2.4 本章小结............................................... - 7 -

第3章 编译................................................... - 8 -

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

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

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

3.4 本章小结............................................. - 11 -

第4章 汇编................................................. - 12 -

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

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

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

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

4.5 本章小结............................................. - 15 -

第5章 链接................................................. - 16 -

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

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

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

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

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

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

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

5.8 本章小结............................................. - 19 -

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

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

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

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

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

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

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

6.7本章小结.............................................. - 21 -

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

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

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

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

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

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

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

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

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

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

7.10本章小结............................................ - 24 -

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

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

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

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

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

8.5本章小结.............................................. - 25 -

结论............................................................... - 26 -

附件............................................................... - 27 -

参考文献....................................................... - 28 -

第1章 概述

1.1 Hello简介

从hello.c经过预处理、编译、汇编、链接生成可执行文件hello,执行中又需要考虑内存、进程、异常、IO管理等问题,才能成功运行hello’

1.2 环境与工具

1.2.1 硬件环境

X64 CPU;2GHz;2G RAM;256GHD Disk 以上

1.2.2 软件环境

Windows11 64位;

Vmware 17;Ubuntu 16.04 LTS 64位;

1.2.3 开发工具

Visual Studio 2022 64位;CodeBlocks 64位;vi/vim/gedit+gcc

1.3 中间结果

hello.c :源文件

hello.s:预处理文件

hello.i:编译文件

hello.o:汇编文件

hello:链接后的可执行文件

asm.txt:反汇编文件

objdump_hello.txt:链接后反汇编文件

readelf.txt: elf文件

readelf_hello: 链接后的elf文件

1.4 本章小结

本章对文章目的进行介绍,并介绍了开发环境与必要附件

第2章 预处理

2.1 预处理的概念与作用

概念:预处理是生成二进制程序过程的第一步,预处理由预处理器完成,预处理器是编译器的一部分。

作用:预处理在实际编译源代码之前对代码进行预处理,它会处理源代码中的预处理指令,主要作用有宏定义和替换、文件包含、条件编译、编译控制等。

2.2在Ubuntu下预处理的命令

gcc -o hello.i -E hello.c

2-1 Ubuntu下的预处理命令

2-2 源文件hello.c与结果文件hello.i

2.3 Hello的预处理结果解析

hello.c的长度为24行,而hello.i的长度达到了3092行,主要为预处理过程包括的头文件源码,即stdio.h , unistd.h , stdlib.h ,以及对一些函数的声明

2-3 hello.i的开头内容

hello.i末尾的内容为hello.c的主函数

2-4 hello.i的末尾内容

2.4 本章小结

本章总结了预处理的概念和作用,使用gcc -o hello.i -E hello.c在Ubuntu下进行了预处理,并分析了预处理结果hello.i的内容

第3章 编译

3.1 编译的概念与作用

概念:编译是指将预处理后的代码转换为汇编语言代码的过程,即从.i.s的过程。       

作用:编译过程由编译器完成,主要作用有词法分析,语法分析,语义分析,代码优化,生成汇编代码等。

3.2 在Ubuntu下编译的命令

gcc -o hello.s -S hello.c

3-1 Ubuntu下的编译命令

3-2 hello.c的编译结果文件

3.3 Hello的编译结果解析

3.3.1 常量数据

      int型数值常量直接以立即数的形式表示

3-3 数值常量的存储

字符串常量,直接存储在汇编代码中

3-4 字符串常量的存储

3.3.2 局部变量

hello.c中的int i被保存在堆栈中,即-4(%rbp)

3-5 局部变量的存储

3.3.3 赋值

将0赋值给i, 对应hello.c中的i=0

3-6 赋值操作

3.3.4 算数操作

加法操作(+),将-4(%rbp)的值+1,对应hello.c的i++

3-7 加法算数操作

3.3.5 关系操作

判断是否相等(==),对应hello.c的if(argc!=5)

3-8 判断是否相等

判断是否小于(<),对应hello.c的i<10

3-9 判断是否小于

3.3.6 控制转移

主要对应hello.c的if判断与for循环,在汇编代码中通常表现为比较和跳转

3-10 控制转移

3.3.7 函数操作

调用函数时,需要将当前的基址寄存器压入栈中,保存调用者的基址,将栈指针寄存器的值赋给基址寄存器,然后通过寄存器传递参数,并把返回值存储在寄存器中,最后恢复栈帧并返回

3.4 本章小结

本章总结了编译的概念和作用,在Ubuntu下编译了hello.c得到hello.s,然后分析了汇编代码中的常量数据,局部变量,赋值操作,算术操作,关系操作,控制转移和函数调用

第4章 汇编

4.1 汇编的概念与作用

概念:汇编是将汇编语言代码转换为机器语言二进制代码的过程,即从 .s 文件到 .o 文件。机器代码是计算机可以直接执行的二进制代码。

作用:主要由汇编器进行,主要作用为解析、符号解析、指令翻译、生成机器码、生成符号表

4.2 在Ubuntu下汇编的命令

as -o hello.o hello.s

4-1 Ubuntu下的汇编命令

4-2 结果文件hello.o

4.3 可重定位目标elf格式

4-3 Ubuntu下的readelf指令

ELF头:Magic表示文件字符类型,类别表示这是一个64位的ELF文件数据,表示数据编码方式为小端序,还表明了文件类型、系统架构、文件版本号、程序的入口点地址,程序头起点表示程序头表在文件中的偏移,标志表示ELF头的大小,程序头表中的条目数等

4-4 ELF

节头表:显示所有节的名称、类型、地址、偏移量、大小等

4-5节头表

重定位节:重定位节描述了各节的重定位信息和地址修正,主要包括对.rodata(存放只读数据)putsexitprintfatoisleepgetchar的重定位信息

4-6重定位节

符号表:符号表包含了程序中所有符号的信息,包括函数、变量和节等。每个符号表条目提供了符号的详细信息,如其在内存中的地址、大小、类型、绑定属性、可见性和关联的节等。

4-7 符号表

4.4 Hello.o的结果解析

objdump -d -r hello.o > asm.txt

4-8 Ubuntu下的反汇编命令

4-9 反汇编的内容(部分)

4-10 hello.s的内容(部分)

相比于hello.s的内容,反汇编多出了地址偏移量与16进制机器指令;反汇编代码中的数字为16进制,而hello.s中的数字为10进制;反汇编代码中的跳转地址使用相对地址表示,而hello.s中使用标签来表示,用于之后重定位。

汇编代码中使用符号和偏移量,而机器代码中使用的是相对地址或绝对地址, 机器代码中的操作数是相对于当前指令的偏移量;汇编代码中立即数通常是明确的数字,而在机器代码中,这些立即数被直接嵌入到指令中。汇编代码中使用符号标签来表示跳转目标,而机器代码中用相对偏移量表示跳转条目。

4.5 本章小结

本章总结了汇编的概念和作用,阐述了ELF文件各部分的内容和意义,解析了hello.o反汇编后的内容并作对比

第5章 链接

5.1 链接的概念与作用

概念:链接是将一个或多个目标文件组合成一个可执行文件的过程,即将.o文件转化为可执行文件。

作用:链接主要由链接器完成,主要作用有符号解析、地址重定位、段合并和生成可执行文件

5.2 在Ubuntu下链接的命令

5-1 Ubuntu下的链接命令

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

hello的ELF分为主要分为ELF头、节头表、程序头、动态偏移表、重定位节、符号表等部分,其中各个段的信息主要在节头表中说明

5-2 节头表(部分)

5.4 hello的虚拟地址空间

使用edb加载hello,其中各段地址与节头表中标识一致:

5-3 edbhello的虚拟地址空间

  

5.5 链接的重定位过程分析

objdump -d -r hello > objdump_hello.txt

5-4 objdump_hello.txt(部分)

相比于链接前的hello.o,链接后的hello反汇编代码中出现了其他的库函数,并且将重定位标签改为了确定的地址,说明链接的过程将程序调用的各种函数组装在一起,并且将跳转标签全部替换为具体地址

5.6 hello的执行流程

执行流程:

_start 、_libc_start_main、main、puts、printf、exit、sleep、getchar

5-5 使用edb追踪hello的执行流程

5.7 Hello的动态链接分析

对于位置无关代码,需要添加重定向记录,因此动态链接器使用过程链接表与全局偏移量表,即PLT和GOT,在程序加载时在具体解析重定向位置

5-6 readelf_hello.txt中的地址记录

5-7 edb中的PLT表位置

调用动态链接器前后,PLT函数的调用地址都是改变

5.8 本章小结

本章总结了链接的概念和作用,描述了hello的elf表格式,阐述了hello的虚拟地址空间特性、重定位过程和执行流程,对动态链接前后进行分析对比,链接后,hello.c正式成为可执行文件hello

第6章 hello进程管理

6.1 进程的概念与作用

概念:一个执行中程序的实例

作用:资源分配和保护、并发处理、简化编程模型

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

shell 是一个交互型应用级程序,代表用户运行其他程序。shell是信号处理的代表,负责各进程创建与程序加载运行及前后台控制,作业调用,信号发送与管理等。

处理流程:

1. 提示符,当用户打开终端或命令行界面时,Shell会显示一个提示符,等待用户输入命令。

2. 解析命令,一旦用户输入命令并按下回车键,Shell会解析这个命令,识别命令的名称、参数和选项。

3. 执行命令,Shell将解析后的命令传递给操作系统内核,内核根据命令的要求执行相应的操作,比如创建、删除、移动文件,启动程序等。

4. 输出结果,当命令执行完成后,Shell会将操作系统内核返回的结果显示在命令行界面上,让用户查看。

5. 循环等待,完成命令执行后,Shell会再次显示提示符,等待用户输入下一个命令,整个过程循环进行。

6.3 Hello的fork进程创建过程

调用fork会创建一个新的子进程。子进程是父进程的一个副本,几乎完全相同,包括代码、数据、堆和栈等。当fork被调用时,程序从用户模式切换到内核模式,进入内核的系统调用处理程序。复制父进程上下文和文件描述符,设置返回值,然后返回用户模式

6.4 Hello的execve过程

execve调用会将当前进程替换为hello程序,若未成功则返回-1。操作系统内核根据路径名加载 hello 程序的可执行文件,读取程序头,设置进程上下文、切换到并跳转到入口点,开始执行hello

6.6 hello的异常与信号处理

6-1 各命令运行结果

主要会出现四类异常,即中断、陷阱、故障和终止,会产生SIGCHLD,SIGSTP,SIGINT等信号。SIGSTP 信号会使hello进程挂起, SIGINT 信号会结束hello,Kill命令会将挂起的hello被终止,不停乱按会使程序正常运行但命令行中显示输入的乱码

6.7本章小结

本章总结了进程的概念和作用,Shell的作用和处理流程,分析了hello的fork和execve过程,分析了hello对于各种异常和信号的处理过程

第7章 hello的存储管理

7.1 hello的存储器地址空间

逻辑地址:程序员在源代码中使用的地址。这些地址在编译时生成,是相对于某个段的偏移量。

线性地址:由段选择器和段内偏移量组合而成的平坦地址空间中的地址。线性地址是通过段寄存器和逻辑地址转换得到的。

虚拟地址:进程所看到的地址空间中的地址。虚拟地址空间是由操作系统提供的一种抽象,使每个进程都认为自己独占一个完整的内存空间。虚拟地址通过页表映射到物理内存中的实际地址。

物理地址:内存单元在物理内存中的实际位置。处理器通过内存管理单元将虚拟地址转换为物理地址。

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

在Intel架构中,逻辑地址到线性地址的转换过程即为段式管理。其中逻辑地址由段选择子和段内偏移量组成。段选择子包括段描述符表中的索引、表指示位,和请求的特权级别。段描述符包含段的基址、限长和类型及访问权限等信息 段选择子从段寄存器中获取,用于在段描述符表中查找对应的段描述符。段描述符提供了该段的基址和限长,用于确定该段的内存范围。线性地址通过将段描述符中的基址与逻辑地址中的段内偏移量相加得到。

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

线性地址到物理地址的转换过程即为页式管理。这个过程通过页表将线性地址映射到物理地址。 页式管理将内存分为页和页框。线性地址由页目录、页表、和页内偏移量组成。页目录和页表用于逐级查找物理地址,页内偏移量用于定位具体物理内存中的地址。

主要流程:处理器使用线性地址中的页目录项,其包含页表的物理基址;使用线性地址中的中间部分索引页表中的页表项。页表项包含页框的物理基址;页框基址与线性地址中的低位部分相加,得到最终的物理地址。

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

四级页表支持下,虚拟地址到物理地址的变换过程依赖于多级页表和TLB的协作。当CPU需要转换一个虚拟地址时,首先查询TLB。如果TLB命中,直接返回对应的物理地址,避免访问页表,从而加快转换速度,否则CPU会执行四级页表遍历。四级页表由PGD、PUD、PMD和PT组成。

主要流程:使用PGD索引从页全局目录中查找页上级目录的地址;使用PUD索引从页上级目录中查找页中间目录的地址;使用PMD索引从页中间目录中查找页表的地址;使用PT索引从页表中查找页框的物理基址,并加上页内偏移量得到最终的物理地址。

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

三级Cache支持下,物理内存访问流程可以分为CPU缓存访问和主存访问

CPU缓存访问:CPU首先在最快的L1 Cache中查找所需数据。如果未命中,继续查询L2 和L3Cache。如果在某级缓存中命中,则将数据返回给CPU。

      主存访问:如果在所有Cache都找到数据,则CPU向主内存发起请求。内存控制器根据请求的物理地址从主内存中读取数据,并将其传输到CPU缓存中。

7.6 hello进程fork时的内存映射

调用fork函数创建子进程时,操作系统会复制父进程的地址空间,包括代码段、数据段、堆和栈,形成一个新的地址空间给子进程使用。fork()会复制父进程的页表,但并不会复制整个物理内存内容。而是将父进程的页表条目中的读/写权限改为只读,并标记为共享,即两个进程的页表指向同一块物理内存。

7.7 hello进程execve时的内存映射

调用execve时,操作系统会清除当前进程的地址空间,加载新程序的代码段和数据段,通常,代码段会被映射到进程的可执行内存区域,数据段会被映射到进程的数据段区域。然后操作系统会根据新程序的要求,在进程的地址空间中分配堆和栈,并更新页表和内存映射,设置栈指针。之后操作系统成功加载新程序并将进程的地址空间映射到新程序的内存布局,使得进程可以开始执行新程序的代码。

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

当一个进程访问的页面不在主存中时触发异常,即缺页故障。

       处理流程:触发缺页中断,保存上下文,查找缺页位置,选择牺牲页,加载缺页,更新页表并恢复上下文

7.9动态存储分配管理

动态内存管理是指在程序运行过程中,根据需要动态分配和释放内存的机制。常用方法包括:内存分配器,如malloc函数,其中分配器分为显式和隐式分配器,分配器需要分割和合并空闲块。

7.10本章小结

本章概括了逻辑地址、线性地址、虚拟地址、物理地址的概念,简述了段式管理、页式管理的流程,简述了四级页表支持下的VA到PA的变换与三级Cache支持下的物理内存访问,描述了hello的fork与execve内存映射,阐述了缺页中断处理与动态存储分配管理方法

第8章 hello的IO管理

8.1 Linux的IO设备管理方法

设备的模型化:文件

设备管理:unix io接口

Linux的IO设备管理方法包括设备的模型化和设备管理。设备的模型化将所有设备抽象为文件,通过统一的文件接口进行操作。这种统一接口允许用户空间程序通过标准的文件操作函数来访问不同类型的硬件设备。

8.2 简述Unix IO接口及其函数

Unix IO接口提供了一组用于文件和设备操作的系统调用函数,包括open,read,write,close等

8.3 printf的实现分析

https://www.cnblogs.com/pianist/p/3315801.html

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

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

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

8.4 getchar的实现分析

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

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

8.5本章小结

本章关于hello的IO管理,包括Linux的IO设备管理方法,Unix IO接口及函数以及printf和getchar的实现分析

结论

              hello从hello.c诞生以来经历了预处理、编译、汇编、链接的过程称为可执行文件hello,执行中又需要考虑内存、进程、异常、IO管理等问题,hello的运行实属不易。对hello诞生于运行流程的了解可以促进我们对计算机系统的方方面面的理解,一个简单的程序却有着重大的启发作用。

附件

hello.c :源文件

hello.s:预处理文件

hello.i:编译文件

hello.o:汇编文件

hello:链接后的可执行文件

asm.txt:反汇编文件

objdump_hello.txt:链接后反汇编文件

readelf.txt: elf文件

readelf_hello: 链接后的elf文件

参考文献

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

[2]  苏小红, 赵玲玲, 孙志岗, 王宇颖. C语言程序设计. 高等教育出版社, 2022.

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值