Though I am not sure if this is the exact answer, this is my understanding. (Also, my terminology for CPP is bad - ignore that if possible)
For C++, when any class is declared (i.e. no instant created yet), the functions are placed in the .text section of the binary being created. When an instant is created, Functions or Methods are not duplicated. That is, when the compiler is parsing the CPP file, it would replace the function calls for ptr->print()
with appropriate address defined in the .text section.
Thus, all the compiler would have done is replace appropriate address based on the type of ptr
for function print
. (Which also means some checking related public/private/inheritance etc)
I did the following for your code (named test12.cpp
):
EDIT: Adding some comments to ASM below ( I really am _not_ good at ASM, I can barely read it - just enough to understand some basic stuff) - best would be to read this Wikibook link, which I too have done :D
In case someone finds errors in the ASW, please do leave a comment - I would glad to fix them and learn more too.
$ g++ test.cpp -S
$ cat test.s
...
// Following snippet is part of main function call
movl $0, -8(%ebp) //this is for creating the NULL pointer ABC* ptr=NULL
//It sets first 8 bytes on stack to '0'
movl -8(%ebp), %eax //Load the ptr pointer into eax register
movl %eax, (%esp) //Push the ptr on stack for using in function being called below
//This is being done assuming that these elements would be used
//in the print() function being called
call _ZN3ABC5printE //Call to print function after pushing arguments (which are none) and
//accesss pointer (ptr) on stack.
...
vWhere ZN3ABC5printEv
represents the global definition of the function defined in class ABC
:
...
.LC0: //This declares a label named .LC0
.string "hello" // String "hello" which was passed in print()
.section .text._ZN3ABC5printEv,"axG",@progbits,_ZN3ABC5printEv,comdat
.align 2
.weak _ZN3ABC5printEv //Not sure, but something to do with name mangling
.type _ZN3ABC5printEv, @function
_ZN3ABC5printEv: //Label for function print() with mangled name
//following is the function definition for print() function
.LFB1401: //One more lavbel
pushl %ebp //Save the 'last' known working frame pointer
.LCFI9:
movl %esp, %ebp //Set frame (base pointer ebp) to current stack top (esp)
.LCFI10:
subl $8, %esp //Allocating 8 bytes space on stack
.LCFI11:
movl $.LC0, 4(%esp) //Pushing the string represented by label .LC0 in
//in first 4 bytes of stack
movl $_ZSt4cout, (%esp) //Something to do with "cout<<" statement
call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
movl $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, 4(%esp)
movl %eax, (%esp)
call _ZNSolsEPFRSoS_E //Probably call to some run time library for 'cout'
leave //end of print() function
ret //returning control back to main()
...
Thus, even ((ABC *)0)->print();
works perfectly well.