Frontend Labs
⋯

50. Your first Linux kernel module: hello world, the Makefile, insmod/dmesg

A kernel module is code the kernel loads into its own address space at runtime — no main(), no libc, no user-space memory protection between your bug and a full system crash. Everything here needs a Linux machine (a real one, a VM, or Raspberry Pi) with kernel headers installed for your exact running kernel (sudo apt install linux-headers-$(uname -r) on Debian/Ubuntu).

// hello.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>

static int __init hello_init(void) {
    printk(KERN_INFO "hello: module loaded\n");   // printk, not printf — there is no stdout
    return 0;                                        // 0 = success, matching every syscall convention
}

static void __exit hello_exit(void) {
    printk(KERN_INFO "hello: module unloaded\n");
}

module_init(hello_init);   // register these as the load/unload entry points
module_exit(hello_exit);

MODULE_LICENSE("GPL");                 // non-GPL modules can't call GPL-only kernel symbols
MODULE_AUTHOR("you");
MODULE_DESCRIPTION("A minimal Linux kernel module");
# Makefile — a "Kbuild" makefile, not the CMake/Make from Section 41
obj-m += hello.o

all:
	$(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
	$(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
make
sudo insmod hello.ko
dmesg | tail -1        # hello: module loaded
lsmod | grep hello      # confirms it's resident
sudo rmmod hello
dmesg | tail -1        # hello: module unloaded

Why the build looks nothing like Section 41's CMake setup: a kernel module isn't linked against glibc or any user-space ABI at all — it's compiled against, and only guaranteed to load into, the exact kernel tree at /lib/modules/$(uname -r)/build. This is the sharp edge behind Section 40's ABI-stability discussion: user-space libraries go to great lengths (opaque pointers, symbol versioning) to stay binary-compatible across versions; the Linux kernel's internal APIs deliberately make no such promise between kernel versions — a module built for 6.6 is not expected to load into 6.8 without a rebuild. That's a conscious trade-off (it lets kernel internals evolve freely) that every driver maintainer has to live with.


Generated from real-life-c-guide.md · 8 Oct 2026 16:36