We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
Hi to everyone,
i am trying to use pointer functions to do indirect branch in C code, i am working with an NXP ARM LPC2478
This is my code:
// in internal flash unsigned char* MD5BuffSE(unsigned char *pBuffer, unsigned long lOffset, unsigned long lSize) { ... } g_CriptAddress.pMd5 = (void*)&MD5BuffSE; // g_CriptAddress is an array of void* ..... // in internal ram @ 0x4000fd00 typedef unsigned char* (*MD5)(unsigned char* , unsigned long , unsigned long ); MD5 Md5 = (MD5)g_CriptAddress.pMd5; if(memcmp(Md5((byte*)TOS_START, 0, TOS_DIM),pDataProt->ChkSumMd5,16)!=0) return false;
with this code all seems to works fine (code jumps to the right address and returns well), but next branch causes execution to fail with an abort exception.
if i use MD5BuffSE directly all works, but i noticed that compiler insert a long ARM to ARM veneer
so i ask myself if exist a way to tell compiler that it has to consider typedef MD5 a far call or to force it to create a long ARM to AMR veneer
what happens when i call a thumb function from arm code with indirect branch?
Lorenzo
For starters, you shouldn't mix up function pointers and data pointers like that:
g_CriptAddress.pMd5 = (void*)&MD5BuffSE; // g_CriptAddress is an array of void*
It's apparently easy to arrive at the belief that a (void*) in C could hold literally arbitrary pointers. Well, close enough, but function pointers are the exception from that rule.
As a rule of thumb one should never cast a function pointer. If it seems like the need to do so arises, that's usually a hint you're working towards creating undefined behaviour of your program. And in the few cases where it's actually the correct thing to do, you still shouldn't cast to (void*), nor any other data pointer type --- use a function pointer type instead.
if i have well understood, you are saying that i have to do something like this:
// in internal flash unsigned char* MD5BuffSE(unsigned char *pBuffer, unsigned long lOffset, unsigned long lSize) { ... } typedef unsigned char* (*MD5)(unsigned char* , unsigned long , unsigned long ); g_CriptAddress.pMd5 = &MD5BuffSE; // g_CriptAddress.pMd5 is an MD5 type ..... // in internal ram @ 0x4000fd00 MD5 Md5 = g_CriptAddress.pMd5; if(memcmp(Md5((byte*)TOS_START, 0, TOS_DIM),pDataProt->ChkSumMd5,16)!=0) return false;
it seems to do the same thing, compiler do not add a long ARM to ARM Veneer
is this what you call "function pointer type"?
[LPC2478 is an ARM7TDMI.]
A call via a function pointer will typically generate ADR lr, ...; BX <reg>* which needs no veener and can handle pointers to ARM state and Thumb state functions as long as the target function has been built for interworking (that is, uses BX <reg> to return). If the target function is in ARM state the low two bits of the function pointer will be zero. If the target function is in Thumb state the lowest bit of the function pointer will be one.
When you say "but next branch causes execution to fail with an abort exception" do you mean the next branch, the next call of any function or the next call via that function pointer?
If you mean the next call via that function pointer then I would suspect that your function pointer had been overwritten somehow -- can you check its value when it works and when things go wrong?
[*] or just BLX <reg> on newer cores
[By the way, I agree that casts are evil and best avoided whenever possible -- and not just for function pointers.]
That's insufficient evidence to support that conclusion. The difference this make could just as well manifest itself at this point of the code, instead:
g_CriptAddress.pMd5 = &MD5BuffSE; // g_CriptAddress.pMd5 is an MD5 type
One possible problem that can be caused by mixing function pointers with data pointers is that the compiler might be using shorter pointers for data than for code, which would cause a (void*) cast to lose significant bits. This would more likely cause a code difference in the above line than in the place where a call is made via mMD5.
To really check whether the change of type for pMD5 makes a difference, you should compare program hex files before and after the change.
thanks to all, i found what was wrong and it was a problem caused by MY code. so problem solved
thank to you scott, 'cause you clean all my doubts about indirect branch and Veneer generation
"A call via a function pointer will typically generate ADR lr, ...; BX <reg>* which needs no veener and can handle pointers to ARM state and Thumb state functions as long as the target function has been built for interworking (that is, uses BX <reg> to return)."
thank to you Hans for the tip about function pointers, now compiler alerts if i call a function with wrong parameters
problem: code in ram corrupts itself and stack generates an abort exception on next return