1、目标代码逻辑地址的查看与比较
(1)先编写一段完整而简单的代码
(2)使用gcc进行编译和汇编,但不链接成可执行文件,得到目标代码sample.o;
使用objdump对sample.o进行反编译,查看输出结果,体会目标程序各条指令的逻辑地址。
(3)使用gcc对sample.c执行编译、链接,生成可执行文件,再用objdump对其进行反编译,查看输出结果,比较两次反编译得到的各条指令地址的异同,分析其原因,进一步加深对应用程序处理过程、逻辑地址等概念的理解。
(1)
(2)
(3)
使用GCC进行编译和链接生成可执行文件后,再使用objdump对可执行文件进行反编译,可以查看反编译的汇编代码和各条指令的地址。而将GCC的编译过程分为编译和汇编两步,生成目标代码(.o文件),再使用objdump对目标代码进行反编译,可以查看目标代码的汇编代码和各条指令的逻辑地址。
两种方式的区别在于,编译和链接生成的可执行文件已经经过了链接阶段,各个目标代码文件之间的符号引用和地址重定位已经完成,因此对可执行文件进行反编译会得到完整的汇编代码和逻辑地址。而仅编译和汇编生成的目标代码文件还没有完成链接过程,它只包含了符号的地址标识和未解析的引用,因此对目标代码文件进行反编译只能得到未经链接的汇编代码和逻辑地址。
通过进行这两种方式的比较,可以更深入地理解应用程序的处理过程和逻辑地址的概念。编译、汇编和链接的过程中,源代码被转换为机器码,并按照内存布局和符号表来分配地址。在可执行文件的反编译中,可以看到完整的处理过程和最终的指令实现。在目标代码的反编译中,可以观察到未经链接的数据和引用,加深对程序结构和内存布局的理解。
总而言之,两种方式的区别在于是否经过链接过程,从而影响到反编译后得到的汇编代码的完整性、引用解析和地址重定位的状态。
2、进程的内存映像
(1)先编写一段完整而简单的代码,运行,观察不同类型变量起始地址的值。
(2)重新打开一个终端,先后执行ps -e命令,找到并记录进程process_image的pid(设为XXXX);
执行cat /proc/XXXX/maps指令,观察指定进程的内存镜像。查找资料,了解输出结果中各字段的含义,找出这个进程在内存中数据段、代码段、堆、栈等四个部分在输出结果中所对应的行,对比第(1)问的执行结果,截屏并作出适当说明。
//process_image.c
#include<stdlib.h>
#include<unistd.h>
#include<stdio.h>
int global_var=5;
int main()
{
static int static_var=6;
int local_var=7;
int*p=(int *)malloc(100);
printf("the global_var address is %p\n",&global_var);
printf("the static_var address is %p\n",&static_var);
printf("the local_var address is %p\n",&local_var);
printf("the adress which the p points to %p\\n",p);
free(p);
sleep(1000);
return 0;
}
截图时两处错误:local单词拼写错误
static所在行最后没有分号
打开另一个窗口
- 第一列:起始地址和结束地址,以十六进制表示。这两个地址定义了内存段的范围。
- 第二列:访问权限,表示对应内存段的读、写、执行权限。"r"表示可读,"w"表示可写,"x"表示可执行。
- 第三列:偏移量,指出内存段在文件中的偏移量,如果是匿名映射,值为"00000000"。
- 第四列:设备编号和inode编号,标识映射的设备和文件。
- 第五列:文件路径,标识映射的文件路径,若为匿名映射,则为""。
- 第六列:偏移量的地址,以十六进制表示,标识内存段的起始地址。
- 第七列:附加标记,可能会有空间、权限等标志位的更多信息。
- 数据段通常包含已初始化的全局变量和静态变量等数据。在给出的内存映射表中,数据段的起始地址是`556921f28000`,对应的行是第5行。
- 代码段包含程序的可执行代码。在给出的内存映射表中,代码段的起始地址是`556921f26000`,对应的行是第2行。
- 堆是动态分配的内存,通常用于程序中动态分配内存的操作。在给出的内存映射表中,堆的起始地址是`556922308000`,对应的行是第6行。
- 栈用于存储函数调用、局部变量和运行时上下文信息等。在给出的内存映射表中,栈的起始地址是`7ffcf98b3000`,对应的行是第33行。
根据以上分析,可以确定在给出的内存映射表中,数据段、代码段、堆和栈分别对应的行是:
- 数据段:第5行
- 代码段:第2行
- 堆:第6行
- 栈:第33行