汇编,栈上局部变量的算术运算

Posted

技术标签:

【中文标题】汇编,栈上局部变量的算术运算【英文标题】:Assembly, arithmetic operation on local variable on the stack 【发布时间】:2013-02-17 08:42:07 【问题描述】:

我最近一直在使用 Visual C++ 中的内联汇编,我想知道是否可以直接将值添加到堆栈上的局部变量,例如:

push 5
add [esp], 7

这样做可以吗?我在问,因为我随机遇到了一些奇怪的问题(尽管大多数时候它工作正常),但是如果我通过一个寄存器我从来没有任何问题,就像这样:

push 5
mov eax, [esp]
add eax, 7
mov [esp], eax

【问题讨论】:

您的“奇怪问题”的性质是什么?头发长在奇怪的地方?不合时宜的花开? 基本上在某些时候我没有得到我期望得到的值,就好像堆栈被损坏了一样。 可能编译器无法正确评估指针的大小。尝试使用:添加 DWORD PTR [esp], 7 您是否尝试过在 OllyDbg 之类的程序集调试器下运行它以检查它是否按照您的想法执行? 内置调试器可以显示反汇编和单步执行指令,无需OllyDbg。 【参考方案1】:

正如 Vlad Krasnov 在对该问题的评论中所说,问题来自编译器(和/或汇编器)不知道代码中参数的大小,例如 add [esp], 7。如果您写的是add [esp], eax,则不会出现此问题。

如果你是编译器,你会如何解释这条指令?您被要求将 7 添加到 ESP 指向的内存位置。但是 7 和 [esp] 都没有指定加法的参数有多大。一个字节?两个字节?四个字节?如果这不是内联汇编,甚至 8 个字节也是可能的(在 64 位代码中是不允许的。)

请注意,虽然 ESP 是 4 个字节,但它指向的内存位置可以是任意大小。立即数 7 也是如此,它可以容纳任意数量的字节。

Vlad Krasnov 在 cmets 中再次提到的解决方案是明确指定操作数的大小。你可以查看你最喜欢的汇编器的文档,但是在这种情况下,如果你想要 32 位加法,你可以写add DWORD PTR [esp], 7。这显然表示[esp] 指向内存中的一个 DWORD(对于 MASM,它是 32 位。)

另请注意,并非 x86 上的所有指令都支持其中包含立即值内存地址的形式。对于每条指令,您可以查看“英特尔架构软件开发人员手册”第 2 卷(这是指令集参考),以确保您尝试使用的指令确实存在!

而且,您应该始终检查编译器的汇编输出(因为您使用的是内联汇编),以确保编译器生成的代码实际上是您想要的。指示编译器生成汇编代码很容易,而且可读性很强!

【讨论】:

以上是关于汇编,栈上局部变量的算术运算的主要内容,如果未能解决你的问题,请参考以下文章

算术和关系运算符

汇编语言通用数据处理指令——算术运算类指令

汇编语言通用数据处理指令——算术运算类指令

汇编--算术运算类指令

运算或算术指令

使用 SSE(IA32 汇编)执行简单的算术运算