long call_proc() {
long x1 = 1;
int x2 = 2;
short x3 = 3;
char x4 = 4;
proc(x1, &x1, x2, &x2, x3, &x3, x4, &x4);
return (x1+x2)*(x3-x4);
}
本书提供了由GCC生成的汇编代码:
long call_proc()
call_proc:
; Set up arguments to proc
subq $32, %rsp ; Allocate 32-byte stack frame
movq $1, 24(%rsp) ; Store 1 in &x1
movl $2, 20(%rsp) ; Store 2 in &x2
movw $3, 18(%rsp) ; Store 3 in &x3
movb $4, 17(%rsp) ; Store 4 in &x4
leaq 17(%rsp), %rax ; Create &x4
movq %rax, 8(%rsp) ; Store &x4 as argument 8
movl $4, (%rsp) ; Store 4 as argument 7
leaq 18(%rsp), %r9 ; Pass &x3 as argument 6
movl $3, %r8d ; Pass 3 as argument 5
leaq 20(%rsp), %rcx ; Pass &x2 as argument 4
movl $2, %edx ; Pass 2 as argument 3
leaq 24(%rsp), %rsi ; Pass &x1 as argument 2
movl $1, %edi ; Pass 1 as argument 1
; Call proc
call proc
; Retrieve changes to memory
movslq 20(%rsp), %rdx ; Get x2 and convert to long
addq 24(%rsp), %rdx ; Compute x1+x2
movswl 18(%rsp), %eax ; Get x3 and convert to int
movsbl 17(%rsp), %ecx ; Get x4 and convert to int
subl %ecx, %eax ; Compute x3-x4
cltq ; Convert to long
imulq %rdx, %rax ; Compute (x1+x2) * (x3-x4)
addq $32, %rsp ; Deallocate stack frame
ret ; Return
我能理解这段代码:编译器在栈上分配了32字节的空间,其中前16字节保存传递给proc
的参数,最后16字节保存4个本地变量。
然后我在GCC 11.2上使用优化标志-Og
测试了此代码,并得到了以下汇编代码:
call_proc():
subq $24, %rsp
movq $1, 8(%rsp)
movl $2, 4(%rsp)
movw $3, 2(%rsp)
movb $4, 1(%rsp)
leaq 1(%rsp), %rax
pushq %rax
pushq $4
leaq 18(%rsp), %r9
movl $3, %r8d
leaq 20(%rsp), %rcx
movl $2, %edx
leaq 24(%rsp), %rsi
movl $1, %edi
call proc(long, long*, int, int*, short, short*, char, char*)
movslq 20(%rsp), %rax
addq 24(%rsp), %rax
movswl 18(%rsp), %edx
movsbl 17(%rsp), %ecx
subl %ecx, %edx
movslq %edx, %rdx
imulq %rdx, %rax
addq $40, %rsp
ret
我注意到gcc先为4个本地变量分配了24字节。然后它使用pushq
将2个参数添加到堆栈中,因此最终的代码使用addq $40, %rsp
来释放堆栈空间。
与书中的代码相比,GCC在这里多分配了8个字节的空间,而且它似乎没有使用额外的空间。为什么它需要额外的空间呢?
pushq %rbx; ...; addq $32, %rsp; pop %rbx
。 - Antti Haapala -- Слава Україніcall
之前没有保持16字节的堆栈对齐。为什么x86-64 / AMD64 System V ABI要求16字节的堆栈对齐? 如果这是来自CS:APP全球版,那是因为出版商雇佣了一些无能的人编写了糟糕的练习题,其中包括虚假地声称他们的垃圾是实际的编译器输出,而它甚至无法汇编。书中其他部分仍然不错。 - Peter Cordes