_ZN4leftC2Ev:
.LFB6:
.cfi_startproc ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pushq %rbp ; LFB6 Associated with the adress for the class left constructor
.cfi_def_cfa_offset 16 ;
.cfi_offset 6, -16 ; %rdi, -8(%rbp) - his doesn't initialize anything - it is just pushing this value on local stack, in optimized version it will probably dissapear.
movq %rsp, %rbp ; %rsi, -16(%rbp) - just as above;
.cfi_def_cfa_register 6 ; %rsi - pointer to virtual table table (not a mistake it's vtt, not vt) for left-in-bottom
movq %rdi, -8(%rbp) ; %rdi - pointer to left instance
movq %rsi, -16(%rbp) ;
movq -16(%rbp), %rax ; What does the rest of this do?
movq (%rax), %rdx ; It is just copying vtable address form vtt to first eight bytes of actual object.
movq -8(%rbp), %rax
movq %rdx, (%rax)
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
This is an unoptimized code so compiler does lots of unnecessary stuff like putting values from registers to memory and then back again into registers, but if you follow values around, you will notice there isn't really that much happening. Code gets pointer to storage for object and pointer to vtt entry, it is just deferencing vtt entry and putting found vtable pointer to first 8 bytes of object storage. Vtt being used is actually just a temporary one, used for sub-object construction, as the final one is added by bottom
constructor:
movl $_ZTV6bottom+24, %edx
movq -8(%rbp), %rax
movq %rdx, (%rax)
movl $_ZTV6bottom+48, %edx
movq -8(%rbp), %rax
movq %rdx, 16(%rax)
As for main
:
main:
.LFB0:
.cfi_startproc ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pushq %rbp ; Store off the base pointer
.cfi_def_cfa_offset 16 ; Debug code to trace where stack pointer is?
.cfi_offset 6, -16 ;
movq %rsp, %rbp ; Move where stack pointer is to base pointer
.cfi_def_cfa_register 6 ;
pushq %rbx ; Store off what might have been in rbx
subq $24, %rsp ; Push argc onto stack
.cfi_offset 3, -24 ;
movl $40, %edi ; Push argv onto stack
call _Znwm ; Call new
movq %rax, %rbx ; Create room for b %rax contains address of memory
movq $0, (%rbx) ; location where new returned?
movq $0, 8(%rbx) ; A: Yes - eax contains address of returned buffer
movq $0, 16(%rbx) ; It is being zeroed to 5*8 = 48 bytes
movq $0, 24(%rbx) ;
movq $0, 32(%rbx) ;
movq %rbx, %rdi ; Move that data into dynamic memory? -hmmm, what? Just moving pointr to it into rdi, where bottom constructor expects it
; it is still where it was - in dynamic memory from new (_Znwm), jut it's pointer changed register ;)
call _ZN6bottomC1Ev ; Call the construtor of the object
movq %rbx, -32(%rbp) ;
movq -32(%rbp), %rax ; Here isn't happening much - classes bottom and left are sure to start at the same address, so compiler doesn't need to chack for anything,
movl $5, 8(%rax) ; just use offset to addres fields, and copy the pointer without modification to do the castting from bottom to left.
movq -32(%rbp), %rax ;
movq %rax, -24(%rbp)
movq -24(%rbp), %rax
movl 8(%rax), %eax
movl %eax, %esi
movl $.LC0, %edi
movl $0, %eax
call printf
movl $0, %eax
addq $24, %rsp
popq %rbx
popq %rbp
.cfi_def_cfa 7, 8
ret
As for linked article, I am unsure what part do you mean. Of what exactly you are unsure? Your code actually doesn't do anything with fields in your classes, and they don't appear in assembly - code is just handling vmt pointers around. What exactly is what you do not understand?
One thing worth noticing is that even though virtual-offsets for sub-class instance are in the vtable, everywhere where object's full type is known those values can be simply hardcoded; same goes for virtual method call and anything that touches vtable for that matter. I am surprised though that unoptimized version still uses hardcoded values.