AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / coding / 问题 / 78941247
Accepted
Sukram 22
Sukram 22
Asked: 2024-09-02 23:48:07 +0800 CST2024-09-02 23:48:07 +0800 CST 2024-09-02 23:48:07 +0800 CST

如果堆栈指针进入第二个嵌套函数,堆栈中的帧指针会发生什么情况?

  • 772

我正在尝试学习 x86。(IA-32 架构)今天我学习了 Stack。我认为我理解的是:

StackPointer (SP) 指向堆栈的“顶部”(最小地址)并存储在 ESP 寄存器中。帧指针 (FP) 可以访问参数和局部变量,因为它是“弹出地址”,因此即使 SP 在堆栈内进一步移动也是静态的。

int addSome(int arg1, int arg2);

int main(void){
  int answer = addSome(1,2);
}


int addSome(int arg1, int arg2){
  return arg1 + arg2;
}

堆栈看起来应该是这样的:

帧指针显示“弹出地址”的堆栈

如果有嵌套函数,FP 会发生什么情况?它不能上移,因为如果弹出子函数,将需要它的位置。

为了实现可视化,添加此函数,它将在 addSome() 内部调用:

int subSome(int arg3, int arg4);
int subSome(int arg3, int arg4){
  return arg3 - arg4;
}

FP 在此处如何处理?如何知道新的“弹出地址”以及新参数的位置? 堆栈中的帧指针显示第一个函数的“弹出地址”,第二个函数未知

我的猜测是 addSome 的堆栈大小将被保存在某个地方,以获取相对于 FP 的新“弹出地址”的位置:

帧指针与新“弹出地址”有相对差异的堆栈

但是堆栈大小必须保存在某个地方,如果有更多的嵌套函数,就必须有更多的地方来存储这些大小,我认为这是不可能的。

pointers
  • 1 1 个回答
  • 46 Views

1 个回答

  • Voted
  1. Best Answer
    Mike Nakis
    2024-09-03T00:46:41+08:002024-09-03T00:46:41+08:00

    首先,在 x86 中,我们用来寻址堆栈框架中的值的寄存器称为“基指针”,或ebp。我不知道你为什么这么叫它fp。

    其次,我们不需要讨论subSome(),因为我们已经有了第二个嵌套函数,因为我们有两个函数:main()和addSome()。

    x86 中函数的标准序言和结尾如下所示:

    push ebp       ; save caller's ebp
    mov ebp, esp   ; make ebp point to the frame of this function
    ...            ; main function body goes here
    pop ebp        ; restore caller's ebp
    ret            ; return to caller
    

    现实世界中,正常的物理堆栈(例如一叠卡片)从底部向上增长。当您向堆栈中添加一张卡片时,它会移到堆栈顶部。x86 并非如此;在 x86 中,堆栈从顶部向下增长。该push <32-bit-operand>指令将寄存器减esp4,然后将 32 位操作数存储到寄存器新值指向的内存地址esp。该pop <32-bit-operand>指令执行相反的操作。

    此外,返回值通常不保存在堆栈上。具体细节取决于实际的 ABI(应用程序二进制接口),但它通常在寄存器中返回eax。也许你指的是返回地址,它实际上是由指令推送到堆栈call并由指令从堆栈弹出的ret。

    因此,在内部addSome(),你的堆栈将如下所示:

    top-of-stack        `argc` parameter to `main()` pushed by the standard library
    top-of-stack - 4    `argv` parameter to `main()`  pushed by the standard library
    top-of-stack - 8    return address of standard library code that invoked `main()`
    top-of-stack - 12   ebp that was saved by `main()`
    top-of-stack - 16   arg1 parameter to `addSome()` (value: 1)
    top-of-stack - 20   arg2 parameter to `addSome()` (value: 2)
    top-of-stack - 24   return address back to `main()`
    top-of-stack - 28   ebp that was saved by `addSome()` <-- esp points here
    

    (请注意,top-of-stack通常不会是堆栈的真正顶部;在其他所有内容之上还会有一些内容,由调用您的标准库代码推送main()。但显示的部分是我们关心的部分。)

    • 2

相关问题

  • 结构和指针:请帮我理解这行代码

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    Vue 3:创建时出错“预期标识符但发现‘导入’”[重复]

    • 1 个回答
  • Marko Smith

    为什么这个简单而小的 Java 代码在所有 Graal JVM 上的运行速度都快 30 倍,但在任何 Oracle JVM 上却不行?

    • 1 个回答
  • Marko Smith

    具有指定基础类型但没有枚举器的“枚举类”的用途是什么?

    • 1 个回答
  • Marko Smith

    如何修复未手动导入的模块的 MODULE_NOT_FOUND 错误?

    • 6 个回答
  • Marko Smith

    `(表达式,左值) = 右值` 在 C 或 C++ 中是有效的赋值吗?为什么有些编译器会接受/拒绝它?

    • 3 个回答
  • Marko Smith

    何时应使用 std::inplace_vector 而不是 std::vector?

    • 3 个回答
  • Marko Smith

    在 C++ 中,一个不执行任何操作的空程序需要 204KB 的堆,但在 C 中则不需要

    • 1 个回答
  • Marko Smith

    PowerBI 目前与 BigQuery 不兼容:Simba 驱动程序与 Windows 更新有关

    • 2 个回答
  • Marko Smith

    AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String”

    • 1 个回答
  • Marko Smith

    我正在尝试仅使用海龟随机和数学模块来制作吃豆人游戏

    • 1 个回答
  • Martin Hope
    Aleksandr Dubinsky 为什么 InetAddress 上的 switch 模式匹配会失败,并出现“未涵盖所有可能的输入值”? 2024-12-23 06:56:21 +0800 CST
  • Martin Hope
    Phillip Borge 为什么这个简单而小的 Java 代码在所有 Graal JVM 上的运行速度都快 30 倍,但在任何 Oracle JVM 上却不行? 2024-12-12 20:46:46 +0800 CST
  • Martin Hope
    Oodini 具有指定基础类型但没有枚举器的“枚举类”的用途是什么? 2024-12-12 06:27:11 +0800 CST
  • Martin Hope
    sleeptightAnsiC `(表达式,左值) = 右值` 在 C 或 C++ 中是有效的赋值吗?为什么有些编译器会接受/拒绝它? 2024-11-09 07:18:53 +0800 CST
  • Martin Hope
    The Mad Gamer 何时应使用 std::inplace_vector 而不是 std::vector? 2024-10-29 23:01:00 +0800 CST
  • Martin Hope
    Chad Feller 在 5.2 版中,bash 条件语句中的 [[ .. ]] 中的分号现在是可选的吗? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench 为什么双破折号 (--) 会导致此 MariaDB 子句评估为 true? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng 为什么 `dict(id=1, **{'id': 2})` 有时会引发 `KeyError: 'id'` 而不是 TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String” 2024-03-20 03:12:31 +0800 CST
  • Martin Hope
    MarkB 为什么 GCC 生成有条件执行 SIMD 实现的代码? 2024-02-17 06:17:14 +0800 CST

热门标签

python javascript c++ c# java typescript sql reactjs html

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve