Getting started with Assembly Level Coding – How to make your own Bootloader

Learning Assembly level programming in 2019 may seem ridiculous. It is hardly used anywhere except in the most rudimentary bootloader programs. Even bootloaders are not coded in C and then translated into assembly.

But then if you are plan to truly understand how your code interacts with the system hardware – how memory is allocated and how registers function, you will have to understand asm.

Before you jump ahead to code, there are a number of things that you need to know.

assembly level coding - compile with nasm
We will be extensively using nasm to compile our bootloaders. Going through the man pages for it will help.

Let’s get into the Assembly level world herein.

The primary source for this post is mentioned in the footnotes. Be sure to check and/or follow the respective authors if you wish to follow up in detail.

Q. What is a bootloader?

A. A bootloader is simply a program that is executed whenever a bootable device is initialized by the computer.

Q. When is a bootable device initialized by the computer?

A. When a computer is switched on, the power supply to the internal components of the system is enabled. Once the power to the CPU is triggered, it initializes the Basic Input Output System. This is a Read Only Memory chip that your CPU comes preinstalled with. When it is initialized (voltages are set and checks if the power is available), it executes a program called the BIOS. This program in turn checks for the following –

  • Runs POST – acronym for Power on Self Test: This program in turn verifies the following –
    • the integrity of the BIOS code itself – if the BIOS code is corrupted, you will have to flash it again.
    • CPU registers present and their specifications
    • Checks on components like DMA, interrupt controller, timers etc.
    • Checks the main memory modules present on system
    • Initialises BIOS
    • Identify and prioritize available bootable devices

You may be familiar with the various BIOS post codes, the beeps that allow users to troubleshoot their failing systems.

The bootable device in the system has the bootloader stored in it. As that is loaded into the memory, the operating system of your choice gets loaded into the primary memory. It this then that you see the familiar boot logos of your operating system.

The boot sector is identified by the storage location in any bootable device where the first set of instructions for initializing the boot loader for that particular device.

When the bootable device is initialized, the BIOS loads the first sector of the bootable device (also the boot sector) and stores in the primary memory (RAM). This actually begins your boot sequence.

As of now 64 bit processors are the most popular bunch. But for the sake of simplicity I will be giving you a tour of 16 bit code. These are backwards compatible and hence should have no problem compiling and running. For the records, the increased bit size increases the memory space available to the programs, thereby increasing performance.

Q. What is real mode?

A. Real mode, also known as Read Address Mode is a 20 bit segmented memory address space that gives exactly 1 MB of addressable memory. This is no longer in use today. But processors back in the day of Windows 98 and older used to start in real mode. For purposes of simplicity, that is what we are going to build our bootloader on.

Objective: Create a simple bootloader using assembly code


  • Operating system – In may case, I am using Ubuntu 18.04 LTS. I prefer Linux distros to get things done. But, you should be able to function well on other operating systems too – as long as you can get hold of the asm compilers for your specific OS.
  • Assembler (In my case – GNU Assembler)
  • x86 Instruction set
  • Compiler and Linker (in Linux, this is easily taken care of with gcc/cc)
  • Any x86 emulator (I will use qemu)

I am going to assume that you know the basics of an operating system. What it does, how it is installed and so on. Since you are already working on a system with an operating system installed, you should have already covered the basics. For a technical follow up, please google each item above for a more detailed description.

I will have to focus our attention to what counts the most for this article. That is microprocessors.

To actually understand and write assembly code, it is a must to understand microprocessors. There is no way around it.

In the next follow up post, we will go through the basics so that you can jump right in. For advanced programmers or those who wish to go for an unguided adventure, the links below will help.