程序集:此程序中 movl data_items(,%edi,4), %eax 的目的是什么

标签 assembly x86 att addressing-mode array-indexing

此程序(来自 Jonathan Bartlett 的 Programming From the Ground Up )使用 .long 循环遍历存储在内存中的所有数字,并在程序完成时将最大的数字放入 EBX 寄存器以供查看。

.section .data
data_items:
    .long 3, 67, 34, 222, 45, 75, 54, 34, 44, 33, 22, 11, 66, 0

.section .text
.globl _start

_start:
    movl $0, %edi
    movl data_items (,%edi,4), %eax
    movl %eax, %ebx
start_loop:
    cmpl $0, %eax
    je loop_exit
    incl %edi
    movl data_items (,%edi,4), %eax
    cmpl %ebx, %eax
    jle start_loop
    movl %eax, %ebx
    jmp start_loop
loop_exit:
    movl $1, %eax
    int $0x80

我不确定此程序中 (,%edi,4) 的用途。我读到逗号是用来分隔的,4是为了提醒我们的计算机数据项中的每个数字都是4个字节长。既然我们已经用.long声明了每个数字都是4个字节,为什么还要在这里重新声明呢?另外,有人可以更详细地解释这两个逗号在这种情况下的作用吗?

最佳答案

在 AT&T 语法中,内存操作数有 the following syntax 1:

displacement(base_register, index_register, scale_factor)

The base, index and displacement components can be used in any combination, and every component can be omitted

但很明显,如果您省略了基址寄存器,则必须保留逗号,否则汇编程序将无法理解您遗漏了哪些组件。

所有这些数据都会结合起来计算您指定的地址,公式如下:

effective_address = displacement + base_register + index_register*scale_factor

(顺便说一下,这几乎正是您在 Intel 语法中指定的方式)。

因此,有了这些知识,我们就可以解码您的指令:

movl data_items (,%edi,4), %eax

匹配上面的语法,你会看到:

  • data_items为位移;
  • base_register被省略了,所以不带入上面的公式;
  • %ediindex_register
  • 4scale_factor

因此,您是在告诉 CPU 从 data_items+%edi*4 位置移动e l到寄存器 %eax.

*4 是必需的,因为数组的每个元素都是 4 字节宽,因此要将索引(在 %edi 中)转换为偏移量(以字节为单位) ) 从数组的开头开始,你必须将它乘以 4。

Since we've already declared that each number is 4 bytes with .long, why do we need to do it again here?

汇编程序是对类型一无所知的低级工具。

  • .long 不是数组声明,只是指令汇编程序发出与其参数的 32 位表示对应的字节;
  • data_items 不是一个数组,只是一个被解析到某个内存位置的符号,与其他标签完全一样;事实上,您在它之后放置了一个 .long 指令,这对汇编程序没有特别的意义。

注释

  1. 从技术上讲,还会有段说明符,但考虑到我们在 Linux 上讨论 32 位代码,我将完全省略段,因为它们只会增加困惑。

关于程序集:此程序中 movl data_items(,%edi,4), %eax 的目的是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48178969/

相关文章:

x86 - 在 x86 Intel VT-X 非根模式下,是否可以在每个指令边界传递中断?

assembly - 有没有一个网站或工具可以解析、分解和解释 x86 字节码

assembly - Linux内核0.01引导加载程序使用rep movw,而不是rep movsw?这实际上是重复普通的 MOV 吗?

GCC 生成的 asm::我在哪里分配给该寄存器?

c - gcc 在我的系统上生成什么汇编语言?

c++ - 从本地指针复制数据作为返回值

assembly - 帮助理解 RedCode

assembly - 为什么 x86 和 ARM 之间的 GNU 语法不同?

assembly - 如何更改 Commodore 64 中的内核 MONKEY 例程行为

assembly - Intel 8080 仿真器测试仪