• 34.栈的初始化


    34.栈的初始化

    前面知道,uboot的第一阶段是用汇编代码来对硬件等进行初始化的。第二阶段是用C语言的。但是此时没有C语言的运行环境。而C语言的运行需要堆栈等资源。所以这一节是第二阶段的C语言环境运行的栈的初始化。

    1.栈:是一种具有先进先出性质的数据组织方式,也就是说后存进去的先取出,后存进去的后取出的。栈底是第一个进栈的数据所处的位置,栈顶是最后一个进栈的数据所处的位置。

    2.满栈和空栈

    根据sp指针指向的位置,栈可以分为满栈和空栈:

    满栈:当堆栈指针sp总是指向最后压入堆栈的数据。

    空栈:当堆栈指针sp总是指向下一个将要放入数据的空位置。

    注意:ARM采用满栈的方式

    满栈

    空栈

    3.升栈和降栈

    升栈:随着数据的入栈,sp指针从低地址à高地址移动

    降栈:随着数据的入栈,sp指针从高地址à低地址移动

    注意:ARM采用降栈。

    升栈

    降栈

    4.栈帧:就是一个函数所用的那部分栈,所有函数的栈帧串联起来就是一个完整的栈。栈帧的两个边界分别由fp(r11)和sp(r13)来限定。

    C代码分析:

    局部变量保存在栈里:

    Stack1.c:

    #include <stdio.h>

    int main()

    {

    int a;

    a++;

    return a;

    }

    编译和反汇编:

    反汇编文件:

    int main()

    {

    834c:    e52db004     push    {fp}        ; (str fp, [sp, #-4]!)

    8350:    e28db000     add    fp, sp, #0    ; 0x0

    8354:    e24dd00c     sub    sp, sp, #12    ; 0xc //准备工作,保存现场

    int a;

    a++;

    8358:    e51b3008     ldr    r3, [fp, #-8]

    835c:    e2833001     add    r3, r3, #1    ; 0x1 //a++,局部变量

    8360:    e50b3008     str    r3, [fp, #-8]

    return a;

    8364:    e51b3008     ldr    r3, [fp, #-8]

    }

    8368:    e1a00003     mov    r0, r3

    836c:    e28bd000     add    sp, fp, #0    ; 0x0

    8370:    e8bd0800     pop    {fp}

    8374:    e12fff1e     bx    lr

    Stack2.c:

    函数参数多于四个的那些参数保存在栈里,4个之内的保存在寄存器r0-r3里。

    #include <stdio.h>

    void func1(int a,int b,int c,int d,int e,int f)

    {

        int k;

        k=e+f;

    }

    int main()

    {

    func1(1,2,3,4,5,6);

    return 0;

    }

    编译和反汇编:

    0000834c <func1>:

    #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]!) //fp入栈

    8350:    e28db000     add    fp, sp, #0    ; 0x0 //fp和sp相同的位置

    8354:    e24dd01c     sub    sp, sp, #28    ; 0x1c

    8358:    e50b0010     str    r0, [fp, #-16]

    835c:    e50b1014     str    r1, [fp, #-20]

    8360:    e50b2018     str    r2, [fp, #-24]

    8364:    e50b301c     str    r3, [fp, #-28] //参数在四个内

        int k;

        k=e+f;

    8368:    e59b3004     ldr    r3, [fp, #4]//多于四个的保存在栈里,参数5,6

    836c:    e59b2008     ldr    r2, [fp, #8]

    8370:    e0833002     add    r3, r3, r2

    8374:    e50b3008     str    r3, [fp, #-8]

    }

    8378:    e28bd000     add    sp, fp, #0    ; 0x0

    837c:    e8bd0800     pop    {fp}

    8380:    e12fff1e     bx    lr

    00008384 <main>:

    int main()

    {

    8384:    e92d4800     push    {fp, lr}

    8388:    e28db004     add    fp, sp, #4    ; 0x4

    838c:    e24dd008     sub    sp, sp, #8    ; 0x8

    func1(1,2,3,4,5,6);

    8390:    e3a03005     mov    r3, #5    ; 0x5

    8394:    e58d3000     str    r3, [sp]

    8398:    e3a03006     mov    r3, #6    ; 0x6

    839c:    e58d3004     str    r3, [sp, #4]

    83a0:    e3a00001     mov    r0, #1    ; 0x1 //函数的参数在四个之内的采用寄存器r0-r3来传递,大于四个的那些参数,就要使用栈来传递的。

    83a4:    e3a01002     mov    r1, #2    ; 0x2

    83a8:    e3a02003     mov    r2, #3    ; 0x3

    83ac:    e3a03004     mov    r3, #4    ; 0x4

    83b0:    ebffffe5     bl    834c <func1>

    return 0;

    83b4:    e3a03000     mov    r3, #0    ; 0x0

    }

    83b8:    e1a00003     mov    r0, r3

    83bc:    e24bd004     sub    sp, fp, #4    ; 0x4

    83c0:    e8bd4800     pop    {fp, lr}

    83c4:    e12fff1e     bx    lr

    保存寄存器的值:

    Statk3.c:

    #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;

    }

    编译和反汇编:

    0000834c <func2>:

    #include <stdio.h>

    void func2(int a,int b)

    {

    834c:    e52db004     push    {fp}        ; (str fp, [sp, #-4]!)

    8350:    e28db000     add    fp, sp, #0    ; 0x0

    8354:    e24dd014     sub    sp, sp, #20    ; 0x14

    8358:    e50b0010     str    r0, [fp, #-16]

    835c:    e50b1014     str    r1, [fp, #-20]

    int k;

    k=a+b;

    8360:    e51b3010     ldr    r3, [fp, #-16]

    8364:    e51b2014     ldr    r2, [fp, #-20]

    8368:    e0833002     add    r3, r3, r2

    836c:    e50b3008     str    r3, [fp, #-8]

    }

    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}

    8380:    e28db004     add    fp, sp, #4    ; 0x4

    8384:    e24dd010     sub    sp, sp, #16    ; 0x10

    8388:    e50b0010     str    r0, [fp, #-16]

    838c:    e50b1014     str    r1, [fp, #-20] //将寄存器里的值存入栈

        int c;

        func2(3,4); //之所以要把寄存器里的值保存入栈,是因为这里的func2(3,4)函数也有两个参数,不保存的话会被覆盖掉。后面再进行相加就会出错。因为系统还是会用寄存器r0和r1来存func2函数的参数。

    8390:    e3a00003     mov    r0, #3    ; 0x3

    8394:    e3a01004     mov    r1, #4    ; 0x4

    8398:    ebffffeb     bl    834c <func2>

        c=a+b;

    839c:    e51b3010     ldr    r3, [fp, #-16]

    83a0:    e51b2014     ldr    r2, [fp, #-20]//从栈里面取出值放入寄存器

    83a4:    e0833002     add    r3, r3, r2

    83a8:    e50b3008     str    r3, [fp, #-8]

    }

    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}

    83bc:    e28db004     add    fp, sp, #4    ; 0x4

    func1(1,2);

    83c0:    e3a00001     mov    r0, #1    ; 0x1

    83c4:    e3a01002     mov    r1, #2    ; 0x2 //用寄存器来保存参数

    83c8:    ebffffeb     bl    837c <func1>

    return 0;

    83cc:    e3a03000     mov    r3, #0    ; 0x0

    }

    83d0:    e1a00003     mov    r0, r3

    83d4:    e24bd004     sub    sp, fp, #4    ; 0x4

    83d8:    e8bd4800     pop    {fp, lr}

    83dc:    e12fff1e     bx    lr

    接下来就是完成堆栈的初始化:

    知道6410的内存是256MB,210是512MB,2440是64MB。这里我选的是6410的。Sp指针指向64MB的位置。

    2440内存开始的地方:30000000

    6410内存开始的地方:50000000

    210内存开始的地方:20000000

    所以要sp指针指向64MB的地址就是500000000(6410)+64MB即可:

    64MB=0x4000000,所以sp指向的地方是0x54000000即可:

  • 相关阅读:
    GC 案例收集整理
    Netty ByteBuf泄露定位修改。
    使用Modernizr 检测HTML5和CSS3浏览器支持功能 (转自http://www.adobe.com/cn/devnet/dreamweaver/articles/using-modernizr.html)
    drupal网站邮件发送功能的实现
    Customizing and Overriding User Login page, Register, and Password Reset in Drupal 6 and 7
    WordPress网站迁移
    HTTP协议详解 (转)
    HTTP协议
    Apache服务器放置多个站点的配置方法 (转)
    Apache禁止或允许固定IP访问特定目录、文件、URL
  • 原文地址:https://www.cnblogs.com/FORFISH/p/5188758.html
Copyright © 2020-2023  润新知