10

我在组装方面完全是个菜鸟,只是四处逛逛看看发生了什么。无论如何,我写了一个非常简单的函数:

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

我编译它:

gcc -S -m64 -O2 fun.c

我明白了:

    .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

除了 line 之外,程序集输出对我来说(主要)是有意义的xorl %eax, %eax。通过谷歌搜索,我了解到这样做的目的只是设置%eax为零,在这种情况下对应于我的 iterator long i;

但是,除非我记错了,%eax是一个 32 位的寄存器。所以在我看来,这实际上应该是xorq %rax, %rax,特别是因为它持有一个 64 位长整数。此外,在代码的更下方,它实际上使用 64 位寄存器%rax进行迭代,它永远不会在 之外初始化xorl %eax %eax,这似乎只会将寄存器的低 32 位归零。

我错过了什么吗?

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

4

2 回答 2

9

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

是的。

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

不,您i在声明中未初始化。严格来说,该操作对应i = 0于 for 循环中的表达式。

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

但是清除寄存器的低位双字会清除整个寄存器。这不是直观的,但它是隐含的。

于 2013-09-29T19:16:31.203 回答
2

只是回答第二部分:.long表示 32 位,两个并排的整数常量形成双 2.4 的 IEEE-754 表示:

Dec: 1073951539  858993459
Hex: 0x40033333 0x33333333

     400 3333333333333
     S+E Mantissa

指数偏移了 1023,因此实际指数为 0x400 − 1023 = 1。尾数中的前导“一”是隐含的,因此它是 2 1  × 0b1.001100110011...(您将这种周期性扩展识别为 3/15 ,即0.2。果然,2×1.2 = 2.4。)

于 2013-09-29T19:27:20.087 回答