
计算机系统
大作业
题 目 程序人生-Hello’s P2P
专 业 计算机科学与技术
学 号 2021110908
班 级 2103103
学 生 朱宸慷
指 导 教 师 刘宏伟
计算机科学与技术学院
2022年5月
本文主要通过结合本学期计算机系统这门课程所学习的知识,以及教材《深入理解计算机系统》相关内容,分析研究了hello.c文件的生命周期。本文从hello.c这个c源文件开始,深入分析在linux系统下c源文件经过的预处理、编译、汇编、链接、执行、终止以及最后被回收的过程。通过对于这一过程的学习,得以深入理解linux系统下程序的构造、执行、回收过程等等,从而回顾本学期所学习到的内容的知识要点,从而得以梳理知识框架,做到学以致用、融会贯通。
关键词: Hello’s P2P;程序人生;计算机系统;程序生命周期
目 录
第1章 概述................................................................................... - 4 -
1.1 Hello简介............................................................................ - 4 -
1.2 环境与工具........................................................................... - 4 -
1.3 中间结果............................................................................... - 4 -
1.4 本章小结............................................................................... - 5 -
第2章 预处理............................................................................... - 6 -
2.1 预处理的概念与作用........................................................... - 6 -
2.2在Ubuntu下预处理的命令................................................ - 6 -
2.3 Hello的预处理结果解析.................................................... - 6 -
2.4 本章小结............................................................................... - 7 -
第3章 编译................................................................................... - 9 -
3.1 编译的概念与作用............................................................... - 9 -
3.2 在Ubuntu下编译的命令.................................................... - 9 -
3.3 Hello的编译结果解析........................................................ - 9 -
3.4 本章小结............................................................................. - 13 -
第4章 汇编................................................................................. - 14 -
4.1 汇编的概念与作用............................................................. - 14 -
4.2 在Ubuntu下汇编的命令.................................................. - 14 -
4.3 可重定位目标elf格式...................................................... - 14 -
4.4 Hello.o的结果解析........................................................... - 16 -
4.5 本章小结............................................................................. - 17 -
第5章 链接................................................................................. - 18 -
5.1 链接的概念与作用............................................................. - 18 -
5.2 在Ubuntu下链接的命令.................................................. - 18 -
5.3 可执行目标文件hello的格式......................................... - 18 -
5.4 hello的虚拟地址空间....................................................... - 21 -
5.5 链接的重定位过程分析..................................................... - 22 -
5.6 hello的执行流程............................................................... - 23 -
5.7 Hello的动态链接分析...................................................... - 24 -
5.8 本章小结............................................................................. - 25 -
第6章 hello进程管理.......................................................... - 26 -
6.1 进程的概念与作用............................................................. - 26 -
6.2 简述壳Shell-bash的作用与处理流程........................... - 26 -
6.3 Hello的fork进程创建过程............................................ - 26 -
6.4 Hello的execve过程........................................................ - 27 -
6.5 Hello的进程执行.............................................................. - 27 -
6.6 hello的异常与信号处理................................................... - 28 -
6.7本章小结.............................................................................. - 32 -
参考文献....................................................................................... - 36 -
第1章 概述
1.1 Hello简介
1.1.1 P2P
P2P是指From Program to Process,也即从一个c源文件hello.c程序(Program)到一个可执行的程序(Process)的过程。Hello首先是一个存储在磁盘上的文本文件,使用预处理器处理这个文件,将头文件插入,得到hello.i。之后将hello.i输入编译器,编译器生成汇编语言文件hello.s。之后,通过汇编器,我们讲文本文件hello.s转换为二进制机器码格式的可重定位文件hello.o。此时使用链接器,就可以将hello.o链接生成可执行文件hello,再调用shell运行hello为其创建进程(process),就完成了p2p
1.1.2 020
020 是指 from zero to zero。Hello 程序执行前,不占用内存空间,这就是第一个0。使用shell执行hello后,首先调用execve,依次进行虚拟内存映射、物理内存载入等等步骤,再进程的上下文中运行hello。执行时,这一进程被分配进入流水线,执行完毕后,由父进程回收进程,之后内核清除相关信息,就完成了第二个0.
1.2 环境与工具
硬件环境:
处理器:AMD Ryzen 7 5800H 3.2GHz
内存:16GB(3200MHz)
软件环境:
Windows10;Ubantu
开发与调试工具:gcc,cpp,as,ld,edb,gdb,readelf
1.3 中间结果
| 文件名 | 功能 |
| hello.i | hello.c经过预处理得到的文本文件 |
| hello.s | 编译后得到的汇编文件 |
| hello.o | 汇编后得到的可重定向文件 |
| hello | 链接得到的可执行文件 |
| hello1_elf.txt | 用readelf读hello.o得到的elf文件 |
| hello1_dis.txt | 反汇编hello.o得到的文件 |
| hello2_elf.txt | hello的elf格式文件 |
| hello2_dis.txt | hello的反汇编文件 |
1.4 本章小结
本章首先介绍了hello中p2p和020的概念,之后介绍了所用到的实验环境,最后介绍了本文中所涉及到的中间文件的名称及功能。
第2章 预处理
2.1 预处理的概念与作用
2.1.1概念:
预处理是在编译文件前对文本文件进行的处理,修改原始的c程序。这一过程中预处理器cpp会根据文件头部#开头的语句进行操作。
2.1.2作用:
预处理器会读取到#include<>相关内容,并且把头文件插入到文本文件中。此外,预处理器还会根据#define的内容进行宏替换,将代码中使用宏定义的地方替换为定义的实际值。预处理器还有可能根据#ifdef等决定是否插入某些内容。在这一过程中,预处理器会忽略所有的注释以及空白,最终生成hello.i这个预处理后的文件。
2.2在Ubuntu下预处理的命令
cpp hello.c>hello.i
使用预处理器将hello.c的结果输出到hello.i中
运行截图如下:
图2-1预处理命令
2.3 Hello的预处理结果解析

图2-2 预处理文件部分内容
可以发现,原本很短的程序被扩展到了3091行,而原先的主函数对应着从3078行开始的内容。之前的三千余行,都是cpp在预处理过程中插入的头文件。cpp删除掉了原本文本中的#include,并且在ubantu的环境中寻找stdio.h等,并且将它的内容插入文本文件中。除了原本明确#include的三个头文件外,cpp还插入了其他的头文件,这些头文件是原本头文件中#include的内容,而如果这些文件中有宏定义,预处理器也会递归地将他们表现出来。除此之外,预处理器还删除了文件中的注释和多余的空白等。

图2-3 预处理文件中main函数与原始代码对比

图2-4 插入的头文件

图2-5 部分类型的定义
2.4 本章小结
本章展示了将原始c文件进行预处理的方法,以及预处理过程中预处理器的工作。同时,结合ubantu系统,展示了预处理的过程和预处理文件的部分内容。这一过程中预处理器的工作为之后的编译等流程提供了前提。
第3章 编译
3.1 编译的概念与作用
3.1.1概念:
编译是指编译器ccl在通过对于hello.i内容的检查之后,将其翻译成汇编语言文件hello.s的过程
3.1.2作用:
编译的作用可以通过以下几步来体现。(1)词义分析,编译器通过逐个扫描输入的字符 ,产生一个个的单词,从而把源程序改造为一个由单词组成的中间程序。(2)语法分析,编译器通过基于词义分析的每个单词,生成语法分析树。之后进行判断每个指令是否是符合c语言指令的合法指令。(3)代码优化,编译器根据用户选择的不同优化等级,保守地对于代码进行不同程度的优化,这种优化是等价且安全的。(4)生成代码,编译器可以将优化后的代码转换为汇编语言代码,生成hello.s文件
3.2 在Ubuntu下编译的命令
gcc -S hello.i hello.s
运行结果如下:

图3-1 编译命令运行
3.3 Hello的编译结果解析
3.3.1数据
(1)常量
数字:通过观察我们可以得知,在程序中我们使用了许多的数字常量,这些常量都存储在程序的.text节中,直接体现在代码部分。部分截图如下:

图3-2 代码中的数字常量
我们可以看到,许多的运算都使用了数字常量。
字符串常量:程序中使用了printf()函数,这一输出中涉及了一些格式串,而格式串一般存储在.rodata节中,截图如下:
图3-3 代码中的字符串常量
(2)全局变量
程序中的全局变量只有main,我们知道这是一个函数型的全局变量,而且是一个强符号。
图3-4 全局变量main
(3)局部变量
程序中的局部变量都存储在堆栈段或者寄存器中,本程序中的局部变量有int argc,char *argv[],int i等等。
其中argc和argv都是运行时从寄存器传入,之后保存在运行时栈中。我们可以发现argc存储在%rbp-20的地方,它用来和4比较来决定程序的输入是否正确
图3-5 传入的argc与argv
而循环变量i保存在%rbp-4,它用来比较决定何时结束循环
图3-6 循环变量i
3.3.2 赋值
通过观察,我们可以知道程序中主要有两个赋值
(1)对循环变量i进行赋值,每次加1,截图如下:![]()
图3-7 对循环变量i进行赋值
(2)在调用sleep函数之前,对传入的参数进行赋值,我们可以发现eax中的值是由atoi()函数得来,这就是我们所输入的argv[3]中的秒数,作为参数被从eax中复制到rdi中,截图如下:
图3-8 对sleep()传入的参数进行赋值
3.3.3 类型转换
(1)字符串变量转为整型数
程序中通过调用atoi()函数,来讲我们输入的字符串给转换为一个整型数字,截图如下:
图3-9 字符串转换为整型数字
3.3.4 算术操作
程序中最主要的算术操作就是计算循环变量i的值,每次循环递增,截图如下:![]()
图3-10 循环变量递增
3.3.5 关系操作
程序中主要有两处关系操作,分别对应着两种条件下的跳转指令。
(1)argc!=4时的跳转,如果输入不符合要求,就打印正确做法并退出。
图3-11 第一次跳转
(2)循环变量达到9时结束循环

图3-12 第二次跳转
3.3.6 数组/指针/结构操作
程序中只有一处对于数组进行的操作,也就是传入的argv数组,通过观察我们可以知道,argv数组的4部分都存在栈中

图3-13 数组操作
3.3.7 控制转移
程序中控制转移相关操作与关系操作中相同
3.3.8 函数调用
程序主要存在三处函数调用,分别是main函数,atoi函数和 sleep函数
(1)main函数
参数传入:argc存放在rdi中,argv存放在rsi中,这两个参数通过寄存器传入后被压入运行时栈中

图3-14 main函数调用
(2)atoi函数
我们可以看到参数从rax中被复制入rdi,传入atoi函数调用

图3-15 atoi函数调用
(3)sleep函数
我们可以看到参数从eax中被复制入rdi,传入sleep函数调用
![]()
图3-16 sleep函数调用
3.4 本章小结
本章主要介绍了将预处理后的文件转化为汇编语言文件时发生的变化,并且展示了汇编代码中的一些主要操作,验证了这些操作的实现。
第4章 汇编
4.1 汇编的概念与作用
4.1.1概念:
汇编是指汇编器将hello.s的汇编语言程序翻译为机器语言程序,并且将机器语言程序打包为可重定位文件hello.o的过程。
4.1.2作用:
汇编器将汇编代码根据特定的转换规则转换为二进制代码,也就是机器码,机器只能理解机器代码。
4.2 在Ubuntu下汇编的命令
命令 as hello.s -o hello.o
汇编命令截图如下:

图4-1 汇编命令截图
4.3 可重定位目标elf格式
使用readelf -a hello.o > hello1_elf.txt将内容导出
(1)ELF头
以一个16字节的序列开始,这个序列描述了生成该文件系统下的字的大小以及一些其他信息。ELF头剩下的部分包含帮助链接器语法分析和解释目标文件的信息:包括ELF头的大小、目标文件的类型、机器类型、节头部表的文件偏移,以及节头部表中条目的大小和数量。具体ELF头的代码如下:

图4-2 ELF头
(2)节头:
这里包含了文件中各个节的信息,包括类型、位置和大小等等

(3)重定位节.rela.text:
这个节中包含.text节中需要进行重定位的信息,在链接的时候,连接器会根据这些信息重定位节中的地址。节中包含这些内容:偏移量、信息、类型、 符号值、符号名称 + 加数。

图4-4 重定位节.rela.text
(4)符号表:
.symtab是一个符号表,它存放在程序中定义和引用的函数和全局变量的信息。本程序中的getchar等函数名都需要在这一部分体现,具体信息如下图所示:

图4-5 符号表
4.4 Hello.o的结果解析
命令:objdump -d -r hello.o >hello1_dis.txt

图4-6 反汇编命令
通过对比生成的文件和原文件,我们可以发现一些差异:
(1)分支转移:
在hello.s中,我们可以看到跳转的时候是直接指明段名称的,例如.L2,.L3等等,然而反汇编的得到的文件中,跳转主要是通过计算偏移量得到的

图4-7 跳转命令
(2)函数调用
在我们之前的汇编语言文件,call之后直接跟着函数名称,而在反汇编得到的文件,call 的目标地址是当前指令的下一条指令。这是因为 hello.c 中调用的函数都是共享库中的函数,最终需要通过链接器才能确定函数运行时的地址,在汇编的时候,对于这些不确定地址的函数调用,需要将其相对地址设置为全 0,然后在.rela.text节中为其添加重定位条目,等待链接时确定。
图4-8 call命令
(3)参数
在访问参数时,同样使用类似上述函数调用时的方式,将偏移地址暂时设为0,等待重定位时修改。
图4-9 访问参数
4.5 本章小结
本章主要介绍了汇编的过程,文件经过汇编器的转化,生成了一个可重定位的文件,为下一步的链接过程做准备。本章同时展示了可重定位文件的反汇编结果,,展示了暂时为0的偏移值,这些都是为了链接过程所做的准备。
第5章 链接
5.1 链接的概念与作用
5.1.1概念:
链接是将各种不同文件的代码和数据片段收集并组合成一个单一文件的过 程,这个文件可被加载到内存并执行。
5.1.2作用:
链接可以把预编译好了的若干目标文件合并成为一个可执行目标文件。使得分离编译成为可能,不用将一个大型的应用程序组织为一个巨大的源文件,而是可以把它分解为可独立修改和编译的模块。当改变这些模块中的一个时,只需简单重新编译它并重新链接即可,不必重新编译其他文件。
5.2 在Ubuntu下链接的命令
ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/x86_64-linux-gnu/crt1.o hello.o /usr/lib/x86_64-linux-gnu/crti.o /usr/lib/x86_64-linux-gnu/libc.so /usr/lib/x86_64-linux-gnu/crtn.o -o hello 
图5-1 链接
5.3 可执行目标文件hello的格式
命令:readelf -a hello > hello2_elf.txt
打开文件,内容如下:
(1)ELF头:
基本信息未发生改变,但是类型发生了变化并且添加了程序入口的地址。
图5-2 ELF头
(2)节头包含的信息更加丰富

图5-3 节头
(3)程序头中出现了偏移量、虚拟地址和物理地址

图5-4 程序头
(4)Dynamic section

图5-5 Dynamic section
(5)符号表
图5-6 符号表
5.4 hello的虚拟地址空间
使用edb打开hello,查看datadump窗口,我们可以得到虚拟地址空间结果如下所示:
我们可以发现这部分代码的地址是从0x401000开始的,地址从401000到401280
通过对照符号表,我们可以发现对应关系。

图5-7 data dump窗口和符号表
5.5 链接的重定位过程分析
命令objdump -d -r hello >hello2_dis.txt

图5-8 反汇编代码(部分)
不同之处有以下几点:
(1)hello中存在程序所调用的一些库函数的实现,例如getchar等
(2)链接后的函数都有了虚拟地址

图5-9 虚拟地址
(3)对于变量的引用也有了偏移量

图5-10 引用变量
链接的过程:
链接主要分为两个过程:符号解析和重定位。
(1)符号解析:目标文件定义和引用符号,符号解析将每个符号引用和一个符号定义关联起来。(2)重定位:编译器和汇编器生成从0开始的代码和数据节。链接器通过把每个符号定义与一个内存位置关联起来,从而重定位这些节,然后修改所有对这些符号的引用,使得它们指向这个内存位置。链接器使用汇编器产生的重定位条目的详细指令,不加甄别地执行这样的重定位。
5.6 hello的执行流程
通过对照符号表,以及使用edb跟踪执行,我们可以得到执行流程如下

图5-11 符号表和datadump
图5-11 符号表和datadump
| 子程序名 | 地址 |
| hello! _start | 0x4010f0 |
| Libc.so.6!__libc_start_main | 0x7ae62d588b0 |
| hello!_init | 0x401000 |
| hello!main | 0x401125 |
| hello!printf@plt | 0x401040 |
| hello!sleep@plt | 0x401080 |
| hello!getchar@plt | 0x401050 |
| Libc.so.6!exit | 0x7ae62d635f0 |
5.7 Hello的动态链接分析
当程序调用一个由共享库定义的函数时,由于编译器无法预测这时候函数的地址是什么,所以需要添加重定位记录,等待动态链接器处理。链接器采用延迟绑定的方法,将过程地址的绑定推迟到第一次调用该过程时。通过 GOT 和过程链接表 PLT 的协作来解析函数的地址。在加载时,动态链接器会重定位 GOT 中的每个条目,使它包含正确的地址。
首先查看elf中.got.plt节的内容

图5-12 .got.plt

图5-13 改变后的.got.plt
通过调用dl_init,我们可以发现.got.glt的内容发生了改变
5.8 本章小结
本章主要介绍了将可重定位目标文件链接生成可执行文件的过程。首先分析了链接的概念和作用,之后查看并验证了hello虚拟地址和节头部表的信息,最后分析了hello的执行流程并对动态链接进行了分析,加深了对于重定位和动态链接的理解。
第6章 hello进程管理
6.1 进程的概念与作用
6.1.1概念:
进程是一个正在运行的程序的实例,系统中的每一个程序都运行在某个进程的上下文中。
6.1.2作用:
进程为应用程序提供两个关键抽象(1)一个独立的逻辑控制流,提供一个假象,好像程序独立地使用处理器(2)一个私有地址空间,提供一个假象,好像程序独占地使用内存
6.2 简述壳Shell-bash的作用与处理流程
6.2.1作用:
shell是一个用C语言编写的交互型应用程序,代表用户运行其他程序。shell应用程序提供了一个界面,用户可以通过这个界面进行系统的基本操作,访问操 作系统内核的服务。shell执行一系列的读/求值步骤,然后终止。读步骤读取来自用户的一个命令行,求值步骤解析命令行,并根据解析结果运行程序。
6.2.2处理流程:
(1)shell从终端读入命令(2)shell将命令行拆分获得命令行参数,并且扫描识别所有参数(3)如果是一个内置命令,就执行(4)如果不是一个内置命令,那说明要执行一个程序,调用fork创建一个子进程(5)通过命令结尾处是否有&决定是否切入后台执行(6)执行任务
6.3 Hello的fork进程创建过程
父进程通过调用fork函数创建一个新的运行的子进程。调用fork函数后,新 创建的子进程几乎但不完全与父进程相同:子进程得到与父进程虚拟地址空间相同 的(但是独立的)一份副本,包括代码、数据段、堆、共享库以及用户栈,子进程获 得与父进程任何打开文件描述符相同的副本,这意味着当父进程调用fork时,子进程可以读写父进程中打开的任何文件。fork被调用一次,却返回两次,子进程返 回0, 父进程返回子进程的PID。父进程和新创建的子进程之间最大的区别在于它 们有不同的 PID。
在本程序里,我们输入对应的指令调用hello,shell为为hello调用fork创建一个子进程。当子进程结束时,如果父进程尚未结束,就由父进程负责回收,否则由init回收。

图6-1 fork()创建进程
6.4 Hello的execve过程
exceve 函数在当前进程的上下文中加载并运行一个新程序。exceve 函数加载 并运行可执行目标文件,并带参数列表和环境变量列表。只有当出现错误时,exceve 才会返回到调用程序。所以,与 fork 一次调用返回两次不同,在 exceve 调用一次 并从不返回。当加载可执行目标文件后,exceve 调用启动代码,启动代码设置栈, 将可执行目标文件中的代码和数据从磁盘复制到内存中,然后通过跳转到程序的 第一条指令或入口点来运行该程序,由此将控制传递给新程序的主函数。
execve在加载了hello之后,会构造argc,argv和envp,并将控制传递给main函数。
6.5 Hello的进程执行
上下文:
内核重新启动一个被抢占的进程所需要恢复的原来的状态,由寄存器、程序计数器、用户栈、内核栈和内核数据结构等对象的值构成。
进程时间片:
一个进程执行它的控制流的一部分的每一个时间段叫做时间片。
进程调度:
在进程执行的某些时刻,内核可以决定抢占当前进程,并重新开始一个先前被抢占的进程,这种决策称为调度,是由内核中的调度器代码处理的。当内核选择一个新的进程运行,我们说内核调度了这个进程。在内核调度了一个新的进程运行了之后,它就抢占了当前进程,并使用上下文切换机制来将控制转移到新的进程。
用户模式与核心模式的转换:
为了保证系统安全,需要限制应用程序所能访问的地址空间范围。因而存在用户态与核心态的划分,核心态拥有最高的访问权限,而用户态的访问权限会受到一些限制。处理器使用一个寄存器作为模式位来描述当前进程的特权。进程只 有故障、中断或陷入系统调用时才会得到内核访问权限,其他情况下始终处于用户权限之中,一定程度上保证了系统的安全性。

图6-2 用户模式与核心模式的转换
6.6 hello的异常与信号处理
正常执行结果:

图6-3 正常执行
异常类型如下:
图6-4 异常类型
处理方法如下:



图6-5 异常的处理方法
异常:
(1)不停乱按:乱码会被认为是命令,不影响执行,但是会提示未找到命令
图6-6 不停乱按
(2)ctrl + z

图6-7 ctrl + z
通过使用ctrl + z命令,将进程挂起
(3)ps

图6-8 ps命令
在进程挂起后使用ps指令,打印pid
(3)jobs

图6-9 jobs命令
使用jobs命令,打印了被挂起的进程的jid
(4)pstree

图6-10 pstree命令
挂起后使用pstree命令
(5)fg

图6-11 fg命令
运行fg命令会把之前挂起在后台的hello重新调到前台并且执行,打印出剩余部分。
(6)kill

图6-12 kill命令
重新运行程序,我们可以找到pid为5558,通过使用kill -9 5558命令发送SIGKILL信号,可以杀死进程。
(7)ctrl + c

图6-13 ctrl + c命令
在程序运行时输入ctrl + c,向进程发送SIGINT信号,结束hello进程。这时再使用ps和jobs均查询不到hello。
6.7本章小结
本章主要介绍了 hello 可执行文件的执行过程,包括进程创建、加载和终止, 以及通过键盘输入等过程。之后介绍了异常以及异常的处理方法。 最后通过对hello进行操作直观地体现了进程的控制。在hello程序运行的过程中,内核对其进行进程管理,决定何时进行进程调度,在接收到不同信号时,还要进行对应的处理。
结论
hello所经历的历程:hello从一个c源文件,到成为一个可执行文件,最终成为进程,被执行并且回收,它的经历如下:
(1)预处理:hello.c源代码文件经过预处理器cpp 的处理,插入了头文件,结构得到调整,得到处理后的文本文件helli.i
(2)编译:hello.i经过编译器的编译,得到了汇编语言文件hello.s
(3)汇编:hello.s经过汇编器的汇编,得到了可重定向文件hello.o
(4)链接:hello.o经过链接器的链接,整合生成了可执行目标文件hello
(5)加载:在shell中输入命令,使用shell调用fork函数,为shell生成进程
(6)运行:使用execve加载并运行hello,把代码和数据加载进入虚拟内存空间
(7)执行:在该进程被调度时,CPU为 hello其分配时间片,在一个时间片中,hello进程独占CPU全部资源,CPU不断地取指,顺序执行逻辑流。hello在这一过程中会处理各种异常,除此之外,还有访问内存等等行为。进程还调用了printf和getchar等函数,与linux系统的I/O设备等密切相关
(8)回收:shell父程序等待hello结束,并且将它回收,之后内核清除所有hello的信息。如果shell提前结束,那么由init作为hello的养父,负责回收。
完成回收后,hello就结束了它的一生。
我的感悟如下:
(1)经过本文的撰写,我深刻体会到计算机的各个层次都是密切相关的。即使是一个小小的几十行的hello程序,也要经历重重复杂的路径,被数个应用进行处理,逐步优化,最终生成一个可执行文件。在加载进入内存后,又与linux系统产生反应,从加载、运行到最终结束被回收,完成hello的一生。
(2)hello的一生中经历了多重精密的计算,无论是内容的转换,还是链接时地址的计算,无不透露着过往计算机领域人才们的思维火花,令人感叹其中的奥妙。
(3)经过这一系列的操作和学习,我对于本学期所学的内容有了更深刻的认识,对于csapp这本书,之所以叫从“程序员角度”有了更进一步的认识。我希望能够利用在本书中学到的知识,在未来的学习生活中进一步使用、创新。
附件
| 文件名 | 功能 |
| hello.i | hello.c经过预处理得到的文本文件 |
| hello.s | 编译后得到的汇编文件 |
| hello.o | 汇编后得到的可重定向文件 |
| hello | 链接得到的可执行文件 |
| hello1_elf.txt | 用readelf读hello.o得到的elf文件 |
| hello1_dis.txt | 反汇编hello.o得到的文件 |
| hello2_elf.txt | hello的elf格式文件 |
| hello2_dis.txt | hello的反汇编文件 |
参考文献
[1] GCC online documentation - GNU Project
[2] 《深入理解计算机系统》 Randal E.Bryant David R.O’Hallaron 机械工业出版
社
[3] 编译的整个过程:预编译、编译、汇编、链接 - mhq_martin - 博客园 (cnblogs.com)
[4] 什么是链接,为什么需要链接?_陶通宁的博客-CSDN博客_程序为什么需要链接
[5] Shell 教程 | 菜鸟教程 (runoob.com)
转载自CSDN-专业IT技术社区
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/ZZZZZZZeno/article/details/127851327



