【问题标题】:Assembly code generalization汇编代码泛化
【发布时间】:2017-07-26 16:10:40
【问题描述】:

我在计算机体系结构课上遇到​​了如下代码:

void mystery( long A[], long B[], long n )
{
  long i;
  for ( i = 0; i < n; i++ ) {
    B[i] = A[n-(i+1)];
  }
}

我的教授展示了 GCC 在 Ubuntu 机器上生成的相应汇编代码,他似乎也很困惑:

mystery:
    pushq   %rbp
    movq    %rsp, %rbp
    movq    %rdi, -24(%rbp)
    movq    %rsi, -32(%rbp)
    movq    %rdx, -40(%rbp)
    movq    $0, -8(%rbp)
    jmp .L2
.L3:
    movq    -8(%rbp), %rax
    leaq    0(,%rax,8), %rdx
    movq    -32(%rbp), %rax
    addq    %rax, %rdx
    movq    -8(%rbp), %rax
    notq    %rax
    movq    %rax, %rcx
    movq    -40(%rbp), %rax
    addq    %rcx, %rax
    leaq    0(,%rax,8), %rcx
    movq    -24(%rbp), %rax
    addq    %rcx, %rax
    movq    (%rax), %rax
    movq    %rax, (%rdx)
    addq    $1, -8(%rbp)
.L2:
    movq    -8(%rbp), %rax
    cmpq    -40(%rbp), %rax
    jl  .L3
    popq    %rbp
    ret

但我不明白为什么编译器会生成这段代码。看起来 A、B 和 n 被压入堆栈,但堆栈指针 %rsp 并没有改变它的值。此外, -16(%rbp) 似乎也已分配,但从未放入值中。 GCC 有什么理由会这样吗?

【问题讨论】:

  • 它使用的是红色区域,无需分配即可使用。至于具体的布局,谁知道呢。 PS:还要注意这是未优化的代码,通常可能会做一些愚蠢的事情。尝试使用-O2,这样你会得到更合理的输出。
  • gcc -O2: godbolt.org/g/pS3tu8 的输出更加合理/可读
  • A, B, n, i 存储在本地堆栈内存中并不断被读取/更新,因为这是调试版本,因此调试器可以使用堆栈帧来显示每个变量中具有适当值的“监视”窗口。优化的程序集不会这样做,调试器中的“监视”窗口可能无法跟踪变量中的当前值。关于布局而不是使用 -16 ......好吧,生成漂亮的最小堆栈框架布局不是编译器的任务。有效+工作是它的唯一目标。一个疯狂的猜测(90% 无效):n-(i+1) 的临时确实触发了预订,没有在代码中实现。
  • 好吧,也许我猜对了。如果你引入本地临时的long z = n-(i+1);B[i] = A[z];,它将进入-16(%rbp),其他的保持原样。

标签: c gcc assembly optimization x86


【解决方案1】:

Compiler Explorer (godbolt.org) 是一个很棒的工具,可以查看从各种编译器和不同标志生成的程序集。以下是 g++7 -O2 为您的代码生成的内容:

mystery(long*, long*, long):
        test    rdx, rdx
        jle     .L1
        lea     rax, [rdi-8+rdx*8]
        sub     rdi, 8
.L3:
        mov     rdx, QWORD PTR [rax]
        sub     rax, 8
        add     rsi, 8
        mov     QWORD PTR [rsi-8], rdx
        cmp     rax, rdi
        jne     .L3
.L1:
        rep ret

回答您的问题:在禁用优化的情况下进行编译通常是意外/不太明智的输出。 “为什么?” 是一个很难回答的问题,因为这在很大程度上取决于编译器的实现方式。

这是一个屏幕截图,显示了-O2-O0-Ofast 的比较:

在这里试试:https://godbolt.org/g/pQ637a

【讨论】:

  • 实际上没有优化,生成的代码非常清晰,因为它主要由构建原始语言的模式组成。对于非平凡的程序,优化的代码不太明显。并且不要发布文字截图。
  • @Olaf:正如 OP 的问题所示,-O0 生成的代码不是很清楚 - 在这种情况下,-O2 生成的代码更接近原始代码。此外,我将发布并鼓励在适当的情况下发布屏幕截图 - 在这种情况下,列的颜色和对齐方式优于文本。
猜你喜欢
  • 2013-07-24
  • 1970-01-01
  • 1970-01-01
  • 2016-12-25
  • 2013-01-22
  • 1970-01-01
  • 2015-04-26
  • 2018-05-07
  • 2012-01-15
相关资源
最近更新 更多