Function Pointers and FCALL - Stack memory issues

取消
显示结果 
显示  仅  | 搜索替代 
您的意思是: 

Function Pointers and FCALL - Stack memory issues

3,331 次查看
lak
Contributor I
Hi all,
 
I had been debugging on an ILLEGAL_BP  hit on my EVB9S12XEP100 using codewarrior 4.6 for the past few days. My code is built on a LARGE MEMORY MODEL and and has a number of function pointer tables which is fetched by a small OS and run on timely manner.
 
I did observe that the illegal bp occurs very consistently when my interrupts are enabled and as an example, tried sending some serial data through SCI1 which was configured to receive interrupt.
Always, the stack used to get corrupted and hence not finding a valid return address, the code would crash.
 
Further debugging, the interesting thing is whenever the function pointers are accessed, the FCALL is fetched which expects a pre-aligned stack as shown below containing the function pointer address and the return address.
Before FCALL is called, there are some 10 assembly instructions generated which will arrange the addresses in the stack as expected by the FCALL.
 
/*----------------- FAR FUNCTION PTR Call ------------------------------------------------
  Parameters:
  - the normal function parameters according
  - on the stack: address of function to be called
  Result :
  - Function is called with unchanged D & X register
  - Y is changed
  - the function address is removed from the stack before the function call

  Stack layout (in):
    5, SP  : page of function to be called
  3-4, SP  : offset of function to be called
  1-2, SP  : offset of return address
    0, SP  : page of return address
       function ptr to be called (3 bytes)
       return address caller     (3 bytes)
  Idea:
       exchanging function ptr and return address
       because function ptr and return address have the page at different offset a
       complicated transformation must be done
              before        after
      0,SP    page ret  A    page fkt  F
      1,SP    high ret  B    high fkt  D
      2,SP    low  ret  C    low fkt   E
      3,SP    high fkt  D    page ret  A
      4,SP    low fkt   E    high ret  B
      5,SP    page fkt  F    low  ret  C
*/
void __far _FCALL(void)
{
  __asm {
                          
    LDY   1, SP                    ; A B C D E F    Y = B C   ; 2 bytes
    MOVW  3, SP,  1, SP            ; A D E D E F    Y = B C   ; 4 bytes
    MOVB  0, SP,  3, SP            ; A D E A E F    Y = B C   ; 4 bytes
    MOVB  5, SP,  0, SP            ; F D E A E F    Y = B C   ; 4 bytes
    STY   4, SP                    ; F D E D B C    Y = B C   ; 2 bytes
                                   ; F D E A B C              ;16 bytes
    RTC                            ; call function pointer
  }
}
 
 
So, what I strongly suspect is during a call through Function ptr and an interrupt occurs, the micro would jump to the isr and before it does, it would stack the present address and when returns back to the FCALL, the FCALL routine computes a wrong return address based on the modified stack by the interrupt.
 
I tried two methods to validate my observation.
First, I verfied this by replacing the function pointers with a direct call to the function and all is fine over here.
Second, I tried by disabling the interrupts before function pointer call and re-enabling the interrupts back after return from the function pointer. This also works fine.
 
Hence, I need some advice on how to go about this(unless my above observation is illogical??)
 
I can't adopt the second method since I need interrupts to be active as the functions could be large nor the first one as the OS needs them.
 
Would modifiying the FCALL method with instructions to disable and enable the interrrupts at the begining and end  a good idea?
Or is there any other alternative.  please advice..
 
with regards,
Lak
 
 
标签 (1)
0 项奖励
回复
4 回复数

1,484 次查看
CompilerGuru
NXP Employee
NXP Employee
I doubt a bit that the problem is the shown _FCALL runtime routine, but that the bug
does not occur if you use direct calls is strange.
Did you check that you have enough stack space left? Disabling the interrupts while calling those function could also just help on the stack usage, also I could imagine that direct calls cause less spill space to be used.
Another suspect are the OS and all interrupt handlers, do they properly save all used page registers?

Daniel


0 项奖励
回复

1,484 次查看
lak
Contributor I
Hi,
I have enough stack reserved(around 1.5K - to be very comfortable ) and all my interrupt handlers are filled.
what i am seeing is that as soon as function ptr is called, the code generated is similar to this.
This code actually forms the stack layout with the return and calling function address as required by the FCALL.
 
Ptr_array[index]();
 ||
 V
 
 
FE93AB LDAB #3
FE93AD LDAA 1,SP
FE93AF MUL
FE9390 MOVB #127,0X0010
FE9395 TFR D,X
FE9397 GLDY 32990,X
FE939C GLDAA 32989,X
FE93A1 PSHY
FE93A2 PSHA
FE93A3 CALL 0xc74A,0x00  /* This is the call to the FCALL function mentioned in in my previous post */
 
Now, my suspicion is while it is executing the above instructions any where before FCALL and an interrupt occurs,
the cpu might not be stacking all the registers affected during jump to ISR and so when it returns, the valued put to the stack could be different if the registers would have changed.
 
What all the registers saved to stack for an isr call ?
I did a trace of the instructions executed from the debugger and observed that whenever the cpu was interrupted at FE9397, it returned back to here, entered FCALL and inside FCALL, after RTC, it crashed.
 
This makes me think that stack is somewhere corrupted during ISR switching and still wondering why?
 
 
with regards,
Lak
 
 
0 项奖励
回复

1,484 次查看
CompilerGuru
NXP Employee
NXP Employee
It's a bug in the interrupt handlers if they do not properly stack all modified registers, not a bug in _FCALL.
I would check all your handlers if they do save GPAGE (at address 0x10), if they are potentially modifying it.
The core stacks all internal CPU registers (CCR,X,Y,D,PC) but it does not safe the page registers on its own,
so the entry code of the interrupt handler has to do that.
When I remember right (out of my memory, and has been a while) the compiler does it if you use the -CpGPAGE=0x10 option (actually I'm not sure about the large memory model, did not use that).

Daniel
0 项奖励
回复

1,484 次查看
lak
Contributor I
Hi Daniel,
Your suspicion was very much right. The GPAGE register was not being restored by the core and neither I had worried about it. Actually if you see the instruction at FE9390 MOVB #127,0x0010 , I had neglected this which loads the GPAGE register with a value of 0x7F.
So, if an isr is hit after this and on return, the further GLD instructions would not be guaranteed for the correct GPAGE value. This would further result in not loading the proper function address on to stack.
 
Thanks for your advice, now with the GPAGE access enabled, it is working properly. Thanks a lot again
 
with regards,
Lak
0 项奖励
回复