ARM——棧


1 棧:棧是一種具有后進先出數據組織方式,也就是說后存放的先取出,先存放的后取出。棧底是第一個進棧的數據所處位置,棧頂是最后一個數據進棧所處的位置。

  數據組織:有鏈表、圖、樹等等(就數據結構那些東東)

2 滿/空棧

  根據SP指針指向的位置,棧可以分為滿棧空棧

  滿棧:當堆棧指針總是指向最后壓入堆棧的數據

  空棧:當堆棧指針總是指向下一個將要放入數據的空位置

  ARM采用滿棧

3 升/降棧

  根據SP指針移動的方向,棧可以分為升棧和降棧

  升棧:隨着數據的入棧,SP指針從低地址->高地址移動

  降棧:隨着數據的入棧,SP指針從高地址->低地址移動

    ARM采用降棧

注:ARM是滿降棧

4 棧幀

  上圖描述的是ARM的棧幀布局方式,main stack frame為調用函數的棧幀,func1 stack frame為當前函數(被調用者)的棧幀,棧底在高地址,棧向下增長。圖中FP就是棧基址,它指向函數的棧幀起始地址;SP則是函數的棧指針,它指向棧頂的位置。ARM壓棧的順序依次為當前函數指針PC、返回指針LR、棧指針SP、棧基址FP、傳入參數個數及指針、本地變量和臨時變量。如果函數准備調用另一個函數,跳轉之前臨時變量區先要保存另一個函數的參數。
  ARM也可以用棧基址和棧指針明確標示棧幀的位置,棧指針SP一直移動。

  棧幀(stack frame):就是一個函數所使用的那部分棧,所有函數的棧幀串起來就組成了一個完整的棧。棧幀的兩個邊界分別由fp(r11)和sp(r13)來限定。

#include <stdio.h>

int main()
{
    ...
    func1();
    ...
}

int func1()
{
    ...
}

  例子中有兩個函數,程序運行起來會有一個棧。

  fp(r11)棧幀指針,棧幀上邊界由fp指針界定,下邊界有sp指針界定。從main函數進入到func1函數,main函數的上邊界和下邊界保存在被它調用的棧幀里面。

5 棧的作用

5.1 保存局部變量

#include <stdio.h>

int main()
{
    int a;
    a++;
    return a;
}
/******************************************************
反匯編找到main函數
dongry@d-linux:~/test/hardwork/stack$ arm-linux-gcc -g stack1.c -o stack1
dongry@d-linux:~/test/hardwork/stack$ arm-linux-objdump -D -S stack1 >dump
dongry@d-linux:~/test/hardwork/stack$ vim dump

/main
*******************************************************/
/*反匯編代碼*/
 000083a0 <main>:
 #include <stdio.h>
 
 int main()
 {
     83a0:       e1a0c00d        mov     ip, sp                    
     83a4:       e92dd800        stmdb   sp!, {fp, ip, lr, pc}
     83a8:       e24cb004        sub     fp, ip, #4      ; 0x4
     83ac:       e24dd004        sub     sp, sp, #4      ; 0x4
         int a;
         a++;
     83b0:       e51b3010        ldr     r3, [fp, #-16]
     83b4:       e2833001        add     r3, r3, #1      ; 0x1
     83b8:       e50b3010        str     r3, [fp, #-16]
         return  a;
     83bc:       e51b3010        ldr     r3, [fp, #-16]
 }
/*分析*/
    mov ip,sp        //保存sp到ip
    stmdb sp!,{fp,ip,lr,pc}   /*先對sp-4,再對fp,ip,lr,pc壓棧*/
                             //sp=sp-4;push {pc};sp=pc;  /*先壓pc*/
                             //sp=sp-4;push {lr};sp=lr; /*壓lr*/
                             //sp=sp-4;push {ip};sp=ip;  /*壓ip*/
                             //sp=sp-4;push {fp};sp=fp; /*壓fp*/
    sub fp,ip,#4        //fp指向ip-4
    sub sp,sp,#4       //開辟一塊空間
  
    ldr r3,[fp,#-16]   //臨時存放在[fp-16]
    add r3,r3,#1
    str r3,[fp,#-16]

5.2 參數傳遞

#include <stdio.h>

void func(int a,int b,int c,int d,int e,int f)
{
    int k;
    int l;
    k=e+f;
    l=a+b;
}

int main()
{
    func(1,2,3,4,5,6);
    return 0;
}

  參數大於4個的時候,多出來的參數用棧傳遞;

5.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);
}

int main()
{
    func1(1,2);
    return 0;
}

  如果不用棧,會將原來r0、r1寄存器中的值覆蓋掉

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM