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

arm平台下使用反汇编分析c内存分布:

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

第一步变量如下c文件.
vim tmp.c

	#include<stdio.h>

	#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 <__data_start>:
	11020:	00000000	andeq	r0, r0, r0

	00011024 <__dso_handle>:
	11024:	00000000	andeq	r0, r0, r0

	00011028 <c>:
	11028:	0000000a	andeq	r0, r0, sl      

	0001102c <d>:
	1102c:	00000014	andeq	r0, r0, r4, lsl r0

	00011030 <k.1728>:
	11030:	0000000a	andeq	r0, r0, sl

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

	Disassembly of section .bss:
	00011034 <completed.5796>:
	11034:	00000000	andeq	r0, r0, r0

	00011038 <a>:
	11038:	00000000	andeq	r0, r0, r0

	0001103c <b>:
	1103c:	00000000	andeq	r0, r0, r0

	00011040 <f.1727>:
	11040:	00000000	andeq	r0, r0, r0

	00011044 <final>:
	11044:	00000000	andeq	r0, r0, r0

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

	00008488 <_IO_stdin_used>:
	8488:	00020001	andeq	r0, r2, r1

	0000848c <finalone>:
	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 <main>:
	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 <_init+0x44>
	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修饰的只读变量具有特定的类型.

时间: 2024-08-09 00:04:16

使用汇编分析c代码的内存分布的相关文章

高级C代码的汇编分析

在windows上,常用的函数调用方式有: Pascal方式,WINAPI(_stdcall)方式 和C方式(_cdecl) _cdecl调用规则: 1,参数从右到左入堆栈 2,在函数返回后,调用者要负责清除堆栈 所以这种调用常会生成较大的可执行文件. _stdcall又称为WINAPI调用方式,规则: 1,参数从右向左入堆栈 2,被调用的函数在返回前自行清理堆栈 所以这种调用会生成比cdecl小的代码 Pascal调用方式,主要用在WIN16函数库中,现在基本不用 规则: 1,参数从左向右入堆

C语言中内存分布及程序运行中(BSS段、数据段、代码段、堆栈)

BSS段:(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域.BSS是英文Block Started by Symbol的简称.BSS段属于静态内存分配. 数据段 :数据段(data segment)通常是指用来存放程序中 已初始化 的 全局变量 的一块内存区域.数据段属于静态内存分配. 代码段: 代码段(code segment/text segment)通常是指用来存放 程序执行代码 的一块内存区域.这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于 

《C++反编译与逆向分析技术揭秘》之学习笔记02--结构体和类之内存分布

※结构体和类之内存分布 1.空类的大小空类:其实空类至少会占用1个字节的长度. 2.字节对齐在为结构体和类中的数据成员分配内存时,结构体中的当前数据成员类型长度为M,指定对齐值为N,那么实际对齐值位q=min(M,N),其成员的地址安排在q的倍数上. vc6.0缺省对齐8个字节sShort占用2个字节,所以安排的地址0x0012FF70为2的倍数.nInt占用4个字节,所以安排的地址0x0012FF74为4的倍数.因为结构体中最大的字段长度为4,所以对齐值调整为4个字节.因为test对象为8个字

C语言的内存管理分析 栈区 代码区 堆区 静态区 常量区

系统为了管理内存 把内存划分了几个区域 1> 栈区 栈区之中的数据在栈区之中以栈的形式进行存储. 栈区的特点:数据是先进后出, 放在栈区里面存放的是局部变量.(例如定义在函数内部的变量) 栈区之中的数据(局部变量)的作用范围过了之后,系统就会回收自动管理栈区的内存(分配内存 , 回收内存),不需要开发人员来手动管理 2> 堆区 高效的使用内存 这里的内存可以由程序员自己手动管理 高效的使用内存  例如: 申请内存 释放内存.优化内存 ARC 申请内存的函数 malloc()  memary a

C++ 内存分布

C++内存分布 参考链接http://www.cnblogs.com/skynet/archive/2011/03/07/1975479.html# 作者 吴秦 为什么需要知道C/C++的内存布局和在哪可以可以找到想要的数据?知道内存布局对调试程序非常有帮助,可以知道程序执行时,到底做了什么,有助于写出干净的代码.本文的主要内容如下: 源文件转换为可执行文件 可执行程序组成及内存布局 数据存储类别 一个实例 总结 源文件转换为可执行文件 源文件经过以下几步生成可执行文件: 1.预处理(prepr

GDB调试汇编分析

GDB调试汇编分析 代码 本次实践我参照了许多先做了的同学的博客,有卢肖明,高其,张梓靖同学.代码借用的是卢肖明同学的代码进行调试运行. GCC编译 使用gcc -g gdbtest.c -o gdbtest -m32命令在64位的机器上产生32位汇编代码 在使用gdb进行调试运行时,有cgdb和gdb两种工具,我建议大家使用张梓靖同学使用的cgdb工具,因为使用时可以随时看到自己的源代码,看到我们的断点在哪里,每一步返回值到了哪行,更加直观. 分析过程 使用b main指令在main函数处设置

[GeekBand] C++继承关系下虚函数内存分布

本文参考文献:GeekBand课堂内容,授课老师:侯捷 :深度探索C++对象模型(侯捷译) :网络资料,如:http://blog.csdn.net/sanfengshou/article/details/4574604 说明:由于条件限制,仅测试了Windows平台下的VS2013 IDE.其余平台结果可能不同,但原理都类似.建议读者自己在其他平台进行测试. 1.什么是虚函数? 虚函数是类的非静态成员函数,在类中的基本形式如下:virtual 函数返回值类型 虚函数名(形参表) 如:virtu

C++对象模型之简述C++对象的内存分布

在C++中,有两种类的成员变量:static和非static,有三种成员函数:static.非static和virtual.那么,它们如何影响C++的对象在内存中的分布呢? 当存在继承的情况下,其内存分布又是如何呢? 下面就一个非常简单的类,通过逐渐向其中加入各种成员,来逐一分析上述两种成员变量及三种成员函数对类的对象的内存分布的影响. 注:以下的代码的测试结果均是基于Ubuntu 14.04 64位系统下的G++ 4.8.2,若在其他的系统上或使用其他的编译器,可能会运行出不同的结果. 1.含

VS中的类的内存分布(上)

0.序 目前正在学习C++中,对于C++的类及其类的实现原理也挺感兴趣.于是打算通过观察类在内存中的分布更好地理解类的实现.因为其实类的分布是由编译器决定的,而本次试验使用的编译器为VS2015 RC,所以此处的标题为<VS中的类的内存分布>. 1.对无继承类的探索 1.1 空类 我们先一步一步慢慢来,从一个空的类开始. //空类 class test { }; int main(int argc, char *argv[]) { test ts; cout << sizeof(t