xorl%eax,g86生成的x86_64汇编代码中的%eax

mri*_*rip 7 assembly gcc x86-64

我在集会上总是一个菜鸟,只是捅了一下看看发生了什么.无论如何,我写了一个非常简单的函数:

void multA(double *x,long size)
{
  long i;
  for(i=0; i<size; ++i){
    x[i] = 2.4*x[i];
  }
}
Run Code Online (Sandbox Code Playgroud)

我编译它:

gcc -S -m64 -O2 fun.c
Run Code Online (Sandbox Code Playgroud)

我得到了这个:

    .file   "fun.c"
    .text
    .p2align 4,,15
    .globl  multA
    .type   multA, @function
multA:
.LFB34:
    .cfi_startproc
    testq   %rsi, %rsi
    jle .L1
    movsd   .LC0(%rip), %xmm1
    xorl    %eax, %eax
    .p2align 4,,10
    .p2align 3
.L3:
    movsd   (%rdi,%rax,8), %xmm0
    mulsd   %xmm1, %xmm0
    movsd   %xmm0, (%rdi,%rax,8)
    addq    $1, %rax
    cmpq    %rsi, %rax
    jne .L3
.L1:
    rep
    ret
    .cfi_endproc
.LFE34:
    .size   multA, .-multA
    .section    .rodata.cst8,"aM",@progbits,8
    .align 8
.LC0:
    .long   858993459
    .long   1073951539
    .ident  "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
    .section    .note.GNU-stack,"",@progbits
Run Code Online (Sandbox Code Playgroud)

装配输出对我(大多数)有意义,除了线xorl %eax, %eax.从谷歌搜索,我收集到这个的目的只是设置%eax为零,在这种情况下对应于我的迭代器long i;.

但是,除非我弄错了,否则%eax是32位寄存器.所以在我看来这实际上应该是xorq %rax, %rax,特别是因为它持有一个64位长的int.此外,在代码中,它实际上使用64位寄存器%rax进行迭代,从而不会在外部进行初始化xorl %eax %eax,这似乎只是将寄存器的低32位清零.

我错过了什么吗?

另外,出于好奇,为什么.long底部有两个常数?第一个,858993459等于双浮点表示,2.4但我无法弄清楚第二个数字是什么或它为什么存在.

小智 9

我认为这样做的目的只是将%eax设置为零

是.

在这种情况下,它对应于我的迭代器long i;.

不,你i在声明中没有初始化.严格地说,该操作对应i = 0于for循环中的表达式.

但是,除非我弄错了,%eax是一个32位寄存器.所以在我看来,这实际上应该是xorq%rax,%rax,特别是因为它持有一个64位长的int.

但清零寄存器的低位双字会清除整个寄存器.这不直观,但它含蓄.

  • @ us2012英特尔完全忽略了"字大小"的通常定义.一个字总是16位.32 = dword,64 = qword. (2认同)
  • @ us2012我不是一个伟大的硬件黑客,所以你可能实际上是对的,但在我的阅读中(除了挑剔的C术语,我并不总是适用于一般情况),字节= 1字节或8位,字= 2字节或16位,双字= 4字节或32位,四字= 8字节或64位. (2认同)