Home > Blockchain >  Does function binding occur at the call or at an assignment?
Does function binding occur at the call or at an assignment?

Time:11-02

I am currently wrapping my head around function binding and what binding actually is C . Function binding is assigning an address to function? Does only refer to when the function is called? or does binding occur when function the function is called?

Here is the program

#include <iostream>

int one() { return 1; }

int main()
{
    // 1. Does binding occur here when the function pointer is assigned the address of the function
    int (*one_ptr)() = one;
    // 2. or does binding occur here when the function is called
    one_ptr();
}

Does binding occur when the function pointer is assigned the address of the function:

int (*one_ptr)() = one;

or does the binding occur when the function is called:

one_ptr();

Here is the relevant objdump of the program:

0000000000001169 <_Z3onev>:
    1169:   f3 0f 1e fa             endbr64
    116d:   55                      push   rbp
    116e:   48 89 e5                mov    rbp,rsp
    1171:   b8 01 00 00 00          mov    eax,0x1
    1176:   5d                      pop    rbp
    1177:   c3                      ret

0000000000001178 <main>:
    1178:   f3 0f 1e fa             endbr64
    117c:   55                      push   rbp
    117d:   48 89 e5                mov    rbp,rsp
    1180:   48 83 ec 10             sub    rsp,0x10
    1184:   48 8d 05 de ff ff ff    lea    rax,[rip 0xffffffffffffffde]        # 1169 <_Z3onev>
    118b:   48 89 45 f8             mov    QWORD PTR [rbp-0x8],rax
    118f:   48 8b 45 f8             mov    rax,QWORD PTR [rbp-0x8]
    1193:   ff d0                   call   rax
    1195:   b8 00 00 00 00          mov    eax,0x0
    119a:   c9                      leave
    119b:   c3                      ret

This is the assembly version of the function pointer being declared and initialized

lea    rax,[rip 0xffffffffffffffde]        # 1169 <_Z3onev>
mov    QWORD PTR [rbp-0x8],rax

Here, relative rip addressing is used to assign the address of the function to the local variable. The address of the function is stored in rax as we can see here

lea    rax,[rip 0xffffffffffffffde]        # 1169 <_Z3onev>

So calling rax makes sense. It is an indirect function call (I believe).

call   rax

So, is the function is bound to 00000001169, the address of one()? And in this case, it's static bound because the objdump is able to determine the address of the function could be determined at compile time.

CodePudding user response:

"Binding" is not really a thing in C as a language. When dealing with function calling, the term tends to be used with "early" and "late". Early binding typically refers to compile-time determination of which exactly which code will be executed for a given function call. For C , this means overload resolution. These are implemented as direct calls: the address to where execution will jump is written directly into the assembly.

Late binding is contrasted with early binding in that you cannot know at compile-time exactly which function will be called purely from the call itself (ie: the name of the function and its arguments). C has two features that allow for late binding: virtual functions and function pointers. These are all implemented as indirect calls: you read some memory to determine to where execution will jump.

Using a function pointer is, at least conceptually, a form of late binding. In your exact code example, a decent optimizing compiler can detect that one_ptr only ever assumes one value and therefore optimize out the indirect call.

CodePudding user response:

I would say:

  1. The address of one() is ultimately set at link time.
  2. In your example, the compiler generates code for setting one_ptr to something (let's say "address of one", that the linker would resolve later, and it will appear as a constant address in the final binary). During runtime, one_ptr will be set to the address of one and called.
  3. You could do the same at compile time (get "address of one", later to be resolved by the linker, and assign that to a constant expression). During runtime, we would just see a call to one. [Demo]
  •  Tags:  
  • c
  • Related