GCC ruins stack

Programming, for all ages and all languages.
Post Reply
evoex
Member
Member
Posts: 103
Joined: Tue Dec 13, 2011 4:11 pm

GCC ruins stack

Post by evoex »

I'm trying to compile my kernel, and all worked fine, until I turned on optimization to -O3.

The relevant code is as follows (A lot has been removed to locate the error, so it's not the actual code):

Code: Select all

void outportb(uint16_t port, uint8_t value);

void isr_handler(isr_argument_t regs)
{
  if(__LIKELY(regs.int_nr >= IRQ0 && regs.int_nr <= IRQ15)) {
    if(regs.int_nr >= IRQ7) {
      outportb(0xA0, 0x20);
    }

    outportb(0x20, 0x20);
  }
}
And outportb:

Code: Select all

outportb:
	mov	dx, word [esp+4]			; dx = port
	mov	al, byte [esp+8]			; al = value
	out	dx, al
	ret
However, this gets compiled to the following:

Code: Select all

push   %ebp
mov    %esp,%ebp
sub    $0x18,%esp
mov    0x2c(%ebp),%eax
lea    -0x20(%eax),%edx
cmp    $0xf,%edx
ja     c0101926 <isr_handler+0x46>
cmp    $0x26,%eax
ja     c0101910 <isr_handler+0x30>
movl   $0x20,0xc(%ebp)                       ; ?????????????????????
movl   $0x20,0x8(%ebp)                       ; ?????????????????????
leave  
jmp    c0103100 <outportb>
I've traced the error back to the lines with the question marks. Those shouldn't be there, and I'm not sure how they ever came to be.
It seems like it comes from the outportb(0x20, 0x20) instruction. However, why does this function overwrite the parameters, even though the calling function may still actually use them (one of them happens to be the segment register value, causing a crash)?

I guess I have to specify to GCC that I don't want it to wreck the parameters. How do I do that?

PS: This function is only called from assembly language.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: GCC ruins stack

Post by Brendan »

Hi,

That looks like a perfectly valid tail call optimisation to me.

The problem is that you want "isr_handler()" not to modify it's own arguments. You could try "void isr_handler(const isr_argument_t regs)" but then you won't be able to change the caller's registers if/when you need to.

The normal approach would be to pass a pointer to the structure rather than passing the structure itself, with "void isr_handler(isr_argument_t *pointer_to_regs)". This has the added advantage that later on you could do something like "return kernel_API(pointer_to_regs)" and it will work (rather than creating a copy of the entire structure to pass to "kernel_API()" so that "kernel_API()" can only modify a discarded copy).


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
evoex
Member
Member
Posts: 103
Joined: Tue Dec 13, 2011 4:11 pm

Re: GCC ruins stack

Post by evoex »

Thanks for your answer!

I've tried making the structure const, but it didn't fix it.
But your other idea sounded like a good solution to me. Good point about passing it as a parameter to another function - at first I didn't want to waste the instructions, but it will probably be faster.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: GCC ruins stack

Post by Combuster »

How are you calling the code? If you do it from assembly you'll have to remember that there is no convention that arguments on the stack must be preserved.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
Post Reply