Address of function error

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Address of function error

Jump to solution
1,590 Views
rlw
Contributor I

In the code below, the pointer, p, gets initialized to 0xC3D0, even though the funtion. NvStartAndWait is located at 0xD0C3.

Similarly, it gets compared to 0xD6D0 even though the next function begins at 0xD0D6.

 

I checked that I am using the correct syntax, so this seems like an error in the compiler.

 

I am using CodeWarrior 5.9.0 build 2836 for S12XE.

 

#define FCNBUFLEN 24vuint8 NvWaitBuf[FCNBUFLEN]; // RAM buffer to hold copy of NvStartAndWait()// Start pending FLASH command then wait for completion// Must immediately preceed CopyNvStartAndWait()void NvStartAndWait(void){   FSTAT = CCIF;   while ((FSTAT & CCIF) == 0)   {      (*WDFct)(); // Feed the watch dog while we wait   }}// Copies the start and wait function to RAM// Must immediately follow NvStartAndWait()vuint8 CopyNvStartAndWait(void){   vuint8 i;   vuint8 * p;   for(i = 0, p = (vuint8 *)NvStartAndWait; p < (vuint8 *)CopyApplNvStartAndWait; p++)   {      NvWaitBuf[i] = *p;      i++;      if (i >= FCNBUFLEN)      {         return Failed;      }   }   return Ok;}
Labels (1)
Tags (1)
0 Kudos
1 Solution
676 Views
CompilerGuru
NXP Employee
NXP Employee

>I checked that I am using the correct syntax, so this seems like an error in the compiler.

 

I wonder how you checked this Smiley Happy.

 

Anyway, which memory model are you using? My guess: banked. In the banked memory model function pointers (as just the name NvStartAndWait) are 24 bit in size and have a special byte ordering.

If you want to copy the function like this, my suggestion would be to allocate the NvStartAndWait and CopyNvStartAndWait functions non banked.

E.g. something like (not tested)

 

 

#pragma push#pragma CODE_SEG __NEAR_SEG NON_BANKEDvoid NvStartAndWait(void){....}#pragma pop

 

Non banked functions play much nicer with 16 bit pointers, assignments and comparisons as done in the code do work.

 

 

It's also possible with banked code with __far data pointer, but the code would also have to adjust for the different byte orderings of function and data pointers.

Also I'm wondering where WDFct points to, should not be the flash the routine is programming...

Daniel

 

View solution in original post

0 Kudos
8 Replies
676 Views
Lundin
Senior Contributor IV

Besides the issues with far pointers, wild typecasts between integer pointers and function pointers are undefined behavior in the C language. So the compiler can conjure any random behavior for your code and it would still be fully standard-compliant. Instead of casting to an int pointer, cast to an int. Then the behavior is defined in the C standard.

 

You should also loop and check against FCNBUFLEN, instead of the address of some other function. There is no guarantee what-so-ever by the C standard that the functions are placed at adjacent space in the program memory.

 

 

vuint8 * p = (vuint8 *)(vuint16)NvStartAndWait;

for(i = 0, i<FCNBUFLEN; i++)


0 Kudos
676 Views
rlw
Contributor I

The suggested #pragma did the job. Thanks.

 

Also, I am checking against both the buffer length and the code address.

 

0 Kudos
676 Views
Lundin
Senior Contributor IV

Yes but the code as it is isn't portable and there are no guarantees it will work on a standard C compiler. I'm just saying that you should remove all undefined behavior from your program before complaining of "errors in the compiler".

 

0 Kudos
676 Views
rlw
Contributor I

It is a policy driven trade-off. Yes, it is not portable. But by also comparing against the presumed end of the function, there is an automatic detection of buffer over flow. True, it is a run time detection, but still automatic.

 

(Yes, we do have code reviews to look for problems, but company policy dictates we automate detection of problems as much as possible.)

 

Any other method would also be nonportable. If this method broke, then I'd have to devise another way. If there was no other way, I would have to explain to management why it could not be done. Stating that it is not portable would not be good enough.

 

For that matter, copying code from ROM to RAM and executing is also nonportable.

 

For what it is worth, my favorite way to get code into RAM is:

 

unsigned char CodeBuffer[] = { 0xC6, 0x55, 0x5B, 0x3F, 0x58, 0x5B, 0x3F, 0x3D };

 

This way the compiler will take care of copying it for me as well as making sure the buffer fits the code. Unfortunately, there are technical reasons that require a complex function that can not simply be converted into a constant string of bytes.

0 Kudos
676 Views
Lundin
Senior Contributor IV

It is the undefined behavior typecast I'm mainly referring to. As I mentioned in my first post, you can't cast between common pointers and function pointers in the C language. If you had an automated code analysis tool it should have detected that bug.

 

0 Kudos
677 Views
CompilerGuru
NXP Employee
NXP Employee

>I checked that I am using the correct syntax, so this seems like an error in the compiler.

 

I wonder how you checked this Smiley Happy.

 

Anyway, which memory model are you using? My guess: banked. In the banked memory model function pointers (as just the name NvStartAndWait) are 24 bit in size and have a special byte ordering.

If you want to copy the function like this, my suggestion would be to allocate the NvStartAndWait and CopyNvStartAndWait functions non banked.

E.g. something like (not tested)

 

 

#pragma push#pragma CODE_SEG __NEAR_SEG NON_BANKEDvoid NvStartAndWait(void){....}#pragma pop

 

Non banked functions play much nicer with 16 bit pointers, assignments and comparisons as done in the code do work.

 

 

It's also possible with banked code with __far data pointer, but the code would also have to adjust for the different byte orderings of function and data pointers.

Also I'm wondering where WDFct points to, should not be the flash the routine is programming...

Daniel

 

0 Kudos
676 Views
rlw
Contributor I

This application is actually a loader for the real application. The loader resides completely in the range 0xC000 through 0xFFFF. (FYI, the real application does use multiple banks. Its vector table is at 0x7F10 through 0x7FFF.)

 

Also, WDFct will point to another function that will be copied to RAM in a similar manner (and is likewise failing to copy).

 

I tried qualifying p with __far, but that resulted in 0xD6D07F. p was already a 16 bit variable, so I assume qualifying as __near won't help either.

 

Will __far pointers work in code compiled non-banked? I have a CRC routine to verify the real application was programmed correctly before allowing it to run and it uses a __far pointer to read from FLASH ROM.

 

I will try non-banked tomorrow.

0 Kudos
676 Views
CompilerGuru
NXP Employee
NXP Employee

The key is not the qualifier of the pointer, it's the qualifiers of the functions being copied (or compared against).

__far function pointers (e.g. the name of a far function) have the special byte ordering, __near functions do not.

Therefore if you can allocate the functions in a #pragma code_seg __NEAR_SEG section, then the assignment to the 16 bit data pointer will work as you expect it to.

With a far data pointer (and far functions), the code would have to explicitly handle the differences in the byte ordering. But instead I would use just near functions.

And yes, __far (or __near) pointers work in any memory model. The memory model just defines how unqualified pointers (and functions, variables) behave.

Daniel

0 Kudos