Printing text with a C kernel doesn't work properly

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.
lucasrdrgs
Posts: 9
Joined: Sun Feb 03, 2019 9:47 am

Printing text with a C kernel doesn't work properly

Post by lucasrdrgs »

Hello. I am trying to print some text with my bootloader and my kernel written in C (loaded at 0x7e00) but it doesn't print the whole text. However, if I declare the following char* and fill it with some text and print all the characters inside it one by one, it works but it's not very practical:

Code: Select all

char* message = (char*)0x80000;
It makes me think it's a memory related issue and I am unsure how I can fix it. I read a post on reddit made by a person with the same problem as me and one of the replies said the .text section is fully loaded:
If it’s getting through any one of the function calls correctly, then .text is probably fully loaded, at least. Is the entire string there? Try pooping the second-to-last byte out into Bochs’ debug port before writing, and see if it matches the character it should. Idunno how it’s arranged pre-load, but .rodata usually comes after .text so that and .data would be the last things to load. You’re (oddly) not using .data to preinitialize your VGA stuff (all those init values are compile-time-constant), so you’ve lost one potential canary there. I’d also put a magic value within your image at the very end, and have the loader place one just after it. Then you can check that both sync up with what they should be, = you’re reasonably sure your entire kernel has loaded.
Here is my source code:
https://hastebin.com/ehogozibuc.cpp Kernel's main file
https://hastebin.com/emuhexaqob.cpp video.c (functions to play with video memory)
https://hastebin.com/tacavorolu.sql Bootloader
https://hastebin.com/fudowoyude Linker script

Any thoughts or suggestions? Sorry if this is a noobish question, I just started learning this kind of thing. Thanks in advance :)
MichaelPetch
Member
Member
Posts: 729
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: Printing text with a C kernel doesn't work properly

Post by MichaelPetch »

Are you reading enough sectors to cover your entire kernel (including data)? I haven't actually looked at your code, but that is my first thought.
Last edited by MichaelPetch on Sun Feb 03, 2019 10:59 am, edited 1 time in total.
User avatar
iansjack
Member
Member
Posts: 4662
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Printing text with a C kernel doesn't work properly

Post by iansjack »

You've written your bootloader with SQL?

(I haven't download your source files as I don't click on random links - you'd do better to store your source code in GitHub, or something similar.)
lucasrdrgs
Posts: 9
Joined: Sun Feb 03, 2019 9:47 am

Re: Printing text with a C kernel doesn't work properly

Post by lucasrdrgs »

iansjack wrote:You've written your bootloader with SQL?

(I haven't download your source files as I don't click on random links - you'd do better to store your source code in GitHub, or something similar.)
No. It's just Hastebin thinking the assembly code is SQL.
MichaelPetch
Member
Member
Posts: 729
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: Printing text with a C kernel doesn't work properly

Post by MichaelPetch »

Your bootloader only reads 2 sectors from disk. That is a total of 1024 bytes. If your kernel code and data exceed 1024 bytes not all the data will be loaded in memory. I happened to see a comment in the code that a string 2000 bytes long didn't work:

Code: Select all

// However, if I have a 2000 characters long string and
    // call print(myString, 0x4f); it doesn't print the entire thing.
You don't say how you build your code either. If you are using a 64-bit compiler make sure you compile as 32-bit code with -m32 (or use an i686/i386 cross compiler)
Last edited by MichaelPetch on Sun Feb 03, 2019 11:22 am, edited 1 time in total.
lucasrdrgs
Posts: 9
Joined: Sun Feb 03, 2019 9:47 am

Re: Printing text with a C kernel doesn't work properly

Post by lucasrdrgs »

MichaelPetch wrote:Your bootloader only reads 2 sectors from disk. That is a total of 1024 bytes. If your kernel code and data exceed 1024 bytes not all the data will be loaded in memory. I happened to see a comment in the code that a string 2000 bytes long didn't work:

Code: Select all

// However, if I have a 2000 characters long string and
    // call print(myString, 0x4f); it doesn't print the entire thing.
I changed AL to 0x04 so it reads 4 sectors and it did print more stuff but didn't print the whole string. I tried to go with 0x05 and it also worked. Then with 0x06 but any value greater than 0x05 bricks the code and nothing is printed.
MichaelPetch
Member
Member
Posts: 729
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: Printing text with a C kernel doesn't work properly

Post by MichaelPetch »

Since you read data into memory from disk and you don't know where the stack is that the BIOS set you should be setting SS:SP to something that won't be clobbered by the disk reads prior to using the int 13h/ah=2 BIOS function. SS=0x0000 and SP=0x7c00 would be fine given the stack will grow down from below where the bootloader is in memory.
lucasrdrgs
Posts: 9
Joined: Sun Feb 03, 2019 9:47 am

Re: Printing text with a C kernel doesn't work properly

Post by lucasrdrgs »

MichaelPetch wrote:Since you read data into memory from disk and you don't know where the stack is that the BIOS set you should be setting SS:SP to something that won't be clobbered by the disk reads prior to using the int 13h/ah=2 BIOS function. SS=0x0000 and SP=0x7c00 would be fine given the stack will grow down from below where the bootloader is in memory.
Isn't this enough?

Code: Select all

mov ebp, 0x90000    
mov esp, ebp
This is executed after int 13h/ah=2.
I also tried this before int13h:

Code: Select all

xor ax, ax
mov ss, ax
mov sp, 0x7c00 ; I'm probably not doing this right.
Octocontrabass
Member
Member
Posts: 5418
Joined: Mon Mar 25, 2013 7:01 pm

Re: Printing text with a C kernel doesn't work properly

Post by Octocontrabass »

How big is your kernel, anyway? Randomly changing the number of sectors you load is pointless if you don't know how many you really need.

Your bootloader doesn't set up the stack before it starts using the BIOS interrupts. Remember, those need the stack too. If the stack overlaps the memory you're loading your kernel into, bad things will happen.

Your linker script is awfully small. You may be missing one or more sections that are required for your code to run correctly. The lack of .bss is particularly glaring - you can't guarantee uninitialized RAM will be set to zero, you need to initialize it yourself somehow, and including it in your binary is the simplest way.

I notice you didn't provide any of your build scripts. How are you building your kernel? A cross-compiler is strongly recommended.
MichaelPetch
Member
Member
Posts: 729
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: Printing text with a C kernel doesn't work properly

Post by MichaelPetch »

To make sure you don't clobber the stack during disk reads (which can cause the entire BIOS interrupt to fail or never return to your code) you must set a real mode stack before you do the disk read. There is nothing wrong with setting the protected mode stack after, but that doesn't help deal with the issue of the real mode stack needing to be set to something out of the way before doing a disk read. But yes, doing this before the disk read is fine:

Code: Select all

xor ax, ax
mov ss, ax
mov sp, 0x7c00 ; I'm probably not doing this right.
It would also help to know what command lines you use to compile, assemble, and link all your code together as that can also cause problems if done improperly.
lucasrdrgs
Posts: 9
Joined: Sun Feb 03, 2019 9:47 am

Re: Printing text with a C kernel doesn't work properly

Post by lucasrdrgs »

Here is the build script (I'm using Parrot OS (linux) x64):

Code: Select all

# clear
rm *.bin *.img *.o

# compile
nasm boot.asm -f bin -o boot.bin
gcc -m32 -ffreestanding -c main.c -o main.o
gcc -m32 -static -nostartfiles -c video.c -o video.o

# link
ld -melf_i386 -N -T link.ld -o kernel.o main.o video.o
objcopy -R .note -R .comment -S -O binary kernel.o kernel.bin

boot_sz=$(stat -c %s boot.bin)
kernel_sz=$(stat -c %s kernel.bin)
sum_sz=$(($boot_sz + $kernel_sz))
dummy_sz=$(./dummy_size.py $sum_sz)
head -c $dummy_sz < /dev/zero > tmp

cat boot.bin kernel.bin tmp > kernel.img
#cat 
rm tmp
rm *.o
lucasrdrgs
Posts: 9
Joined: Sun Feb 03, 2019 9:47 am

Re: Printing text with a C kernel doesn't work properly

Post by lucasrdrgs »

Octocontrabass wrote:How big is your kernel, anyway? Randomly changing the number of sectors you load is pointless if you don't know how many you really need.

Your bootloader doesn't set up the stack before it starts using the BIOS interrupts. Remember, those need the stack too. If the stack overlaps the memory you're loading your kernel into, bad things will happen.

Your linker script is awfully small. You may be missing one or more sections that are required for your code to run correctly. The lack of .bss is particularly glaring - you can't guarantee uninitialized RAM will be set to zero, you need to initialize it yourself somehow, and including it in your binary is the simplest way.

I notice you didn't provide any of your build scripts. How are you building your kernel? A cross-compiler is strongly recommended.
The final size of kernel.bin is 2248 bytes and I tried this before using interrupts:

Code: Select all

xor ax, ax
mov ss, ax
mov sp, 0x7c00
MichaelPetch
Member
Member
Posts: 729
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: Printing text with a C kernel doesn't work properly

Post by MichaelPetch »

Houston we have a problem:

Code: Select all

gcc -m32 -ffreestanding -c main.c -o main.o
gcc -m32 -static -nostartfiles -c video.c -o video.o

# link
ld -melf_i386 -N -T link.ld -o kernel.o main.o video.o
objcopy -R .note -R .comment -S -O binary kernel.o kernel.bin
First off you aren't using a cross compiler so you may have potential issues with position independent code. You can compile each C file with -fno-PIC. You'd normally use the -fno-PIE when using GCC to link to an executable.This leads to the big glaring problem.You are generating the binary from the .o(object file).You are not linking your code into an executable and then converting the executable to a binary file.
lucasrdrgs
Posts: 9
Joined: Sun Feb 03, 2019 9:47 am

Re: Printing text with a C kernel doesn't work properly

Post by lucasrdrgs »

MichaelPetch wrote:Houston we have a problem:

Code: Select all

gcc -m32 -ffreestanding -c main.c -o main.o
gcc -m32 -static -nostartfiles -c video.c -o video.o

# link
ld -melf_i386 -N -T link.ld -o kernel.o main.o video.o
objcopy -R .note -R .comment -S -O binary kernel.o kernel.bin
First off you aren't using a cross compiler so you may have potential issues with position independent code. You can compile each C file with -fno-PIC. You'd normally use the -fno-PIE when using GCC to link to an executable.This leads to the big glaring problem.You are generating the binary from the .o(object file).You are not linking your code into an executable and then converting the executable to a binary file.
So should I do

Code: Select all

gcc -fno-PIC -m32 -ffreestanding -c main.c -o main.o
gcc -fno-PIC -m32 -static -nostartfiles -c video.c -o video.o
instead?
MichaelPetch
Member
Member
Posts: 729
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: Printing text with a C kernel doesn't work properly

Post by MichaelPetch »

I'd clean it up and do it this way:

Code: Select all

#!/bin/bash

nasm -f bin boot.asm -o boot.bin
gcc -m32 -c -ffreestanding -fno-PIC main.c -o main.o
gcc -m32 -c -ffreestanding -fno-PIC video.c -o video.o

# Link files to kernel.elf using GCC rather than LD
gcc -m32 -Tlink.ld -fno-PIE -nostartfiles main.o video.o -o kernel.elf

objcopy -R .note -R .comment -S -O binary kernel.elf kernel.bin

# Make disk image size of 1.44MiB floppy
dd if=/dev/zero of=disk.img bs=1024 count=1440

dd if=boot.bin of=disk.img conv=notrunc
dd if=kernel.bin of=disk.img seek=1 conv=notrunc
This should compile each individual file, link them to an executable called kernel.elf and that executable is converted into a binary file call kernel.bin. I also simplify creating a disk image (I chose a nominal floppy disk size of 1.44MiB). Bootloader in first sector and kernel starting in second sector.
As was mentioned to you by the other commenter you rely on the BSS section of memory already being zero. You may be lucky that is the case but it isn't guaranteed and could cause you problems later on.
Last edited by MichaelPetch on Sun Feb 03, 2019 12:24 pm, edited 2 times in total.
Post Reply