picking apart a function pointer

Hi -

I have been given a line of code that I know works, but I want to understand it better. Here's a snippet:

1
2
3
4
5
6
int main()
{
   int addr;  // assume addr gets a value (actually an address)
   ((void(*)(void))(*((int*)(addr+4))))();
   return 0;
}


This code is used in a simple bootloader, and passes control of the program pointed to by addr.

I'd like to break this into bite-size pieces perhaps like this:

1
2
3
void (*pApp)();
pApp = (void *) addr + 4;
pApp();


(I can't test this currently, as I don't have access to the development hardware.) It compiles successfully, but...will it work? I'm particularly interested in whether the pointer arithmetic will be OK with the "+ 4".

Thanks for any clarification.
This would only work on a platform where a value of type int is capable of holding a value of a pointer to data. I am going to replace your int with uintptr_t because otherwise it won't work on my system. If you don't have uintptr_t, size_t works on many platforms too.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <cstdint>
void f()
{
    std::cout << "foo\n";
}
int main()
{
   void(*fptr)() = f; // assuming C++, where f(void) and f() are the same
   void(**fptrptr)() = &fptr;
   std::uintptr_t addr = reinterpret_cast<std::uintptr_t>(fptrptr);
   addr -= 4;

   (
      (void(*)(void)) // cast to function pointer the following value
      (
        *( // obtain the value pointed to by the following pointer
          (std::uintptr_t*)( // cast to intptr_t pointer
            addr+4 // add 4 to the memory address (a uintptr_t value)
           )
         )
      )
   )(); // invoke the function pointer
}

online demo: http://ideone.com/PwbgfX

in short, your addr is the numeric value of a pointer to a pointer to a function, minus 4.

PS: Actually, this line would be more logical if you cast addr+4 to a pointer to pointer to function (since you're going to dereference it and invoke the result as a pointer to function anyway):
(*(void(**)(void))(addr+4))(); or, in C++, (*reinterpret_cast<void(**)()>(addr+4))();
Last edited on
Hey, Cubbi -

I should have mentioned that portability is really a non-issue for this passage of code. It's going onto an ARM device and some of the code I left out is hard-coded values to set up the stack and VTOR for the code that this branches to.

Regarding the "+ 4," I'm pretty sure this is to skip over the first four bytes of the image file (probably contains a checksum or something).

So, while your example is definitely worth studying for my education, I want to keep the code in this bootloader to something I can readily understand. Other than your proviso about int being the correct size for a pointer, can you see any showstoppers in my implementation?

Thanks.
As long as the value at addr+4 is indeed the address of an address of a function, there's no problem with this.

To make it really easy to understand, I would have written maybe
1
2
3
   typedef void(*fptr_t)(void);
   fptr_t* fptrptr = (fptr_t*)(addr+4);
   (*fptrptr)();
No, the addr+4 should point to the start of a function. My interpretation of:

((void(*)(void))(*((int*)(addr+4))))();

Is that it's casting addr+4 to an int pointer, then casting that to a function pointer, and invoking it. No?

EDIT:

I may have gotten that wrong. Here's the entire code passage:

1
2
3
4
 __set_MSP(*((int*)addr));  // setup stack pointer for the app
   *((int*)0xE000ED08) = addr;  // Setup the VTOR for the app
   ((void(*)(void))(*((int*)(addr+4))))();  // jump to the app
 }


So maybe it is a pointer to a pointer of sorts.
Last edited on
no, it's cast, dereference, cast, function call.

Edit: right, I should have said the value OF addr+4 is the address of an address of a function. The value AT addr+4 is indeed the address of a function.


   vtor   fptr
|_|_|_|_|_|_|_|_|
 ↑       ↑
addr    addr+4
Last edited on
Right...so how is that not a pointer to a function?

1. addr is cast to a pointer
2. addr is then dereferenced
3. what addr points to then becomes cast to a pointer to a void function
4. that pointer is then called

So, how is the value addr not simply an address to be branched to?
the value *(addr+4) is the address to be branched to. The value addr+4 is the address of that address.
OK, then, I must not understand how the VTOR works. (No big surprise there.) I'll review it tomorrow and make my change accordingly.

Thanks for the help.
Topic archived. No new replies allowed.