This code is for my undergraduate OS course. I am trying to call a function on the same stack of new_sp
and then return to whatever new_sp
was doing. It is not working and I'm not even sure how to debug it. Suggestions or a solution would be great. I tried to be through if there is anything I left out please let me know.
Notes: It is part of a special OS (xinu) we are using for the class. The function is called from within C code. A reference I was using: http://www.unixwiz.net/techtips/win32-callconv-asm.html
This part of the code is what saves a process to the stack before it is switched out. The stack pointed to by new_sp
was saved this way as well.
.text
.globl callsw
/*---------------------------------------------------------------------
* callsw - call is callsw(&old_sp, &new_sp, &call_back)
*---------------------------------------------------------------------*/
callsw:
/*keep all of the old contex switch instructions so it will work with
with cxtsw*/
pushl %ebp /* push ebp onto stack */
movl %esp,%ebp /* record current SP in ebp */
pushfl /* record flags */
pushal /* save general regs on stack */
/* save old segment registers here, if multiple allowed */
movl 8(%ebp),%eax /* Get mem location in which to */
/* save the old process's SP */
movl %esp,(%eax) /* save old process's SP */
movl 12(%ebp),%eax /* Get location from which to */
Here begins the code to switch to the call back function. I want the call back function to run and then return to executing the code associated with the new_sp
stack.
/* Switch to a new stach instead */
movl (%eax),%esp /* pick up new process's SP */
/* restore new seg. registers here, if multiple allowed */
popal /* restore general registers */
movl (%ebp),%eax /*keep old ebp for acess to arg 3*/
movl 4(%esp),%ebp /* pick up ebp before restoring */
/* interrupts */
popfl /* restore interrupt mask */
add $4,%esp /* skip saved value of ebp */
/* Switch to a new call back instead */
movl (%eax),%esp /* pick up new process's SP */
/* restore new seg. registers here, if multiple allowed */
popal /* restore general registers */
movl (%ebp),%eax /*keep old ebp for acess to arg 3*/
movl 4(%esp),%ebp /* pick up ebp before restoring */
/* interrupts */
popfl /* restore interrupt mask */
add $4,%esp /* skip saved value of ebp */
This is where I try to set up the stack and jump to the new process. The function I am calling is a C function with no arguments and no return value.
pop %ebx /* save the ra*/
movl %esp,%ebp /* move the base pointer to the bottom of the stack */
add -18,%ebp /* move stack down*/
/*set up stack and jump */
movl %ebp,%esp /* nothing on stack they are = */
movl %ebx, 0(%ebp) /* save ebp to stack */
movl %ebx, 4(%ebp) /* save ra */
movl 16(%eax),%ecx
JMP (%ecx) /* jump to call_back */
I think your problem is here:
popal /* restore general registers */
movl (%ebp),%eax /*keep old ebp for acess to arg 3*/
The popal
restores ALL the registers (including ebp) from the ones that were saved on the stack you're switching to. So movl (%ebp),%eax
loads a value from the new stack (actually the value of %ebp
belonging to the caller of callsw
. So when you later do
movl (%eax),%esp /* pick up new process's SP */
you're not getting the new process's SP -- you're getting the frame pointer from two levels up the stack (the caller of the caller of callsw).