Stack Underflow

Go To Last Post
8 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm using AVR Studio 4.13 #528 to simulate an 8515. My C code was compiled with gcc and I'm not doing anything "clever" to the stack. I am merely calling a function and returning at the end of it. However, AVR Studio *CONSISTENTLY* declares a

AVR Simulator: Stack Underflow at 0x0428

at this one particular point in my code.

I have single-stepped right up to the RET instruction and it all looks good to me. Here's what I see (all numbers are in hex) before I hit F11:

SP=253 PC=428
00000428: 9508 RET
00000250: 00 01 04 26 07 85 02 5F

This looks 100% Kosher to me. I'm about to pop 785 from the stack, which should return me to where I expect to be. I hit F11, get the error and find myself at:

SP=255 PC=785
00000785: 3F8F CPI R24,0xFF
00000250: 00 01 04 26 07 85 02 5F

This is precisely where I would expect to be, so why an error?

Naturally, my first guess is that the simulator is screwing up, but there's no denying that this part of my code isn't working as I would expect, so perhaps the simulator is right... but how could it be?

Does anyone have a guess why I'm getting an underflow error here when my stack pointer is less than 260?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Did you set the correct AVR model, both in the project (build) setup and in the simulator options?
Are you sure that the subroutine/function you are returning from does not thrash the stack in any way?
Can we see the code?
Did you search these forums for "stack underflow"? (I get 20 hits...)

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

JohanEkdahl wrote:
Did you set the correct AVR model, both in the project (build) setup and in the simulator options?
Yes, I believe so. When I compile, I'm using -mmcu=atmega8515, and I have ATmega8515 selected as the target device for the AVR Simulator debugger.

JohanEkdahl wrote:
Are you sure that the subroutine/function you are returning from does not thrash the stack in any way?
Pretty certain. I've single-stepped through the function call with F10 and I see no changes to the 785 return vector or anything above it on the stack.

JohanEkdahl wrote:
Can we see the code?
I'll try to paste it here. I have not yet done a code reduction to see how much I can remove and still reproduce the error. It's such a quirky thing that I'm afraid that if I change anything that the symptoms will change too.

Calling the function:

Err = WriteHolding(Addr++,
            RevWord(Buffer.WriteMultipleRegsReq.Data[i]));

Which calls:

static uint8_t WriteHolding(uint8_t Addr, uint16_t Data)
{
    uint8_t Offset;

    switch (Addr)
    {
(many cases removed)
        case HoldAddrGeneral:
        case HoldAddrGeneral + 1:
        case HoldAddrGeneral + 2:
        case HoldAddrGeneral + 3:
        case HoldAddrGeneral + 4:
        case HoldAddrGeneral + 5:
            Settings.General[Addr - HoldAddrGeneral] = Data;
            WriteEEPROM((uint8_t *) &Settings.General[Addr - HoldAddrGeneral],
                (uint8_t *) &EEContents.General[Addr - HoldAddrGeneral],
                sizeof(Settings.General[Addr - HoldAddrGeneral]));
            return 0;
        default:
            return ErrIllegalDataAddr;
    }
}

static void WriteEEPROM(void *RAM, void *EEPROM, uint8_t Len)
{
    eeprom_write_block(RAM, EEPROM, Len);
}

uint16_t RevWord(uint16_t X)
{
    return (X << 8) | (X >> 8);
}

JohanEkdahl wrote:
Did you search these forums for "stack underflow"? (I get 20 hits...)
Yes, and the things I see are warnings not to pop too much off the stack (I'm not manually pushing or popping anything) and a warning that AVR Studio (certain versions) will erroneously report a stack underflow error in certain instances when you do an ICALL or EICALL instruction. This function is being called with an RCALL, so I don't think they apply.

Besides, my code DOES seem to fail at this point, so even though I don't see why the simulator is complaining of an error at this point, I have to agree that something weird is happening here.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, it looks like this problem is entirely in the simulator. It seems to be a coincidence that the simulator is throwing an underflow error around the same spot where my code is going awry.

For those who are curious, here is why the latest AVR Studio is generating stack underflow errors in my code:

AVR Studio is clearly keeping an internal counter which increments each time you CALL (RCALL, ICALL, etc.) and decrements each time you RET (or RETI). If this number ever goes negative, then it assumes you have returned more times than you called, and therefore the stack must have underflown.

At first glance, this seems like a logical way to watch for stack underflows, but it is an oversimplification. The problem is that compilers such as gcc will do tricky things like pushing an address on the stack and then calling RET to jump to that address. It did this when it compiled my switch statement above, for example.

So even though there is nothing wrong with pushing an address on the stack and calling RET, this screwed up the CALL/RET counter balance, because there was no CALL to offset the RET. Here is some example code which proves my case:

.globl main
main:
1:
    ldi   r30, 0x1E  ; Do a jump by pushing the address...
    ldi   r31, 0x00
    push  r30
    push  r31
    ret              ; and calling ret

JumpTo:
    rjmp  1b

This code is perfectly legal, but AVR Studio will stupidly think the RET underflows the stack.

Atmel *SHOULD* be looking at the stack pointer to determine underflows. I have no idea why they didn't.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

yeah, thats the spirit, feckin' underflows, who cares, it works. Spent the entire day try to solve why it fdoes this. Then again I am playing with the stack.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I follow your explanation, but no way can I see anyone writing a Simulator do CALL/RET counting.

OTOH, I have just tried this:

	.include "m128def.inc"
;	.include "m8515def.inc"
	.def temp = r16

reset:
    ldi	temp,low(RAMEND)
    out	SPL,temp          	;init Stack Pointer     
    ldi	temp,high(RAMEND)
    out	SPH,temp        	
main:
    ldi   r30, 0x1E  ; Do a jump by pushing the address...
    ldi   r31, 0x00
    push  r30
    push  r31
    ret              ; and calling ret

    .org  0x1E
JumpTo:
    nop
    rjmp  main

And sure enough Simulator1 produces "stack underflow"
and Simulator2 is fine.

Both simulators seem to perform the indirect jump correctly. Unfortunately Simulator2 will not do a m8515.

It would be interesting to see if Studio4.13 will behave the same. ( I used Studio4.15 )

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Gre7g wrote:
I'm using AVR Studio 4.13 #528 to simulate an 8515.
That's a pretty old version of AVR Studio (March 2007). The latest, I believe, is 4.16 SP1 build 638 (May 2009). I recall AVR Studio having a problem incorrectly reporting stack underflow. I believe it's been fixed. I'd upgrade to the latest version and give it a try.

Don

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Don,

I think the bug in question was:

Quote:
4736: The simulator could start generate Stack Overflow messages for a program using IJMP instead of RET/IRET to return from a function. This has been fixed.

This appears in the release notes of 4.13 in fact.

Searching the release notes (of 4.16SP1) for the word "stack" this is the first hit.