tags:

views:

137

answers:

5

I'm writing a bootloader for the PIC32MX, using HiTech's PICC32 compiler (similar to C90). At some point I need to jump to the real main routine, so somewhere in the bootloader I have

void (*user_main) (void);
user_main = (void (*) (void)) 0x9D003000;
user_main();

(Note that in the actual code, the function signature is typedef'd and the address is a macro.)

I would rather calculate that (virtual) address from the physical address, and have something like:

void (*user_main) (void);
user_main = (void (*) (void)) (0x1D003000 | 0x80000000);
user_main();

...but when I try that I get a compiler error:

Error #474: ; 0: no psect specified for function variable/argument allocation

Have I tripped over some vagarity of C syntax here?

This error doesn't reference any particular line, but if I comment out the user_main() call, it goes away. (This might be the compiler removing a redundant code branch, but the HiTech PICC32 isn't particularly smart in Lite mode, so maybe not.)

Update: I notice also that if I use

void (*user_main) (void);
unsigned int x = 0x9D003000;
user_main = (void (*) (void)) x;
user_main();

I get the same error.

+1  A: 

You may be correct with regards to the removing of redundant code by the compiler when you remove the call to the function. GCC -S i think will get you the assembly output which you could then use to confirm the absence of the function definition once the function call site is removed.

I guess this would help you progress your debugging...

JC
A: 

An ugly way to do it might be to put your pointer type and an unsigned long in a union. You know what you need to do. The C standard makes that undefined behaviour, but you're already in undefined territory and at the mercy of your compiler as soon as you need to convert an integer to a pointer.

Windows programmer
This particular compiler fully supports type-punning (I've checked)
detly
+3  A: 

This isn't a general C problem -- it's HI-TECH specific.

I've never used HI-TECH products, but the problem seems to be that the linker doesn't know where in memory it should place the arguments or the local variables of the user_main routine. From the PICC manual:

(474) no psect specified for function variable/argument allocation (Linker)

The FNCONF assembler directive which specifies to the linker information regarding the auto/parameter block was never seen. This is supplied in the standard runtime files if necessary. This error may imply that the correct run-time startoff module was not linked. Ensure you have used the FNCONF directive if the runtime startup module is hand-written.

Martin B
But why would it work for the literal `0x9D003000` but not `(0x1D003000 | 0x80000000)`?
detly
Actually, rather than chase this around here, if it's not an obvious C problem I'll just contact HiTech about it.
detly
+1  A: 

I realize that this is not the answer to the original question, but the syntax of the function call via a pointer-to-function could be made much clearer (correct) with the following construct:

(*user_main)();

If you do this, you immediately see that user_main is a pointer that is dereferenced and a function call is executed. This avoids confusing user_main pointer-to-function with user_main() function.

Miro
I like it, thanks.
detly
+1  A: 

Sorry to answer my own question, but it was a fault in the compiler. They sent me a more recent build that fixed the problem.

detly