20191317王鹏宇2.3.1测试

2.3.1测试

编辑并运行代码

教材代码:


t1.c代码:

#include <stdio.h>
/**********t1.c************/
int g = 1314;
int h;
static int s;

int main(int argc, char *argv[])
{
    int a = 1;int b;
    static int c = 3;
    b = 2;
    c = mysum(a,b);
    printf("sum=%d\n", c);
}

t2.c代码

/**************t2.c*********/
extern int g;
int mysum(int x, int y)
{
    return x + y + g;
}

实践截图:

objdump学习

相关博客链接:

参考网站

参考网站

参考网站

参考网站

参考网站

嵌入式C语言自我修养:从芯片、编译器到操作系统 第四章

奔跑吧 Linux内核 第六章

使用objdump命令分析目标文件与可执行文件

编译器编译源代码后生成的文件叫做目标文件。在Linux下,使用gcc -c xxxx.c编译生成.o文件。

目标文件的文件类型为ELF,ELF文件存放数据的格式也是固定的,计算机在解析目标文件时,就是按照它每个字段的数据结构进行逐字解析的。ELF文件结构信息定义在/usr/include/elf.h中,整个ELF文件的结构如下图:

这里对应教材24页与25页

首先我们来分析目标文件:
t1.o:

t2.o:

我们得到了两个目标文件的文件头,从这两张图可以看出两个目标文件个字段的大小,我们的代码是存放到.text中,已初始化全局变量和局部静态变量存放在.data中,未初始化全局变量和局部静态变量存放在.bss中:

我们先来分析t1.o的其他几个字段:objdump -d -s t1.o

代码段:

这里最左边的四位字段是偏移量,一共55字节,通过之前对文件头的分析,可知代码段大小就是55字节

对t2.o的代码段进行解析:

同t1.o的解析结果类似。

对t1.o和t2.o的数据段进行解析:

.data字段存储已初始化非0全局变量和静态变量,需要分配空间用于存储数据
.rodata字段表示为只读数据段,存放C中的字符串和常量,优化后会只存储一份。常量并不一定在此段,有可能存放在代码段。

从符号表中可以看出,static int s,s为未初始化静态变量,存储在.bss字段中,static int c = 3 c作为已初始化局部变量,存储在.data字段中,int g = 1314 g作为已初始化全局变量存储在.data字段中,h作为未初始化变量,存储在.comment变量中。

接下来分析可执行文件a.out如何链接函数mysum:

从符号表中可以看出,函数mysum的地址为0000000000401177,这里对应的是教材的第24页,当编译器在t1.c中发现c = mysum(a,b)时,它并不知道mysum在何处。所以它在t1.o中留下一个空白作为mysum的入口地址,但是在符号表的记录中,必须用mysum的入口地址替换空白。链接器将t1.o与t2.o合并时,它知道mysum在组合代码段中的位置。链接器用mysum的入口地址替换掉t1.o中的空白。

使用objdump -d a.out指令查看函数地址,可以看出mysum的地址就是0000000000401177。

所以链接器是通过替换mysum函数的入口地址,来达到让可执行文件链接mysum函数的目的。

posted @ 2021-10-30 16:41  Bzrael  阅读(48)  评论(0编辑  收藏  举报