从汇编看C++函数传入对象以及返回对象
测试代码structpass.cpp
struct Vertex
{
int x, y, z;
};
Vertex getVertex(Vertex a)
{
a.x = 111;
a.z = 222;
return a;
}
int main() {
Vertex t;
t.x = 1;
t.y = 2;
t.z = 3;
Vertex y = getVertex(t);
y.x = 7;
y.y = 8;
y.z = 9;
t.x = 11;
t.y = 21;
t.z = 31;
return 0;
}
这段代码在gcc下生成汇编,g++ -o structpass.s -fverbose-asm -S -O0 -g structpass.cpp, 得到汇编代码如下。
汇编代码
_Z9getVertex6Vertex:
.LFB0:
.file 1 "structpass.cpp"
.loc 1 6 1
.cfi_startproc
endbr64
pushq %rbp #
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp #,
.cfi_def_cfa_register 6
movq %rdi, %rdx # a, tmp83
movl %esi, %eax # a, tmp84
movq %rdx, -32(%rbp) # tmp83, a
movl %eax, -24(%rbp) # tmp84, a
# structpass.cpp:7: a.x = 111;
.loc 1 7 6
movl $111, -32(%rbp) #, a.x
# structpass.cpp:8: a.z = 222;
.loc 1 8 6
movl $222, -24(%rbp) #, a.z
# structpass.cpp:9: return a;
.loc 1 9 16
movq -32(%rbp), %rax # a, tmp85
movq %rax, -12(%rbp) # tmp85, D.2351
movl -24(%rbp), %eax # a, tmp86
movl %eax, -4(%rbp) # tmp86, D.2351
movq -12(%rbp), %rax # D.2351, tmp87
movl -4(%rbp), %ecx # D.2351, tmp88
movq %rcx, %rdx # tmp88,
# structpass.cpp:10: }
.loc 1 10 1
popq %rbp #
.cfi_def_cfa 7, 8
ret
.cfi_endproc
main:
endbr64
pushq %rbp #
movq %rsp, %rbp #,
subq $32, %rsp #,
# structpass.cpp:11: int main() {
movq %fs:40, %rax # MEM[(<address-space-1> long unsigned int *)40B], tmp93
movq %rax, -8(%rbp) # tmp93, D.2358
xorl %eax, %eax # tmp93
# structpass.cpp:13: t.x = 1;
movl $1, -32(%rbp) #, t.x
# structpass.cpp:14: t.y = 2;
movl $2, -28(%rbp) #, t.y
# structpass.cpp:15: t.z = 3;
movl $3, -24(%rbp) #, t.z
# structpass.cpp:16: Vertex y = getVertex(t);
movq -32(%rbp), %rdx # t, tmp84
movl -24(%rbp), %eax # t, tmp85
movq %rdx, %rdi # tmp84,
movl %eax, %esi # tmp85,
call _Z9getVertex6Vertex #
movq %rax, -20(%rbp) # tmp86, y
movl -12(%rbp), %eax # y, tmp89
andl $0, %eax #, tmp90
orl %edx, %eax # tmp88, tmp91
movl %eax, -12(%rbp) # tmp91, y
# structpass.cpp:17: y.x = 7;
movl $7, -20(%rbp) #, y.x
# structpass.cpp:18: y.y = 8;
movl $8, -16(%rbp) #, y.y
# structpass.cpp:19: y.z = 9;
movl $9, -12(%rbp) #, y.z
# structpass.cpp:20: t.x = 11;
movl $11, -32(%rbp) #, t.x
# structpass.cpp:21: t.y = 21;
movl $21, -28(%rbp) #, t.y
# structpass.cpp:22: t.z = 31;
movl $31, -24(%rbp) #, t.z
# structpass.cpp:23: return 0;
movl $0, %eax #, _12
# structpass.cpp:24: }
movq -8(%rbp), %rcx # D.2358, tmp94
xorq %fs:40, %rcx # MEM[(<address-space-1> long unsigned int *)40B], tmp94
je .L5 #,
call __stack_chk_fail@PLT #
.L5:
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
movq %rdx, -32(%rbp) # tmp83, a
movl %eax, -24(%rbp) # tmp84, a
a.x = 111;
movl $111, -32(%rbp) #, a.x
a.z = 222;
movl $222, -24(%rbp) #, a.z
结论2. 返回的对象并不是结论一中copy的对象,而是重新在[rbp, rsp]分配另外的stack空间,一模一样的复制到这个空间中,再把这个stack的地址传到调用函数。
结论3.调用函数在自己的stack中,通过传回来的寄存器,rax or rdx之类的,一模一样的复制到stack空间中。
call _Z9getVertex6Vertex #
movq %rax, -20(%rbp) # tmp86, y
movl -12(%rbp), %eax # y, tmp89
andl $0, %eax #, tmp90
orl %edx, %eax # tmp88, tmp91
movl %eax, -12(%rbp) # tmp91, y