IMPLEMENTING A LITTLE OS #2

Ushani Anuradha
3 min readOct 12, 2022

--

A beginners guide to Operating System — Part 2 (Start implementing with C)

Welcome to the second episode of my operating system development series. You may read how to set up the development environment and boot the simplest OS we can construct in my first article, which was published last week.

I’ll demonstrate in this article how to create a C program for our kernel and call it from Assembly code. Therefore, in the future, we can design our OS using C and only use Assembly as necessary.

Setting up a stack

One prerequisite for using C is a stack since all non-trivial C programs use a stack. To form a stack we need to point the esp register to the end of a properly aligned free memory area.

We could point esp to a random area in memory since, so far, the only thing in the memory is GRUB, BIOS, the OS kernel, and some memory-mapped I/O. This is not a good idea — we don’t know how much memory is available. A better idea is to reserve a piece of uninitialized memory in the bss section of the kernel.

The NASM pseudo-instruction resb can be used to declare uninitialized data:

Reserving memory for the stack

Copy the above code into the file loader.s, right after the last definition (CHECKSUM).

Then set the stack pointer by pointing esp register to the end of the kernel_stack memory. To do this, replace the instructions in the loader label in the loader.s file with the following code.

Setting up the stack pointer

Calling C Code From Assembly

Below, the C function will take three integer arguments and return the sum. Copy the following code into a new file named kmain.c. This will be the source file of our first C code that we will call from our assembly code.

C function to add three integers

Using assembly to call a C function

Just writing a C function is not enough. We need to call it using assembly.

We will use the cdecl calling convention because it is the one used by GCC. The arguments to a C function should be pushed to the stack in right-to-left order, with the rightmost argument being pushed first. The function’s return value will be stored in the eax register.

To accomplish the task, place the following code after the esp instruction in the loader.s file.

Calling C function from Assembly

Compiling C code

When compiling the C code for the OS, GCC needs to use a lot of flags. This is because C code should not assume there is a standard library as there is none for our operating system. In addition, we should enable all warnings and treat them as errors. When compiling the C code, we use the following flags to achieve the above goals.

(We will use these in the Makefile which we are going to create in the next step):

-m32 -nostdlib -nostdinc -fno-builtin -fno-stack-protector 
-nostartfiles -nodefaultlibs -Wall -Wextra -Werror

Set up Build Tools

Now we’ll set up some build tools to make it easier to compile and test our operating system. We will use Make as our build system.

Here is a simple Makefile for our OS. Create a file named Makefile and save the above text in that file.

Makefile configuration

Following is the loader.s file after all the modifications have been done:

loader.s file after the modifications

The contents of your working directory should now look like the following figure:

working directory

Now you should be able to start the OS with the simple command run, which will compile the kernel and start it in Bochs.

Now we can use C language to develop our operating system. This is a huge achievement considering how easy it is compared to developing an OS with only Assembly Language.

Let’s come up with the next part of this os developing series.

References ….

The Little OS Book: https://littleosbook.github.io/book.pdf

--

--

Ushani Anuradha
Ushani Anuradha

Written by Ushani Anuradha

BSc.(Hons) Software Engineering Undergraduate | University Of Kelaniya.