C ++ & assembly, C Language
C ++ is an object-oriented High-level language, but it is developed based on C language, so its internal principle is exactly the same as that of C language, so let's take a look at what the C ++ program translates into assembly code (in the x86 linux environment, the Translation results are obtained using g ++ ), the new C ++ 11 standard is adopted, so we can take a look at the implementation of mov semantics in C ++ 11.
I. Translated original cpp file:
extern double sqrt(double x);extern double abs(double x);struct Position{public: Position(double px = 0 , double py = 0 , double pz = 0) : px(px) , py(py) , pz(pz){} double px , py , pz;};int distance(const Position &x , const Position &y){ return abs(sqrt((x.px * x.px + x.py * x.py + x.pz * x.pz)) - sqrt((y.px * y.px + y.py * y.py + y.pz * y.pz)));}class Gun {public: Gun(unsigned nbullet = 0) : nbullet(nbullet){} virtual bool shot(const Position &pfrom , const Position &pto); void set_bullet(unsigned n) { nbullet = n; } unsigned get_bullet()const { return nbullet; } virtual Gun* copy_self()const; virtual ~Gun(){}private: unsigned nbullet;};Gun* Gun::copy_self()const{ return new Gun(*this);}bool Gun::shot(const Position &pfrom , const Position &pto){ if(nbullet == 0) return false; else nbullet--; return true;}class HandGun : public Gun{public: HandGun(unsigned nbullet = 0 , double dist = 0) : Gun(nbullet) , dist(dist){} bool shot(const Position &px , const Position &py); HandGun* copy_self()const; void set_dist(double d) { dist = d; } double get_dist()const { return dist; }private: double dist;};HandGun* HandGun::copy_self()const{ return new HandGun(*this);}bool HandGun::shot(const Position &px , const Position &py){ if(!Gun::shot(px , py)) return false; return distance(px , py) < dist;}class Soldior{public: Soldior(const Position &pos , const Gun *g = nullptr) : pos(pos) { if(g == nullptr) gun = nullptr; else gun = g->copy_self(); } Soldior(const Soldior& s) { if(s.gun == nullptr) gun = nullptr; else gun = s.gun->copy_self(); pos = s.pos; } Soldior(Soldior &&s) noexcept { gun = s.gun; s.gun = nullptr; pos = s.pos; } bool shot(const Position &pt) { return gun->shot(pos , pt); } Soldior& operator=(const Soldior &s) { if(this == &s) return *this; if(gun != nullptr) delete gun; if(s.gun == nullptr) gun = nullptr; else gun = s.gun->copy_self(); pos = s.pos; return *this; } Soldior& operator=(Soldior &&s) { if(this == &s) return *this; if(gun != nullptr) delete gun; gun = s.gun; s.gun = nullptr; pos = s.pos; return *this; } ~Soldior() { if(gun != nullptr) delete gun; }private: Gun *gun; Position pos;}; extern Soldior getSoldior();int main(int argc , char *argv[]){ Gun *g = new Gun(100); Soldior *s = new Soldior(Position(20 , 30 , 50) , g); *s = getSoldior(); delete g; delete s;}
II. The translated asm Assembly file: (only useful parts of our understanding of C ++ are retained)
_ZN8PositionC2Eddd: ;constructor of Positionpushq%rbpmovq%rsp, %rbp ;save rbp movq%rdi, -8(%rbp) ;get this pointermovsd%xmm0, -16(%rbp) ;get pxmovsd%xmm1, -24(%rbp) ;get py movsd%xmm2, -32(%rbp) ;get pzmovq-8(%rbp), %rdx movq-16(%rbp), %raxmovq%rax, (%rdx) ;init px movq-8(%rbp), %rdxmovq-24(%rbp), %raxmovq%rax, 8(%rdx) ;init pymovq-8(%rbp), %rdxmovq-32(%rbp), %raxmovq%rax, 16(%rdx) ;init pzpopq%rbp ;recover rbpret_Z8distanceRK8PositionS1_: ;distancepushq%rbpmovq%rsp, %rbpsubq$32, %rsp ;extend stack movq%rdi, -8(%rbp) ;get address of xmovq%rsi, -16(%rbp) ;get address of ymovq-8(%rbp), %raxmovsd(%rax), %xmm1 ;get x.pxmovq-8(%rbp), %raxmovsd(%rax), %xmm0 ;get x.pxmulsd%xmm0, %xmm1 ;%xmm1 = x.px * x.pxmovq-8(%rbp), %raxmovsd8(%rax), %xmm2movq-8(%rbp), %raxmovsd8(%rax), %xmm0mulsd%xmm2, %xmm0 ;%xmm0 = x.py * x.pyaddsd%xmm0, %xmm1 ;%xmm1 += %xmm0movq-8(%rbp), %raxmovsd16(%rax), %xmm2movq-8(%rbp), %raxmovsd16(%rax), %xmm0mulsd%xmm2, %xmm0 ;%xmm0 = x.pz * x.pzaddsd%xmm1, %xmm0 ;%xmm0 += %xmm1call_Z4sqrtd ;call sqrt with argument %xmm0movsd%xmm0, -24(%rbp) ;save return value of sqrtmovq-16(%rbp), %rax ;mov address value of y into %raxmovsd(%rax), %xmm1movq-16(%rbp), %raxmovsd(%rax), %xmm0mulsd%xmm0, %xmm1 ;%xmm1 = y.px * y.pxmovq-16(%rbp), %raxmovsd8(%rax), %xmm2movq-16(%rbp), %raxmovsd8(%rax), %xmm0 mulsd%xmm2, %xmm0 ;%xmm0 = y.py * y.pyaddsd%xmm0, %xmm1 ;%xmm1 += %xmm0movq-16(%rbp), %raxmovsd16(%rax), %xmm2movq-16(%rbp), %raxmovsd16(%rax), %xmm0mulsd%xmm2, %xmm0 ;%xmm0 = y.pz * y.pzaddsd%xmm1, %xmm0 ;%xmm0 += %xmm1call_Z4sqrtd ;call sqrt with argument %xmm0movsd-24(%rbp), %xmm3 ;mov return value of first call to sqrt to %xmm3subsd%xmm0, %xmm3 ;%xmm3 -= %xmm0movapd%xmm3, %xmm0 ;save %xmm3 to %xmm0 for pass to call absd as argumentcall_Z3absd ;call absdcvttsd2si%xmm0, %eax ret_ZN3GunC2Ej: ;constructor of Gunpushq%rbpmovq%rsp, %rbpmovq%rdi, -8(%rbp) ;get this pointermovl%esi, -12(%rbp) ;get nbulletmovq-8(%rbp), %raxmovq$_ZTV3Gun+16, (%rax) ;pointer to virtual function table of class Gunmovq-8(%rbp), %raxmovl-12(%rbp), %edxmovl%edx, 8(%rax) ;init nbulletpopq%rbpret_ZN3GunD2Ev:pushq%rbpmovq%rsp, %rbpsubq$16, %rsp ;extend stack storagemovq%rdi, -8(%rbp) ;get this pointermovq-8(%rbp), %raxmovq$_ZTV3Gun+16, (%rax) ;get pointer to virtual function table of class Gunmovl$0, %eaxtestl%eax, %eaxje.L5movq-8(%rbp), %raxmovq%rax, %rdicall_ZdlPv.L5:leaveret_ZN3GunC2ERKS_: ;copy constructor of Gunpushq%rbpmovq%rsp, %rbpmovq%rdi, -8(%rbp) ;get this pointermovq%rsi, -16(%rbp) ;get address of argument gunmovq-8(%rbp), %rax movq$_ZTV3Gun+16, (%rax) ;set pointer to virtual table with class Gun's virtual table addressmovq-16(%rbp), %rax movl8(%rax), %edx ;%edx point to address of argument gun's nbulletmovq-8(%rbp), %raxmovl%edx, 8(%rax) ;init this->nbulletpopq%rbpret_ZNK3Gun9copy_selfEv: ;Gun::copy_selfpushq%rbpmovq%rsp, %rbppushq%rbxsubq$24, %rsp ;extend stackmovq%rdi, -24(%rbp) ;get this pointermovl$16, %edi ;mov size of Gun to %edicall_Znwm ;alloc memory on heapmovq%rax, %rbx ;this pointer to new gunmovq-24(%rbp), %raxmovq%rax, %rsi ;my own this pointermovq%rbx, %rdi ;this pointer to new guncall_ZN3GunC1ERKS_ ;call copy constructor of Gunmovq%rbx, %rax ;set return value as this pointer to new gunaddq$24, %rsp ;resave stackpopq%rbxpopq%rbpret_ZN3Gun4shotERK8PositionS2_: ;Gun::shotpushq%rbpmovq%rsp, %rbpmovq%rdi, -8(%rbp) ;this pointermovq%rsi, -16(%rbp) ;address of xmovq%rdx, -24(%rbp) ;address of ymovq-8(%rbp), %raxmovl8(%rax), %eax ;address of this->nbullettestl%eax, %eaxjne.L14 ;nbullet != 0movl$0, %eaxjmp.L13.L14:movq-8(%rbp), %raxmovl8(%rax), %eax ;address of this->nbulletleal-1(%rax), %edx movq-8(%rbp), %raxmovl%edx, 8(%rax).L13:popq%rbpret_ZN7HandGunC2Ejd: ;constructor of HandGunpushq%rbpmovq%rsp, %rbpsubq$32, %rspmovq%rdi, -8(%rbp)movl%esi, -12(%rbp)movsd%xmm0, -24(%rbp)movq-8(%rbp), %raxmovl-12(%rbp), %edxmovl%edx, %esi ;set nbulletmovq%rax, %rdi ;set this pointercall_ZN3GunC2Ej ;call constructor of Gunmovq-8(%rbp), %raxmovq$_ZTV7HandGun+16, (%rax) ;set virtual function pointermovq-8(%rbp), %rdxmovq-24(%rbp), %raxmovq%rax, 16(%rdx) ;init distleaveret_ZN7HandGunC2ERKS_: ;copy constructor of HandGunpushq%rbpmovq%rsp, %rbpsubq$16, %rspmovq%rdi, -8(%rbp)movq%rsi, -16(%rbp)movq-16(%rbp), %rdxmovq-8(%rbp), %raxmovq%rdx, %rsi ;set arg gun's this pointermovq%rax, %rdi ;set my own this pointercall_ZN3GunC2ERKS_ ;call Gun's copy constructormovq-8(%rbp), %raxmovq$_ZTV7HandGun+16, (%rax) ;set virtual function pointermovq-16(%rbp), %raxmovq16(%rax), %rax ;get arg gun's distmovq-8(%rbp), %rdxmovq%rax, 16(%rdx) ;init distleaveret_ZNK7HandGun9copy_selfEv: ;HandGun::copy_selfpushq%rbpmovq%rsp, %rbppushq%rbxsubq$24, %rspmovq%rdi, -24(%rbp) ;my own this pointermovl$24, %edicall_Znwmmovq%rax, %rbx ;get address of new gunmovq-24(%rbp), %raxmovq%rax, %rsi ;set arg gun's address (my own this pointer)movq%rbx, %rdi ;set this pointer (new gun's this pointer)call_ZN7HandGunC1ERKS_ ;call copy constructor of HandGunmovq%rbx, %rax ;set new this pointer as return valueaddq$24, %rsp ;resave stackpopq%rbxpopq%rbpret_ZN7HandGun4shotERK8PositionS2_: ;HandGun::shotpushq%rbpmovq%rsp, %rbpsubq$32, %rspmovq%rdi, -8(%rbp)movq%rsi, -16(%rbp)movq%rdx, -24(%rbp)movq-8(%rbp), %rax ;thismovq-24(%rbp), %rdx ;addr of xmovq-16(%rbp), %rcx ;addr of ymovq%rcx, %rsi ;set ymovq%rax, %rdi ;set thiscall_ZN3Gun4shotERK8PositionS2_ ;call Gun::shotxorl$1, %eax ;check return valuetestb%al, %alje.L21 ;truemovl$0, %eaxjmp.L22.L21:movq-24(%rbp), %rdxmovq-16(%rbp), %raxmovq%rdx, %rsi ;set xmovq%rax, %rdi ;set ycall_Z8distanceRK8PositionS1_ ;call distancecvtsi2sd%eax, %xmm0 movq-8(%rbp), %raxmovsd16(%rax), %xmm1 ucomisd%xmm0, %xmm1seta%al.L22:leaveret_ZN7SoldiorC2ERK8PositionPK3Gun: ;constructor of Soldiorpushq%rbpmovq%rsp, %rbpsubq$32, %rspmovq%rdi, -8(%rbp)movq%rsi, -16(%rbp)movq%rdx, -24(%rbp)movq-8(%rbp), %rax ;thismovq-16(%rbp), %rdx ;addr of posmovq(%rdx), %rcxmovq%rcx, 8(%rax) ;init pos.pxmovq8(%rdx), %rcxmovq%rcx, 16(%rax) ;init pos.pymovq16(%rdx), %rdxmovq%rdx, 24(%rax) ;init pos.pzcmpq$0, -24(%rbp) jne.L24 ;g != nullptrmovq-8(%rbp), %raxmovq$0, (%rax) ;init gun as nullptrjmp.L23.L24:movq-24(%rbp), %rax ;thismovq(%rax), %rax ;pointer to Gun's virtual functions tableaddq$8, %raxmovq(%rax), %rax ;second function pointer of g's virtual tablemovq-24(%rbp), %rdxmovq%rdx, %rdi ;set g as 'this' argumentcall*%rax ;call g->copy_selfmovq-8(%rbp), %rdxmovq%rax, (%rdx) ;gun = g.L23:leaveret_ZN7SoldioraSEOS_: ;mov assignmentpushq%rbpmovq%rsp, %rbpsubq$16, %rspmovq%rdi, -8(%rbp)movq%rsi, -16(%rbp)movq-8(%rbp), %raxcmpq-16(%rbp), %rax jne.L27 ;if(this != &s)movq-8(%rbp), %raxjmp.L28.L27:movq-8(%rbp), %rax movq(%rax), %raxtestq%rax, %raxje.L29 ;this->gun == nullptrmovq-8(%rbp), %raxmovq(%rax), %raxtestq%rax, %raxje.L29movq-8(%rbp), %raxmovq(%rax), %raxmovq(%rax), %raxaddq$24, %raxmovq(%rax), %raxmovq-8(%rbp), %rdxmovq(%rdx), %rdxmovq%rdx, %rdicall*%rax ;call gun's destructor.L29:movq-16(%rbp), %raxmovq(%rax), %rdxmovq-8(%rbp), %raxmovq%rdx, (%rax) ;gun = s->gunmovq-16(%rbp), %raxmovq$0, (%rax) ;s->gun = nullptrmovq-8(%rbp), %raxmovq-16(%rbp), %rdxmovq8(%rdx), %rcxmovq%rcx, 8(%rax) ;pos.px = s->pos.pxmovq16(%rdx), %rcxmovq%rcx, 16(%rax) ;pos.py = s->pos.pymovq24(%rdx), %rdxmovq%rdx, 24(%rax) ;pos.pz = s->pos.pz movq-8(%rbp), %rax ;return this.L28:leaveret_ZN7SoldiorD2Ev: ;destructor of Soldiorpushq%rbpmovq%rsp, %rbp subq$16, %rspmovq%rdi, -8(%rbp)movq-8(%rbp), %raxmovq(%rax), %rax ;%rax = guntestq%rax, %rax je.L30 ;gun == nullptrmovq-8(%rbp), %raxmovq(%rax), %raxtestq%rax, %rax je.L30 ;gun == nullptrmovq-8(%rbp), %raxmovq(%rax), %raxmovq(%rax), %rax ;gun->vptraddq$24, %rax ;third function pointer in gun's virtual tablemovq(%rax), %raxmovq-8(%rbp), %rdx movq(%rdx), %rdx ;get gunmovq%rdx, %rdi ;set gun as 'this' argumentcall*%rax ;call gun's destructor.L30:leaveretmain:pushq%rbpmovq%rsp, %rbppushq%r12pushq%rbxsubq$80, %rspmovl%edi, -68(%rbp)movq%rsi, -80(%rbp)movl$16, %edi ;set alloc size as Guncall_Znwm ;alloc memory on heapmovq%rax, %rbx ;%rbx is this pointer of new gunmovl$100, %esi ;set nbulletmovq%rbx, %rdi ;set 'this' argcall_ZN3GunC1Ej ;call constructor of Gunmovq%rbx, -64(%rbp) ;save %rbxmovabsq$4632233691727265792, %rcx ;constexpr accessed as static addressmovabsq$4629137466983448576, %rdxmovabsq$4626322717216342016, %raxleaq-48(%rbp), %rsimovq%rcx, -88(%rbp)movsd-88(%rbp), %xmm2 ;pxmovq%rdx, -88(%rbp)movsd-88(%rbp), %xmm1 ;pymovq%rax, -88(%rbp)movsd-88(%rbp), %xmm0 ;pzmovq%rsi, %rdi ;set 'this' argcall_ZN8PositionC1Eddd ;call constructor of Positionleaq-48(%rbp), %r12 movl$32, %edi ;set alloc size as Soldior's sizecall_Znwmmovq%rax, %rbx ;smovq-64(%rbp), %raxmovq%rax, %rdx ;set gmovq%r12, %rsi ;set posmovq%rbx, %rdi ;set 'this' argcall_ZN7SoldiorC1ERK8PositionPK3Gun ;call Soldior's constructormovq%rbx, -56(%rbp) ;save %rbxleaq-48(%rbp), %raxmovq%rax, %rdi ;set return addr of next functioncall_Z10getSoldiorv ;call getSoldiorleaq-48(%rbp), %rdx ;get return valmovq-56(%rbp), %rax ;get smovq%rdx, %rsi ;set 's' argmovq%rax, %rdi ;set 'this' argcall_ZN7SoldioraSEOS_ ;call mov assignment of Soldiorleaq-48(%rbp), %rax movq%rax, %rdicall_ZN7SoldiorD1Ev ;delete return val of getSoldiormovl$0, %eaxjmp.L38.L37:movq%rax, %r12movq%rbx, %rdicall_ZdlPvmovq%r12, %raxmovq%rax, %rdicall_Unwind_Resume.L38:addq$80, %rsppopq%rbxpopq%r12popq%rbpret_ZTV3Gun: ;Gun's virtual functions table.quad0.quad_ZTI3Gun ;some information of this table , we can ignore.quad_ZN3Gun4shotERK8PositionS2_ .quad_ZNK3Gun9copy_selfEv.quad_ZN3GunD1Ev.quad_ZN3GunD0Ev.weak_ZTI7HandGun.section.rodata._ZTI7HandGun,"aG",@progbits,_ZTI7HandGun,comdat.align 16.type_ZTI7HandGun, @object.size_ZTI7HandGun, 24_ZTV7HandGun: ;virtual function table of HandGun.quad0.quad_ZTI7HandGun.quad_ZN7HandGun4shotERK8PositionS2_.quad_ZNK7HandGun9copy_selfEv.quad_ZN7HandGunD1Ev.quad_ZN7HandGunD0Ev.section.text._ZN7HandGunD2Ev,"axG",@progbits,_ZN7HandGunD5Ev,comdat.align 2.weak_ZN7HandGunD2Ev.type_ZN7HandGunD2Ev, @function_ZN7HandGunD2Ev: ;destructor of HandGunpushq%rbpmovq%rsp, %rbpsubq$16, %rspmovq%rdi, -8(%rbp)movq-8(%rbp), %raxmovq$_ZTV7HandGun+16, (%rax) ;set vptrmovq-8(%rbp), %raxmovq%rax, %rdicall_ZN3GunD2Ev ;call Gun's destructormovl$0, %eaxtestl%eax, %eaxje.L39movq-8(%rbp), %raxmovq%rax, %rdicall_ZdlPv.L39:leaveret
Copyright Disclaimer: This article is an original article by the blogger and cannot be reproduced without the permission of the blogger.