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.