Search code examples
cassemblycallbackx86xinu

C call back function from assembly (x86) and process switching


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        */

Solution

  • 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).