Page 1 of 1

stack transition in C

Posted: Sun Nov 20, 2005 11:14 pm
by earlz
I am having some problems changing my stack in C, i use a seperate selector for my stack so that if i overpush/pop my stack i get a page fault
It looks as if it works fine but i get a gpf
and it gets the gpf at eip 3 which makes no sense
here is my asm and C code

Code: Select all

;asm
_gdt_flush:
    lgdt [_gp]        ; Load the GDT with our '_gp' which is a special pointer
    mov ax, 0x8      ; 0x10 is the offset in the GDT to our data segment
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    pop edx
    pop ecx
    mov ax,0x18 ;stack gets special selector
    mov ss,ax
    jmp 0x10:flush2   ; 0x08 is the offset to our code segment: Far jump!
flush2:
mov esp,0x1000 ;now if we go past the stack limit we get a nice page fault
mov ebp,0x1000
push ecx
push edx
    ret

//C code
void gdt_install()
{
    /* Setup the GDT pointer and limit */
    gp.limit = (sizeof(struct gdt_entry) * 4) - 1;
    gp.base = &gdt;

    /* Our NULL descriptor */
    gdt_set_gate(0, 0, 0, 0, 0);

    /* The thrid entry is our Code Segment. The base address
    *  is 0, the limit is 4GBytes, it uses 4KByte granularity,
    *  uses 32-bit opcodes, and is a Code Segment descriptor.
    *  Please check the table above in the tutorial in order
    *  to see exactly what each value means */
    gdt_set_gate(2, 0, 0xFFFFFFFF, 0x9A, 0xCF);

    /* The second entry is our Data Segment. It's EXACTLY the
    *  same as our code segment, but the descriptor type in
    *  this entry's access byte says it's a Data Segment */
    gdt_set_gate(1, 0, 0xFFFFFFFF, 0x92, 0xCF);
    /*The fourth entry is our stack segment. The base address
    * is 0x1000, the limit is 0x1000 or 1 4k page(1024 stack entries), it uses 4Kbyte 
    * granularity, is 32bit, and is a data/stack segment
    */
    gdt_set_gate(3,0x1000,1,0x92,0xCF);

    /* Flush out the old GDT and install the new changes! */
   
    gdt_flush();
    __asm("pop %eax");
    __asm("ret");
}


Re:stack transition in C

Posted: Sun Nov 20, 2005 11:58 pm
by AR

Code: Select all

    gdt_flush();
    __asm("pop %eax");
    __asm("ret");
This is very hacky and I don't see the point of it either. I'm inclined to think that you may be popping the EBP value into EIP with that RET.

Re:stack transition in C

Posted: Mon Nov 21, 2005 1:56 am
by Candy
AR wrote:

Code: Select all

    gdt_flush();
    __asm("pop %eax");
    __asm("ret");
This is very hacky and I don't see the point of it either. I'm inclined to think that you may be popping the EBP value into EIP with that RET.
You're messing with the stack. Prepare to do some late-night hacking.

Other than that, why do you want the ebp not to be used off the stack? If you set up a stack, it should be on there.




Small summary:

You empty the stack.
You push two values (which are probably the old eip and the value above that).
You then return from that function, popping the eip into the current eip, IE, actually returning.
You then, in that function, pop the top value into eax and then you return, popping a third value (which isn't on the stack!) into the eip register.

You're overrunning the stack.

Re:stack transition in C

Posted: Mon Nov 21, 2005 3:16 am
by earlz
yes i just now noticed that I was over running it, i know, i will put my gdt init in my startup code(before main and it is what gets executed by the bootloader)