problems with stack and pointers

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Andrej
Posts: 19
Joined: Wed Jun 22, 2016 2:52 pm

problems with stack and pointers

Post by Andrej »

Hello,
I have the following test code:

Code: Select all


int printint(int i);

struct test{
    int i;
};

void f(struct test *t)
{
    printint(t->i);
}

void f2(struct test t)
{
    printint(t.i);
}

struct test t1;

int main()
{
    struct test t2;
    t1.i = 9;
    t2.i = 5;
    f(&t1);
    f(&t2);
    f2(t1);
    printint(t2.i);
    __asm__("jmp .");
}
The required output would be: 9, 5, 9, 5. But instead of that I get: 9, 0, 9, 5. Could anybody help me to investigate this?
My os is using 32 bit protected mode. The code snippet which is changing to protected mode:

Code: Select all

.code16
.text
.globl _start
_start:
    ...
    /*some code to enable a20 line and to detect the memory*/
    ...
    xor     %ax,%ax
    movw    %ax,%es
    movw    %ax,%si
    mov     %ax,%ss
    mov     %ax,%ds
    mov     %ax,%gs
    jmp     switsching_to_protected

/* base address of code and data segment is 0x0
   limit for code and data segment is 0xfffff
   code segment access byte: 0b10011010
   data segment access byte: 0b10010010
   stack base: 0xAC00
   stack limit: 0x05
   stack segment access byte: 0b10010110
   the granuality and size flag is set for all the segments*/

.equ STACK_BASE, 0xAC00
.equ STACK_LIMIT, 0x05
StartOfGDT:
    zerodescriptor:
        .quad   0
    OScode:
        .quad   0x00cf9a000000ffff
    OSdata:
        .quad   0x00cf92000000ffff
    OSstack:
        .quad   0x00C09600AC000005
    GDTend:

GDTdescriptor:
    .word   0x1f
    .int    StartOfGDT



switsching_to_protected:
    cli
    lgdt    (GDTdescriptor)
    mov     %cr0,%eax
    or      $0x1,%ax
    mov     %eax,%cr0
    jmp     $8,$init_protected
    ret


.code32

init_protected:
    mov     $0x10,%ax
    mov     %ax,%ds
    mov     %ax,%es
    mov     %ax,%fs
    mov     %ax,%gs
    mov     $0x18,%ax
    mov     %ax,%ss
    mov     $STACK_BASE,%ebx
    movl    $STACK_LIMIT,%ecx
    movl    $4096, %eax
    mull    %ecx
    addl    %ebx,%eax
    sub     $16,%eax
    mov     %eax,%esp
    call    main
    jmp .
Thank you in advance,
Andrej
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: problems with stack and pointers

Post by Brendan »

Hi,
Andrej wrote:Could anybody help me to investigate this?
Can you post a disassembly of "main()" too?


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.
alexfru
Member
Member
Posts: 1112
Joined: Tue Mar 04, 2014 5:27 am

Re: problems with stack and pointers

Post by alexfru »

I'd check the stack alignment (AFAIR, gcc wants ESP to be a multiple of 16) and if there's any subroutine used to pass or return structures by value (e.g. memcpy() or something similar), I'd check its code too. Oh, and things like stack overflow checks and the so-called red zone may be at fault as well.
linuxyne
Member
Member
Posts: 211
Joined: Sat Jul 02, 2016 7:02 am

Re: problems with stack and pointers

Post by linuxyne »

The OSstack segment is an expand-down segment. Moreover, the code calls 0xac00 as the STACK_BASE, but then it manually sets esp to 0xfc00 (-0x10), making 0xfc00 the actual STACK_BASE and 0xac00 the actual STACK_TOP.

There's contradiction between the GDT and the manual setup of the stack.

Despite that, I am not sure if problems should arise. This should cause problems if the unexpected addresses the stack happen to touch are found to be invalid/unavailable/inuse, or if the offset (i.e. esp value) is not greater than the limit in which case the cpu raises exceptions.

With the limit set to 0x5000, the segment has almost the entire linear address space to consume as stack.

You can remove the expand-down marker for the stack segment, if the expansion facility provided by such a segment will not be used.
Octocontrabass
Member
Member
Posts: 5587
Joined: Mon Mar 25, 2013 7:01 pm

Re: problems with stack and pointers

Post by Octocontrabass »

Modern C compilers assume CS, DS, ES, and SS all refer to the same address space. Your code fails because the base address for SS doesn't match the other segments.
Andrej
Posts: 19
Joined: Wed Jun 22, 2016 2:52 pm

Re: problems with stack and pointers

Post by Andrej »

Hello,
The disassembled code of main:

Code: Select all

./Kernel/main.o:     file format elf32-i386


Disassembly of section .text:

00000000 <f>:
   0:	55                   	push   %ebp
   1:	89 e5                	mov    %esp,%ebp
   3:	83 ec 18             	sub    $0x18,%esp
   6:	8b 45 08             	mov    0x8(%ebp),%eax
   9:	8b 00                	mov    (%eax),%eax
   b:	89 04 24             	mov    %eax,(%esp)
   e:	e8 fc ff ff ff       	call   f <f+0xf>
  13:	c9                   	leave  
  14:	c3                   	ret    

00000015 <f2>:
  15:	55                   	push   %ebp
  16:	89 e5                	mov    %esp,%ebp
  18:	83 ec 18             	sub    $0x18,%esp
  1b:	8b 45 08             	mov    0x8(%ebp),%eax
  1e:	89 04 24             	mov    %eax,(%esp)
  21:	e8 fc ff ff ff       	call   22 <f2+0xd>
  26:	c9                   	leave  
  27:	c3                   	ret    

00000028 <main>:
  28:	55                   	push   %ebp
  29:	89 e5                	mov    %esp,%ebp
  2b:	83 e4 f0             	and    $0xfffffff0,%esp
  2e:	83 ec 20             	sub    $0x20,%esp
  31:	c7 05 00 00 00 00 09 	movl   $0x9,0x0
  38:	00 00 00 
  3b:	c7 44 24 1c 05 00 00 	movl   $0x5,0x1c(%esp)
  42:	00 
  43:	c7 04 24 00 00 00 00 	movl   $0x0,(%esp)
  4a:	e8 fc ff ff ff       	call   4b <main+0x23>
  4f:	8d 44 24 1c          	lea    0x1c(%esp),%eax
  53:	89 04 24             	mov    %eax,(%esp)
  56:	e8 fc ff ff ff       	call   57 <main+0x2f>
  5b:	a1 00 00 00 00       	mov    0x0,%eax
  60:	89 04 24             	mov    %eax,(%esp)
  63:	e8 fc ff ff ff       	call   64 <main+0x3c>
  68:	8b 44 24 1c          	mov    0x1c(%esp),%eax
  6c:	89 04 24             	mov    %eax,(%esp)
  6f:	e8 fc ff ff ff       	call   70 <main+0x48>
  74:	c7 04 24 00 00 00 00 	movl   $0x0,(%esp)
  7b:	e8 fc ff ff ff       	call   7c <main+0x54>
  80:	eb fe                	jmp    80 <main+0x58>
  82:	c9                   	leave  
  83:	c3                   	ret    
Also the source code of printint:

Code: Select all

printreg:
    #push   %ebp
    pusha
    movl    %esp,%ebp
    movl    $4,%ecx
    xor     %ebx,%ebx
    movl    36(%ebp),%eax
    start_printing:
    roll    $8,%eax
    movb    %al,%bl
    shrb    $4,%bl
    call    printNible
    movb    %al,%bl
    andb    $0x0f,%bl
    call    printNible
    loop    start_printing
    mov     %ebp,%esp
    popa
    #pop    %ebp
    ret

printNible:
    cmpb    $0xA,%bl
    jl      lessthen_0xA
    addb    $0x37,%bl
    push    %ebx
    call    printchar
    pop     %ebx
    ret
    lessthen_0xA:
    addb    $0x30,%bl
    push    %ebx
    call    printchar
    pop     %ebx
    ret

...

.global printint
.type printint, @function
printint:
    push    %ebp
    mov     %esp, %ebp
    movl    8(%ebp), %eax
    push    %eax
    call    printreg
    push    $10
    call    printchar
    mov     %ebp, %esp
    pop     %ebp
    ret
The function printchar is just working with the text mode video memory (starting with 0xb8000).
Oh, and things like stack overflow checks and the so-called red zone may be at fault as well.
I tried to disable the red-zone, but it did not helped. I do not think that stack overflow would be an issue. Just before calling the main the value of esp is 0000fbdc.
You can remove the expand-down marker for the stack segment, if the expansion facility provided by such a segment will not be used.
When I remove the expand down bit from the stacks GDT descriptor then the os fails to start.
Modern C compilers assume CS, DS, ES, and SS all refer to the same address space. Your code fails because the base address for SS doesn't match the other segments.
Will I be able to write some data to my code segment if I set the DS and CS to the same descriptor?


Best Regards,
Andrej
Octocontrabass
Member
Member
Posts: 5587
Joined: Mon Mar 25, 2013 7:01 pm

Re: problems with stack and pointers

Post by Octocontrabass »

Andrej wrote:Will I be able to write some data to my code segment if I set the DS and CS to the same descriptor?
Code segments are not writable, and data segments are not executable. You can't use the same descriptor for both CS and DS because you need CS to be executable and DS to be writable.
User avatar
SpyderTL
Member
Member
Posts: 1074
Joined: Sun Sep 19, 2010 10:05 pm

Re: problems with stack and pointers

Post by SpyderTL »

Code: Select all

00000028 <main>:
38:   00 00 00 
42:   00 
Any idea what is going on here?

EDIT: And here?

Code: Select all

4a:   e8 fc ff ff ff          call   4b <main+0x23>
4f:   8d 44 24 1c             lea    0x1c(%esp),%eax
Project: OZone
Source: GitHub
Current Task: LIB/OBJ file support
"The more they overthink the plumbing, the easier it is to stop up the drain." - Montgomery Scott
Octocontrabass
Member
Member
Posts: 5587
Joined: Mon Mar 25, 2013 7:01 pm

Re: problems with stack and pointers

Post by Octocontrabass »

SpyderTL wrote:Any idea what is going on here?

EDIT: And here?
When an opcode is longer than 7 bytes, objdump displays it on multiple lines.

When an object file hasn't been linked, the jump destinations are placeholders.
linuxyne
Member
Member
Posts: 211
Joined: Sat Jul 02, 2016 7:02 am

Re: problems with stack and pointers

Post by linuxyne »

Andrej wrote:When I remove the expand down bit from the stacks GDT descriptor then the os fails to start.
expand-down segments are not necessary, although here, they have become a necessity for some reason. There could be fundamental problems lurking somewhere.

Andrej wrote:Just before calling the main the value of esp is 0000fbdc.
The linear address in use should be 0xac00 + 0xfbdc = 0x1A7DC.

Are you working on an emulator? If so, try bochsdbg to debug the behaviour.
Andrej
Posts: 19
Joined: Wed Jun 22, 2016 2:52 pm

Re: problems with stack and pointers

Post by Andrej »

Hi,
I'm using virtualbox. The upper limit of the stack is 0xFBE0 in linear address space. Maybe the stack pointer is configured wrongly?

Code: Select all

    mov     %ax,%ss
    mov     $STACK_BASE,%ebx
    movl    $STACK_LIMIT,%ecx
    movl    $4096, %eax
    mull    %ecx
    addl    %ebx,%eax
    sub     $0x20,%eax
    mov     %eax,%esp
Br,
Andrej
Octocontrabass
Member
Member
Posts: 5587
Joined: Mon Mar 25, 2013 7:01 pm

Re: problems with stack and pointers

Post by Octocontrabass »

Andrej wrote:Maybe the stack pointer is configured wrongly?
The stack base in your GDT is configured wrong.

You must use the same base address for CS, DS, ES, and SS. You're using 0 for CS, DS and ES, but you're using 0xAC00 for SS. Compiled code won't work properly unless all four of those segment registers have the same base address.
linuxyne
Member
Member
Posts: 211
Joined: Sat Jul 02, 2016 7:02 am

Re: problems with stack and pointers

Post by linuxyne »

esp stores the offset of the seg:offset pair.
So 0xfbe0 is not the linear address (i.e. not where the stack resides), unless the segment is based at 0 (which it is not).

Nevertheless, if you do wish to debug this (not only the stack, but also your primary problem of unexpected prints) yourself, you can convert the disk to raw using 'vboxmanage clonemedium', fill in the bochs config file appropriately and begin debugging using bochsdbg. Virtualbox has a --dbg switch, although I have not used it, nor do I know if it allows debugging straight at the beginning of your mbr.


Edit0: I think that you want your stack to be 5 pages long with the base at linear 0xfc00 and the top at linear 0xac00 i.e the linear range is [0xac00, 0xfc00). Segmentation, even when using a non-zero-based segment, can definitely be used to restrict the stack in a range, although do read up on the way in which the cpu checks for segment limits, since your base and top are not page-aligned and G bit is set.
User avatar
SpyderTL
Member
Member
Posts: 1074
Joined: Sun Sep 19, 2010 10:05 pm

Re: problems with stack and pointers

Post by SpyderTL »

What compiler options are you using?

Try disabling optimizations.
Project: OZone
Source: GitHub
Current Task: LIB/OBJ file support
"The more they overthink the plumbing, the easier it is to stop up the drain." - Montgomery Scott
Andrej
Posts: 19
Joined: Wed Jun 22, 2016 2:52 pm

Re: problems with stack and pointers

Post by Andrej »

Hello,
Setting the base of the stack segment actually helped a little bit. The only problem with this was when I enabled the hardware virtualization in Virtual Box the vm went to guru meditation state. Now just a basic flat model is set up in the GDT and it's working.
I played a bit with the stack segment in the GDT and my conclusion is that when hardware virtualization is enabled then the vm doesn't really like if the base of the stack segment is 0. Is there any restriction to the stack base?

Best Regards,
Andrej
Post Reply