Chinaunix首页 | 论坛 | 博客
  • 博客访问: 474928
  • 博文数量: 223
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 2145
  • 用 户 组: 普通用户
  • 注册时间: 2014-03-01 10:23
个人简介

该坚持的时候坚持,该妥协的时候妥协,该放弃的时候放弃

文章分类

全部博文(223)

文章存档

2017年(56)

2016年(118)

2015年(3)

2014年(46)

我的朋友

分类: 嵌入式

2016-09-30 21:56:49

一、概念解析
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.保存局部变量

  1. #include <stdio.h>

  2. int main()
  3. {
  4.     int a;

  5.     a++;

  6.     return a;
  7. }
dump后,有这样一段:

  1. 0000834c <main>:
  2. #include <stdio.h>

  3. int main()
  4. {
  5.     834c:    e52db004     push    {fp}        ; (str fp, [sp, #-4]!)                 将数据压入栈,等同于str fp, [sp #-4]!将fp压入栈(sp指针向下以一“格”的位置),sp同时也指向下一格。
  6.     8350:    e28db000     add    fp, sp, #0    ; 0x0                                 将sp中的内容赋值给fp
  7.     8354:    e24dd00c     sub    sp, sp, #12    ; 0xc                                将sp向下移动3“格”
  8.     int a;

  9.     a++;
  10.     8358:    e51b3008     ldr    r3, [fp, #-8]                                        将fp向下2“格”中的数据提取到r3
  11.     835c:    e2833001     add    r3, r3, #1    ; 0x1                                  将r3加上立即数1
  12.     8360:    e50b3008     str    r3, [fp, #-8]                                        存回fp向下2“格”中

  13.     return a;
  14.     8364:    e51b3008     ldr    r3, [fp, #-8]                                        将fp继续提取出来
  15. }

2.传递参数

  1. #include <stdio.h>

  2. void func1(int a,int b,int c,int d,int e,int f)                                       这里定义了6个参数
  3. {
  4.     int k;
  5.     k=e+f;
  6. }

  7. int main()
  8. {
  9.     func1(1,2,3,4,5,6);                                                               传递了6个参数
  10.     return 0;
  11. }
dump后,有这样一段:
  1. #include <stdio.h>

  2. void func1(int a,int b,int c,int d,int e,int f)
  3. {
  4.     834c:    e52db004     push    {fp}        ; (str fp, [sp, #-4]!)                   依然是压入栈,sp指向fp.(下移了一“格”)
  5.     8350:    e28db000     add    fp, sp, #0    ; 0x0                                   fp指向了sp所指
  6.     8354:    e24dd01c     sub    sp, sp, #28    ; 0x1c                                 sp向下移动了7“格”
  7.     8358:    e50b0010     str    r0, [fp, #-16]                                        r0存到fp的下4“格”中
  8.     835c:    e50b1014     str    r1, [fp, #-20]                                        r1存到fp的下5“格”中
  9.     8360:    e50b2018     str    r2, [fp, #-24]                                        r2存到fp的下6“格”中
  10.     8364:    e50b301c     str    r3, [fp, #-28]                                        r3存到fp的下7“格”中
  11.     int k;
  12.     k=e+f;
  13.     8368:    e59b3004     ldr    r3, [fp, #4]                                          将fp上面一“格”,(main中的数值5)存到r3
  14.     836c:    e59b2008     ldr    r2, [fp, #8]                                          将fp上面2“格”,(main中的数值6)存到r2
  15.     8370:    e0833002     add    r3, r3, r2                                            r3 = r3 +r2
  16.     8374:    e50b3008     str    r3, [fp, #-8]                                         将r3存到下面3“格”
  17. }
  18.     8378:    e28bd000     add    sp, fp, #0    ; 0x0
  19.     837c:    e8bd0800     pop    {fp}
  20.     8380:    e12fff1e     bx    lr

  21. 00008384 <main>:

  22. int main()
  23. {
  24.     8384:    e92d4800     push    {fp, lr}                                              将fp和lr压入栈,sp指向lr
  25.     8388:    e28db004     add    fp, sp, #4    ; 0x4                                    fp是sp的上面一”格“
  26.     838c:    e24dd008     sub    sp, sp, #8    ; 0x8                                    sp向下移动2“格“
  27.     func1(1,2,3,4,5,6);
  28.     8390:    e3a03005     mov    r3, #5    ; 0x5                                        设置r3为5
  29.     8394:    e58d3000     str    r3, [sp]                                               将r3保存到sp指向的位置(数5)
  30.     8398:    e3a03006     mov    r3, #6    ; 0x6                                        将r3设为6
  31.     839c:    e58d3004     str    r3, [sp, #4]                                           将r3保存到sp上面一“格”(数6)
  32.     83a0:    e3a00001     mov    r0, #1    ; 0x1                                        设置r0为1(数1)
  33.     83a4:    e3a01002     mov    r1, #2    ; 0x2                                        设置r1为2(数2)
  34.     83a8:    e3a02003     mov    r2, #3    ; 0x3                                        设置r2为3(数3)
  35.     83ac:    e3a03004     mov    r3, #4    ; 0x4                                        设置r3为4(数4)
  36.     83b0:    ebffffe5     bl    834c <func1>                                            跳转到func1处
  37.     return 0;
  38.     83b4:    e3a03000     mov    r3, #0    ; 0x0                                        
  39. }
在c语言中如果一个函数的参数小于或等于4个,那么会用寄存器r0、r1、r2、r3、r4。如果超过4个,就是用栈传递参数

3.保存寄存器值

  1. #include <stdio.h>

  2. void func2(int a,int b)
  3. {
  4.     int k;
  5.     k = a+b;
  6. }

  7. void func1(int a,int b)
  8. {
  9.     int c;
  10.     func2(3,4);
  11.     c = a+b;
  12. }

  13. int main()
  14. {
  15.     func1(1,2);
  16.     return 0;
  17. }
dump后,有这样一段:

  1. #include <stdio.h>

  2. void func2(int a,int b)
  3. {
  4.     834c:    e52db004     push    {fp}        ; (str fp, [sp, #-4]!)              压入了fp,sp指向fp
  5.     8350:    e28db000     add    fp, sp, #0    ; 0x0                              fp指向了sp所指
  6.     8354:    e24dd014     sub    sp, sp, #20    ; 0x14                            sp向下移动5格
  7.     8358:    e50b0010     str    r0, [fp, #-16]                                   r0存到fp下面4格
  8.     835c:    e50b1014     str    r1, [fp, #-20]                                   r1存到fp下面5格
  9.     int k;
  10.     k = a+b;
  11.     8360:    e51b3010     ldr    r3, [fp, #-16]                                  提取r3到fp下面4格
  12.     8364:    e51b2014     ldr    r2, [fp, #-20]                                  提取r2到fp下面5格
  13.     8368:    e0833002     add    r3, r3, r2                                      r3 = r1 + r2
  14.     836c:    e50b3008     str    r3, [fp, #-8]                                   保存r3到fp下面2格
  15. }
  16.     8370:    e28bd000     add    sp, fp, #0    ; 0x0
  17.     8374:    e8bd0800     pop    {fp}
  18.     8378:    e12fff1e     bx    lr

  19. 0000837c <func1>:

  20. void func1(int a,int b)
  21. {
  22.     837c:    e92d4800     push    {fp, lr}                                          又压入了fp,lr,sp指向lr
  23.     8380:    e28db004     add    fp, sp, #4    ; 0x4                                再次赋值fp
  24.     8384:    e24dd010     sub    sp, sp, #16    ; 0x10                              sp向下移动4“格”
  25.     8388:    e50b0010     str    r0, [fp, #-16]                                     将r0存到fp下面4格
  26.     838c:    e50b1014     str    r1, [fp, #-20]                                     将r1存到fp下面5格
  27.     int c;
  28.     func2(3,4);
  29.     8390:    e3a00003     mov    r0, #3    ; 0x3                                    设置r0为3(数1)
  30.     8394:    e3a01004     mov    r1, #4    ; 0x4                                    设置r1为4(数1)
  31.     8398:    ebffffeb     bl    834c <func2>                                        跳转到func2
  32.     c = a+b;
  33.     839c:    e51b3010     ldr    r3, [fp, #-16]                                     提取fp下面4格
  34.     83a0:    e51b2014     ldr    r2, [fp, #-20]                                     提取fp下面5格
  35.     83a4:    e0833002     add    r3, r3, r2                                         r3 = r3+r2
  36.     83a8:    e50b3008     str    r3, [fp, #-8]                                      将r3存到fp下面3格
  37. }
  38.     83ac:    e24bd004     sub    sp, fp, #4    ; 0x4
  39.     83b0:    e8bd4800     pop    {fp, lr}
  40.     83b4:    e12fff1e     bx    lr

  41. 000083b8 <main>:

  42. int main()
  43. {
  44.     83b8:    e92d4800     push    {fp, lr}                                             将fp和lr压入栈,sp指向lr
  45.     83bc:    e28db004     add    fp, sp, #4    ; 0x4                                   fp指向sp上面一“格”
  46.     func1(1,2);
  47.     83c0:    e3a00001     mov    r0, #1    ; 0x1                                       设置r0为1(数1)
  48.     83c4:    e3a01002     mov    r1, #2    ; 0x2                                       设置r1为2(数1)
  49.     83c8:    ebffffeb     bl    837c <func1>                                           跳转到func1
  50.     return 0;
  51.     83cc:    e3a03000     mov    r3, #0    ; 0x0
  52. }

三、初始化堆栈

  1. init_stack:
  2.     ldr sp, =0x34000000                 初始化sp指针,默认为内存起始地址的64MB位置
  3.     mov pc, lr                          返回bl init_stack

阅读(734) | 评论(0) | 转发(0) |
0

上一篇:代码搬移不可少

下一篇:BSS初始化

给主人留下些什么吧!~~