Page 1 of 2
problems with stack and pointers
Posted: Tue Aug 02, 2016 3:32 pm
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
Re: problems with stack and pointers
Posted: Tue Aug 02, 2016 4:33 pm
by Brendan
Hi,
Andrej wrote:Could anybody help me to investigate this?
Can you post a disassembly of "main()" too?
Cheers,
Brendan
Re: problems with stack and pointers
Posted: Tue Aug 02, 2016 7:09 pm
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.
Re: problems with stack and pointers
Posted: Wed Aug 03, 2016 6:49 am
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.
Re: problems with stack and pointers
Posted: Wed Aug 03, 2016 7:07 am
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.
Re: problems with stack and pointers
Posted: Wed Aug 03, 2016 2:22 pm
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
Re: problems with stack and pointers
Posted: Wed Aug 03, 2016 2:41 pm
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.
Re: problems with stack and pointers
Posted: Wed Aug 03, 2016 2:59 pm
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
Re: problems with stack and pointers
Posted: Wed Aug 03, 2016 5:55 pm
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.
Re: problems with stack and pointers
Posted: Thu Aug 04, 2016 4:15 am
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.
Re: problems with stack and pointers
Posted: Thu Aug 04, 2016 5:18 am
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
Re: problems with stack and pointers
Posted: Thu Aug 04, 2016 5:27 am
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.
Re: problems with stack and pointers
Posted: Thu Aug 04, 2016 5:28 am
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.
Re: problems with stack and pointers
Posted: Thu Aug 04, 2016 8:33 am
by SpyderTL
What compiler options are you using?
Try disabling optimizations.
Re: problems with stack and pointers
Posted: Thu Aug 04, 2016 2:26 pm
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