2.3.1测试

一、任务详情

0 推荐在OpenEuler系统中实现
1 编辑并运行2.3.1中的代码,要求在不修改t2.c 和 t1.c中main函数中的代码的情况下,程序运行结果是你的后四位学号。提交代码和运行结果截图。
2 网上学习objdump命令,提交不少于5篇博客链接和微信读书上的图书链接,并给出你认为最好的讲解资源的链接或图书名及章节
3 用objdump分析第1步中的可执行文件和目标文件,提交你的分析截图以及如何和教材讲解内容对应的,比如obj文件的文件头,代码段,数据段等,可执行文件如何链接mysum的。

二、任务解决过程

本次任务在openeuler系统下实现

1、2.3.1代码修改

只用修改g的值,代码如下:

运行结果:

2、objdump命令学习

我找了6条比较不错的链接:
博客链接1
博客链接2
博客链接3
博客链接4
微信读书:嵌入式c语言自我修养-第4.8动态链接
微信读书:linux设备驱动开发详解-3.6工具链
其中,我认为最好的是博客链接3。该篇博客写得很详细,并且用大量实例来演示objdump命令的参数、功能。

3、objdump命令实例

编译
整个编译过程分为预编译、编译和汇编,最终生成可执行文件,其中在windows下生成 .obj文件,在linux下生成 .o文件,学名叫做二进制可重定位文件。

链接
(1)合并所有obj文件的段,并调整段偏移和段长度,合并符号表,进行符号解析,分配内存地址(虚拟地址)。
(2)链接的核心:符号的重定位。

readelf -h 20191223t1.o输出obj文件头部,可以查看到obj文件一些重要信息。

可以看见入口地址是0x0
obj是一个二进制可重定位文件,不能执行,并不是一个executable的文件。

下面分析.obj文件的组成格式

objdump -s 20191223t1.o

readelf -S 20191223t1.o产看当前二进制可重定位文件中所有的段。

我们可以分析得出,obj文件中都没有存储.bss段的信息。

那么问题来了,链接的第二步具体做了哪些事情,什么是符号重定位?

链接器只对所有.obj文件的global符号进行处理,对local的符号不做任何处理。如static生成的符号就是local的符号。

分别查看20191223t1.o和t2.o所生成的符号表:

符号解析:所有obj文件符号表中对符号引用的地方都要找到符号定义的地方,否则就会出现链接错误。由于源文件是单独编译的,所以对外部的符号处理为UND即undefine。

objdump -d 20191223t1.o

可以看到编译过程并不给数据和函数入口分配内存地址,都是以0地址作为替代。
下面详细看链接过程:
简单的合并策略,将每个obj文件的段拿来即可,像下边这样:

我们总结一下obj文件与exe文件的区别:

  • 1.首先obj和exe组成格式开始都是ELF Header,但是exe的ELF Header中的程序入口地址不再是0,而且一个main函数的地址。
    2.exe的ELF Header也是52个字节,和obj一样,但是exe中.text起始地址不再是0x34了,exe比obj多了一块空间,在ELF和.text中间,叫做program headers.
    3.exe本身还是按照段进行存储的,不过两个LOAD项指明了哪些段要放在一个页面上。
    这些区别也说明了为什么exe文件可以运行,而obj文件不能运行。
    ELF文件头包括程序入口地址,obj的入口地址是0,0地址不能访问,而且obj文件是可重定位文件,他在编译后生成,而编译的时候是不给符号分配地址的,内存地址是在链接的时候分配,符号解析完以后就分配虚拟内存地址。其实说到底就是因为obj文件没有program headers,就没有两个LOAD页面,LOAD页面就指示了加载器,把当前程序的哪些东西加载到内存上。
posted @ 2021-10-25 21:03  20191223张俊怡  阅读(56)  评论(0编辑  收藏  举报