Page 1 of 1

C lang goes crazy???

Posted: Thu Apr 28, 2022 4:28 am
by BoazTene
I'm writing a simple OS, mainly to practice C and 'cause it fun.

I've already written a bootloader (in asm), I've successfully moved to 32 bit protected mode and I run and load C code.
Currently I'm trying to build a simple screen driver.

I'm initializing this pointer (so far, nothing wrong).

Code: Select all

unsigned char *video_memory = (unsigned char*) VIDEO_ADDRESS;
now I want to access the pointer.

Code: Select all

video_memory[0]; (so far so god)
now I want to do it with a variable

Code: Select all

int offset = 2;
video_memory[offset]; (now it doesn't work) 
The code doesn't crash, it will access always the same place no matter if I change the offset variable or not.

Lets say I want to access the pointer in other way.

Code: Select all

video_memory += offset;
*video_memory = lalala  (it will work)
I don't have a clue of what causing this, maybe I got something wrong with my C code :x or I have some bug in the bootloader or something :oops: .


[EDIT]

bootlaoder:

Code: Select all

[org 0x7c00] ; bootloader offset
    KERNEL_OFFSET equ 0x1000
    mov [BOOT_DRIVE], dl
    
    mov bp, 0x9000 ; set the stack
    mov sp, bp

    mov bx, MSG_REAL_MODE
    call print.print_string ; This will be written after the BIOS messages

    call load_kernel

    call switch_to_pm ; We are never return from here.
    jmp $ ; this will actually never be executed

%include "src/boot/modules/disk.asm"
%include "src/boot/switch_pm/gdt.asm"
%include "src/boot/modules/console.asm"
%include "src/boot/modules/console32.asm"
%include "src/boot/switch_pm/switch_to_pm.asm"


[bits 16]
; loads the kernel
load_kernel:
    mov bx, MSG_LOAD_KERNEL
    call print.print_string

    mov bx, KERNEL_OFFSET
    mov dh, 15
    mov dl, [BOOT_DRIVE]
    call disk.load

    ret


[bits 32]
BEGIN_PM: ; after the switch we will get here
    call console.clear
    mov ebx, MSG_PROT_MODE
    call console.print_string_pm ; Note that this will be written at the top left corner

    call KERNEL_OFFSET

    jmp $


; globals
BOOT_DRIVE db 0
MSG_REAL_MODE db "Started in 16-bit real mode", 0
MSG_PROT_MODE db "Loaded 32-bit protected mode", 0
MSG_LOAD_KERNEL db "Starts loading the kernel", 0

; bootsector
times 510-($-$$) db 0
dw 0xaa55
makefile:

Code: Select all

OSNAME = "SuperDuperOS"
C_SOURCES = $(wildcard src/kernel/*.c src/drivers/*.c)
HEADERS = $(wildcard kernel /*.h drivers /*.h)
OBJ = ${C_SOURCES:.c=.o}


# call with make src='your-asm-file.asm'
# Example make src=bootloader.asm
all: os-image
	

# Compiles the bootloader
bin/bootloader.bin: src/boot/bootloader.asm
	nasm $< -f bin -o $@

# Compiles the kernel_entry.
bin/kernel_entry.o: src/boot/kernel_entry.asm
	nasm $< -f elf64 -o $@

# Compiles the kernel.
bin/kernel.o: src/kernel/kernel.c
	gcc -ffreestanding -c $< -o $@


bin/kernel.bin: bin/kernel_entry.o 	${OBJ}
	ld -o $@ -Ttext 0x1000 $^ --oformat binary

# Generic rule for building ’somefile.o’ from ’somefile.c’
%.o: %.c ${HEADERS}
	gcc -ffreestanding -c $< -o $@

# lunch the last binary via qemu
qemu:
	qemu-system-x86_64 bin/$(OSNAME)

# This is the actual disk image that the computer loads ,
# which is the combination of our compiled bootsector and kernel
os-image: bin/bootloader.bin bin/kernel.bin
	cat $^ > bin/$(OSNAME)

# cleans the entire bin folder.
clean:
	rm -r bin || true
	mkdir bin

# Disassemble our kernel - might be useful for debugging.
bin/kernel.dis : bin/kernel.bin
	ndisasm -b 32 $< > $@

Re: C lang goes crazy???

Posted: Thu Apr 28, 2022 10:59 am
by Octocontrabass
You're right, problems like this are often caused by a bug in the bootloader. It can also be caused by incorrectly linking your kernel, or placing your stack at an invalid address, or even running 64-bit code in 32-bit mode.

I can say for sure there's nothing wrong with the C code you've posted, but I don't have enough information to tell you exactly where the bug is.

Re: C lang goes crazy???

Posted: Thu Apr 28, 2022 12:06 pm
by iansjack
The cases that work don’t use the stack; the case that fails does use the stack, so that’s a good place to start looking. What’s the address of your stack?

C doesn’t go crazy, but it doesn’t stop the programmer doing crazy things.

Re: C lang goes crazy???

Posted: Thu Apr 28, 2022 11:00 pm
by Gigasoft
Oh, you'd be surprised. Compilers sometimes have silly bugs, so the first thing to do would be to check what the compiler outputs. I remember one of them being confused by pointers having a constant numeric value.

Re: C lang goes crazy???

Posted: Thu Apr 28, 2022 11:33 pm
by iansjack
Yes, I’d be very surprised if such an obvious bug existed in a current compiler.

It’s easy to blame the machine when human error is more likely.

Re: C lang goes crazy???

Posted: Fri Apr 29, 2022 2:46 am
by mtbro
Have you checked the assembly of the given code? Maybe worth setting up breakpoint and see what it does step-by-step too.

How did you verify it's not working? Thinking out loud: maybe attribute of the given char position is 0? I access video memory by short ints (uint16_t) so I can write attribute and char at the same time.

Re: C lang goes crazy???

Posted: Mon May 02, 2022 10:21 am
by Octocontrabass
BoazTene wrote:

Code: Select all

    mov [BOOT_DRIVE], dl
Virtual machines tend to initialize segment registers to 0 before jumping to your bootloader, but the actual values are undefined and may not be zero on some PCs. You should set the segment registers to known values before using them. For example, this instruction uses the DS register. (Pay special attention to setting up the SS register. Interrupts will use the stack.)
BoazTene wrote:

Code: Select all

	gcc -ffreestanding -c $< -o $@
You are running 64-bit code in 32-bit mode. Also, it's a good idea to use a cross-compiler.

Re: C lang goes crazy???

Posted: Tue May 03, 2022 3:14 am
by BoazTene
Octocontrabass wrote:
BoazTene wrote:

Code: Select all

    mov [BOOT_DRIVE], dl
Virtual machines tend to initialize segment registers to 0 before jumping to your bootloader, but the actual values are undefined and may not be zero on some PCs. You should set the segment registers to known values before using them. For example, this instruction uses the DS register. (Pay special attention to setting up the SS register. Interrupts will use the stack.)
BoazTene wrote:

Code: Select all

	gcc -ffreestanding -c $< -o $@
You are running 64-bit code in 32-bit mode. Also, it's a good idea to use a cross-compiler.
I've changed everything to 32-bit mode and now the bootloader can't read from the disk.

makefile:

Code: Select all

OSNAME = "SuperDuperOS"
C_SOURCES = $(wildcard src/kernel/*.c src/drivers/*.c)
HEADERS = $(wildcard kernel /*.h drivers /*.h)
OBJ = ${C_SOURCES:.c=.o}


# call with make src='your-asm-file.asm'
# Example make src=bootloader.asm
all: os-image
	

# Compiles the bootloader
bin/bootloader.bin: src/boot/bootloader.asm
	nasm $< -f bin -o $@

# Compiles the kernel_entry.
bin/kernel_entry.o: src/boot/kernel_entry.asm
	nasm $< -f elf -o $@

# Compiles the kernel.
bin/kernel.o: src/kernel/kernel.c
	i686-elf-gcc -c $< -o $@ -ffreestanding -O2 -Wall -Wextra


bin/kernel.bin: bin/kernel_entry.o 	${OBJ}
	i686-elf-gcc -Ttext 0x1000 -o $@ -ffreestanding -O2 -nostdlib $^ -lgcc 
# i686-elf-ld -o $@ -Ttext 0x1000 $^ --oformat binary
# ld -o $@ -Ttext 0x1000 $^ --oformat binary

# Generic rule for building ’somefile.o’ from ’somefile.c’
%.o: %.c ${HEADERS}
	i686-elf-gcc -c $< -o $@ -ffreestanding -O2 -Wall -Wextra

# lunch the last binary via qemu
qemu:
	qemu-system-x86_64 bin/$(OSNAME)

# This is the actual disk image that the computer loads ,
# which is the combination of our compiled bootsector and kernel
os-image: bin/bootloader.bin bin/kernel.bin
	cat $^ > bin/$(OSNAME)

# cleans the entire bin folder.
clean:
	rm -r bin || true
	mkdir bin

# Disassemble our kernel - might be useful for debugging.
bin/kernel.dis : bin/kernel.bin
	ndisasm -b 32 $< > $@
bootloader:

Code: Select all

[org 0x7c00] ; bootloader offset
    KERNEL_OFFSET equ 0x1000
    mov [BOOT_DRIVE], dl
    
    mov bp, 0x9000 ; set the stack
    mov sp, bp

    mov bx, MSG_REAL_MODE
    call print.print_string ; This will be written after the BIOS messages

    call load_kernel

    call switch_to_pm ; We are never return from here.
    jmp $ ; this will actually never be executed

%include "src/boot/modules/disk.asm"
%include "src/boot/switch_pm/gdt.asm"
%include "src/boot/modules/console.asm"
%include "src/boot/modules/console32.asm"
%include "src/boot/switch_pm/switch_to_pm.asm"


[bits 16]
; loads the kernel
load_kernel:
    mov bx, MSG_LOAD_KERNEL
    call print.print_string

    mov bx, KERNEL_OFFSET
    mov dh, 48
    mov dl, [BOOT_DRIVE]
    call disk.load

    ret


[bits 32]
BEGIN_PM: ; after the switch we will get here
    call console.clear
    mov ebx, MSG_PROT_MODE
    call console.print_string_pm ; Note that this will be written at the top left corner

    call KERNEL_OFFSET

    jmp $


; globals
BOOT_DRIVE db 0
MSG_REAL_MODE db "Started in 16-bit real mode", 0
MSG_PROT_MODE db "Loaded 32-bit protected mode", 0
MSG_LOAD_KERNEL db "Starts loading the kernel", 0

; bootsector
times 510-($-$$) db 0
dw 0xaa55
disk error:
ah = 0c:
unsupported track/invalid media

Re: C lang goes crazy???

Posted: Tue May 03, 2022 11:44 am
by Octocontrabass
BoazTene wrote:

Code: Select all

    mov dh, 48
How big is your disk image?