Writing Our Own Operating System (Part 2)
October 12, 2022
Read on MediumIn the last week, we have seen how to set up the booting part of our operating system. In this article, we will see how we can develop our operating system further with the C programming language. Most of the popular operating system’s kernels such as Windows, Mac, Android, and Linux are developed using the C programming language, even the device drivers are also written in the C language than assembly code because the assembly code is somewhat difficult to work with because it is very closer to the machine than humans in understandability. So, we will also develop our Operating System further with the C programming Language. This article will further explain setting up a stack, calling a C program from assembly language, and compilation of C code we wrote
(1)Setting up the stack
So, the first thing we have to do is set up our stack, and it’s quite easy to do too. All we have to do is point our esp register to the end of an area of free memory that is correctly aligned. When the system boots the only thing in the Operating System are GRUB, BIOS, the OS kernel, and some memory-mapped I/O. So, if we make our esp register to an arbitrary location in the memory that location may not be available so it’s always better to make use of the “bss” section instead of the “data” section to reduce the size of the OS executable. Since GRUB understands ELF, GRUB will allocate any memory reserved in the “bss” section when loading the OS.

The NASM pseudo-instruction RESB, RESW, RESD, RESQ, REST, RESO, RESY and RESZ are designed to be used in the BSS section of a module: they declare uninitialized storage space.
Here we use resb to declare the Kernel Stack size.
https://medium.com/media/3f7032d7b53d1eeb3b47dd71be170507/hrefadd the above code to the loader.s file we made in the previous section right after the right last definition (CHECKSUM).And also add the below code to set up the stack pointer. This is done by pointing esp to the end of the kernel_stack memory.
https://medium.com/media/88e00a8efa77e793168e59e62d6f542d/href(2) Calling C Function from Assembly Code
The second step is to call the c function from the assembly code to do that we have to create our c program. So, let’s create a small C program that takes three arguments and adds them
https://medium.com/media/b75e4c7b02e428145a16a19001c73477/hrefUse the pseudo instruction `extern` to indicate that the assembler that the C function is defined elsewhere. Add the following code to the loader.s file
extern kmain ; the function kmain is defined elsewhere
after that add the code below to the loader label to call the kmain function.
call kmain ; call the function
The assembly code,
external sum_of_three ; the function sum_of_three is defined elsewhere push dword 3 ; arg3
push dword 2 ; arg2
push dword 1 ; arg1
call sum_of_three ; call the function, the result will be in eax
add that assembly code in to loader.s file.
(3) Compiling C Code
The next step is compiling. For normal compilations, we can use gcc fileName.c -o objectName, but in this instance, A lot of GCC flags must be used while building the C code for the OS since otherwise, the C code might assume the existence of a standard library, the flags used are -m32 -nostdlib -nostdinc -fno-builtin -fno-stack-protector -nostartfiles -nodefaultlibsand it is also recommended to turn on all warnings and treat warnings as errors when writing C programs.
(4) Build Tools
In order to make compiling and test running the OS easier, we use the make build system.
https://medium.com/media/2d0a7c25f4223b31210ac532625bdc16/hrefcopy the code above and make a new file in the current directory as Makefile
if every instruction is followed correctly, The contents of your working directory should look like this,
|-- bochsrc.txt
|-- iso
| |-- boot
| |-- grub
| |-- menu.lst
| |-- stage2_eltorito
|-- kmain.c
|-- loader.s
|-- link.ld
|-- Makefile
and loader.s file should look like this
https://medium.com/media/a26f4527cc4c39b943dfab931549ec6c/hrefsince we passed arguments 1,2,3 , now when you boot up the Bochs and then display the log produced by Boch (using cat bochslog.txt),we should see the summation EAX=6 written in it. We can change the arguments and find the value in hexadecimal form in the EAX register
So that brings the end of our second article in our journey of designing the OS. We will see a new topic related to developing OS in the next article as well!
Thank you!
Reference : Helin, E., & Renberg, A. (2015). The little book about OS development