Upcoming Posts

Upcoming Posts....

Make your own partition magic software.
How to make an assembler.
What is booting?
Write a simple OS!

‎"I have no special talents. I am only passionately curious." - Albert Einstein

Tuesday, January 3, 2012

How does compiler achieve runtime binding/polymorphism?

Compiler determines address of every variables and methods while compiling source code not while executing the binary (it is applicable to virtual methods and dynamic link libs as well). Now the question is when address is determined at compile time, how run time binding works?

Here is the answer:

Whenever a method is called, compiler puts machine level code (‘call’ instruction in assembly level language) and supplies method’s address to call that method. Let’s take an simple example to understand this:

class test {
public:

void compile_time_binding_method()
{ printf("\nIn compile_time_binding_method() method"); }

virtual void run_time_binding_method()
{ printf("\nIn compile_time_binding_method() method"); }

};

Here, the ‘test’ class contain a virtual method ‘run_time_binding_method()’ and a non-virtual method ‘compile_time_binding_method()’.

Let’s create an object, its reference and a pointer to point to the created object:

test a; // Created a object of test class
test &refA = a; // Reference of object ‘a’
test *ptrA = &a; // Pointer of object ‘a’

Let’s call methods using object:

What do think calling a virtual method via its object will be a run time binding? If your answer is no, you are correct. When any method is called using its object, compiler is sure about the method to call. So dynamic binding/call is not at all required here even if a virtual method is being called. You can verify this by reviewing generated dis-assembly code.

a.compile_time_binding_method();
lea ecx,[a] // Dis-assembly code
call test::compile_time_binding_method (41118Bh)

a.run_time_binding_method();
lea ecx,[a] // Dis-assembly code
call test::run_time_binding_method (4110EBh)

In above generated dis-assembly code, we can see that the address of both the methods are hard coded (address determined by compiler while compiling the source code) to resolve the call. This hard coded address will never change (unless you modify and re-compile the source code) in the binary. Such binding/linking is known as static binding/linking (or compile time binding).

These calls are static calls because address is hard coded with machine code generated by compiler (same as ‘call ’ in assembly level language). Instead of using hard coded address, if compiler puts machine code for ‘call EAX’ where EAX register will hold the address of method to call. This way, the value of AX register can be changed any time and can call any method. I.e. Any method can be called at run-time by putting its address in AX register. This is how run-time binding is implemented. See the dis-assembly code generated for following call:

Let’s call methods using its pointer:

For non-virtual methods:

ptrA->compile_time_binding_method();
mov ecx,dword ptr [ptrA]
call test::compile_time_binding_method (41118Bh)

ptrA->run_time_binding_method();
mov eax,dword ptr [ptrA] //getting object's address
mov edx,dword ptr [eax] //getting VTABLE's address
mov esi,esp
mov ecx,dword ptr [ptrA]

//The following line will gets the address of
//run_time_binding_method() from VTABLE
mov eax,dword ptr [edx]
call eax // will call run_time_binding_method
cmp esi,esp
call @ILT+370(__RTC_CheckEsp) (411177h)

Let’s call methods using its reference:

As reference is nothing but an implicit pointer to the object, the method calls via reference is same as method calls via pointer:

refA.compile_time_binding_method();
mov ecx,dword ptr [refA]
call test::compile_time_binding_method (41118Bh)

refA.run_time_binding_method();
mov eax,dword ptr [refA]
mov edx,dword ptr [eax]
mov esi,esp
mov ecx,dword ptr [refA]
mov eax,dword ptr [edx]
call eax
cmp esi,esp
call @ILT+370(__RTC_CheckEsp) (411177h)

As I am not an author by profession, I might not have explained it in a best way J. Please help me make it best by raising your question/doubt.

6 comments:

  1. Dew , You want to say
    test &refA = a; // Reference of object ‘a’
    test *ptrA = &a; // Pointer of object ‘a’
    above two statement are same.
    Will we get the same output if we call the method with refA and ptrA object.
    will refA will resolve the late binding?

    ReplyDelete
  2. Thanks for the question!!! It indicated that someone is reading my blog :).

    Yes, in both the cases, output will be same and call will be resolved at run-time.

    For more information, please read "Reference Vs. Pointer".

    ReplyDelete
  3. still we are touch with c language , this blog very helpfull for us .
    Thanks

    ReplyDelete
  4. thanks for sharing such a valuable knowledge ...

    ReplyDelete