• 谈谈arm下的函数栈


    引言

      这篇文章简要说说函数是怎么传入参数的,我们都知道,当一个函数调用使用少量参数(ARM上是少于等于4个)时,参数是通过寄存器进行传值(ARM上是通过r0,r1,r2,r3),而当参数多于4个时,会将多出的参数压入栈中进行传递(其实在函数调用过程中也会把r0,r1,r2,r3传递的参数压入栈),具体是什么实现的呢,我们看看。

    函数栈

      首先我们需要了解一下linux下一个进程的内存地址空间是如何布局的,在linux中,0~3G的虚拟地址为进程所有,3G~4G由内核所使用,每一个进程都有自己独立的0~3G内存地址空间。当进程进行函数调用时,我们都知道传入被调用函数的参数是通过栈进行操作的,这里我们只需要简单了解一下linux的内存地址空间中的栈是自顶向下生长的,就是栈底出于高地址处,栈顶出于低地址处。

      好的,简单了解了内存地址空间的栈后,我们还需要简单了解一下EBPESP这两个寄存器,EBP是用保存栈低地址的,而ESP用于保存栈顶地址,而每一次函数调用会涉及到一个栈帧

    举个实例详细说明一下一个函数帧的特点,比如

     1 /* B被A调用
     2  * 参数:data1, data2, data3
     3  * 局部变量: s1, s2, s3 */
     4 void B (int data1, int data2, int data3)
     5 {
     6     int b_s1;
     7     int b_s2;
     8     int b_s3;
     9 }
    10  
    11 /* A调用B函数 */
    12 void A (void)
    13 {
    14     int a_s1;
    15     int a_s2;
    16     int a_s3;
    17     
    18     B (1, 2, 3);
    19     printf ("1
    ");
    20 }

    在以上例子中栈帧情况如下图所示

      从图例中可以看出,当A函数没有调用B函数时,A函数的栈帧只保存着局部变量,而EBP(栈底指针)指向的是A函数的函数栈帧头,而当A函数调用B函数时,A函数会将B函数所需要的参数从右往左压入栈(在例子中先压入3,之后是2,最后是1),之后会将A调用完B之后所需要运行的第一条指令压入栈,此时建立一个B的栈帧,具体流程:

    • 从右往左将B函数所需参数压入栈
    • 压入执行完B函数之后的第一条指令地址
    • 建立B栈帧
    • 压入A栈帧的栈底
    • 压入B函数保护的寄存器
    • 压入B函数的局部变量

    小结

       其实每一种处理器架构所使用的方式都不一样,在arm上我几个参数和不定参数的情况通过汇编代码查看又不相同,之后反汇编后研究透了会再发布一篇博文专门说这个,现在这篇就当做一个入门知识吧。

  • 相关阅读:
    SpringBoot04-web
    springboot03-日志功能
    SpringBoot02-自动配置原理
    SpringBoot02
    SpringBoot01
    八大排序算法
    SpringSecurity04
    SpringSecurity03
    SpringSecurity02
    SpringSecurity01
  • 原文地址:https://www.cnblogs.com/tolimit/p/4226839.html
Copyright © 2020-2023  润新知