- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I was stepping through my code trying to figure out how a block of data was being overwritten by some of the initialization code on my project. I was rather surprised to find the data changed as soon as I stepped into any one of several simple functions - it was overwritten with the argument for the simple function, even before I had executed any statements in the body of the routine. When I looked at the assembly code generated for the function prolog, it was obvious what the problem was.
; flat prologue begin
; Expand callers frame 26 words.
mov %g1, %sp
pfx %hi(104)
subi %sp, %lo(104)
sts , %fp
; save call preserved regs
sts , %o7
sts , %l0
; Set frame pointer
mov %fp, %g1
; flat prologue end
pfx 17
st , %o0
pfx 18
st , %o1
pfx 19
st , %o2
The prolog sets up a stack frame (bounded by %fp at the top and %sp at the bottom), but then when it saves the arguments (%o0, %o1 and %o2), it uses a positive offset from %fp! This means the arguments are saved in the space allocated for saved arguements in the callers stack frame. Most of the time this works by accident, and doesn't cause an obvious problem, since the caller has made the same mistake (and thus isn't using this space). But it is noticeable when calling a routine that saves arguments on a newly set-up stack: it saves its arguments 17 32-bit words above the top of the stack (in memory that is probably allocated to something else). Fortunately, as a work around one just has to make sure there 23 32-bit words available above the initial stack pointer when setting up a stack. I haven't figured out how functions with more than six 32-bit arugments are actually working, I'm planning on avoiding them.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
On reflection, I don't think this is a bug after all (or maybe just a a documentation bug). The description of the Nios stack frame in the "ABI Summary" section of the manual "User's Guide for Altera Nios" v1.0 is not as clear as it might be, and I think I misunderstood it. This became clear when I tried to figure out how things worked when there were more than 6 arguments to be passed to a function.
Stack space for the arguments to a function (including arguments passed in registers %o0 - %o5) is indeed allocated in the frame of the calling function. However, these arguments aren't pushed on to the stack - the space must be allocated by setting the %sp register to point 23 32-bit words below the top of the stack before making any calls (further if the calling a function with more than 6 arguments). Indeed, the startup code from Altera does this. Thus, although the %fp and %sp registers mark the boundaries of the stack space a routine is responsible for allocating, they do not mark the boundaries of where a routine is allowed to write to. In addition to the stack space a routine has allocated, a routine is free to write to the stack space allocated by its caller for its argument save area. When setting up a new stack, this argument save area has to be provided before calling any routines.- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page