csuwr@warwick.ac.uk (Derek Hunter) (03/27/91)
Why, in the APCS section of the PRMs, does the example code suggest saving the /old/ pc onto the stack? # Mov ip,sp \ This is all from memory # StmFD sp!,{a1-a4} \ please forgive mistakes. # StmFD sp!,{v1-v6,fp,ip,lr,pc} # Sub fp,ip,#20 # # ... other bits # # LdmDB fp,{v1-v6,fp,sp,pc}^ Does LdmXX Rn,{...,pc}^ restore the flags from the next word, and not from the pc word, or is this a sneaky way of setting up some traceback block-type-thing (If so, where is the traceback word that describes which registers have been saved)? Also, if we can access the parameters relative to fp, why the distinction with the local variables? (If an answer to this involves stack segmentation, please feel free. I was confused by that concept.) It's a shame that Basic attempts to interpret sp! as the first half of a word indirection, rather than noting that it's inside assembly, and checking sp! type things for a following comma. Derek Hunter. +------------------------------------------------------------------------+ | Can someone who has actually done it, mail me (or post here) a piece | | describing the trouble that initiating shareware involves - amount of | | time spent in distributing upgrades to registered users, maintainance, | | answering fan/hate mail, evaluating bugfixes etc. Ta. | +------------------------------------------------------------------------+ .------------------------------------+---------------------------------------. | `Osmosis is an absorbing hobby.' | Derek Hunter csuwr@cu.warwick.ac.uk |
john@acorn.co.uk (John Bowler) (03/27/91)
In article <+?R&L0#@warwick.ac.uk> csuwr@warwick.ac.uk (Derek Hunter) writes: >Why, in the APCS section of the PRMs, does the example code suggest > saving the /old/ pc onto the stack? > ># Mov ip,sp \ This is all from memory ># StmFD sp!,{a1-a4} \ please forgive mistakes. ># StmFD sp!,{v1-v6,fp,ip,lr,pc} old? The lr value is saved to allow the function to return... I assume what you mean is the *current* pc (ie the last register in the above instruction). This is done because the pc points to the STMFD which saved it + 12 bytes. So you can find the code which made the stack frame, so you can find which registers were saved (and you know where, from the FP) so you can reclaim callee save registers (v1-v6) and hence find the register values in the *caller*, so you can write a stack traceback, (ie unwind the whole stack and find callee save register values in every function on the stack), so you can debug your programs. This is the only thing which APCS does to support debuggers... The instruction sequence is not mandated, instead [fp], when the relevant bits have been cleared, points *12 bytes beyond* a word which looks remarkably like an STMDB instruction. Ok, we admit it, you have to use that instruction sequence :-) ># Sub fp,ip,#20 ># ># ... other bits ># ># LdmDB fp,{v1-v6,fp,sp,pc}^ > >Does LdmXX Rn,{...,pc}^ restore the flags from the next word, and not > from the pc word, DB == decrement before. The registers are loaded from fp-4, so the pc value is skipped, and the saved lr value gets put into the pc. > or is this a sneaky way of setting up some traceback > block-type-thing Exactly. > (If so, where is the traceback word that describes which > registers have been saved)? In the code :-) >Also, if we can access the parameters relative to fp, why the distinction > with the local variables? (If an answer to this involves stack segmentation, > please feel free. I was confused by that concept.) It's totally horrible (but, on the other hand, it does work). Only the callee necessarily knows the number of local variables (because of separate compilation), therefore only the callee can check to see if there is enough room on the stack. If there isn't the callee has to call rather a lot of code (including malloc) to get some more stack; something has to save registers for this code to run. It is convenient to save the registers on the stack (actually, it is almost impossible to save them statically in a multi-threaded world), so they are saved on the ``old'' stack (ie the current stack segment when the callee is entered). The local variables, however, are on the new stack. Now, the stack extension code doesn't know how many arguments the function has, because:- i) The function doesn't tell it. ii) The function may be a varargs one, in which case it doesn't even know itself. So it cannot copy *all* the arguments onto the new stack, although it could copy the stack frame and saved arguments. Rather than doing this copying (which isn't required) the stack frame is left on the old stack (plus some junk from the stack extension code) and the local variables are on the new stack. Since there is no necessary relationship between these pieces of store the code needs two pointers; one (the fp) to get at the arguments and stack frame (for procedure return) and the other (the sp) to get at locals. As if this isn't bad enough the stack extension code can fix up the callee stack frame so that control returns to the extension code when the callee attempts to return. Then the extension code can free the stack frame if desirable. John Bowler