Jump to content
Sign in to follow this  
philb

Function Pointers Resolved To Incorrect Constants

Recommended Posts

Hello.

 

v6.95 on WinXP, compiling for 18F24k20.

 

When I try to use function pointers I get weird results, for example:

 

typedef void (*fp) (void);

 

void TestFP (void)

{

//determine the values to input

fp low = InitCapture; //any global function with the write signature

fp high = ClearRDSState; //ditto

unsigned short adrs = (unsigned short)high >> 1;

puts("\nhigh value is: ");

puthex(adrs>>8);

puthex(adrs);

adrs = (unsigned short)low >> 1;

puts("\nlow value is: ");

puthex(adrs>>8);

puthex(adrs);

}

 

the output shows values of 0 or 1 being output for the function addresses - looking at part of the assembler from the casm file:

 

fp low = InitCapture;

1944 0E01 MOVLW 0x01

1946 0100 MOVLB 0x00

1948 6FF3 MOVWF TestFP_00000_1_low, 1

 

fp high = ClearRDSState;

194A 0E02 MOVLW 0x02

194C 6FF4 MOVWF TestFP_00000_1_high, 1

 

unsigned short adrs = (unsigned short)high >> 1;

194E 6FF5 MOVWF TestFP_00000_1_adrs, 1

1950 6BF6 CLRF TestFP_00000_1_adrs+D'1', 1

1952 90D8 BCF STATUS,C

1954 33F6 RRCF TestFP_00000_1_adrs+D'1', F, 1

1956 33F5 RRCF TestFP_00000_1_adrs, F, 1

 

Which seems to think that the function pointer has a size of 1 byte only, and that value is a constant of 1 or 2 (InitCapture & ClearRDSState respectively). Surely the size of a function pointer must be 2 bytes to accommodate the address range? fwiw looking at the map file, the functions are actually at addresses 0x370 and 0x350 respectively.

 

The manual says that function pointers are supported, but perhaps in a very constrained way? The only restriction I saw was not supporting arrays of function pointers...

Share this post


Link to post
Share on other sites

This is problem with your code. Compiler behaves correctly. Your code uses function pointer values instead of calling them.

 

Regards,

Pavel

Share this post


Link to post
Share on other sites

Sorry I disagree - this form of code is fine on various platforms using various compilers (e.g. GCC on x86) - how else would you generate function pointer based callback jump tables in code such as DLLs/shared objects?

 

A function pointer is a variable of a standard type - it must have a size and location, and in essence is the same as any other pointer. If you initialise a function pointer variable to the address of a function, then the storage associated with the function pointer should be initialised to the address of the function. What you later choose to do with the contents of that location via casting is somewhat irrelevant. Of course if you call the function via the function pointer it should then generate an indirect function call using the contents of the location assigned to the function pointer - but fundamentally the location associated with the function pointer should be initialised.

 

For example, on x86 using GCC:

 

typedef void (*fp) (void);

 

void testfp (void)

{

fp high = test1; //some function

fp low = test2; //some other function

printf("\nValue of test1: 0x%X, value of test2: 0x%X",(unsigned long)test1,(unsigned long)test2);

printf("\nValue of high: 0x%X, value of low: 0x%X",(unsigned long)high,(unsigned long)low);

printf("\nSize of fp: %d\n",sizeof(fp));

}

 

will result in:

 

Value of test1: 0x8048344, value of test2: 0x80448358

Value of high: 0x8048344, value of low: 0x80448358

Size of fp: 4

 

And objdump confirms that the address of the functions is indeed as printed.

 

Why do you think that the example code I provided is invalid?

 

regards

 

Phil

Share this post


Link to post
Share on other sites

Your code is correct from language point of view but it relies on the assumption that function pointer value should be equal to the function code address in code memory. This is not the case. PIC architecture doesn't allow to use absolute function addresses. To overcome this limitation compiler uses function ordinals that are assigned at link time and builds jump table that uses these ordinals to rout code execution to the correct place. The values 1 and 2 are ordinals of the functions InitCapture and ClearRDSState from your code.

 

Regards,

Pavel

Share this post


Link to post
Share on other sites

Before I say anything, let me start by saying that I haven't tried this on a PIC. From my experience with C programming, I noticed a few things that might be causing problems:

 

Issue 1

 

typedef void (*fp) (void);

This will cause the function pointer to point to a function that looks like:

void samplefunc (void) {
// Code here
}

Since you are casting the output later in the program, I assume you wanted:

typedef void * (*fp) (void);

That will call something like:

void * samplefunc (void) {
// Code here
}

 

Issue 2

fp high = test1; //some function

This will assign the pointer "high" the value of "test1". Since the pointer should point to an address, I believe it should be written as:

fp high = &test1; //some function

 

Issue 3

unsigned short adrs = (unsigned short)high >> 1;

Even though high takes no arguments, parentheses should still be included because it is a function call.

unsigned short adrs = (unsigned short)(high()) >> 1;

 

 

 

Again, I have no idea how well this works on the PIC. This is solely from my experience as a C programmer. I've never personally done this using BoostC.

 

I'm curious to see how you manage to implement this. Good luck.

 

- Bill

Share this post


Link to post
Share on other sites
Your code is correct from language point of view but it relies on the assumption that function pointer value should be equal to the function code address in code memory. This is not the case. PIC architecture doesn't allow to use absolute function addresses. To overcome this limitation compiler uses function ordinals that are assigned at link time and builds jump table that uses these ordinals to rout code execution to the correct place. The values 1 and 2 are ordinals of the functions InitCapture and ClearRDSState from your code.

 

Regards,

Pavel

 

Thanks for the clarification. OK, so it's a 'speciality' of PICs that this sort of code wont work. Perhaps you can suggest how I get the address of a function into a 16-bit variable... is it only possible using assembler?

 

btw: I need the address of a function as my application performs self-modification to switch between sets of interrupt handlers (i.e. it reads/modifies/writes the first 64-bytes to change the jump addresses for the high/low priority interrupt handlers) - this allows each (separate) mode of operation to have optimal interrupt performance. To do this I need to know the address of the functions to switch to (the addresses of the ones I'm switching from can be deduced from reading the flash)

 

regards

 

Phil.

Share this post


Link to post
Share on other sites
...I need the address of a function as my application performs self-modification to switch between sets of interrupt handlers (i.e. it reads/modifies/writes the first 64-bytes to change the jump addresses for the high/low priority interrupt handlers) - this allows each (separate) mode of operation to have optimal interrupt performance. To do this I need to know the address of the functions to switch to (the addresses of the ones I'm switching from can be deduced from reading the flash)...

 

There is no way to get address of a function at run time. I suggest to use fixed addresses for functions you want to modify:

 

void foo() @ 0x100 //this function will start at address 0x100
{
}

 

 

Regards,

Pavel

Share this post


Link to post
Share on other sites

Hello Bill,

 

thanks for the offer of help, however I think you didn't quite get what I was trying to do - it was all about determining the address of functions and manipulating the address to make it suitable for modifying the code at runtime.

 

 

* Issue 1: No, the function pointer is the correct type (i.e. pointer to function of "void foo (void)") - it's not the return value of the function I want, but the address of the function. As a "function pointer" is a pointer to a function, it should contain the address of the function being pointed to (which is fine on other architectures, but as Pavel has pointed out, won't work here...)

 

* Issue 2: Actually no, odd as it seems you don't need the ampersand here.

 

* Issue 3: As per Issue 1, it's not a function call, so the code is correct from a C point of view, and works fine on (say) x86, sadly it won't work on this architecture.

 

* How to do it... well Pavel suggests fixing the address of functions using the language extensions so that I know at coding time what they are, rather than determining them at link time - of course it's very specific to PIC/BoostC, but that's not really a problem for me, so that's what I'll settle on.

 

thanks

 

Phil.

Share this post


Link to post
Share on other sites

I guess I didn't realize exactly what you were doing. I assumed that the function pointers would fill themselves in at compile time. I don't know why I thought that.

 

I'm glad that you were able to figure it out, though.

 

- Bill

Share this post


Link to post
Share on other sites

Hi guys,

 

I'm doing something similar and encountered the same problem.

Basically I have a table of function addresses, and a system that calls them when required. A simple kind of task switching.

 

I've been trying to use the fix address thing but couldn't get it to work so far, not sure why.

But I've found another workaround albeit a stupid one.

That is I fill my table with all zeroes and compile my code once.

After that, I open up the generated list file, and manually fill up my table, then recompile again and it works.

I figured it should be possible to write a simple script to automate this job, so the only drawback is the need to compile twice.

 

Anyway I've been exploring C compiler alternatives for a while now, and just got on to SourceBoost a couple of weeks ago. So far I find SourceBoost pretty good and surprisingly economical for it's capability. Compared to the bloated code generated by Hi-Tech Lite version, this is leagues better. Seems to be much less well known though unfortunately.

Share this post


Link to post
Share on other sites

Join the conversation

You are posting as a guest. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
Sign in to follow this  

×
×
  • Create New...