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:
- The address of
one()
is ultimately set at link time. - In your example, the compiler generates code for setting
one_ptr
to something (let's say "address ofone
", 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 ofone
and called. - 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 toone
. [Demo]