Programming Languages for OS
Hello Readers, Welcome back to another article in the Developing an Operating Systems series. Today I’m going to talk about the languages you can use to write an OS, especially Assembly and C.
So last week I talked about making an OS that has minimal functionality which was written completely using assembly language. But when developing an OS with more functionality it is easier to use another programming language like C. In order to use any other programming languages when writing an OS first, you have to set up a stack. In this week’s article, I’m going to talk about how to set up a stack to use C in programming the OS.
Assembly is a low-level programming language in which there is a strong connection between the instructions in the language and the machine code. Therefore Assembly language provides access to all the functions in the processor.
Assembly code is converted into executable machine instructions using a utility called an assembler. This process is referred to as assembly. Usually, assembly languages have one statement per machine instruction and also supports constants, comments and assembler directives are also supported. Since assembly depends on the machine code, every assembly language is designed for one specific computer architecture and are also only works with a particular operating system. But most of them can be used with any operating system running on the same architecture.
C is a general-purpose procedural computer programming language. By design, C provides constructs that map efficiently to typical machine instructions. Therefore, it is used for applications previously coded in assembly including include operating systems and various application software for computer architectures that range from supercomputers to PLCs and embedded systems.
C was developed by Dennis Ritchie at Bell Labs in 1973 to construct utilities running on Unix. Since then it has gained popularity and become a widely used language with compilers available for most current computer architectures and operating systems. C is an imperative procedural language designed to be compiled to provide low-level access to memory and language constructs that map efficiently to machine instructions, all with minimal runtime support. Despite its low-level capabilities, the language was designed to encourage cross-platform programming. A standard program written in C can be easily compiled to be used in a wide range of operating systems with minimal changes to its source code. While C does not include certain features found in other languages like object orientation and garbage collection, these can be implemented or emulated, often through the use of external libraries.
A stack is an abstract data type that serves as a collection of elements. In common terms, storing data to the stack is called pushing (using the PUSH instruction) and restoring data from the stack is called popping (using the POP instruction).
Since all major programs written in C use a stack it is needed to create a stack in memory before trying to write an OS using C.
My OS Developing Experiance
Creating a stack to use in my OS is not much harder than pointing the ESP register to the end of free area in the memory. This can be easily done by pointing the ESP register to a random area in the memory since there are nothing there other than the GRUB BIOS and the OS Kernel but this is not a good idea since we are unclear on how much memory is available, therefor there is a chance that the area ESP would point to is already in use. The better way to do this is to reserve a piece of uninitialized memory in the BSS section of the kernel to be used as the stack.
This can be done by declaring the uninitialized data using the resb function in the loader.s file. Then the stack pointer is created by pointing the ESP register to the end of the kernel_stack memory in the same file. The finished loader.s file will look like this.
Compiling the C code
Since there are no standard libraries available for our OS, the C code should not assume their presence so a lot of GCC flags are needed when compiling the C code. It is also best to turn on all warnings and treat them as errors. So I’ll use the following tags when compiling the code.
As for this step i’m not running any C codes so i’ll just create a kmain.c file with an empty function.
Since we are using the same codes every time we compile and run the OS it is a good idea to automate this process using build tools. Build tools are programs that automate the creation of executable applications from source code. Make is a build system available in ubuntu so we’ll use it to automate our OS building process. The final build file will look like this.
After creating the build file it can be run using the make run command in the terminal. Once it is successfull it will create the iso file and boot it up in borchs.
Thank you for reading and I will be back next week with the next article.