Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function Pointer Memory Explanation in C

#include <stdio.h>
#include <stdlib.h>

int (*fptr1)(int);

int square(int num){
  return num*num;
}

void main(){
  fptr1 = &square;
  printf("%d\n",fptr1(5));
}

Can someone briefly explain what happens in stack when we call a function pointer? What is the difference between calling a function directly in main() and calling it by function pointer in C language by the means of physical memory and process?

I tried to understand what happens in memory when we call a function with function pointer but it is not enough to me.

  1. When we call a function by pointer, does pointer have this function's location at code space?
  2. When called function is running is it same as normally called function in main()?
  3. What is the difference of calling function directly or using function pointer when code is running in a pipelined branch predictive processor?
like image 735
cycrel Avatar asked Aug 16 '13 23:08

cycrel


2 Answers

The best way to answer this is to look at the disassembly (slightly modified sample):

fptr1 = &square;
int result1 = fptr1(5);
int result2 = square(5);

Results in this x64 asm:

    fptr1 = &square;
000000013FA31A61  lea         rax,[square (013FA31037h)]  
000000013FA31A68  mov         qword ptr [fptr1 (013FA40290h)],rax  
    int result1 = fptr1(5);
000000013FA31A6F  mov         ecx,5  
000000013FA31A74  call        qword ptr [fptr1 (013FA40290h)]  
000000013FA31A7A  mov         dword ptr [result1],eax  
    int result2 = square(5);
000000013FA31A7E  mov         ecx,5  
000000013FA31A83  call        square (013FA31037h)  
000000013FA31A88  mov         dword ptr [result2],eax  

As you can see the assembly is virtually identical between calling the function directly and via a pointer. In both cases the CPU needs to have access to the location where the code is located and call it. The direct call has the benefit of not having to dereference the pointer (as the offset will be baked into the assembly).

  1. Yes, you can see in the assignment of the function pointer, that it stores the code address of the 'square' function.
  2. From a stack setup/tear down: Yes. From a performance perspective, there is a slight difference as noted above.
  3. There are no branches, so there is no difference here.

Edit: If we were to interject branches into the above sample, it wouldn't take very long to exhaust the interesting scenarios, so I will address them here:

In the case where we have a branch before loading (or assignment) of the function pointer, for example (in pseudo assembly):

branch zero foobar
lea square
call ptr

Then we could have a difference. Assume that the pipeline chose to load and start processing the instructions at foobar, then when it realized that we weren't actually going to take that branch, it would have to stall in order to load the function pointer, and dereference it. If we were just calling a know address, then there would not be a stall.

Case two:

lea square
branch zero foobar
call ptr

In this case there wouldn't be any difference between direct calls vs through a function pointer, as everything we need is already know if the processor starts executing down the wrong path and then resets to start executing the call.

The third scenario is when the branch follows the call, and that is obviously not very interesting from a pipeline perspective as we've already executed the subroutine.

So to fully re-answer question 3, I would say Yes, there is a difference. But then the real question is whether or not the compiler/optimizer is smart enough to move the branch after the function pointer assignment, so it falls into case 2 and not case 1.

like image 183
josh poley Avatar answered Oct 13 '22 19:10

josh poley


  1. The pointer to function contains the address of the start of the function in the text segment of the program.
  2. Once called, the function runs identically whether it is called directly or by a pointer to function.
  3. I'm not sure. Often, there won't be much difference; the pointer to function doesn't change very often, if at all (e.g. because you loaded a shared library dynamically, so you have to use a pointer to function to call the function).

What is the difference between calling a function directly in main() and calling it by function pointer?

The only difference is possibly an extra memory reference to fetch the function pointer from memory.

like image 21
Jonathan Leffler Avatar answered Oct 13 '22 20:10

Jonathan Leffler