assembly - 我们如何判断堆栈帧当前是空的?
问题描述
假设在一个循环中,我想根据一些比较条件从堆栈中弹出元素(该函数还将根据一些条件将一些元素推送到堆栈中)。如何避免弹出空堆栈?
如果在函数的开头,我做
push %rbp
movq %rsp, %rbp
在循环内部,我检查是否
cmpq %rbp, %rsp
je emptyStack
这是一个可能的解决方案吗?
解决方案
是的,如果您想将调用堆栈用作堆栈数据结构,则弹出直到堆栈指针回到起点是正常的。将地址视为未签名:如果要检查 RSP 是否低于 RBP,请使用cmp
/ jb
。或者只是cmp/jne
如果您确定 RSP 不能超过RBP。
如果您需要除数据结构之外的局部变量的任何堆栈空间,则需要除 之外的参考点rbp
,或者仅使用rbp
不完全传统的帧指针。例如,在将 RSP复制到 RBP之前,移动 RSP 为当地人腾出空间。无论如何,拥有一个帧指针是可选的。
在 RBP 上方保留一些仍然是堆栈数据结构的一部分的空间还可以简化极端情况的处理,而不会有踩到已保存的 RBP 值或返回地址的风险。无论出于何种原因,您都可以让它更高。
例如
func:
push %rbp
sub $32, %rsp
mov %rsp, %rbp
# Space from 0(%rbp) to 31(%rbp) can be used for locals separate from your stack data structure
...
lea 32(%rbp), %rsp # point RSP at the saved RBP value
pop %rbp
ret
请注意,寻址模式0(%rbp)
仍然需要 a disp8
,不像0(%rbx)
它可以只使用无位移 as (%rbx)
。因此,您可能会选择使用不同的寄存器(如 RBX)作为锚点。如果这是一个叶函数,甚至是一个调用破坏寄存器,比如 RDX 或 R8。(如果您不打算在任何寻址模式下使用它,那么选择一个需要 REX 前缀的模式并不重要;无论如何,在与 RSP 进行比较时,您将使用 64 位操作数大小。除非您想通过假设您的堆栈不跨越 4GB 边界并使用cmp %ecx, %esp
来节省 1 个字节的代码大小来进行优化。)
func:
lea -8(%rsp), %rsi # or just mov, depending what you want.
...
# once RSP is pointing back where it started
ret
推荐阅读
- ubuntu - 如何在 Bluemix Pipeline Test Stage 上安装浏览器?
- angular - Gmail Chrome 扩展程序中的 Angular 元素
- php - Codeigniter 中的简单 CRUD 操作?
- javascript - 您可以动态解构对象以使用柯里化吗?
- sql - 聚合函数导致 SQL 错误
- php - 使用 PHP 拉取广告照片
- c - 递归除法的迷宫不起作用 - C
- django - Django 信号 dispatch_uid
- excel - 在 vba 中创建数据透视表过滤器时出错
- ubuntu-14.04 - 使用 valgrind 运行时不会生成核心