栈、函数调用和栈帧

发布时间 2023-05-16 17:18:52作者: 夜owl

 

栈、函数调用和栈帧

堆栈(stack)又称为栈或堆叠

一种计算机最常用的数据结构之一,有以下几个相关概念:

  1. 栈顶和栈底:允许元素插入与删除的一端称为栈顶,另一端称为栈底
  2. 压栈POP:栈的插入操作,叫做进栈,也称压栈、入栈。
  3. 弹栈PUSH:栈的删除操作,也叫做出栈。
  4. 栈操作原则(First In Last Out,后进先出)。
  5. 栈增长方向,C语言默认是从高到低,也就是逆增长

需要注意的是,栈顶和栈底容易和增长方向混淆,高到低的增长方向,那么底部是栈顶,也就是“逆”向的。

栈帧

栈操作频繁的就是函数调用,而栈帧每个函数独有的栈,而一个栈中按照函数调用顺序有多个栈帧按增长方向顺序排列

 

栈相关指针

从技术上说,栈就是CPU寄存器里的某个指针所指向的一片内存区域。了解指针是必要的,而且需要知道栈指针由特定寄存器保存,不同平台命名不同

SP寄存器-ARM平台(x86/x64平台的ESP寄存器/RSP寄存器

sp寄存器是栈顶指针,特点为

随着栈操作一直变化

按照栈增长方向增加机器对应位数的数值,以从高到低增长为例,入栈则指针减去4(32位)或8(64位)

BP寄存器-ARM平台(x86/x64平台的EBP寄存器/RBP寄存器

bp寄存器是栈底指针,特点为

栈指针不会变化

帧指针每次都会随函数调用变化

 

 

函数调用

栈操作频繁的就是函数调用,而函数调用在栈的操作有不同的约定,如c语言默认调用约定cdecl为

  函数参数从右向左进栈

   然后返回地址进栈

 进入子函数后

  栈帧指针进栈

   临时变量进栈

 

调用者清栈

详细描述可以参考

堆栈、栈帧、函数调用过程_堆栈和栈帧_Lemonbr的博客-CSDN博客

另外的调用约定

(2)_stdcall:按从右至左的顺序压参数入栈,由被调用者把参数弹出栈。调用约定在输出
函数名前加上一个下划线前缀,后面加上一个“@”符号和其参数的字节数。
(3)_fastcall:主要特点就是快,因为它是通过寄存器来传送参数的,和__stdcall很
象,唯一差别就是头两个参数通过寄存器传送。注意通过寄存器传送的两个参数是从左向右的,
即第一个参数进ECX,第2个进EDX,其他参数是从右向左的入stack。返回仍然通过EAX。

 

实例

现在再来看栈帧的一个图

int main(int argc, char *args[])
{
    sum(3, 4, 5, 6);  
  return 0;
}

 

 


现在再来看栈帧的一个图