计算机系统
大作业
题 目 程序人生-Hello’s P2P
专 业 计算机
学 号
班 级
学 生
指 导 教 师 史先俊
计算机科学与技术学院
2022年5月
本文借助程序hello.c实例,对深入理解计算机系统这门课程的知识体系进行了一个完整的梳理归纳:从程序的编译,链接,加载,运行,终止到回收,完整的展现了程序hello.c的“生命周期”,并详细展开每一个环节。通过该过程,我们得以将课堂所学的每一个知识串联在一起,对计算机系统有一个更系统全面的认识。
关键词:深入理解计算机系统;程序生命周期;Linux平台;进程;存储;
(摘要0分,缺失-1分,根据内容精彩称都酌情加分0-1分)
目 录
2.2在Ubuntu下预处理的命令............................................................................. - 5 -
5.3 可执行目标文件hello的格式........................................................................ - 8 -
6.2 简述壳Shell-bash的作用与处理流程........................................................ - 10 -
6.3 Hello的fork进程创建过程......................................................................... - 10 -
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 -
8.2 简述Unix IO接口及其函数.......................................................................... - 13 -
第1章 概述
1.1 Hello简介
hello.c文件是一个C语言程序。功能为在接收正确的参数之后,会在控制台中输出”Hello 学号 姓名 秒数”。要使得程序可以运行,程序需要经历以下过程:预处理(宏定义,展开头文件)、编译(翻译为汇编语言程序)、汇编(翻译成可重定位的目标程序)、链接(生成可执行目标程序),最终得到可执行文件,我们称为程序的Program To Progress,即P2P。
要想运行该程序,shell先在磁盘上找到该程序,fork子进程,然后用execve对hello载入物理内存,映射虚拟内存,开始执行。在main函数中,cpu为程序分配时钟周期,执行其控制直流,结束之后,shell令父进程将其回收,即完成了程序的From Zero-0 to Zero-0(O2O)。
1.2 环境与工具
硬件环境:AMD Ryzen 7 4800H with Radeon Graphics 2.90 GHz
16.0 GB RAM
软件环境:Windows 10 家庭中文版 64位 VirtualBox/Vmware 11以上;Ubuntu 20.04 LTS 64位
开发工具:CodeBlocks;vi/vim/gpedit+gcc;Visual Studio 2010 64位以上;GDB/OBJDUMP;DDD/EDB等
1.3 中间结果
hello.i 经过预处理的文本文件
hello.s 完成编译的汇编语言程序
hello.o 经过汇编翻译而成的可重定位的目标程序
hello 链接完成的可执行文件
hello_ELF.txt hello.o的ELF格式文件
hello_ELF2.txt hello的ELF格式文件
hello_obj.txt hello.0的反汇编文件
hello_obj2.txt hello的反汇编文件
1.4 本章小结
对程序hello的一生进行了大体的介绍,简介作业环境工具和中间文件。
(第1章0.5分)
第2章 预处理
2.1 预处理的概念与作用
概念:预处理是指程序源代码在被翻译为目标代码的过程中,生成二进制码之前的过程,由预处理器对程序源代码文本进行处理,其结果再由编译器核心进一步进行编译。
作用:对源程序中的宏定义进行统一替换;包含头文件中被调用的其他模块的函数;对程序中的注释无效化处理,针对不同情况处理条件编译;添加行号信息,方便debug快速定位错误,方便调试。预处理主要起到以上作用。
2.2在Ubuntu下预处理的命令
gcc -m64 -no-pie -fno-PIC -E hello.c -o hello.i
2.3 Hello的预处理结果解析
打开运行上述预处理指令得到的文件,发现文件前面存在大量由头文件展开导入的内容,在hello.c中对应着
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
由此合理猜测:预处理最大的作用是解析头文件的引用,并将其展开。
由图中行号可见,文件3000行后才出现源程序的main函数,可见头文件展开的规模之大。
2.4 本章小结
本章简单介绍了c语言程序有关预处理的知识,得知了c语言预处理ubuntu下的命令,通过阅读hello.i文件得知预处理后引入头文件中的大量定义,函数。理解了程序的编译不是简单的函数式的直接转换,而要经过复杂的过程。
(第2章0.5分)
第3章 编译
3.1 编译的概念与作用
概念:编译是将高级语言转换成汇编语言的过程,编译器(ccl)会进行词法分析,语法分析,并进行翻译(尽管机器仍然无法理解编译后的程序)
作用:编译后hello.i转化为hello.s,其中包含汇编语言程序,程序员可从汇编语言看到程序更偏向底层的运作,例如如何操控数据,调用哪些内存与寄存器。
1.源代码输入扫描器,字符序列被分割成一系列记号。
2.生成语法树。
3.语法分析器指示判断是否合法,并不判断对错。
4.中间代码令编译器分为前端与后端:前端产生与机器环境无关的中间代码,后端将中间代码转换为目标机器代码,使一个前端可以对应多个后端,适应不同平台。其中后端包括:代码生成器(依赖目标机器),目标代码优化器(选择合适寻址方式,删除多余的指令)。
3.2 在Ubuntu下编译的命令
gcc -m64 -no-pie -fno-PIC -S hello.i -o hello.s
3.3 Hello的编译结果解析
现在针对操作处理,数据类型,观察对比hello.c与hello.s,对hello.s进行分析:
3.3.1.数据
字符串常量:在汇编代码中发现代码中存在的两个字符串:"用法: Hello 学号 姓名秒数!\n","Hello %s %s\n"
变量:观察原函数中的变量,得知存在i,argv,argc三个变量。根据所学知识可知存储函参的前六个寄存器为%rdi,%rsi,%rdx,%rcx,%r8,%r9。因此argc存储于%edi中,argv存储于%rsi中,且分别存于栈帧的-20(%rbp),-32(%rbp)位置。
i作为局部变量一般存储于栈中,观察汇编代码得i的存储位置如图。
3.3.2 函数操作
由原函数得知存在对三个函数的调用exit(),sleep(),getchar(),printf(),atoi
();在汇编代码中可以寻找到对应部分:
其中调用atoi(),sleep()的时候,参数均被存入%rdi。atoi的返回值存入%rax后又存入%rdi为sleep调用(atoi为类型转换函数)。
3.3.3 算术操作
for循环中含有i++的算术操作。
3.3.4 关系操作
在for循环中含有i<8的关系操作,此外if判断中还含有argc!=4的关系操作。
通过cmp比较后利用条件跳跃来表示关系比较结果。
3.3.7 控制转移
源程序中存在if跳转和for循环。
if:
若未满足argc!=4,则跳转至L2继续程序,否则调用exit(1)。
for:
先进行L2初始化,然后跳转至L3循环条件判断。
若符合循环条件,则执行跳转至L4循环体。
3.4 本章小结
本章节简单介绍了编译的概念与作用,给出了在ubuntu环境下对hello.i进行编译的对应gcc指令;在hello.c与hello.s的对比中理解高级语言C与汇编语言之间的对应关系,进而理解编译的实际作用原理。
(第3章2分)
第4章 汇编
4.1 汇编的概念与作用
概念:把汇编代码翻译成机器代码,即目标代码的过程,即由.s文件到.o文件。
作用:使得CPU可以执行程序。
4.2 在Ubuntu下汇编的命令
gcc -m64 -no-pie -fno-PIC -c hello.s -o hello.o
4.3 可重定位目标elf格式
执行readelf -a hello.o>hello_ELF.txt,即可生成elf格式的文件。
4.3.1 ELF头
ELF头以16字节的序列开始(包含系统字的大小和字节顺序),其余部分包含ELF头大小、目标文件类型、机器类型、节头部表的文件偏移、条目大小和数量。
#define EI_NIDENT 16
typedef struct{
unsigned char e_ident[EI_NIDENT];
//包含用以表示ELF文件的字符,以及其他一些与机器无关的信息。开头的4个字节值固定不变,为0x7f和ELF三个字符。
Elf32_Half e_type;//文件类型
Elf32_Half e_machine;//运行该程序需要的体系结构
Elf32_Word e_version;//文件版本
Elf32_Addr e_entry;// 程序的入口地址
Elf32_Off e_phoff;// Program header table 在文件中的偏移量
Elf32_Off e_shoff;// Section header table 在文件中的偏移量
Elf32_Word e_flags;// ELF文件平台的相关属性(IA32=0)
Elf32_Half e_ehsize;// ELF header长度
Elf32_Half e_phentsize;// 表示Program header table中条目大小
Elf32_Half e_phnum;// 表示Program header table中条目数量
Elf32_Half e_shentsize;// 表示Section header table中条目大小
Elf32_Half e_shnum;// 表示Section header table中条目数量
Elf32_Half e_shstrndx;// 包含节名称的字符串的下标
} Elf32_Ehdr;
4.3.2 节头
节头是保存ELF文件段的基本属性的结构。ELF文件的段结构由段表决定,编译器,链接器,装载器通过段表来访问各个段的属性。
描述段的结构如下所示:
typedef struct
{
Elf32_Word sh_name; //段的名字
Elf32_Word sh_type; // 段的类型(代码段,数据段,符号表)
Elf32_Word sh_flags; / 段在进程虚拟地址空间中的属性
Elf32_Addr sh_addr; // 段的虚拟地址
Elf32_Off sh_offset; // 段在文件中的偏移
Elf32_Word sh_size; // 段的长度
Elf32_Word sh_link;
Elf32_Word sh_info;
Elf32_Word sh_addralign; // 段地址对齐
Elf32_Word sh_entsize;
} Elf32;
4.3.3 重定位表
链接器需要通过重定位表中的信息来对目标文件中的部分进行重定位。
4.3.4 符号表
用字符串来表示已有的所有字符,用偏移量来取单个字符。
4.4 Hello.o的结果解析
输入objdump -d -r hello.o即可查看hello.o的反汇编结果。(已输出为hello_obj.txt)
与原编译结果hello.s相比较,寻找其中的区别:
1.hello.s相比而言缺少前段的机器码。
2.反汇编代码中函数调用不含函数名。
3.反汇编代码操作数采用16进制而不是10进制。
4.5 本章小结
本章简单介绍了汇编操作的概念与作用,对.s文件进行汇编后,将其转化为elf格式并进行分析,最终反汇编.o文件并与.s文件进行对比。
(第4章1分)
第5章 链接
5.1 链接的概念与作用
概念:链接是处理可重定位文件,把各种符号引用和符号定义转换为可执行文件,组合成一个单一文件的过程。
链接分为静态链接和动态链接:前者是程序开发阶段程序员用ld静态链接器手动链接的过程,后者动态链接则是程序运行期间系统调用动态链接器自动链接的过程。
作用:令不同模块的代码互相整合,可以将多个文件链接彻底转化为机械代码,生成可执行文件。使得分离编程成为可能。
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的格式
输入readelf -S hello(已生成文件hello_ELF2.txt)
5.4 hello的虚拟地址空间
使用edb加载hello,查看本进程的虚拟地址空间各段信息,并与5.3对照分析说明。
打开Plugins-SymbolViewer,观察虚拟空间地址各段信息。与5.3对比发现一致。
5.5 链接的重定位过程分析
输入objdump -d -r hello>hello_obj2.txt,生成hello的反汇编文件hello_obj2.txt。
与前面生成的反汇编hello_obj.txt比较,发现新文件中引入了调用函数(如atoi,sleep,printf等)的详细解释。
此外,新文件中采用的是虚拟地址,与老文件的相对偏移不同。
5.6 hello的执行流程
使用edb执行hello,说明从加载hello到_start,到call main,以及程序终止的所有过程。请列出其调用与跳转的各个子程序名或程序地址。
ld-2.27.so!_dl_start—
ld-2.27.so!_dl_init—
hello!_start—0x400550
hello!_init—0x4004c0
hello!main—0x400582
hello!puts@plt–0x4004f0
hello!exit@plt–0x400530
hello!printf@plt–0x400500
hello!sleep@plt–0x400540
hello!getchar@plt–0x400510
libc-2.27.so!exit+0-0x40530
5.7 Hello的动态链接分析
分析hello程序的动态链接项目,通过edb调试,分析在dl_init前后,这些项目的内容变化。要截图标识说明。
执行_dl_init之后,global_offset表的值从0到被赋予正确的偏移量。
5.8 本章小结
本章了解了链接的概念与作用,分析链接后的可执行文件的ELF格式,了解了动态链接,重定位以及执行过程。
(第5章1分)
第6章 hello进程管理
6.1 进程的概念与作用
概念:进程是一个执行中的程序的实例,每个程序都运行在进程的上下文中。
作用:CPU可以通过进程并行完成任务,达到高效利用的目的。
进程提供给应用程序两个关键抽象:
1、逻辑控制流
a) 每个程序似乎独占地使用CPU
b) 通过OS内核的上下文切换机制提供
2、私有地址空间
a) 每个程序似乎独占地使用内存系统
b) OS内核的虚拟内存机制提供
6.2 简述壳Shell-bash的作用与处理流程
Shell解释用户输入的命令,然后将其送到内核;Shell还具有编程语言,允许编写由shell命令组成的程序。
处理流程:
1.读取用户输入。
2.获取输入参数。
3.解释并执行该命令。
4.返回1.
6.3 Hello的fork进程创建过程
在shell内输入命令./hello 120L020315 胡泽恩 2,于是shell调用fork()函数,创建一个子进程来执行hello。调用一次,返回两次。
6.4 Hello的execve过程
exceve函数加载并运行可执行目标文件,并带参数列表和环境变量列表。除非出现错误,否则execve从不返回。在execve运行时,先从0x00400000开始程序的执行。先是从可执行文件中加载的内容,然后是运行时的堆栈和共享库的存储器映射区域。
6.5 Hello的进程执行
(以下格式自行编排,编辑时删除)
在调用Sleep函数时,由于sleep属于内核code,需要进行进程切换,此时会从user code区域进行上下文切换,进入kernel code,执行完成后再通过上下文切换回到user code区域。
6.6 hello的异常与信号处理
可能异常:1.终止2.故障
可能信号:1.SIGINT 2.SIGSTP 3.SIGCONT 4.SIGKILL
正常执行结果如上图。
在程序执行过程中敲打键盘,并未对程序造成影响,在之后被识别为输入,可见过程中的输入并未对程序运行造成任何影响。
在执行途中按下ctrl+z,发送SIGTSTP信号,使其停止。输入jobs或ps均能看见该进程。
发送SIGCONT,使进程继续进行。
发送SIGKILL,杀死该进程。
在hello执行过程中,按下ctrl+c,发送SIGINT信号,终止该进程。
6.7本章小结
本章介绍了进程的概念作用,运行原理,进程的用户模式和内核模式、上下文切换、重要函数fork和execve、异常与信号、进程的并发执行等等。
(第6章1分)
第7章 hello的存储管理
7.1 hello的存储器地址空间
逻辑地址:又称相对地址,是程序运行由CPU产生的与段相关的偏移地址部分。用于描述程序运行段。
物理地址:内存地址寄存器中的地址,内存单元的真正地址。在前端总线上传输而且唯一。
线性地址:在保护模式下,“段基址+段内偏移地址”叫做线性地址,是用于描述程序分页信息的地址。
虚拟地址:虚拟地址并不真实存在于计算机中。每个进程都分配有自己的虚拟空间,而且只能访问自己被分配使用的空间。虚拟空间受到物理内存大小的限制。
7.2 Intel逻辑地址到线性地址的变换-段式管理
将逻辑地址分成段选择符+段描述符的判别符(TI)+地址偏移量的形式,判断TI字段,当索引位ti=0时,段描述符表在rpgdt中,ti=1时,段描述符表在rpldt中,然后再将其组合成段描述符+地址偏移量的形式,这样就转换成线性地址了。
7.3 Hello的线性地址到物理地址的变换-页式管理
线性地址(虚拟地址)由虚拟页号VPN和虚拟页偏移VPO组成。我们先将线性地址分为VPN(虚拟页号)+VPO(虚拟页偏移)的形式,然后再将VPN拆分成TLBT(TLB标记)+TLBI(TLB索引)然后去TLB缓存里找所对应的PPN(物理页号)如果发生缺页情况则直接查找对应的PPN,找到PPN之后,最后将线性地址中的VPO与PPN组合起来就得到了对应的物理地址。
7.4 TLB与四级页表支持下的VA到PA的变换
虚拟地址VA虚拟页号VPN和虚拟页偏移VPO组成。先还是按照7.3所说的那样将VPN分成三段,若TLB不命中时,VPN被划分为四个片,每个片被用作到一个页表的偏移量,CR3寄存器包含L1页表的物理地址。VPN1提供到一个L1 PTE的偏移量,这个PTE包含L2页表的基地址。VPN2提供到一个L2 PTE的偏移量,依次类推。最后在L4页表中对应的PTE中取出PPN,与VPO连接,形成物理地址PA。
7.5 三级Cache支持下的物理内存访问
将物理地址拆分成CT(标记)+CI(索引)+CO(偏移量),然后在一级cache内部找,如果未能寻找到标记位为有效的字节(miss)的话就去二级和三级cache中寻找对应的字节,找到之后返回结果。
7.6 hello进程fork时的内存映射
fork函数被shell进程调用时,内核为新进程创建各种数据结构,并分配给他一个唯一的PID。它创建了当前进程的mm_struct区域结构和页表的原样副本,并且将两个进程中的每个页面都标记为只读。
7.7 hello进程execve时的内存映射
exceve函数加载和执行程序Hello,需要以下几个步骤:
1.删除已存在的用户区域。
2.映射私有区域。为Hello的代码、数据、bss和栈区域创建新的区域结构,所有这些区域都是私有的、写时复制的。
3.映射共享区域。比如Hello程序与标准C库libc.so链接,这些对象都是动态链接到Hello的,然后再用户虚拟地址空间中的共享区域内。
4.设置程序计数器。exceve做的最后一件事就是设置当前进程上下文的计数器,使得其指向入口。
7.8 缺页故障与缺页中断处理
1.段错误:先判断这个缺页的虚拟地址是否合法,遍历所有的合法区域结构,如果这个虚拟地址对所有的区域结构都无法匹配,那么就返回一个段错误(segment fault)。
2.非法访问:接着查看这个地址的权限,判断一下进程是否有读写改这个地址的权限。
3.如果不是上面两种情况那就是正常缺页,牺牲一个页面然后换入新的页面并更新到页表。
缺页中断处理:当发生缺页故障时,将控制转移给处理程序,处理程序从磁盘加载适当的页面,然后将控制转移给引起故障的指令。接着指令再次执行,相应的物理页面已经驻留在内存中,就可以没有故障地运行指令了。
7.9动态存储分配管理
动态内存分配器维护着一个进程的虚拟内存区域,称为堆。堆是一个请求二进制零的区域,它紧接在未初始化的数据区域后开始,并向上生长。对于每个进程,内核维护着一个变量brk,指向堆的顶部。
分配器有两种风格——显示分配器和隐式分配器,但是这两种风格都要求应用显示的分配块。
其中显示分配器要求显示释放任何已分配的块,如malloc、new等。
隐式分配器要求分配器检测一个已分配块何时不再被程序所使用,那么就释放这个块。所以也叫垃圾收集器。
显示分配器有以下几点要求:能够处理任意请求序列;立即相应请求;只是用堆;对齐开;不修改已分配的块。在性能上有两点追求:最大化吞吐,最大化内存利用率;两者通常矛盾。
7.10本章小结
本章较为详细的介绍了计算机系统存储的概念,引入了四种地址的概念,分别介绍了内存的分页式管理,三级cache的高层内存管理等等,在计算机系统学习占有很大的比重。
(第7章 2分)
第8章 hello的IO管理
8.1 Linux的IO设备管理方法
(以下格式自行编排,编辑时删除)
设备的模型化:文件
文件分为普通文件:包含任意数据的文件;目录(文件夹):包含一组链接的文件,每个链接都将一个文件名映射到一个文件。套接字:用来与另一个进程进行跨网络通信的文件;命名通道;符号链接;字符和块设备;
设备管理:unix io接口:打开和关闭文件,读取和写入文件,改变当前文件的位置。
8.2 简述Unix IO接口及其函数
打开和关闭文件:
int open(char *filename, int flags, mode_t mode);
open函数将filename转换为一个文件描述符,并返回描述符数字。返回的描述符总是在进程中当前没有打开的最小描述符。flags参数指明了进程打算如何访问这个文件,mode参数指定了新文件的访问权限位。
int close(int fd);
进程通过调用close关闭一个打开的文件。
读和写文件:
ssize_t read(int fd, void *buf, size_t n);
read函数从描述符为fd的当前文件位置复制最多n个字节到内存位置buf。返回值-1表示一个错误,而返回值0表示EOF。否则,返回值表示的是实际传送的字节数量。
ssize_t write(int fd, const void *buf, size_t n);
write函数从内存位置buf复制之多n个字节到描述符fd的当前文件位置。
DIO *opendir(const char *name);
函数opendir以路径名为参数,返回指向目录流的指针。流是对条目有序列表的抽象,在这里是指目录项的列表。
struct dirent *readdir(DIR *dirp);
每次对readdir的调用返回的都是指向流dirp中下一个目录项的指针,或者,如果没有更过目录项则返回NULL。
int closedir(DIR *dirp);
函数closedir关闭流并释放其所有的资源。
I/O重定向:
int dup2(int oldfd, int newfd);
dup2函数复制描述符表表项oldfd到描述符表项newfd,覆盖描述符表表项newfd以前的内容。如果newfd已经打开了,dup2会在复制oldfd之前关闭newfd。
8.3 printf的实现分析
printf需要做的事情是:接受一个fmt的格式,然后将匹配到的参数按照fmt格式输出。
从上图可见,调用了两个外部函数:vsprintf,write。
vsprintf的作用是将所有的参数内容格式化之后存入buf,然后返回格式化数组的长度。write函数是将buf中的i个元素写到终端的函数。
字符显示驱动子程序:从ASCII到字模库到显示vram,(存储每一个点的RGB颜色信息)。
显示芯片按照刷新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量)。
8.4 getchar的实现分析
getchar()是 stdio.h.中的库函数,它的作用是从stdin流中读入一个字符,也就是说,如果stdin有数据的话不用输入它就可以直接读取了。
实际上是输入设备->内存缓冲区->程序getchar
异步异常-键盘中断的处理:键盘中断处理子程序。接受按键扫描码转成ascii码,保存到系统的键盘缓冲区。
getchar等调用read系统函数,通过系统调用读取按键ascii码,直到接受到回车键才返回。
8.5本章小结
本章节讲述了linux的I/O设备管理机制与相关函数,简单分析了printf和getchar函数的实现方法以及操作过程。
(第8章1分)
结论
简单的一个hello.c,在计算机内经过了如下步骤:
编写:用编辑器写下hello.c
预处理:hello.c的库展开至hello.i中
编译:将hello.i编译成为汇编文件hello.s
汇编:将hello.s汇编成为可重定位目标文件hello.o
链接:将hello.o与动态链接库链接成为可执行文件hello
运行:在shell中输入./hello 120L020315 胡泽恩 1
创建子进程:shell进程调用fork为其创建子进程
运行程序:shell调用execve,execve调用启动加载器,加映射虚拟内存,进入程序后开始载入物理内存,然后进入 main函数。
此外还有执行指令,访问内存,动态申请内存,接受信号等……短短一个程序在实现其功能的过程中经历了那么多步骤,完成了生命的P2P和O2O,令人不禁感叹:简单的功能背后也离不开各个组成部分的参与,如今的计算机科学大厦下面,是几十年打下的深厚地基在支撑。计算机科学的学习仍然路漫漫,而我也将上下求索,学习不止。
(结论0分,缺失 -1分,根据内容酌情加分)
附件
列出所有的中间产物的文件名,并予以说明起作用。
hello.i 经过预处理的文本文件
hello.s 完成编译的汇编语言程序
hello.o 经过汇编翻译而成的可重定位的目标程序
hello 链接完成的可执行文件
hello_ELF.txt hello.o的ELF格式文件
hello_ELF2.txt hello的ELF格式文件
hello_obj.txt hello.0的反汇编文件
hello_obj2.txt hello的反汇编文件
(附件0分,缺失 -1分)
参考文献
为完成本次大作业你翻阅的书籍与网站等
[1] GCC编译优化和调试选项 https://zhuanlan.zhihu.com/p/342695075
[2] 深入理解计算机系统 Randal E. Bryant David R. O’Hallaron
[3] ELF文件格式 百度百科 https://baike.baidu.com/item/ELF/7120560#1
(参考文献0分,缺失 -1分)