How to Make a Linux Kernel with Nasm, Go Binary, Mini Linuxby@anikishaev
1,008 reads
1,008 reads

How to Make a Linux Kernel with Nasm, Go Binary, Mini Linux

by Andrey NikishaevApril 22nd, 2022
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

How to Make a Linux Kernel with Nasm, Go Binary, Mini Linux
featured image - How to Make a Linux Kernel with Nasm, Go Binary, Mini Linux
Andrey Nikishaev HackerNoon profile picture

Github link for project:


Some things needed for building & running stuff

apt-get install bison flex nasm qemu-system-x86_64 libelf-dev bc

Nasm simple example

The standard boot sector is 512 bytes which should end with 0xaa55 bytes. I’ve created a simple Nasm script that prints “Hello Wolrd!” on boot.

[org 0x7c00]
mov ah, 0x0e
mov bx, hello 

    mov al, [bx]
    cmp al, 0
    je end
    int 0x10
    inc bx
    jmp print

jmp $

    db 'Hello world!',0

times 510-($-$$) db 0  
dw 0xaa55       ; this bytes should end boot sector

Compile Boot binary:

nasm -f bin boot.nasm -o boot.bin

Run it with an emulator

qemu-system-x86_64 boot.bin

Run go binary on Linux Kernel

First, we need to download the latest stable Linux Kernel

curl | tar Jx

Then we need to configure it and select all things that we need. That’s kind of hard, because there are tons of settings. I’ve made some default config in root/.config that u can copy to linux-5.17.4 folder to use.

If you want to build your own config use: make menuconfig

Compile kernel (it will take a while)

cd linux-5.17.4 && make -j4

Now let’s run the image with our kernel to see if it works

qemu-system-x86_64 -serial stdio -kernel linux-5.17.4/arch/x86/boot/bzImage

We got an error saying that we didn’t mount a disk — it ok, cause we really didn’t do it.

Now we need to mount the disk and add our binary, libs, etc to it. We will use initramfs for that, basically putting everything into the RAM.

For that, we need to build our go binary with static linking and create gzip archive with our ram mount(basically only our binary)

Very simple go script:

package main

import (

func main() {
    var data string
    fmt.Println("Hello from your Go image!")
    for {
	fmt.Println("Enter something:")
	fmt.Printf("Echo: %s\n", data)

SPATH=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )

cd $SPATH/gobinary
go build -ldflags="-extldflags=-static" -o init
cd ../
mkdir -p goram
mv $SPATH/gobinary/init $SPATH/goram/init
cd $SPATH/goram
find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../goram.cpio.gz


Now we can run it as before just add our ram mount

qemu-system-x86_64 -serial stdio -kernel linux-5.17.4/arch/x86/boot/bzImage -initrd go-ram.cpio.gz

Creating a mini-linux image

Of course, we can create our custom Linux. For example, we can use Buxybox image for that

curl | tar Jz
cd busybox-1.33.2
make menuconfig 
make -j4
make install
cd ..

Now let’s fill our image

mkdir -p bbram/{bin,sbin,etc,proc,sys,usr/bin,usr/sbin}
cp -a busybox-1.34.1/_install/* bbram/

Let’s create a welcome init script


/bin/mount -t devtmpfs devtmpfs /dev
/bin/mount -t proc none /proc
/bin/mount -t sysfs none /sys

dmesg -n 1
cat << EOF

 Boot took $(cut -d' ' -f1 /proc/uptime) seconds

  __  __ _       _   _      _                  
 |  \/  (_)     (_) | |    (_)                 
 | \  / |_ _ __  _  | |     _ _ __  _   ___  __
 | |\/| | | '_ \| | | |    | | '_ \| | | \ \/ /
 | |  | | | | | | | | |____| | | | | |_| |>  < 
 |_|  |_|_|_| |_|_| |______|_|_| |_|\__,_/_/\_\

exec setsid cttyhack sh #
exec /bin/sh

Save it

cp init bbram/bin/init
chmod +x bbram/bin/init

Create ram archive

cd bbram
find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../bbram.cpio.gz
cd ../

Run it

qemu-system-x86_64 -kernel linux-5.17.4/arch/x86/boot/bzImage -initrd bbram.cpio.gz -m1024