EmbeddedRelated.com
Forums
The 2024 Embedded Online Conference

AVR: Confused About an Array of Functon Pointers at Runtime

Started by the el vez March 20, 2007
I have some code that I am running on an atmega169. I am building a
static array of function pointers like so:

<the 2 routines are defined in a seperate object file>

typedef uint8_t (*routine)(void);

extern routine testRoutine;
extern routine testRoutine2;

routine routines[] = {
    (routine)&testRoutine,
    (routine)&testRoutine2
};

This compiles and links fine and at runtime the "routines" array
contains the addresses that are found for testRoutine and testRoutine2
when I do avr-nm on the .elf file for the project. However, when I
load the hex file onto the device and debug it - there is no code at
those addresses so when the jump is performed it executes the opcode
0xff which is found there. This seems impossible as I thought that avr-
nm was using post link addresses. I don't see how the addresses could
change post link. I am sure I am missing something obvious here.
Please enlighten me. Thanks.

"the el vez" <jonathanm@mindspring.com> wrote in message 
news:1174443864.768321.182050@e65g2000hsc.googlegroups.com...
>I have some code that I am running on an atmega169. I am building a > static array of function pointers like so: > > <the 2 routines are defined in a seperate object file> > > typedef uint8_t (*routine)(void); > > extern routine testRoutine; > extern routine testRoutine2; > > routine routines[] = { > (routine)&testRoutine, > (routine)&testRoutine2 > }; > > This compiles and links fine and at runtime the "routines" array > contains the addresses that are found for testRoutine and testRoutine2 > when I do avr-nm on the .elf file for the project. However, when I > load the hex file onto the device and debug it - there is no code at > those addresses so when the jump is performed it executes the opcode > 0xff which is found there. This seems impossible as I thought that avr- > nm was using post link addresses. I don't see how the addresses could > change post link. I am sure I am missing something obvious here. > Please enlighten me. Thanks.
typedef uint8_t routine(void); uint8_t testRoutine(void); uint8_t testRoutine2(void); routine* routines[] = { testRoutine, testRoutine2 }; Leo Havm&#4294967295;ller.
On Mar 20, 9:39 pm, Leo Havm=F8ller <rtx...@nospam.nospam> wrote:
> "the el vez" <jonath...@mindspring.com> wrote in messagenews:1174443864.7=
68321.182050@e65g2000hsc.googlegroups.com...
> > > > > > >I have some code that I am running on an atmega169. I am building a > > static array of function pointers like so: > > > <the 2 routines are defined in a seperate object file> > > > typedef uint8_t (*routine)(void); > > > extern routine testRoutine; > > extern routine testRoutine2; > > > routine routines[] =3D { > > (routine)&testRoutine, > > (routine)&testRoutine2 > > }; > > > This compiles and links fine and at runtime the "routines" array > > contains the addresses that are found for testRoutine and testRoutine2 > > when I do avr-nm on the .elf file for the project. However, when I > > load the hex file onto the device and debug it - there is no code at > > those addresses so when the jump is performed it executes the opcode > > 0xff which is found there. This seems impossible as I thought that avr- > > nm was using post link addresses. I don't see how the addresses could > > change post link. I am sure I am missing something obvious here. > > Please enlighten me. Thanks. > > typedef uint8_t routine(void); > > uint8_t testRoutine(void); > uint8_t testRoutine2(void); > > routine* routines[] =3D { > testRoutine, > testRoutine2 > > }; > > Leo Havm=F8ller.- Hide quoted text - > > - Show quoted text -
That worked perectly! However, now I am really confused as avr-nm still shows those routines at the higher addresses. And in fact - everything that is listed from avr-nm seems totally out of whack. What gives? Any detailed explaination is greatly greatly appreciated.
"the el vez" <jonathanm@mindspring.com> wrote in message 
news:1174455215.418369.44330@p15g2000hsd.googlegroups.com...

> That worked perectly! However, now I am really confused as avr-nm > still shows those routines at the higher addresses. And in fact - > everything that is listed from avr-nm seems totally out of whack. What >gives? Any detailed explaination is greatly greatly appreciated.
I don't know AVR but it's sounds like in your original case the linker didn't see the references to your functions and decided not to include them while in the second case the reference to the function name, not just the address, was enough to convince the linker to put it in. In this situation I'd create a couple of dummy calls to your functions to see if that solves the problem, e.g. int main(void) { extern dummy; // have int dummy=0; in some other module to make sure the optimizer can't figure out what you're up to if (dummy) { testRoutine(); testRoutine2(); } ... } Andrew
On Mar 20, 9:24 pm, "the el vez" <jonath...@mindspring.com> wrote:
> I have some code that I am running on an atmega169. I am building a > static array of function pointers like so: > > <the 2 routines are defined in a seperate object file> > > typedef uint8_t (*routine)(void); > > extern routine testRoutine; > extern routine testRoutine2; > > routine routines[] = { > (routine)&testRoutine, > (routine)&testRoutine2 > > }; >
I think there are 2 errors here: 1) testRoutine and testRoutine2 are pointers to functions, they are not functions. At run-time you have to initialize them with the addresses of executable functions, otherwise they are uninitialized and points to nothing. What you see as initialized correctly is just the address of a pointer. 2) You shouldn't use the & operator in your array. It does not show a compile error only because you casted to routine.
On 20 Mar 2007 19:24:24 -0700, "the el vez" <jonathanm@mindspring.com>
wrote:

>I have some code that I am running on an atmega169. I am building a >static array of function pointers like so: > ><the 2 routines are defined in a seperate object file> > >typedef uint8_t (*routine)(void); > >extern routine testRoutine; >extern routine testRoutine2; > >routine routines[] = { > (routine)&testRoutine, > (routine)&testRoutine2 >}; > >This compiles and links fine and at runtime the "routines" array >contains the addresses that are found for testRoutine and testRoutine2 >when I do avr-nm on the .elf file for the project. However, when I >load the hex file onto the device and debug it - there is no code at >those addresses so when the jump is performed it executes the opcode >0xff which is found there. This seems impossible as I thought that avr- >nm was using post link addresses. I don't see how the addresses could >change post link. I am sure I am missing something obvious here. >Please enlighten me. Thanks.
It might be optimising the routines away. If you have no direct calls to these routines, the linker or compiler may remove the code as being "dead code". Try adding a dummy call to one of the routines somwhere. Your toolset probably has some directive with which you can tell the compiler / linker that the code is not dead code, and should not be removed. Regards Anton Erasmus
Anton Erasmus wrote:
> On 20 Mar 2007 19:24:24 -0700, "the el vez" <jonathanm@mindspring.com> > wrote: > >> I have some code that I am running on an atmega169. I am building a >> static array of function pointers like so: >> >> <the 2 routines are defined in a seperate object file> >> >> typedef uint8_t (*routine)(void); >> >> extern routine testRoutine; >> extern routine testRoutine2; >> >> routine routines[] = { >> (routine)&testRoutine, >> (routine)&testRoutine2 >> }; >> >> This compiles and links fine and at runtime the "routines" array >> contains the addresses that are found for testRoutine and testRoutine2 >> when I do avr-nm on the .elf file for the project. However, when I >> load the hex file onto the device and debug it - there is no code at >> those addresses so when the jump is performed it executes the opcode >> 0xff which is found there. This seems impossible as I thought that avr- >> nm was using post link addresses. I don't see how the addresses could >> change post link. I am sure I am missing something obvious here. >> Please enlighten me. Thanks. > > It might be optimising the routines away. If you have no direct calls > to these routines, the linker or compiler may remove the code as being > "dead code". Try adding a dummy call to one of the routines somwhere. > Your toolset probably has some directive with which you can tell the > compiler / linker that the code is not dead code, and should not be > removed. >
In that event, I would consider the compiler was too clever for its own good. A pointer to a function is a reference to that function, as surely as a call is.
On Wed, 21 Mar 2007 23:59:26 -0800, David R Brooks
<davebXXX@iinet.net.au> wrote:

>Anton Erasmus wrote: >> On 20 Mar 2007 19:24:24 -0700, "the el vez" <jonathanm@mindspring.com> >> wrote: >> >>> I have some code that I am running on an atmega169. I am building a >>> static array of function pointers like so: >>> >>> <the 2 routines are defined in a seperate object file> >>> >>> typedef uint8_t (*routine)(void); >>> >>> extern routine testRoutine; >>> extern routine testRoutine2; >>> >>> routine routines[] = { >>> (routine)&testRoutine, >>> (routine)&testRoutine2 >>> }; >>> >>> This compiles and links fine and at runtime the "routines" array >>> contains the addresses that are found for testRoutine and testRoutine2 >>> when I do avr-nm on the .elf file for the project. However, when I >>> load the hex file onto the device and debug it - there is no code at >>> those addresses so when the jump is performed it executes the opcode >>> 0xff which is found there. This seems impossible as I thought that avr- >>> nm was using post link addresses. I don't see how the addresses could >>> change post link. I am sure I am missing something obvious here. >>> Please enlighten me. Thanks. >> >> It might be optimising the routines away. If you have no direct calls >> to these routines, the linker or compiler may remove the code as being >> "dead code". Try adding a dummy call to one of the routines somwhere. >> Your toolset probably has some directive with which you can tell the >> compiler / linker that the code is not dead code, and should not be >> removed. >> >In that event, I would consider the compiler was too clever for its own >good. A pointer to a function is a reference to that function, as surely >as a call is.
I cannot which compilers I used that had this behaviour, but it was very aggresive in it's dead code removal. There wer special #pragmas to indicate to the compiler that a functions was being called through some sort of indirect calling mechanism. AFAICR part of the "problem" on why it could not alwyas figure things out correctly was that the linker was single pass. Regards Anton Erasmus
"Anton Erasmus" <nobody@spam.prevent.net> wrote in message 
news:rgp503puvd06htu596f9t5i76rlrlqkssn@4ax.com...
>>> >>> >>> It might be optimising the routines away. If you have no direct calls >>> to these routines, the linker or compiler may remove the code as being >>> "dead code". Try adding a dummy call to one of the routines somwhere. >>> Your toolset probably has some directive with which you can tell the >>> compiler / linker that the code is not dead code, and should not be >>> removed. >>> >>In that event, I would consider the compiler was too clever for its own >>good. A pointer to a function is a reference to that function, as surely >>as a call is. > > I cannot which compilers I used that had this behaviour, but it was > very aggresive in it's dead code removal. There wer special #pragmas > to indicate to the compiler that a functions was being called through > some sort of indirect calling mechanism. AFAICR part of the "problem" > on why it could not alwyas figure things out correctly was that the > linker was single pass. > > Regards > Anton Erasmus
Indeed. IIRC I encountered this dead-code removal issue with a Keil8051 compiler some yrs back. I think there was a pragma available to let the tools know to not optimize the functions out.... Bo
Bo wrote:

> Indeed. IIRC I encountered this dead-code removal issue with a Keil8051 > compiler some yrs back.
I'm reasonably sure you remember that backwards. C51 would only err on the side of caution here (and complain about it rather loudly), i.e. it included all uncalled functions in the final program, at considerable costs to overall RAM consumption because it disturbs call tree analysis.

The 2024 Embedded Online Conference