【发布时间】: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