|
|||||||||||
Technical Support Support Resources
Product Information |
C51: Problems with Function Pointers Overwriting VariablesInformation in this article applies to:
QUESTIONI have a C51 program that uses a function to call other functions via a table of function pointers. I keep having a problem with those functions overwriting the variables used by the main C function. What's going on? ANSWERThe following program will help exemplify this problem. Note that func_a and func_b are called via function pointers from the func_table array. The dispatch function calls these functions through this table.
This simple program appears as though it SHOULD work. However, the following linker MAP file shows some interesting information.
Note that the variables in segment ?PR?MAIN?DMAIN start at the same address as the variables in segments ?PR?_FUNC_A?DMAIN and ?PR?_FUNC_B?DMAIN. This means that the variables in main are OVERLAID with the variables in func_a and func_b. This is NOT what is desired. Whenever func_a or func_b executes, the variables in main will get trashed. In the MAP file, note that ?C_INITSEG is the segment which "calls" func_a and func_b. This is incorrect since ?C_INITSEG is the variable initialization routine which actually calls NO functions. So, why does the linker think these functions are called by the initialization code? Why doesn't it know that they are called by the ?PR?DISPATCHER?DMAIN segment? The reason for this is because the function table is declared as follows:
And, it is stored in the default data space (XDATA in this example). Therefore, the compiler makes a link to func_a and func_b from the PUBLIC XDATA space allocated to the DMAIN module. Since the initialization code initializes the XDATA table, the segment ?C_INITSEG links to these functions. There are 2 ways you can solve this problem. Manually editing the segment links in the call tree or declaring the pointer table to lie in CODE space. Manually Editing Links in the Call TreeYou can manually remove the links from ?C_INITSEG and add them to ?PR?DISPATCHER?DMAIN using the following overlay command for the linker.
The easiest way to do this from µVision is to select the Linker Options and go to the file tab. Check the "User Command File" check box and click the Create button and the Edit button. Close the Linker Options dialog box and enter the overlay command in the linker response file window that was opened. Make sure you put ampersand characters ('&') at the end of each line. In µVision, open the Project Options Dialog, Select the BL51 Misc Tab, and enter the following in the Overlay Input Line:
When you link the project, you will see that the links from ?C_INITSEG are gone and links from ?PR?DISPATCHER?DMAIN have been added.
Declaring the Pointer Table in CODE SpaceAnother method of correcting this problem is to declare the function pointer table to lie in CODE space. For example:
The above declaration causes a new segment ?CO?modulename to be generated. It is this segment (instead of ?C_INITSEG) that is now linked to these functions. This is shown in the following MAP file excerpt.
Note here that ?CO?DMAIN "calls" func_a and func_b. Note also that ?PR?DISPATCHER?DMAIN "calls" ?CO?DMAIN. This completes the call tree and no OVERLAY entries are required. In conclusion, note that function pointers in C51 are not as simple as they may seem. Be cautious when using them, and your program will work as expected. If you are not careful, you may spend a lot of time debugging the problem. MORE INFORMATION
SEE ALSO
Last Reviewed: Thursday, February 25, 2021 | ||||||||||
|
Arm’s Privacy Policy has been updated. By continuing to use our site, you consent to Arm’s Privacy Policy. Please review our Privacy Policy to learn more about our collection, use and transfers
of your data.