汇编:此程序中movl data_items(,%edi,4),%eax的用途是什么

时间:2018-01-10 01:14:55

标签: assembly x86 comma

该程序(来自Jonathan Bartlett的Programming From the Ground Up)以.long循环存储在内存中的所有数字,并将最大数字放在EBX寄存器中,以便在程序完成时查看。 / p>

.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个字节,为什么我们需要在这里再做一次呢?此外,有人可以更详细地解释这两个逗号在这种情况下的用途是什么吗?

1 个答案:

答案 0 :(得分:2)

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

displacement(base_register, index_register, scale_factor)
  

基础,索引和位移组件可以任意组合使用,每个组件都可以省略

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

所有这些数据结合起来计算您指定的地址,使用以下公式:

effective_address = displacement + base_register + index_register*scale_factor

(顺便提一下,你几乎就是在英特尔语法中指定它的方式)。

因此,凭借这些知识,我们可以解读您的指示:

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

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

  • data_items是排量;
  • base_register被省略,因此不会被放入上面的公式中;
  • %ediindex_register;
  • 4scale_factor

所以,你要告诉CPU mov 一个 l ong从data_items+%edi*4到注册%eax

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

  

由于我们已经声明每个数字是.long的4个字节,为什么我们需要在这里再做一次呢?

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

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

<强> 备注

  1. 从技术上讲,也会有段说明符,但鉴于我们在Linux上讨论32位代码,我会完全省略段,因为它们只会增加混乱。