欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

使用汇编分析c代码的内存分布

程序员文章站 2023-04-02 14:13:59
arm平台下使用反汇编分析c内存分布: arm:使用arm-linux-objdump命令将编译完成之后的elf文件,进行反汇编. 之后重定向到tmp.s文件中. 第一步变量如...
arm平台下使用反汇编分析c内存分布:

arm:使用arm-linux-objdump命令将编译完成之后的elf文件,进行反汇编.
之后重定向到tmp.s文件中.

第一步变量如下c文件.
vim tmp.c
	
	#include
	
	#define  VAR 0xFF
	
	int a = 0; 
	static int  b =  0;
	
	int c = 10;
	static int  d = 20; 
	
	const int finalone = 10;
	const int final;
	
	int main(void)
	{
	
		char *hell = "hhhhhhh";
		const int finaltwo = 50 ;
		static int f = 0;
		static int k = 10;
		int aa; 
		int bb=10;
		printf("VAR = %d\n, finalone = %d, finaltwo = %d",VAR,finalone,finaltwo);
	}

第二步:编写Makefile文件如下
	Makefile文件如下:
	vim Makefile
	CC=arm-linux-gcc
	CFLAGS += -march=armv7-a


第三步:编译生成可执行文件.	
	然后使用make命令编译给文件.make tmp 生成tmp elf格式文件.

第四步:
	下面通过使用arm-linux-objdump -D tmp  >  tmp.s

//得到如下文件tmp.s文件.

	:     file format elf32-littlearm
	下面是摘出来的相关内如如下:

//下面是对应的.data段相关的初始化的变量.
//变量c,d,k都存取再该区域内.结论如下:
//需要满足如下要求的变量被放在.data段,也就是初始化数据段.
//所有全局||static关键字修饰)&&初始化不为的变量)

sassembly of section .data: 
	00011020 :
	11020:	00000000	andeq	r0, r0, r0

	00011024 :
	11024:	00000000	andeq	r0, r0, r0

	00011028 :
	11028:	0000000a	andeq	r0, r0, sl      

	0001102c :
	1102c:	00000014	andeq	r0, r0, r4, lsl r0

	00011030 :
	11030:	0000000a	andeq	r0, r0, sl

//下面是对应的.bss段.变量a,b,f都存储再这个区域.
//该区域存储的是没有初始化或者初始化为0的变量.
	这些变量应该满足如下,条件才会被放到给区域:
	(全局的|被static关键字修饰的)&&(为初始化||初始化为0的变量)

	Disassembly of section .bss:
	00011034 :
	11034:	00000000	andeq	r0, r0, r0

	00011038 :
	11038:	00000000	andeq	r0, r0, r0

	0001103c :
	1103c:	00000000	andeq	r0, r0, r0

	00011040 :
	11040:	00000000	andeq	r0, r0, r0

	00011044 :
	11044:	00000000	andeq	r0, r0, r0


//这个区域存放了一些字符串常量.如上c程序中的 "hhhhhhh"对应的686868.....
//还有使用const修饰的全局初始化的常量.如上面的const int finalone变量.它的只对应的是848c的00000000a.	
	sassembly of section .rodata:

	00008488 :
	8488:	00020001	andeq	r0, r2, r1

	0000848c :
	848c:	0000000a	andeq	r0, r0, sl
	8490:	68686868	stmdavs	r8!, {r3, r5, r6, fp, sp, lr}^
	8494:	68686868	stmdavs	r8!, {r3, r5, r6, fp, sp, lr}^
	8498:	00000068	andeq	r0, r0, r8, rrx
	849c:	20524156	subscs	r4, r2, r6, asr r1
	84a0:	6425203d	strtvs	r2, [r5], #-61	; 0x3d
	84a4:	66202c0a	strtvs	r2, [r0], -sl, lsl #24
	84a8:	6c616e69	stclvs	14, cr6, [r1], #-420	; 0xfffffe5c
	84ac:	20656e6f	rsbcs	r6, r5, pc, ror #28
	84b0:	6425203d	strtvs	r2, [r5], #-61	; 0x3d
	84b4:	6966202c	stmdbvs	r6!, {r2, r3, r5, sp}^
	84b8:	746c616e	strbtvc	r6, [ip], #-366	; 0x16e
	84bc:	3d206f77	stccc	15, cr6, [r0, #-476]!	; 0xfffffe24
	84c0:	2c642520	cfstr64cs	mvdx2, [r4], #-128	; 0xffffff80
	84c4:	203d2068	eorscs	r2, sp, r8, rrx
	84c8:	00732520	rsbseq	r2, r3, r0, lsr #10}

//上面还使用#define声明一个宏.它存储再哪里呢.我们可以看一下啊main中的汇编如下:
//第一步找出.在main中声明的局部变量.
	char *hell = "hhhhhhh"	  //这个是hell变量的声明,83c0:	e3083490	movw	r3, #33936	; 0x8490
	const int finaltwo = 50 ; // 83cc:	e3a03032	mov	r3, #50	; 0x32 //它会被保存的栈中.
	static int f = 0;
	static int k = 10;
	int aa;                   //aa变量被默认优化,不存在了.因为没有被使用,也没有使用volatile关键字修饰,
							  //编译在当前arm平台下默认优化等级是O2,那么将将会再汇编中步存在.
	int bb=10;                //83d4:	e3a0300a	mov	r3, #10 这个是bb=10


	//这段汇编代码中还包含一个#255,也就是我们使用#define VAR 255 常量, 
	//它是一个立即数.说明它只占用.text文本段,也就是我们常说的代码段.
	//下面由段详细的解释:说明const,和#define常量的不同之处.

	000083b4 :
	83b4:	e92d4800	push	{fp, lr}
	83b8:	e28db004	add	fp, sp, #4
	83bc:	e24dd018	sub	sp, sp, #24
	83c0:	e3083490	movw	r3, #33936	; 0x8490
	83c4:	e3403000	movt	r3, #0
	83c8:	e50b3008	str	r3, [fp, #-8]
	83cc:	e3a03032	mov	r3, #50	; 0x32
	83d0:	e50b300c	str	r3, [fp, #-12]
	83d4:	e3a0300a	mov	r3, #10
	83d8:	e50b3010	str	r3, [fp, #-16]
	83dc:	e308349c	movw	r3, #33948	; 0x849c
	83e0:	e3403000	movt	r3, #0
	83e4:	e308248c	movw	r2, #33932	; 0x848c
	83e8:	e3402000	movt	r2, #0
	83ec:	e5922000	ldr	r2, [r2]
	83f0:	e51b1008	ldr	r1, [fp, #-8]
	83f4:	e58d1000	str	r1, [sp]
	83f8:	e1a00003	mov	r0, r3
	83fc:	e3a010ff	mov	r1, #255	; 0xff
	8400:	e51b300c	ldr	r3, [fp, #-12]
	8404:	ebffffbc	bl	82fc 
	8408:	e1a00003	mov	r0, r3
	840c:	e24bd004	sub	sp, fp, #4
	8410:	e8bd8800	pop	{fp, pc}
	
//解析define和const的不同之处.	
	const 定义的只读变量从汇编角度来看 只是给出了对应的内存地址 
	而不是像define一样给出的是立即数 所以 const定义的只读变量在程序运行过程中只有一份拷贝
	(因为它是全局的只读变量 存放在静态区) 而define定义的宏变量在内存中有若干个拷贝 define宏是在预编译阶段进行替换 
	而const修饰的只读变量是在编译的时候确定其值 define宏没有类型 而const修饰的只读变量具有特定的类型.