Mikey Chen
Mikey Chen

Reputation: 2420

Stack frame manipulation in xv6 only works correctly with a printf()?

I'm trying to make an extension of the xv6 kernel for my Operating Systems class and I'm running into a strange bug that's taken up 5 hours of my time to no avail. I implemented a signal handling system that inserts a signal handling function and arguments manually into the instruction pointer, and now I'm trying to save the volatile register values by pushing them onto the user stack, then popping them into their original registersafter the signal handler returns.

Here is how I set up the stack frame:

  void handle_signal(int signo, struct trapframe *tf){
         *((uint*)(tf->esp-4)) = tf->eip;
         *((uint*)(tf->esp-8)) = proc->tf->eax;
         *((uint*)(tf->esp-12)) = proc->tf->ecx;
         *((uint*)(tf->esp-16)) = proc->tf->edx;
         *((uint*)(tf->esp-20)) = signo;
         *((uint*)(tf->esp-24)) =(uint)proc->pop;
         tf->esp = tf->esp-24;
         tf->eip = (uint)(proc->sigHandlers[signo]);
  }

So I'm setting the bottom of the stack to the old instruction pointer, pushing the volatile registers, pushing the signal handler argument on, pushing the function that will pop the registers, and then finally setting eip (the instruction pointer) equal to the address of the signal handler.

void
popregs(void){
    sleep(5);

    __asm__ (
    "add $16, %esp;"
    "pop %edx;"
    "pop %ecx;"
    "pop %eax;"
    "ret");
}

Here's the function I'm using to pop the registers. What's really strange is that my program will do the right thing(correctly save the value of the registers) if I have that sleep(5) or a printf() statement right before the inline-assembly, but if I remove it, I get a "out of bounds code" statement which I'm assuming is the xv6 equivalent of a segmentation fault. Even when it does correctly save the values of the registers, I can tell the stack is getting messed up because the handlers fail on later signal handling calls.

I'm struggling to deal with this since I don't really know how to debug assembly well - does anybody have any idea what might be happening?

Upvotes: 3

Views: 1402

Answers (1)

FPK
FPK

Reputation: 2098

When entering a procedure (like popregs), the compiler normally sets up a stackframe by modifying esp. So if the add $16,%esp is correct, depends on the fact, if the compiler subtracted 8 from esp or not. If you remove the sleep(5), the compiler probably does not generated code to modify esp as the procedure is a leaf procedure so you need an add $8,%esp instead.

Upvotes: 4

Related Questions