Strange casting of function in c++ (void (**)())

145 Views Asked by At

I was reading the code of the bitcoin trezor MCU and found this:

(*(void (**)())(FLASH_APP_START + 4))();

By breaking down some things, I tried to analyze what this line meant:

(   *(void (**)())(FLASH_APP_START + 4)    )      ();

I can see that this is a function call with no arguments, due to the () at the end, and that the function is whatever

*(void (**)())(FLASH_APP_START + 4)

points to.

I know that FLASH_APP_START + 4 will resolve into something, so I just need to figure out what is this:

*(void (**)())

It is resolving to whatever void (**)() points to. But what is void (**)()? It looks like a casting to a function, maybe. But I'm not sure. Could you give me an example of what is this calling? Why would you need that?

2

There are 2 best solutions below

5
On

The meaning of (void (**)()) is: cast into pointer to pointer to function returning void. Thus, when you dereference it (*(void(**)())), it's of type pointer to function returning void, and you can call it. The (FLASH_APP_START+4) is a pointer into a function pointer table. If the type of FLASH_APP_START is char*, then the 2nd function in the list will be invoked, assuming 32 bit pointers. If the type of FLASH_APP_START is void*, then 5th function in the table would be called.

E.g. this code would invoke fun2 on a machine with 32 bit pointers.

#include <stdio.h>

void fun1() { printf("fun1\n"); }
void fun2() { printf("fun2\n"); }

int main(void) {
  static void (*table[])() = { fun1, fun2 };

  int const FLASH_APP_START = (int)&table;
  (*(void (**)())(FLASH_APP_START + 4))();
}

If you need help decoding C types, cdecl.org is your friend.

1
On

First, void (**)() is a pointer to a function pointer, with no arguments and void return type.

Second, (void (**)())(FLASH_APP_START + 4) means cast an address value FLASH_APP_START + 4 to the pointer in the first step. FLASH_APP_START should be a fixed value. It maybe the NAND flash start address, always used in embedded systems as the vector table.

Third, *(void (**)())(FLASH_APP_START + 4) dereferences the pointer got in the second step. We got a function pointer now.

Finally, (*(void (**)())(FLASH_APP_START + 4))() calls the function we got in the third step.

Summary: There is a function entrance address stored at the address FLASH_APP_START + 4. We get the function entrance address. cast it to a function pointer, and call it.