Page 1 of 2

Missing pointers

Posted: Thu Apr 01, 2004 8:20 am
by Skute
Hi,

im trying to follow the XOSDev2 tutorial but im having trouble because my pointers arent working properly! I think ive probably got something messed up in boot loader / linker.

This is in my boot loader, it apparently changes where the stack pointer is.
[BITS 32] ; We now need 32-bit instructions
clear_pipe:
mov ax, 10h ; Save data segment identifyer
mov ds, ax ; Move a valid data segment into the data segment register
mov ss, ax ; Move a valid data segment into the stack segment register
mov esp, 090000h ; Move the stack pointer to 090000h

jmp 08h:01000h ; Jump to section 08h (code), offset 01000h
                        ; Where the kernel is located in memory

Should that stack pointer point to the same place as a location in my linker script?

Here is my linker script:
OUTPUT_FORMAT("binary")
ENTRY(start)
SECTIONS
{
.text 0x100000 : {
code = .; _code = .; __code = .;
*(.text)
. = ALIGN(4096);
}
.data : {
data = .; _data = .; __data = .;
*(.data)
. = ALIGN(4096);
}
.bss :
{
bss = .; _bss = .; __bss = .;
*(.bss)
. = ALIGN(4096);
}
end = .; _end = .; __end = .;
}


If its not that, can you give me any other hints as to why this piece of code just isnt working:
char *text_video = (char*)0xB8000;
char attrib = 0x07;
char *str="Kernel Loaded";

while(*str!=0)
{
*text_video = *str;
*text_video++;
*text_video = attrib;
*text_video++;
*str++;
}
But, this piece of code does work:
*text_video = 'H';
   *text_video++;
   *text_video = 0x08;
   *text_video++;
   *text_video = 'e';
   *text_video++;
   *text_video = 0x08;
   *text_video++;
   *text_video = 'l';
   *text_video++;
   *text_video = 0x08;
   *text_video++;
   *text_video = 'l';
   *text_video++;
   *text_video = 0x08;
   *text_video++;
   *text_video = 'o';
   *text_video++;
   *text_video = 0x08;
   *text_video++;

Any help is much appreciated.
Thanks!

(Ive attached my project files so you can take a look at the boot loader, kernel starter and kernel main)

[attachment deleted by admin]

Re:Missing pointers

Posted: Thu Apr 01, 2004 9:01 am
by Pype.Clicker
it looks much more like your load address and your jump address are not the same ... (or is it just a typo ?)

Re:Missing pointers

Posted: Thu Apr 01, 2004 9:21 am
by Skute
Well in my boot loader i do the following:
reset_drive:
mov ah, 0 ; RESET-command
int 13h ; Call interrupt 13h
or ah, ah ; Check for error code
jnz reset_drive ; Try again if ah != 0

mov ax, 0
mov es, ax
mov bx, 0x1000 ; This is where we want to load the kernel into memory(0000:1000)

mov ah, 02h ; READ SECTOR-command
mov al, 02h ; Number of sectors to read = 1
mov ch, 0 ; Cylinder = 0
mov cl, 02h ; Sector = 2
mov dh, 0 ; Head = 0
int 13h ; Call interrupt 13h
or ah, ah ; Check for error code
jnz reset_drive ; Try again if ah != 0
So i load the kernel to 0x1000,
then later i jump to 08h:1000h
so is that not correct?

Re:Missing pointers

Posted: Thu Apr 01, 2004 9:31 am
by Pype.Clicker
that would be quite fine if you hadn't

Code: Select all

.text  0x100000 : {
which will (iirc) generate the kernel as if it was located at 1MB :-/

Moreover 0x00001000 is below the address of the bootloader itself (0x00007c00) and thus there are risks for the bootloader to overwrite itself while loading the kernel (which is no good, as you can presume). 0x00010000 would be a safer location imho...

Re:Missing pointers

Posted: Fri Apr 02, 2004 2:06 am
by Skute
So then to get it to work i need to change the .Text to 10000 and also the load address in the boot loader to 10000?
Or should they not be the same?

Re:Missing pointers

Posted: Fri Apr 02, 2004 2:21 am
by Skute
I tried changing the jump in my boot loader to 10000h but it didnt like it, kept crashing. (I made sure that the .Text value was the same).

Then i changed the .Text value to 1000 which is the same as in the boot loader - my pointers now work! But as i understand it, loading at 1000 is bad because it can overwrite the boot loader itself.
So what should the values be? Instead of 1000.

Thanks

[Edit:]

Basically what i want to know is, what is the correlation between these 3 items:
The .Text value in the linker.
The mov bx, ?? ; Where we want to load the kernel in memory
and the
[BITS 32]
...
jmp 08h:??

Cheers

Re:Missing pointers

Posted: Fri Apr 02, 2004 3:14 am
by Candy
Skute wrote: Basically what i want to know is, what is the correlation between these 3 items:
The .Text value in the linker.
The mov bx, ?? ; Where we want to load the kernel in memory
and the
[BITS 32]
...
jmp 08h:??
You want the jump to be in 16-bit code. You want the jump to go to 32-bit code.

The .text value is where you say you will load the kernel. The mov bx, ... value is where you ask the kernel to be loaded (note, this one offset by ES). The jmp 08h:.. is where you say your kernel is.

Most logical is when these all coincide. If you do not, you'd better have a very good reason & have figured your math out.

Code: Select all

// some 16-bit code
jmpf 08h:entry32 // this encodes to 66 ea entry32 08 00 which is a 16-bit long jump to a 32-bit offset, exactly what you want
[BITS 32]
entry32:
// from this point on your compiler will think you use 32-bit code, and leave out the 66's for 32-bit stuff. It will put them for 16-bit stuff.

Re:Missing pointers

Posted: Fri Apr 02, 2004 3:36 am
by Skute
Cool thanks, i can only get my pointers to work when i have the .Text = 10000 and the boot loader looking at 1000. Other values just dont work :(. I must be going wrong somewhere or not quite understanding.

Here is the code for the specific part of the boot loader:
mov ax, 0
mov es, ax
mov bx, 0x1000 ; This is where we want to load the kernel into memory(0000:1000)

...

jmp 08h:clear_pipe ; Jump to code segment, offset clear_pipe


[BITS 32] ; We now need 32-bit instructions
clear_pipe:
mov ax, 10h ; Save data segment identifyer
mov ds, ax ; Move a valid data segment into the data segment register
mov ss, ax ; Move a valid data segment into the stack segment register
mov esp, 090000h ; Move the stack pointer to 090000h

jmp 08h:01000h ; Jump to section 08h (code), offset 01000h
                        ; Where the kernel is located in memory
And obviously in my loader file it reads like:
OUTPUT_FORMAT("binary")
ENTRY(start)
SECTIONS
{
.text 0x10000 : {
code = .; _code = .; __code = .;
*(.text)
. = ALIGN(4096);
}
.data : {
data = .; _data = .; __data = .;
*(.data)
. = ALIGN(4096);
}
.bss :
{
bss = .; _bss = .; __bss = .;
*(.bss)
. = ALIGN(4096);
}
end = .; _end = .; __end = .;
}
You see how i have different values in the boot loader and in the linker file - thats not right is it? But strangely, this is the only way that my pointers work :(

Re:Missing pointers

Posted: Fri Apr 02, 2004 3:46 am
by Pype.Clicker
use es = 0x1000 and bx=0x0000: they'll magically load your kernel at es*16+bx = 0x10000

if you need deeper enlightenment, may i suggest you get a look at Perica's tutorial on realmode addressing (avl. at BonaFide :)

Re:Missing pointers

Posted: Fri Apr 02, 2004 3:57 am
by Skute
Just gave that a go, it did compile and run, but my pointer still didnt work :( gonna go read that document now. But here are the changes i made:
mov ax, 0x1000
mov es,   ax
mov bx, 0x0000
...
[BITS 32]
...
jmp 08h:010000h
As i say, it loads, but the pointers still dont work :(.
Is it something todo with my stack pointer too? (Points at 090000h)

Thanks

Re:Missing pointers

Posted: Fri Apr 02, 2004 4:17 am
by Pype.Clicker
okay... i should've read your initial post with more attention ...

This is a typical n00b mistake, imho. Your linker script is missing ".rodata*" section which is typically where strings are stored (unless you're using an old version of GCC that still place them in .text or have used -fwritable-strings which places them in .data)

may i suggest you try to run an objdump -x on the object files ? i think it might help you understanding what's in your object file and where it goes after linking.

Re:Missing pointers

Posted: Fri Apr 02, 2004 4:33 am
by Skute
Thankyou, could you help me understand the output from objdump? And also give me a pointer in the right direction for setting up an .rodata section? Cheers

[Edit: I used writeable_strings and the pointers started working :) cheers, ill use that until i get this .rodata thing setup]

[Edit2: Copied the .data definition and modified it into an .rodata section and removed writeable-strings and it worked too :) :)]
C:\asm\SkuteOS\src\kernel>objdump -x main.o

main.o: file format coff-go32
main.o
architecture: i386, flags 0x00000031:
HAS_RELOC, HAS_SYMS, HAS_LOCALS
start address 0x00000000

Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000150 00000000 00000000 000000b4 2**4
CONTENTS, ALLOC, LOAD, RELOC, CODE
1 .data 00000000 00000000 00000000 00000000 2**4
ALLOC, LOAD, DATA
2 .bss 00000000 00000000 00000000 00000000 2**2
ALLOC
3 .comment 00000014 00000000 00000000 00000204 2**2
CONTENTS, DEBUGGING
SYMBOL TABLE:
[ 0](sec -2)(fl 0x00)(ty 0)(scl 103) (nx 1) 0x00000000 main.c
File
[ 2](sec 1)(fl 0x00)(ty 0)(scl 3) (nx 1) 0x00000000 .text
AUX scnlen 0x14d nreloc 1 nlnno 0
[ 4](sec 2)(fl 0x00)(ty 0)(scl 3) (nx 1) 0x00000000 .data
AUX scnlen 0x0 nreloc 0 nlnno 0
[ 6](sec 3)(fl 0x00)(ty 0)(scl 3) (nx 1) 0x00000000 .bss
AUX scnlen 0x0 nreloc 0 nlnno 0
[ 8](sec 4)(fl 0x00)(ty 0)(scl 3) (nx 1) 0x00000000 .comment
AUX scnlen 0x11 nreloc 0 nlnno 0
[ 10](sec 1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x00000000 _clear_screen
[ 11](sec 1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x0000004e _strlen
[ 12](sec 1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x0000007f _kmain


RELOCATION RECORDS FOR [.text]:
OFFSET TYPE VALUE
00000093 dir32 .text

Re:Missing pointers

Posted: Fri Apr 02, 2004 4:40 am
by Candy
Skute wrote: Just gave that a go, it did compile and run, but my pointer still didnt work :( gonna go read that document now. But here are the changes i made:
mov ax, 0x1000
mov es, ax
mov bx, 0x0000
...
[BITS 32]
...
jmp 08h:010000h
As i say, it loads, but the pointers still dont work :(.
Is it something todo with my stack pointer too? (Points at 090000h)

Thanks
Place the bits32 below the jump, as I said. Explanation:

You currently assemble the jmp as if you're already in 32-bit mode. You are not. Therefore, the cpu is going to interpret the bits as if they represent 16-bit opcodes.

Your jump looks like:

EA 08 00 00 10 00 00
for a 32-bit jump in 32-bit mode

66 EA 08 00 00 10 00 00
for that same jump in 16-bit mode

EA 08 00 00 10
for a 16-bit jump in 16-bit mode

66 EA 08 00 00 10
for a 16-bit jump in 32-bit mode (not awfully useful).

You want the second. You tell the assembler to generate the first. Your CPU interprets the third. The net result is that you jump to the exact same place.

BUT:

there is no way to put a 10000 in 16-bit mode!

Your assembler generates
EA 08 00 00 00 01 00 ; 32b jmp 08:10000

Your CPU sees
EA 08 00 00 00 ;16b jmp 08:0000

You want to make
66 EA 08 00 00 00 01 00 ; 16b jmp 08:10000

which you can do by letting NASM compile the jump in 16-bit mode. At least, if you can convince it it's a 32-bit jump (the offset should do the trick).

Re:Missing pointers

Posted: Fri Apr 02, 2004 4:51 am
by Skute
Sorry, the "..." bits meant that stuff was missing. That jump that you can see there is to the kernel entry point.

The relavent part of the loader looks like:
mov ax, 0x1000
mov es,   ax
mov bx, 0x0000

mov ah, 02h ; READ SECTOR-command
mov al, 02h ; Number of sectors to read = 1
mov ch, 0 ; Cylinder = 0
mov cl, 02h ; Sector = 2
mov dh, 0 ; Head = 0
int 13h ; Call interrupt 13h
or ah, ah ; Check for error code
jnz reset_drive ; Try again if ah != 0

cli ; Disable interrupts, we want to be alone

xor ax, ax
mov ds, ax ; Set DS-register to 0 - used by lgdt

lgdt [gdt_desc] ; Load the GDT descriptor

mov eax, cr0 ; Copy the contents of CR0 into EAX
or eax, 1 ; Set bit 0
mov cr0, eax ; Copy the contents of EAX into CR0

jmp 08h:clear_pipe ; Jump to code segment, offset clear_pipe


[BITS 32] ; We now need 32-bit instructions
clear_pipe:
mov ax, 10h ; Save data segment identifyer
mov ds, ax ; Move a valid data segment into the data segment register
mov ss, ax ; Move a valid data segment into the stack segment register
mov esp, 090000h ; Move the stack pointer to 090000h

jmp 08h:010000h ; Jump to section 08h (code), offset 010000h
                        ; Where the kernel is located in memory
Or is that still wrong?

Thanks

Re:Missing pointers

Posted: Fri Apr 02, 2004 6:07 am
by Pype.Clicker
Skute wrote: Thankyou, could you help me understand the output from objdump?
I'll try ...
C:\asm\SkuteOS\src\kernel>objdump -x main.o

main.o: file format coff-go32
main.o
architecture: i386, flags 0x00000031:
HAS_RELOC, HAS_SYMS, HAS_LOCALS
start address 0x00000000
This was the 'general info'. I can tell you're compiling with DjGPP (coff-go32 model). You also have basic information like "does the file contains debugging information ? and symbols/relocation for linking ? ..."
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000150 00000000 00000000 000000b4 2**4
CONTENTS, ALLOC, LOAD, RELOC, CODE
1 .data 00000000 00000000 00000000 00000000 2**4
ALLOC, LOAD, DATA
2 .bss 00000000 00000000 00000000 00000000 2**2
ALLOC
3 .comment 00000014 00000000 00000000 00000204 2**2
CONTENTS, DEBUGGING
Each section is a chunk of your binary file which has specific properties (which are mainly useful when loading the program through a 'normal' loader...)

.text contains your code, is 0000150 (hex) wide and will be aligned on a 16-bytes multiple. In the .o file, you can view
its content at bytes 0xb4 .. 0x204 (if computed properly).

.data is currently empty as you don't have any "static" variable.
the variables declared within functions are 'automatic' and allocated on the stack at runtime, so they're unknown to the linker.

.bss is the 'undefined variable' area. It's a placeholder for uninitialized global (or static) variables and *must* be wiped (with zeroes) by your loader before the C code is launched.
For optimisation, .bss never takes bytes in the file.

.comment is usually comment strings like "compiled with gcc x.y.z"

Now you might ask 'where did "Kernel Loaded" disappeared? '
It has probably been optimized out as no piece of the block where it is defined used it.

If you make an objdump when some 'strlen(str)' is present, it should add a .rodata section that will have the string's size...
SYMBOL TABLE:
[ 0](sec -2)(fl 0x00)(ty 0)(scl 103) (nx 1) 0x00000000 main.c
File
[ 2](sec 1)(fl 0x00)(ty 0)(scl 3) (nx 1) 0x00000000 .text
AUX scnlen 0x14d nreloc 1 nlnno 0
[ 4](sec 2)(fl 0x00)(ty 0)(scl 3) (nx 1) 0x00000000 .data
AUX scnlen 0x0 nreloc 0 nlnno 0
[ 6](sec 3)(fl 0x00)(ty 0)(scl 3) (nx 1) 0x00000000 .bss
AUX scnlen 0x0 nreloc 0 nlnno 0
[ 8](sec 4)(fl 0x00)(ty 0)(scl 3) (nx 1) 0x00000000 .comment
AUX scnlen 0x11 nreloc 0 nlnno 0
you may ignore those sections-symbols for the moment.

[ 10](sec 1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x00000000 _clear_screen
[ 11](sec 1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x0000004e _strlen
[ 12](sec 1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x0000007f _kmain
This is your (unrelocated) symbols map. If something tells you you have an exception at 0x00100050, you know it must be somewhere in strlen as it's the closest symbol below that address.
RELOCATION RECORDS FOR [.text]:
OFFSET TYPE VALUE
00000093 dir32 .text
And this says that somewhere in kmain, there's a dependency on the actual location of .text ... This is probably not a 'jump' or a 'call' as those things can be handled by relative addresses when kept within the same .o file.

To actually find out, the best is to compile with debugging infos (-g flag) and then call "objdump -drS main.o" to get a commented disassembly of your .text section