Page 1 of 1

getting stuck very early on

Posted: Wed Aug 15, 2007 12:36 pm
by mu-law
I feel foolish for asking for help this early on when most of the code isn't even my own.. I'm doing this on Linux with a gcc crosscompiler targeted at i586-elf. Used a combination of the OSDEV wiki's Barebones tutorial and http://www.osdever.net/tutorials/ch02.php.

I use qemu for testing, a GRUB image in drive a: and a raw copy of the linked kernel in drive b: and kernel (fd1)+100000 or so and then boot in GRUB.

It simply halts and prints nothing. I've tried printing individual characters out to the serial console and screen and various other tricks which do work, but anything involving strings or loops seems to fail.

loader.s

Code: Select all

.global _loader           # making entry point visible to linker

# setting up the Multiboot header - see GRUB docs for details
.set ALIGN,    1<<0             # align loaded modules on page boundaries
.set MEMINFO,  1<<1             # provide memory map
.set FLAGS,    ALIGN | MEMINFO  # this is the Multiboot 'flag' field
.set MAGIC,    0x1BADB002       # 'magic number' lets bootloader find the header
.set CHECKSUM, -(MAGIC + FLAGS) # checksum required

.align 4
.long MAGIC
.long FLAGS
.long CHECKSUM

# reserve initial kernel stack space
.set STACKSIZE, 0x4000          # that is, 16k.
.comm stack, STACKSIZE, 32      # reserve 16k stack on a quadword boundary

_loader:
   mov   $(stack + STACKSIZE), %esp # set up the stack
   push  %eax                       # Multiboot magic number
   push  %ebx                       # Multiboot data structure

   call  k_main            # call kernel proper
   hlt                    # halt machine should kernel return
kernel.c

Code: Select all

void k_main() { // like main in a normal C program
  int num;
  char ch;

  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++;
  }
  return;
};
linker.td

Code: Select all

ENTRY (_loader)

SECTIONS{
    . = 0x00100000;

    .text :{
        *(.text)
    }

    .rodata ALIGN (0x1000) : {
        *(.rodata)
    }

    .data ALIGN (0x1000) : {
        *(.data)
    }

    .bss : {
        _sbss = .;
        *(COMMON)
        *(.bss)
        _ebss = .;
    }
}
Makefile

Code: Select all

all:    loader kernel link
        cp krnl ..

loader: loader.s
        $(AS) -o loader.o loader.s

kernel: kernel.c
        $(GCC) -o kernel.o kernel.c -Wall -nostdlib -nostartfiles -nodefaultlibs

link:   loader.o kernel.o
        ld -T linker.td -o krnl loader.o kernel.o

Re: getting stuck very early on

Posted: Wed Aug 15, 2007 3:27 pm
by Gizmo
kernel.c

Code: Select all

void k_main() { // like main in a normal C program
  int num;
  char ch;

  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++;
  }
  return;
};
When you do *str++ you are incrementing the value stored at str and not the pointer itself- this should be str++.
same thing with text_video++

Remember, when you place * in front of a pointer it means you are working with the value its pointing to instead of the pointer itself.

So your code was simply adding 1 to the first byte of video memory and adding 1 to the first byte in the string until you rolled over 255 and hit 0 instead of copying bytes from str to video_memory incrementing the pointer str until the value stored there was 0.

Code: Select all

void k_main() { // like main in a normal C program
  int num;
  char ch;

  char *text_video = (char*)0xB8000;
  char attrib = 0x07;
  char *str="Kernel Loaded";

  while(*str!=0) {
    *text_video = *str; //copy byte stored at str to byte stored at text_video
    text_video++; //increment pointer
    *text_video = attrib; //copy byte attrib to byte pointed to by text_video
    text_video++; //increment pointer
    str++; //increment pointer
  }
  return;
};

Re: getting stuck very early on

Posted: Wed Aug 15, 2007 6:49 pm
by jhawthorn
Gizmo wrote: When you do *str++ you are incrementing the value stored at str and not the pointer itself
Wrong, it does indeed increment the pointer. In this case the * does not change the statement. Please read up on pointers, Gizmo.

mu-law, your C code should work (though it has some problems), I suspect your makefile is at fault.

Code: Select all

all: krnl
        cp krnl ..

loader.o: loader.s
        $(AS) -o loader.o loader.s

kernel.o: kernel.c
        $(CC) -c -o kernel.o kernel.c -Wall -nostdlib -nostartfiles -nodefaultlibs

krnl:   loader.o kernel.o
        ld -T linker.td -o krnl loader.o kernel.o 
This is a more appropriate makefile. You may understand Makefiles better from this example. If not, read up on them.

I said your C code would work, but it could be better.

Code: Select all

void k_main() { // like main in a normal C program
  char *text_video = (char*)0xB8000;
  char attrib = 0x07;
  char *str="Kernel Loaded";

  while(*str!=0) {
    *text_video++ = *str++;
    *text_video++ = attrib;
  }
  return;
}; 
You can see that *ptr++ will increment the pointer after retrieving or setting the value. Previously you were retrieving the value but not using it, which should have generated compiler warnings.

Hope this clears up a few things.
-John Hawthorn

Posted: Wed Aug 15, 2007 8:24 pm
by mu-law
Yep, it now compiles cleanly, without warnings, and works. I guess now all I have to do is write everything! ;) Thanks. :)

Re: getting stuck very early on

Posted: Thu Aug 16, 2007 3:21 am
by Gizmo
jhawthorn wrote:
Gizmo wrote: When you do *str++ you are incrementing the value stored at str and not the pointer itself
Wrong, it does indeed increment the pointer. In this case the * does not change the statement. Please read up on pointers, Gizmo.
Until you post a link to a doc saying otherwise I am sticking to my guns.

Posted: Thu Aug 16, 2007 3:35 am
by pcmattman
Without being able to do

Code: Select all

*ptr-- (or) *ptr++
Most of the task initialization code on this forum would be useless:

Code: Select all

*esp-- = entrypoint;

Posted: Thu Aug 16, 2007 8:13 am
by JamesM
operator (right-to-left associative)
----------
++ --
+ -
! ~
(type)
*
&
sizeof
That quote was taken from http://www.difranco.net/cop2220/op-prec.htm and ascii-fied a little. All those operators have equal precedence and are all right-associative.

Right associative? what does that mean?

well, let's take a simple example.

This is taking away 3 numbers from each other.

Code: Select all

x = 5 - 2 - 1;
Left associative grouping:  x = (5 - 2) - 1; ( = 2 )
Right associative grouping: x = 5 - (2 - 1); ( = 1 )
You can see associativity defines the way in which expressions with multiple operators or instances of the same operator can be grouped or paranthesised into one expression containing nested expressions, of one operation each.

You can see that the top line uses left associativity, and arrives at the correct answer, 2. The bottom line uses right associativity and gets 1. Which is garbage. So we know that '-' is a left-associative operator.

Another example - exponentiation.

Code: Select all

x  = 2^3^4;
left-associative: x = (2^3) ^ 4 (= 8 ^ 4 = 4096.)
right-associative: x = 2 ^ (3^4) (= 2 ^ 81 = 2.41785164e24)
In this case, the bottom one is correct. Mathematically, exponents are grouped right-to-left.

OK, so now back to the example, which was:

Code: Select all

*p++ = var;
Here we have 2 operations (excluding the assignment) a dereference, and an increment.

From the table above, we see that they both have equal precedence, but they are both right-associative. So, this means that

Code: Select all

*p++ = var    ===
*(p++) = var
so, in english, "The value obtained by dereferencing the value at p (= assignment), then increment p".

Why the "then increment p" ? because, whether you know it or not, there are 2 ++ operators. The prefix ++ and the postfix++.

Code: Select all

prefix++:  ++p;
postfix++: p++;
;

The first says: "increment p, then take it's value".
The second says: "take p's value, then increment it".

And that is why the original posters are correct and you are incorrect.

I suggest you read up on pointers, as another already posted.

JamesM

Posted: Thu Aug 16, 2007 10:47 am
by Gizmo
Why did you post a full page just to say "Gizmo, its from right to left because they are equal precedence, here is the link".
Your right, I was wrong, but everybody is wrong at least some of the time. :cry:

I wasn't trying to make anyone mad or doubt anybody's competence, I just wanted some evidence.
But simply saying "your wrong" and saying "read more newb!" isn't very friendly either. You should at least explain your objections and then maybe throw in "go read more newb!". :)
Maybe you think I am some random newb who thinks he knows everything and posts random bs (that would be a good summary of my teenage years :roll: ) but I'm more like a C programmer who is a total osdev newb who is learning asm and osdev at the same time. :wink:

(rereading my earlier reply it probably does sound like I was mad or something, maybe I should have placed a smiley in that line or something?)

Posted: Thu Aug 16, 2007 11:23 am
by JamesM
Gizmo,

Again, that reply wasn't meant as a troll. I told you you were wrong, and, because you hadn't accepted that in a post above, I explained in parsing terms why the syntax means what it means. It is a difficult syntax to understand, i just just explaining.

JamesM

Posted: Thu Aug 16, 2007 12:16 pm
by lukem95
Erm...

if your still having trouble with getting your kernel to work, my contribution is here:

(bearing in mind i'm still fairly new xD)

i noticed you didnt define k_main() as an external call in your asm, you could try adding:

Code: Select all

extern k_main
to your defines and see if that helps

Posted: Sun Aug 26, 2007 10:14 am
by vhg119
lukem_95 wrote:Erm...

if your still having trouble with getting your kernel to work, my contribution is here:

(bearing in mind i'm still fairly new xD)

i noticed you didnt define k_main() as an external call in your asm, you could try adding:

Code: Select all

extern k_main
to your defines and see if that helps
It looks like he might be using AS. If that's the case, AS ignores the 'extern' keyword and treats all undefined symbols as external.