avr-gcc-list
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [avr-gcc-list] When does the Stack Frame Pointer (Y) get setup?


From: Bob Paddock
Subject: Re: [avr-gcc-list] When does the Stack Frame Pointer (Y) get setup?
Date: Fri, 6 Jul 2012 10:57:17 -0400

>> Did I miss anything in the documentation that would tell me not to
>> use auto variables in .initX sections after .init2 that sets the
>> stack?
>
> If you declare the function being "naked", you cannot expect the
> compiler to allocate a stack frame.

What one expects and reality are often different.  Before I submit a
patch for the documentation, to prevent others from shooting
themselves in the foot, I wanted to make sure I understood how stack
frames are working.

In looking at the .lss file, I see something that I do not understand,
when comping code for the
XMega128A1 using GCC 4.7.1-rc1

Is the timing of the XMega OUT instruction different than a non-XMega
part, in that it would prevent an interrupt between two sequential
OUT instructions?  What happens when an interrupt happens between the
instructions that manipulate the stack pointer in the epilogue/prologue?
If there is 256 bytes of stack head-room between the heap/bss maybe nothing
(it would not be noticed as a problem).

Going back to Anatoly original OS_Main/OS_Task patch:

http://www.mail-archive.com/address@hidden/msg03812.html

Using his example code from that email, copied in to the file main.c,
compiling using the Makefile at the end of this message, Non-XMega run:

# Non-XMega the stack manipulation is properly protected.
# The non-XMega parts delay a cycle when enabling interrupts,
# hence it is safe to save stack_hi, enable interrupts, save_lo,
# this code disables interrupts when modifying the stack pointer 0x3E/0x3F:
00000090 <__prologue_saves__>:
[snip pushs]
  b4:   cd b7           in      r28, 0x3d       ; 61
  b6:   de b7           in      r29, 0x3e       ; 62
  b8:   ca 1b           sub     r28, r26
  ba:   db 0b           sbc     r29, r27
  bc:   0f b6           in      r0, 0x3f        ; 63
  be:   f8 94           cli ; Disable Interrupts
  c0:   de bf           out     0x3e, r29       ; 62
  c2:   0f be           out     0x3f, r0        ; 63 Enable Interrupts are 
delayed
till after next instruction
  c4:   cd bf           out     0x3d, r28       ; 61
  c6:   09 94           ijmp

000000c8 <__epilogue_restores__>:
[snip pops]
  f0:   0f b6           in      r0, 0x3f        ; 63
  f2:   f8 94           cli ; Disable Interrupts
  f4:   de bf           out     0x3e, r29       ; 62
  f6:   0f be           out     0x3f, r0        ; 63 Enable Interrupts are 
delayed
till after next instruction
  f8:   cd bf           out     0x3d, r28       ; 61
  fa:   ca 2f           mov     r28, r26
  fc:   db 2f           mov     r29, r27
  fe:   08 95           ret

I'm fine with the above code, however I question this
XMega run:

# This code DOES NOT disable interrupts when modifying the stack
# pointer 0x3D/0x3E:
000002b0 <__prologue_saves__>:
[snip pushs]
 2d4:   cd b7           in      r28, 0x3d       ; 61
 2d6:   de b7           in      r29, 0x3e       ; 62
 2d8:   ca 1b           sub     r28, r26
 2da:   db 0b           sbc     r29, r27
 2dc:   cd bf           out     0x3d, r28       ; 61
; [What happens if an interrupt happens between these two out instructions?]
 2de:   de bf           out     0x3e, r29       ; 62
 2e0:   19 94           eijmp

000002e2 <__epilogue_restores__>:
[snip ldds]
 306:   ce 0f           add     r28, r30
 308:   d1 1d           adc     r29, r1
 30a:   cd bf           out     0x3d, r28       ; 61
; [What happens if an interrupt happens between these two out instructions?]
 30c:   de bf           out     0x3e, r29       ; 62
 30e:   ed 01           movw    r28, r26
 310:   08 95           ret

For anyone that wants to reproduce:

# -------------- Cut Here main.c --------------
__attribute__ ((noinline))
int fn0(long a1, long a2, long a3, long a4, long a5)
{
    return 0;
}

// Note this is commented out, OS_MAIN/OS_TASK are not relevant at this point:
//__attribute__ ((OS_main))
int main(void)
{
   volatile long long a; // local var, need function frame

   a = 1;

   return fn0(1, 2, 3, 4, 5); // use call-saved regs
}
# -------------- Cut Here --------------

And this Makefile of mine:

# -------------- Cut Here Makefile --------------
MCU=atxmega128a1
#
# NOTE, that this is commented out, it is the important point.
# Uncomment to see the Xmega main.lss output and compare.
#
#M_MCU=-mmcu=$(MCU)

SRC=main.c
TARGET=main
OBJDIR = .

CSTANDARD = -std=gnu99
CFLAGS += $(CSTANDARD)

# Functions prologues/epilogues expanded as call to appropriate
# subroutines. Code size will be smaller.  Use subroutines for function
# prologue/epilogue. For complex functions that use many registers (that needs
# to be saved/restored on function entry/exit), this saves some space at the
# cost of a slightly increased execution time.
CFLAGS += -mcall-prologues

#    -adhlns...: create assembler listing
CFLAGS += -Wa,-adhlns=$(<:%.c=$(OBJDIR)/%.lst)

# Be verbose:
CFLAGS += -v

ALL_CFLAGS = -v $(M_MCU) $(CFLAGS)

# Tools:
OBJDUMP = avr-objdump
CC = avr-gcc
SHELL = sh
REMOVE = rm -f

OBJ = $(SRC:%.c=$(OBJDIR)/%.o) $(CPPSRC:%.cpp=$(OBJDIR)/%.o)
$(ASRC:%.S=$(OBJDIR)/%.o)

all: build

build: elf lss

elf: $(TARGET).elf
lss: $(TARGET).lss

# Create extended listing file from ELF output file.
%.lss: %.elf
# -h Display section headers
# -S Intermix source code with disassembly
# -z Do not skip blocks of zero when disassembling
        $(OBJDUMP) -h -S -z $(OBJDIR)/$< > $(OBJDIR)/$@

%.elf: $(OBJ)
        $(info )
        $(info ALL_CFLAGS = $(ALL_CFLAGS))
        $(info )
        $(CC) $(ALL_CFLAGS) $^ --output $(OBJDIR)/$@ $(LDFLAGS)

# Compile: create object files from C source files.
$(OBJDIR)/%.o : %.c
        $(CC) -c $(ALL_CFLAGS) $< -o $@

clean:
        $(REMOVE) $(TARGET).elf
        $(REMOVE) $(TARGET).lss
# -------------- Cut Here --------------



reply via email to

[Prev in Thread] Current Thread [Next in Thread]