【?】没想好标题

共计2398字,阅读大约8分钟。
图片[1]-【?】没想好标题-galgame

函数调用过程中的栈帧

每当一个函数被调用时,系统会为这个函数分配一个栈帧(stack frame)。栈帧是存储函数调用的上下文信息的结构,包括:

  • 函数的参数
  • 局部变量
  • 返回地址
  • 保存的寄存器值

压栈和弹出在函数调用中的作用

压栈

当一个函数被调用时,会发生以下步骤:

  1. 参数压栈:调用函数将实际参数(实参)压入栈中。
  2. 返回地址压栈:将调用点的返回地址压入栈中,以便函数执行完后能返回调用点。
  3. 保存上下文:保存调用点的上下文(如某些寄存器的值)。
  4. 分配局部变量空间:为被调用函数的局部变量分配栈空间。

弹出

当一个函数执行完毕准备返回时,会发生以下步骤:

  1. 清理局部变量空间:释放被调用函数的局部变量所占的栈空间。
  2. 恢复上下文:从栈中恢复调用点的上下文。
  3. 返回地址弹出:从栈中弹出返回地址,并跳转到该地址继续执行。
  4. 参数弹出:清理调用函数压入栈的参数。

示例

#include <stdio.h>

void func(int a, int b) {
    int c = a + b;
    printf("c = %d\n", c);
}

int main() {
    int x = 5;
    int y = 10;
    func(x, y); // 调用函数
    return 0;
}

详细分析

  1. main 函数开始执行
  • xy 被分配在 main 的栈帧中。
  1. 调用 func(x, y)
  • 参数压栈
    • xy 的值(5 和 10)被压入栈中。
  • 返回地址压栈
    • func 函数返回后将继续执行 main 函数的地址被压入栈中。
  • 保存上下文
    • main 函数当前的上下文(如某些寄存器的值)被保存。
  • 分配局部变量空间
    • func 函数的局部变量 c 分配栈空间。
  1. 执行 func 函数
  • ab 从栈中读取,值为 5 和 10。
  • 计算 c = a + b,结果为 15。
  • 输出 c = 15
  1. 返回 main 函数
  • 清理局部变量空间
    • 释放 func 函数的局部变量 c 所占的栈空间。
  • 恢复上下文
    • 恢复 main 函数的上下文。
  • 返回地址弹出
    • 从栈中弹出返回地址,并跳转到该地址继续执行。
  • 参数弹出
    • 清理 main 函数压入栈的参数(xy 的值)。

总结

  • 压栈:当函数被调用时,参数、返回地址、上下文和局部变量都被压入栈中。
  • 弹出:当函数返回时,局部变量空间、上下文、返回地址和参数被从栈中弹出。
  • 栈帧:每个函数调用都有自己的栈帧,存储该函数的所有上下文信息。

在汇编语言中,PUSHPOP 是两条用于栈操作的指令。栈是一种后进先出(LIFO,Last In, First Out)的数据结构,这意味着最后被放入栈中的数据最先被取出。以下是这两条指令的详细说明:

PUSH

PUSH 指令用于将数据压入栈中。它会将一个寄存器或内存位置的值保存到栈顶,然后递减栈指针(通常是 SPESP,在 x86 架构中为 RSP 在 x86-64 架构中)。具体操作步骤如下:

  1. 递减栈指针:将栈指针的值减小,以便为新的值腾出空间。
  2. 保存数据:将要压入的数据存放到栈顶位置。

示例(x86 架构):

PUSH AX  ; 将寄存器 AX 的值压入栈中

POP

POP 指令用于从栈中弹出数据。它会将栈顶的数据取出并放入一个寄存器或内存位置,然后递增栈指针。具体操作步骤如下:

  1. 取出数据:从栈顶位置读取数据。
  2. 递增栈指针:将栈指针的值增加,以便将栈顶向上移动。

示例(x86 架构):

POP BX  ; 将栈顶的值弹出,并存入寄存器 BX

栈操作示例

section .data
    value1 dw 0x1234  ; 定义一个数据

section .bss

section .text
    global _start

_start:
    ; 假设初始 ESP(栈指针)为 0x100

    ; 将 value1 压入栈中
    MOV AX, value1    ; 将 value1 的值加载到寄存器 AX 中
    PUSH AX           ; 将 AX 的值压入栈中 

    ; 假设此时 ESP 递减为 0x0FE
    ; 栈中内容:0x1234

    ; 弹出栈顶的值到 BX
    POP BX            ; 将栈顶的值弹出,并存入寄存器 BX 中

    ; 假设此时 ESP 递增回 0x100
    ; BX 的内容:0x1234

    ; 结束程序
    MOV EAX, 1        ; 系统调用号 (sys_exit)
    XOR EBX, EBX      ; 返回码 0
    INT 0x80          ; 调用内核

在这个示例中,我们将一个 16 位的数据压入栈中,然后再将其弹出到另一个寄存器中。这展示了如何使用 PUSHPOP 指令进行基本的栈操作。

总结

  • PUSH:将数据压入栈,栈指针递减。
  • POP:从栈中弹出数据,栈指针递增。

这两条指令在函数调用、局部变量存储和中断处理等场景中非常常用。

温馨提示:
本文最后更新于2024-09-06 23:35:01,本文具有时效性,若有错误或已失效,请在下方留言或联系站长
© 版权声明
THE END
喜欢就支持一下吧
点赞15 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容