一、概念解析
1.1 概念-栈
栈是一种具有
后进先出性质的数据组织方式,也就是说后存放的先取出,先存放的后取出。
栈底是第一个进栈的数据所处的位置,
栈顶是最后一个进栈的数据所处的位置。
1.2 概念-满/空栈
根据
SP指针指向的位置,栈可以分为
满栈和空栈。
1. 满栈:当堆栈指针
SP总是指向最后压入堆栈的数据
2. 空栈:当堆栈指针
SP总是指向下一个将要放入数据的空位置
ARM采用满栈!
1.3 概念-升/降栈 根据
SP指针移动的方向,栈可以分为升栈和降栈。
1. 升栈:随着数据的入栈,
SP指针从低地址
->高地址移动
2. 降栈:随着数据的入栈,
SP指针从高地址
->低地址移动
ARM采用降栈!
1.4 概念-栈帧
简单的讲
,栈帧
(stack frame)就是一个函数所使用的那部分栈,所有函数的栈帧串起来就组成了一个完整的栈。栈帧的两个边界分别由
fp(r11)和sp(r13)来限定。
妈蛋,这张图有问题。这张图是使用的升栈,所以ARM的降栈,PC应该是在LR的下面。
二、栈作用
1.保存局部变量
-
#include <stdio.h>
-
-
int main()
-
{
-
int a;
-
-
a++;
-
-
return a;
-
}
dump后,有这样一段:
-
0000834c <main>:
-
#include <stdio.h>
-
-
int main()
-
{
-
834c: e52db004 push {fp} ; (str fp, [sp, #-4]!) 将数据压入栈,等同于str fp, [sp #-4]!将fp压入栈(sp指针向下以一“格”的位置),sp同时也指向下一格。
-
8350: e28db000 add fp, sp, #0 ; 0x0 将sp中的内容赋值给fp
-
8354: e24dd00c sub sp, sp, #12 ; 0xc 将sp向下移动3“格”
-
int a;
-
-
a++;
-
8358: e51b3008 ldr r3, [fp, #-8] 将fp向下2“格”中的数据提取到r3
-
835c: e2833001 add r3, r3, #1 ; 0x1 将r3加上立即数1
-
8360: e50b3008 str r3, [fp, #-8] 存回fp向下2“格”中
-
-
return a;
-
8364: e51b3008 ldr r3, [fp, #-8] 将fp继续提取出来
-
}
2.传递参数
-
#include <stdio.h>
-
-
void func1(int a,int b,int c,int d,int e,int f) 这里定义了6个参数
-
{
-
int k;
-
k=e+f;
-
}
-
-
int main()
-
{
-
func1(1,2,3,4,5,6); 传递了6个参数
-
return 0;
-
}
dump后,有这样一段:
-
#include <stdio.h>
-
-
void func1(int a,int b,int c,int d,int e,int f)
-
{
-
834c: e52db004 push {fp} ; (str fp, [sp, #-4]!) 依然是压入栈,sp指向fp.(下移了一“格”)
-
8350: e28db000 add fp, sp, #0 ; 0x0 fp指向了sp所指
-
8354: e24dd01c sub sp, sp, #28 ; 0x1c sp向下移动了7“格”
-
8358: e50b0010 str r0, [fp, #-16] r0存到fp的下4“格”中
-
835c: e50b1014 str r1, [fp, #-20] r1存到fp的下5“格”中
-
8360: e50b2018 str r2, [fp, #-24] r2存到fp的下6“格”中
-
8364: e50b301c str r3, [fp, #-28] r3存到fp的下7“格”中
-
int k;
-
k=e+f;
-
8368: e59b3004 ldr r3, [fp, #4] 将fp上面一“格”,(main中的数值5)存到r3
-
836c: e59b2008 ldr r2, [fp, #8] 将fp上面2“格”,(main中的数值6)存到r2
-
8370: e0833002 add r3, r3, r2 r3 = r3 +r2
-
8374: e50b3008 str r3, [fp, #-8] 将r3存到下面3“格”
-
}
-
8378: e28bd000 add sp, fp, #0 ; 0x0
-
837c: e8bd0800 pop {fp}
-
8380: e12fff1e bx lr
-
-
00008384 <main>:
-
-
int main()
-
{
-
8384: e92d4800 push {fp, lr} 将fp和lr压入栈,sp指向lr
-
8388: e28db004 add fp, sp, #4 ; 0x4 fp是sp的上面一”格“
-
838c: e24dd008 sub sp, sp, #8 ; 0x8 sp向下移动2“格“
-
func1(1,2,3,4,5,6);
-
8390: e3a03005 mov r3, #5 ; 0x5 设置r3为5
-
8394: e58d3000 str r3, [sp] 将r3保存到sp指向的位置(数5)
-
8398: e3a03006 mov r3, #6 ; 0x6 将r3设为6
-
839c: e58d3004 str r3, [sp, #4] 将r3保存到sp上面一“格”(数6)
-
83a0: e3a00001 mov r0, #1 ; 0x1 设置r0为1(数1)
-
83a4: e3a01002 mov r1, #2 ; 0x2 设置r1为2(数2)
-
83a8: e3a02003 mov r2, #3 ; 0x3 设置r2为3(数3)
-
83ac: e3a03004 mov r3, #4 ; 0x4 设置r3为4(数4)
-
83b0: ebffffe5 bl 834c <func1> 跳转到func1处
-
return 0;
-
83b4: e3a03000 mov r3, #0 ; 0x0
-
}
在c语言中如果一个函数的参数小于或等于4个,那么会用寄存器r0、r1、r2、r3、r4。如果超过4个,就是用栈传递参数。
3.保存寄存器值
-
#include <stdio.h>
-
-
void func2(int a,int b)
-
{
-
int k;
-
k = a+b;
-
}
-
-
void func1(int a,int b)
-
{
-
int c;
-
func2(3,4);
-
c = a+b;
-
}
-
-
int main()
-
{
-
func1(1,2);
-
return 0;
-
}
dump后,有这样一段:
-
#include <stdio.h>
-
-
void func2(int a,int b)
-
{
-
834c: e52db004 push {fp} ; (str fp, [sp, #-4]!) 压入了fp,sp指向fp
-
8350: e28db000 add fp, sp, #0 ; 0x0 fp指向了sp所指
-
8354: e24dd014 sub sp, sp, #20 ; 0x14 sp向下移动5格
-
8358: e50b0010 str r0, [fp, #-16] r0存到fp下面4格
-
835c: e50b1014 str r1, [fp, #-20] r1存到fp下面5格
-
int k;
-
k = a+b;
-
8360: e51b3010 ldr r3, [fp, #-16] 提取r3到fp下面4格
-
8364: e51b2014 ldr r2, [fp, #-20] 提取r2到fp下面5格
-
8368: e0833002 add r3, r3, r2 r3 = r1 + r2
-
836c: e50b3008 str r3, [fp, #-8] 保存r3到fp下面2格
-
}
-
8370: e28bd000 add sp, fp, #0 ; 0x0
-
8374: e8bd0800 pop {fp}
-
8378: e12fff1e bx lr
-
-
0000837c <func1>:
-
-
void func1(int a,int b)
-
{
-
837c: e92d4800 push {fp, lr} 又压入了fp,lr,sp指向lr
-
8380: e28db004 add fp, sp, #4 ; 0x4 再次赋值fp
-
8384: e24dd010 sub sp, sp, #16 ; 0x10 sp向下移动4“格”
-
8388: e50b0010 str r0, [fp, #-16] 将r0存到fp下面4格
-
838c: e50b1014 str r1, [fp, #-20] 将r1存到fp下面5格
-
int c;
-
func2(3,4);
-
8390: e3a00003 mov r0, #3 ; 0x3 设置r0为3(数1)
-
8394: e3a01004 mov r1, #4 ; 0x4 设置r1为4(数1)
-
8398: ebffffeb bl 834c <func2> 跳转到func2
-
c = a+b;
-
839c: e51b3010 ldr r3, [fp, #-16] 提取fp下面4格
-
83a0: e51b2014 ldr r2, [fp, #-20] 提取fp下面5格
-
83a4: e0833002 add r3, r3, r2 r3 = r3+r2
-
83a8: e50b3008 str r3, [fp, #-8] 将r3存到fp下面3格
-
}
-
83ac: e24bd004 sub sp, fp, #4 ; 0x4
-
83b0: e8bd4800 pop {fp, lr}
-
83b4: e12fff1e bx lr
-
-
000083b8 <main>:
-
-
int main()
-
{
-
83b8: e92d4800 push {fp, lr} 将fp和lr压入栈,sp指向lr
-
83bc: e28db004 add fp, sp, #4 ; 0x4 fp指向sp上面一“格”
-
func1(1,2);
-
83c0: e3a00001 mov r0, #1 ; 0x1 设置r0为1(数1)
-
83c4: e3a01002 mov r1, #2 ; 0x2 设置r1为2(数1)
-
83c8: ebffffeb bl 837c <func1> 跳转到func1
-
return 0;
-
83cc: e3a03000 mov r3, #0 ; 0x0
-
}
三、初始化堆栈
-
init_stack:
-
ldr sp, =0x34000000 初始化sp指针,默认为内存起始地址的64MB位置
-
mov pc, lr 返回bl init_stack
阅读(773) | 评论(0) | 转发(0) |