arrays - 为什么汇编代码在加总和之前将值从 %edx 复制到 %rcx?

标签 arrays c assembly gcc x86-64

使用 x86-64 gcc -Og -std=gnu99 -xc 编译。

.L3的第二行(addl(%rdi,%rcx,4),%eax),为什么不直接使用寄存器% edx 加到和的时候?

添加 (%rdi,%edx,4), %eax

int sum_arr(int arr[], int nelems) {
  int sum = 0;
  for (int i = 0; i < nelems; i++) {
    sum += arr[i];
  }
  return sum;
}

sum_arr:
        movl    $0, %edx
        movl    $0, %eax
        jmp     .L2
.L3:
        movslq  %edx, %rcx
        addl    (%rdi,%rcx,4), %eax
        addl    $1, %edx
.L2:
        cmpl    %esi, %edx
        jl      .L3
        rep ret

最佳答案

正如 4386427 之前的回答所指出的,您不能在一个有效地址中混用 32 位和 64 位寄存器。 CPU 不支持。所以 addl (%rdi,%edx,4), %eax 将不可编码。

要将i 用作有效地址的索引部分,我们需要在64 位寄存器中使用它。由于 i 是带符号的 int 类型,因此编译器使用 movsx 对其进行符号扩展。并且它使用一个单独的寄存器%rcx,这样%edx可以继续保存变量i的值,让调试器更容易检查此值(例如,gdb 中的 print i)。

事实证明,我们可以证明 i 在这个函数中总是非负的。初始 movl $0, %edx also zeros out the high half of %rdx , 从那时起它将保持为零,所以实际上 %rdx 总是包含变量 i 的正确 64 位值。因此我们可以使用 addl (%rdi, %rdx, 4), %eax 代替,并省略 movsx。不过,编译器可能没有在这种优化级别上进行推论。

(也可以使用地址大小覆盖前缀的有效地址中的所有 32 位寄存器,因此 addl (%edi, %edx, 4), %eax 是一个可编码的指令,但它不会工作,因为它会截断 %rdi 中指针 arr 的高 32 位。因此,地址大小覆盖在64 位代码。)

关于arrays - 为什么汇编代码在加总和之前将值从 %edx 复制到 %rcx?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68609600/

相关文章:

python - 根据给定的excel表设置数组

javascript - 替换数组中缺失/未定义值的最佳方法?

c - if 语句中的结构变量

c - 如何获取我的代码的结束地址

c - VirtualBox 无法加载 .img 或 .flp 文件

c++ - 使用 char 数组反转字符串 C++

javascript - JSON.stringify(object) 不正确

c - C 中的 HTTP 堆栈

c++ - XGCC stdarg.h 没有这样的文件或目录

assembly - x86堆栈指针指向哪里?