20 篇文章 0 订阅

栈的使用很频繁,准确的理解栈很重要。

首先,回顾下ARM 上的栈:

转载: http://blog.163.com/modeng_2005/blog/static/26561120097753251708/?fromdm&fromSearch&isFromSearchEngine=yes

以下是我在学习ARM指令中记录的关于堆栈方面的知识:
1、寄存器 R13 在 ARM 指令中常用作堆栈指针
2、对于 R13 寄存器来说,它对应6个不同的物理寄存器,其中的一个是用户模式与系统模式共用,另外5个物理寄存器对应于其他5种不同的运行模式。采用以下的记号来区分不同的物理寄存器:
R13_<mode>
其中,mode为以下几种模式之一:usr、fiq、irq、svc、abt、und。

3、寄存器R13在ARM指令中常用作堆栈指针,但这只是一种习惯用法,用户也可使用其他的寄存器作为堆栈指针。而在Thumb指令集中,某些指令强制性的要求使用R13作为堆栈指针。由于处理器的每种运行模式均有自己独立的物理寄存器R13,在用户应用程序的初始化部分,一般都要初始化每种模式下的R13,使其指向该运行模式的栈空间,这样,当程序的运行进入异常模式时,可以将需要保护的寄存器放入R13所指向的堆栈,而当程序从异常模式返回时,则从对应的堆栈中恢复,采用这种方式可以保证异常发生后程序的正常执行。

4、有四种类型的堆栈:
堆栈是一种数据结构,按先进后出(First In Last Out,FILO)的方式工作,使用一个称作堆栈指针的专用寄存器指示当前的操作位置,堆栈指针总是指向栈顶。
当堆栈指针指向最后压入堆栈的数据时,称为满堆栈(Full Stack),而当堆栈指针指向下一个将要放入数据的空位置时,称为空堆栈(Empty Stack)。
同时,根据堆栈的生成方式,又可以分为递增堆栈(Ascending Stack)和递减堆栈(DecendingStack),当堆栈由低地址向高地址生成时,称为递增堆栈,当堆栈由高地址向低地址生成时,称为递减堆栈。这样就有四种类型的堆栈工作方式,ARM 微处理器支持这四种类型的堆栈工作方式,即:

◎ Full descending 满递减堆栈
堆栈首部是高地址,堆栈向低地址增长。栈指针总是指向堆栈最后一个元素(最后一个元素是最后压入的数据)。
ARM-Thumb过程调用标准和ARM、Thumb C/C++ 编译器总是使用Full descending 类型堆栈。
◎ Full ascending 满递增堆栈
堆栈首部是低地址,堆栈向高地址增长。栈指针总是指向堆栈最后一个元素(最后一个元素是最后压入的数据)。

◎ Empty descending 空递减堆栈
堆栈首部是低地址,堆栈向高地址增长。栈指针总是指向下一个将要放入数据的空位置。

◎ Empty ascending 空递增堆栈
堆栈首部是高地址,堆栈向低地址增长。栈指针总是指向下一个将要放入数据的空位置。

5、操作堆栈的汇编指令
堆栈类型 入栈指令 出栈指令
Full descending STMFD (STMDB) LDMFD (LDMIA)
Full ascending STMFA (STMIB) LDMFA (LDMDA)
Empty descending STMED (STMDA) LDMED (LDMIB)
Empty ascending STMEA (STMIA) LDMEA (LDMDB)
例子:
STMFD r13!, {r0-r5} ; Push onto a Full Descending Stack
LDMFD r13!, {r0-r5} ; Pop from a Full Descending Stack.

 

今天,在x86 上用 Vc试了一把,参考下面的测试代码,理解下x86 上的栈,也是向下增长的栈:

#include <stdio.h>
#include <stdlib.h>

void main(int argc, char* argv[]) {
	int i = 0;
	unsigned int k = 0xCCCCEEEE;
	unsigned int szTest_A[10] = {0};
	unsigned int x = 0xBBBBDDDD;
	unsigned int szTest_B[10] = {0};
	unsigned int m = 0xDDDDFFFF;

	//init the array A and array B
	for (i = 0; i < 10; i++) {
		szTest_A[i] = 0xAAAAAAA0 + i;
		szTest_B[i] = 0xBBBBBBB0 + i;
	}

	//display the array A and array B
	for (i = 0; i < 10; i++) {
		printf("szTest_A[%d] is %u (0x%x), its memory address is %x \n", i, szTest_A[i], szTest_A[i], &szTest_A[i]);
	}

	printf("====================================== \n");

	for (i = 0; i < 10; i++)	{
		printf("szTest_B[%d] is %u (0x%x), its memory address is %x  \n", i, szTest_B[i], szTest_B[i], &szTest_B[i]);
	}
}

ARM DS-5 运行结果:(严格按照 Full Descending Stack 规律, k 在最高地址, m 在最低地址)

x86 Visual Studio 运行结果:

 


写这段测试代码主要是想搞清楚,在函数f1 调用 f2 时,会将LR 压入栈,在f2 中的局部变量会在栈上分配内存空间。

如果像是测试代码写的这样,100bytes 的数组,但是如果在操作数组的时候越界了,使用的size 超过了100bytes,就会导致LR 被覆盖。这样从f2 返回到 f1 时就会出错了。(满栈递减栈的情况)

今天,遇到一个问题是,如果是满栈递增栈的话,发生上面的情况的话,LR 会被污染掉吗?

答案,是不会,对于100bytes 数组在栈上内存空间的分配方法,a[0] 的地址总是低地址。

Over~~

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值