Double function indirection in C [duplicate]

2019-08-15 17:41发布

问题:

This question already has an answer here:

  • How do function pointers in C work? 11 answers

I am writing a bootloader for an ARM Cortex-M0 CPU. I need to forward the IRQs to the target app, unfortunately the IRQ vector in this CPU is at fixed address and I cannot relocate it, so I need a bit of trickery.

I know the address where the addresses of the target app's IRQs are stored. So let's say, at address 0x5008 there's the address of void x_IRQHandler(void) (target app)

What I want to do is:

  • at start up save the addresses of all x_IRQHandler() (so that it is not calculated at run-time);
  • whenever an IRQ call is received by the bootloader, call the related IRQ function in the target app from its address.

This is what I have done in the bootloader, I can't find the right syntax for it.

//pointers to x_IRQHandler() functions
void(* x_IRQ_addr)(void);
x_IRQ_addr = (void(*)(void))(0x5008);

//here I should call the function pointed by x_IRQ_addr; but this syntax is not valid
void x_IRQ_Handler(void)
{
  *x_IRQ_addr();
}

I have tried different approaches with no success, how can I fix that?

回答1:

The function call operator () has higher precedence than the indirection operator *.

Try using (*x_IRQ_addr)(); instead of *x_IRQ_addr();.

You can also write it as x_IRQ_addr(); because *x_IRQ_addr is a function designator and it will be converted to the pointer pointing the function for operand of () operator, so the dereference goes to waste.



回答2:

Just call

x_IRQ_addr();

No need of * - *x_IRQ_addr() means you want to dereference the value returned by the function (which is void and does not return anything anyway).



回答3:

Hint about using (*x_IRQ_addr)(); or *x_IRQ_addr(); worked; However, there was another problem about assigning the address to it. Indeed, in order to save the address of x_IRQ_addr I should have done

x_IRQ_addr = *(void(**)(void))(0x5008);

instead of

x_IRQ_addr = (void(*)(void))(0x5008);

But my question was probably not clear enough



回答4:

the usual way to get around the underlying problem is to have the linker command file place the interrupt vector array at a different location in the target program,

use the 'copy' to the correct location as one of the linker command file elements.

Then the target code, at startup, before entering 'main()' will copy the interrupt vector array to the correct location, overlaying the boot code interrupt vector array.

In general, this means the boot code will jump (when done loading) to the 'start.s' code location in the target code.

You write/link a custom start.s file that performs the desired copy of the interrupt vector array to the correct location