从汇编看C++类的实现(2)
本文主要从汇编的角度,看C++的类是如何实现的。
1.假设有如下Cpp文件
点击查看代码
//file:fraction.h
class fraction {
public:
fraction();
int public_int;
int getprivate();
void setpub();
private:
int private_int;
};
//file:fraction.cpp
#include "fraction.h"
fraction::fraction(){
private_int = 0;
public_int = 0;
}
void fraction::setpub(){
public_int = 1;
}
int fraction::getprivate(){
return private_int;
}
//file:main.cpp
#include "fraction.h"
fraction::fraction(){
private_int = 0;
public_int = 0;
}
void fraction::setpub(){
public_int = 1;
}
int fraction::getprivate(){
return private_int;
}
1.通过GCC命令生成汇编文件
gcc -o fraction.s -fverbose-asm -S -O0 -g fraction.cpp
gcc -o main.s -fverbose-asm -S -O0 -g main.cpp
点击查看代码
##file:main.s
main:
endbr64
pushq %rbp #
movq %rsp, %rbp #,
subq $32, %rsp #,
# main.cpp:2: int main() {
movq %fs:40, %rax # MEM[(<address-space-1> long unsigned int *)40B], tmp89
movq %rax, -8(%rbp) # tmp89, D.2357
xorl %eax, %eax # tmp89
# main.cpp:3: fraction a;
leaq -16(%rbp), %rax #, tmp85
movq %rax, %rdi # tmp85,
call _ZN8fractionC1Ev@PLT #
# main.cpp:4: a.setpub();
leaq -16(%rbp), %rax #, tmp86
movq %rax, %rdi # tmp86,
call _ZN8fraction6setpubEv@PLT #
# main.cpp:5: int b = a.getprivate();
leaq -16(%rbp), %rax #, tmp87
movq %rax, %rdi # tmp87,
call _ZN8fraction10getprivateEv@PLT #
movl %eax, -20(%rbp) # _6, b
# main.cpp:6: return 0;
movl $0, %eax #, _8
# main.cpp:7: }
movq -8(%rbp), %rdx # D.2357, tmp90
xorq %fs:40, %rdx # MEM[(<address-space-1> long unsigned int *)40B], tmp90
je .L3 #,
call __stack_chk_fail@PLT #
leave
ret
## file:fraction.s
_ZN8fractionC2Ev:
endbr64
pushq %rbp #
movq %rsp, %rbp #,
movq %rdi, -8(%rbp) # this, this
# fraction.cpp:3: private_int = 0;
movq -8(%rbp), %rax # this, tmp82
movl $0, 4(%rax) #, this_2(D)->private_int
# fraction.cpp:4: public_int = 0;
movq -8(%rbp), %rax # this, tmp83
movl $0, (%rax) #, this_2(D)->public_int
# fraction.cpp:5: }
nop
popq %rbp #
ret
_ZN8fraction6setpubEv:
endbr64
pushq %rbp #
movq %rsp, %rbp #,
movq %rdi, -8(%rbp) # this, this
# fraction.cpp:7: public_int = 1;
movq -8(%rbp), %rax # this, tmp82
movl $1, (%rax) #, this_2(D)->public_int
# fraction.cpp:8: }
nop
popq %rbp #
ret
_ZN8fraction10getprivateEv:
endbr64
pushq %rbp #
movq %rsp, %rbp #,
movq %rdi, -8(%rbp) # this, this
# fraction.cpp:10: return private_int;
movq -8(%rbp), %rax # this, tmp84
movl 4(%rax), %eax # this_2(D)->private_int, _3
# fraction.cpp:11: }
popq %rbp #
ret
1.1.从生成的汇编代码,CPP的constructr函数只是把对象的指针传入其中,并且调用了constrctor函数而已。如下所示
fraction a;
leaq -16(%rbp), %rax #, tmp85
movq %rax, %rdi # tmp85,
call _ZN8fractionC1Ev@PLT #
1.2.从生成的汇编代码,一般的Cpp类的函数调用只是,把对象的指针作为第一个参数传入其中,并且调用对应的cpp函数而已。如下所示
main.cpp:4: a.setpub();
leaq -16(%rbp), %rax #, tmp86
movq %rax, %rdi # tmp86,
call _ZN8fraction6setpubEv@PLT #
main.cpp:5: int b = a.getprivate();
leaq -16(%rbp), %rax #, tmp87
movq %rax, %rdi # tmp87,
call _ZN8fraction10getprivateEv@PLT #
movl %eax, -20(%rbp) # _6, b
Summary
CPP的类的函数调用本质上只是普通的C语言的方法调用,唯一的区别就是每一个函数的第一个参数会传入对象的所在地址的。 并且CPP类的函数的命名在汇编的层面上有自己的规则(比如_ZN8fractionC1Ev@PLT这个函数是类的constrctor的)。
Reference
[1] https://bob.cs.sonoma.edu/IntroCompOrg-x64/bookch13.html#x34-15600013