我正在学习类中的x86程序集,我很遗憾你如何区分寄存器操作数和内存引用的作用。我有几个想要澄清的混乱。
以下代码是我的教科书所说的分别是推送和弹出的漫长道路:
subl $4, %esp
movl %ebp, (%esp)
movl (%esp), %eax
addl $4, %esp
那么在subl指令中,我们是否总能指望%esp保存地址值?
两个movl函数之间有什么区别?可以将第一个写成
movl (%ebp), %esp
?对于第二个movl,是移动%esp的地址还是移动%esp指向的值?
作为后续行动,为什么我们不能让源和目标成为这样的内存引用?
movw (%eax), 4(%esp)
最后,对于以下代码:
movb (%esp, %edx, 4), %dh
如果源超过1个字节(%dh的大小),那么会发生什么?它只是截断了这个值吗?
对不起,这是一个很多问题,但任何帮助将不胜感激。
答案 0 :(得分:2)
以下代码是我的教科书所说的推进的漫长道路 并分别弹出:
subl $4, %esp movl %ebp, (%esp) movl (%esp), %eax addl $4, %esp
所以在subl指令中,我们是否总能指望%esp持有 地址值?
是。 ESP
寄存器保存推入堆栈的最后一个值的内存地址。
两个movl函数之间有什么区别?可以 第一个写成
movl (%ebp), %esp
?而对于第二个movl,是否会移动%esp或者地址 它移动%esp?
指向的值
MOV
语法中的AT&T
指令需要两个操作数:source和destination。 MOV
将数据(在本例中为32位,由L
后缀表示)从左侧写入的第一个操作数复制到第二个操作数(右侧写入)。如果其中一个括在括号中,则表示操作数是内存操作数,括号中的值是其内存地址,而不是实际值)
因此,movl %ebp,(%esp)
表示:将寄存器EBP
的值复制到内存中,位于寄存器ESP
的值指向的地址。
您对movl (%ebp),%esp
的意思是:将从EBP
的值指向的内存地址开始的32位数据复制到ESP
寄存器中。
所以你正在改变运动的方向。
作为后续行动,为什么我们不能拥有源和目的地 内存参考如此?
movw (%eax), 4(%esp)
简短回答:因为英特尔使用的编码不允许这样做。答案很长:英特尔设计ISA的方式,可用资源来计算好旧8086中的两个有效地址等等。
最后,对于以下代码:
movb (%esp, %edx, 4), %dh
如果源超过1个字节(%dh的大小),那么什么 发生?它只是截断了值吗?
源与目标的大小相同。这是由B
后缀和目标是8位寄存器的事实强加的。括号中的值则是单个存储器字节的地址。顺便说一下,这个地址是ESP+EDX*4
答案 1 :(得分:1)
那么在subl指令中,我们是否总能指望%esp保存地址值?
根据定义是,因为下一条指令将其用作地址。无论垃圾是什么,现在都有一个地址。如果有一些像0xDEADBEEF这样的废话......那么现在这是一个地址。它可能是也可能不是有效地址(希望有效,无效堆栈有点不好),但这是另一回事。
两个movl函数之间有什么区别?
" push"中使用的那个写入内存,用于" pop"读取。右侧的括号表示它是一个写入,在左侧是它的读取。所以你可以切换它们吗?显然不是,它会做一些不同的事情。 movl (%ebp), %esp
将从内存中读取内容,然后更改堆栈的位置。
作为后续行动,我们为什么不能将源和目标作为内存引用呢?
因为你不能,所以没有这样的指示。它不适合正常的operand encoding。我想这样的指示可能已经存在,但它没有,所以你不能使用它。
movb (%esp, %edx, 4), %dh
如果源超过1个字节(%dh的大小),那么会发生什么?
根据定义,该指令不会读取1个字节。