Page 1 of 1

C invalidates my stack-variables

Posted: Wed Jul 15, 2015 10:01 pm
by tkausl
Hello,

i am working through the following tutorial: http://www.jamesmolloy.co.uk/tutorial_h ... 20PIT.html

My irq_handler_stub with the following code:

Code: Select all

irq_common_stub:
	pusha

	mov %ds, %ax
	push %eax

	mov $0x10, %ax
	mov %ax, %ds
	mov %ax, %es
	mov %ax, %fs
	mov %ax, %gs

	call irq_handler

	pop %eax
	mov %ax, %ds
	mov %ax, %es
	mov %ax, %fs
	mov %ax, %gs

	popa
	add $8, %esp
	sti
	iret
is working as expected. The irq_handler in c looks like this:

Code: Select all

typedef struct registers
{
   u32int ds;                  // Data segment selector
   u32int edi, esi, ebp, esp, ebx, edx, ecx, eax; // Pushed by pusha.
   u32int int_no, err_code;    // Interrupt number and error code (if applicable)
   u32int eip, cs, eflags, useresp, ss; // Pushed by the processor automatically.
} registers_t;
void irq_handler(registers_t regs){
   if (regs.int_no >= 40)
   {
       outb(0xA0, 0x20);
   }
   outb(0x20, 0x20);
   printf("Got HARDWARE-Interrupt %x\n", regs.int_no);
}
i noticed a problem and a endless stream of #13 interrupts. After debugging a little bit in bochs i found the problem, the irq_handler changes the stack-variables (the passed value):
http://prntscr.com/7t8vru
both mov-instructions above the green marked instruction change the top of the stack, the second stack-value on the right (the red marked) is actually my EAX which was pushed (and will eventually get poped) in assembler, so once the CPU reaches the instruction mov %ax, %ds it will interrupt me because EAX is at this point in time just garbage. How could i fix this problem?

Re: C invalidates my stack-variables

Posted: Wed Jul 15, 2015 10:05 pm
by thepowersgang
By passing the registers struct by value, you tell the C compiler that's free to clobber it (it's allowed to by the calling convention).
Instead, push esp and accept a pointer, and this problem will go away.

Re: C invalidates my stack-variables

Posted: Wed Jul 15, 2015 10:18 pm
by tkausl
thepowersgang wrote:By passing the registers struct by value, you tell the C compiler that's free to clobber it (it's allowed to by the calling convention).
Instead, push esp and accept a pointer, and this problem will go away.
Thanks, thats what i did now and it seems to work. Whats suprising me is that i get exactly one IRQ 0 which is the "Programmable Interrupt Timer Interrupt". I've never set it up nor do i get more than a single interrupt, whats this about?

Re: C invalidates my stack-variables

Posted: Wed Jul 15, 2015 11:01 pm
by alexfru
tkausl wrote:

Code: Select all

	sti
	iret
There shouldn't be sti before iret. iret will re-enable interrupts if needed (because it will restore eflags.if when retrieving eflags from the stack). If you enable interrupts in an ISR, you risk overflowing the stack or running into concurrency issues.

Re: C invalidates my stack-variables

Posted: Thu Jul 16, 2015 12:24 am
by Combuster
In other words, read the FAQ which has an entry on James Molloy, describing both these issues and a whole slew more. So, please be more careful about doing your research before posting.

Re: C invalidates my stack-variables

Posted: Tue Aug 18, 2015 11:05 am
by cfenollosa
tkausl wrote:
thepowersgang wrote:By passing the registers struct by value, you tell the C compiler that's free to clobber it (it's allowed to by the calling convention).
Instead, push esp and accept a pointer, and this problem will go away.
Thanks, thats what i did now and it seems to work. Whats suprising me is that i get exactly one IRQ 0 which is the "Programmable Interrupt Timer Interrupt". I've never set it up nor do i get more than a single interrupt, whats this about?
Hi,

I'm facing the same problem but I'm a bit confused as to how to pass the struct registers_t as a pointer since I still haven't implemented a memory manager. Could you please share your implementation?

Thanks

Re: C invalidates my stack-variables

Posted: Tue Aug 18, 2015 12:16 pm
by Roman
cfenollosa wrote:as a pointer since I still haven't implemented a memory manager
A pointer doesn't always point to a location in heap. I don't see any need for a memory manager here.

Re: C invalidates my stack-variables

Posted: Tue Aug 18, 2015 4:35 pm
by hgoel
I'm not sure how providing direct code examples is looked at here but you can look at IDT_DefaultHandler here for an example of how to make the registers struct be passed as a pointer: https://github.com/himanshugoel2797/Ape ... ster/idt.c

Essentially you push esp onto the stack before calling the handler function and set the handler function to take a pointer to the registers struct

Re: C invalidates my stack-variables

Posted: Wed Aug 19, 2015 7:26 am
by cfenollosa
hgoel0974 wrote:I'm not sure how providing direct code examples is looked at here but you can look at IDT_DefaultHandler here for an example of how to make the registers struct be passed as a pointer: https://github.com/himanshugoel2797/Ape ... ster/idt.c

Essentially you push esp onto the stack before calling the handler function and set the handler function to take a pointer to the registers struct
Huh, so that was it. For some reason I was obsessed with placing bytes in memory then passing that memory address to the C routine, but as Roman said, it can just point to the stack.

Thanks for your help!

Re: C invalidates my stack-variables

Posted: Wed Aug 19, 2015 10:21 am
by kzinti
cfenollosa wrote:
hgoel0974 wrote: Huh, so that was it. For some reason I was obsessed with placing bytes in memory then passing that memory address to the C routine, but as Roman said, it can just point to the stack.
The stack *is* in memory...