【问题标题】:x86 mov / add Instructions & Memory Addressingx86 mov / add 指令和内存寻址
【发布时间】:2015-06-25 23:23:37
【问题描述】:

我正在课堂上学习 x86 汇编,我很不知道如何区分寄存器操作数和内存引用的作用。我有几个困惑,我希望能解决。

以下代码是我的教科书所说的分别进行 push 和 pop 的漫长方法:

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 的大小),那么会发生什么?它只是截断值吗?

抱歉,这是一大堆问题,但我们将不胜感激。

【问题讨论】:

    标签: memory assembly x86 att


    【解决方案1】:

    以下代码是我的教科书所说的很长的路要推 和pop分别:

    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 语法中需要两个操作数:源和目标。 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

    【讨论】:

    • 看看你对movl (%ebp),%esp的解释,我觉得不对
    • 谢谢!这是非常深入和有帮助的。我实际上正要问你对此的评论。它不会将 %ebp 指向的值复制到 %esp 上吗?
    • 啊!正确的!我把 EBP 和 ESP 弄得一团糟。固定!
    • @harold 如果你们有时间,介意再回答一个简单的问题吗?如果我有一个 int* x 存储在 ebp 并且我有 movl 8(%ebp), %edi movl 是否意味着我将 x 指向的 int 存储在 %edi 或只是 x 到 %edi?
    • @ChangLiu 如果您已将其存储在(%ebp) 中,则访问8(%ebp) 基本上与它无关,但即使那是x 实际存储的位置,那么仅读取x 也不会不要取消引用 x,你只会得到 x 本身。
    【解决方案2】:

    那么在 subl 指令中,我们可以一直期望 %esp 保存一个地址值吗?

    根据定义是的,因为下一条指令将其用作地址。无论里面有什么垃圾,现在都有一个地址。如果是 0xDEADBEEF 之类的废话 .. 那么现在就是一个地址。它可能是也可能不是有效地址(希望是有效的,无效的堆栈是一件坏事),但这是另一回事。

    另外两个movl函数有什么区别?

    “push”中使用的写入内存,“pop”中使用的读取。右边的括号表示它是一个写,在左边它是一个读。那你能把它们换掉吗?显然不是,它会做一些不同的事情。 movl (%ebp), %esp 会从内存中读取一些内容,然后更改堆栈的位置。

    那么作为后续,为什么我们不能像这样将源和目标设为内存引用?

    因为你不能,所以没有这样的指令。它不适合普通的operand encoding。我想这样的指令可能存在,但它不存在,所以你不能使用它。

    movb (%esp, %edx, 4), %dh 如果源大于 1 字节(%dh 的大小),那么会发生什么?

    根据定义,指令不会读取 1 个字节。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-11-01
      • 1970-01-01
      • 2015-10-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多