push 和 pop 如何在装配中工作

Posted

技术标签:

【中文标题】push 和 pop 如何在装配中工作【英文标题】:how does push and pop work in assembly 【发布时间】:2014-11-19 11:51:35 【问题描述】:

我对@9​​87654323@ 在汇编中的实际作用感到困惑。 pop 是否将值 PUSHed 最后移动到堆栈上(这意味着如果我们 MOV 在最后一个元素 PUSHed 之后的值不适用)还是只是弹出最后一个值堆栈(因此,适用于MOVPUSH),还是弹出堆栈指针指向的值?考虑以下代码:

push $4
mov $5, -4(%esp)
add $4, %esp (esp pointing to an unknown value)
pop %ebp

那么在这段代码中,ebp 中弹出的值是 4、5,还是esp 指向的未知值?

【问题讨论】:

Assembler: Push / pop registers?的可能重复 相关:What is an assembly-level representation of pushl/popl %esp? - 与 push %esppush 其他任何东西的真实行为相匹配的 asm 等效项。英特尔的伪代码没有反映在这种情况下会发生什么,只有文本描述部分涵盖了它。 【参考方案1】:

后者

POP EBP

等价于

MOV EBP, [ESP]
ADD ESP, 4           ; but without modifying flags, like  LEA ESP, [ESP+4]

(在 Intel 语法中 - 左侧为目标,右侧为源)

【讨论】:

所以 pop 实际上并没有从堆栈中删除值,只是移动它? 这是正确的,但是 ESP 的增量有效地隐藏了它以防止进一步访问。理论上,中断可能会在之后立即发生并重用堆栈的该区域进行存储,但我实际上并不相信中断会再使用环 3 堆栈。 在用户空间中,信号处理程序可以异步破坏堆栈。在没有安装信号处理程序的 Linux 中,我认为您可以指望esp 以下的空间不会被异步破坏,但 ABI 仍然不能保证。 (在 x86-64 System V 中,RSP 下面有一个 128B 的红色区域,保证不会被破坏,即使是信号处理程序。但 Windows 没有。) 不,在任何主流操作系统中,中断都不使用用户空间堆栈。那是不安全的:另一个线程可以在内核使用它时修改该内存,并提升它的权限。当然,在内核代码中,堆栈确实可以被异步破坏(如果它不切换到与每个线程内核堆栈分开的中断堆栈;不确定。x86-64 Linux 内核代码不使用红色-不过,我认为是出于这个原因。)【参考方案2】:

PUSH <src> 会:

 ESP := ESP-4  ; for x86; -8 for x64
 MEMORY[ESP]:=<operandvalue>

POP &lt;dst&gt; 会:

 <operandtarget>:=MEMORY[ESP];
 ESP:=ESP+4    ; for x86; +8 for x64

如果您将机器指令的描述写成这样的伪代码,则更容易理解机器指令的作用。英特尔参考手册中充满了这样的伪代码, 值得您花时间和精力去获取它们,并自己阅读详细信息。 (例如,在 html 提取中 https://www.felixcloutier.com/x86/push 和 https://www.felixcloutier.com/x86/pop)

关于您的具体问题:您将$5 存储到-4(%esp) 是有效的机器指令,处理器将毫无怨言地执行它,但这确实是非常不安全的编程。如果处理器在该指令之后发生陷阱或中断,则处理器状态(通常)保存在“堆栈顶部”,并将覆盖您的值。由于中断是异步发生的,您将看到的行为是很少会丢失 5 美元。这使得程序调试起来非常困难。

“add $4”将 ESP 移回推送指令之前的位置。因此,您不能对弹出到 ebp 中的值说任何话,除非它是“未知”,正如您建议的选项之一。

请参阅Raymond Chen's blog,了解为什么在 ESP 下编写即使在 Windows 下的用户空间中也是不安全的。 (中断不会异步使用用户空间堆栈,但有些东西可以。)在非 Windows 上,POSIX 信号处理程序可以踩到用户空间 ESP 下方的空间。 (x86-64 System V 除外,其中 ABI 定义了一个低于 RSP 的 128 字节的“红色区域”,可以安全使用。)

【讨论】:

以上是关于push 和 pop 如何在装配中工作的主要内容,如果未能解决你的问题,请参考以下文章

如何使 Tools->Git->Push 在 Qt Creator 中工作

身份验证令牌和授权如何在 reactjs 中工作?

ViewChild 如何在 Angular 和 Storybook 中工作?

会话如何在 Laravel 5 中工作

复合索引如何在 mongodb 中工作?

复数如何在 Sequelize 中工作?