Learn Modules Programming Basics in Linux with clear examples, step-by-step guidance, and beginner-friendly explanations for efficient kernel module development.
If you are starting your journey into Linux kernel development, modules programming basics is one topic you simply cannot skip. Kernel modules are the safest, cleanest, and most practical way to learn how the Linux kernel really works without constantly rebuilding the entire kernel.
Think of kernel modules like plugins for the Linux kernel. You load them when needed, unload them when you are done, and keep your system flexible and clean. Whether you want to write a device driver, add debugging support, or experiment with kernel internals, understanding module programming basics is step one.
What Are Kernel Modules and Why Do They Matter?
A kernel module is a piece of code that runs inside the Linux kernel space and can be inserted or removed at runtime. Unlike user-space programs, kernel modules have direct access to hardware and core kernel services.
Why does this matter?
Because without kernel modules:
- Every driver change would require a full kernel rebuild
- Development would be slow and risky
- Debugging would be painful
With kernel modules:
- You can load features dynamically
- You can test drivers safely
- You can keep the kernel small and modular
This is why modules programming basics is considered the foundation of Linux kernel programming.
Kernel Module vs Monolithic Kernel Code
Let’s clear one common confusion early.
- Monolithic kernel code is compiled directly into the kernel image
- Kernel modules are compiled separately and loaded at runtime
Most modern Linux drivers are built as modules because:
- They reduce boot time
- They save memory
- They are easier to maintain
As a beginner, modules give you fast feedback. You write code, build it, load it, test it, unload it, repeat. No reboot needed.
Your First Look at a Kernel Module
At its core, a kernel module is just a C file with two special functions:
- An initialization function
- A cleanup function
These tell the kernel:
- What to do when the module is loaded
- What to do when the module is removed
This simple structure is what makes modules programming basics approachable, even for newcomers.
Building Kernel Module Binary
One of the most searched topics in modules programming basics is how to actually build a kernel module binary.
Unlike normal C programs, kernel modules:
- Do not use libc
- Are compiled against kernel headers
- Produce a
.kofile instead of an executable
Basic Requirements
To build a kernel module, you need:
- Linux kernel headers
- GCC
- Make
Simple Kernel Module Makefile
Here is a minimal Makefile used for building kernel module binaries:
obj-m += hello_module.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
What is happening here?
obj-mtells the kernel build system this is a module- The kernel build directory provides the correct compiler flags
- The output is a
.kofile
This build process is a core part of modules programming basics and something you will use daily as a kernel developer.
Loading and Unloading Kernel Modules
Once the kernel module binary is built, you interact with it using standard tools.
Loading a Module
sudo insmod hello_module.ko
Unloading a Module
sudo rmmod hello_module
Checking Loaded Modules
lsmod
These tools let you work with modules without rebooting, which is one of the biggest advantages of module-based development.
Tools for Module Management
Linux provides powerful tools for managing kernel modules. Understanding these tools is a must when learning modules programming basics.
insmod
- Loads a module by file path
- Does not resolve dependencies
rmmod
- Removes a module from the kernel
modprobe
- Loads modules with dependency handling
- Preferred tool in real systems
lsmod
- Shows all loaded modules
- Displays dependency relationships
modinfo
- Shows module metadata
- Useful for debugging and verification
These tools work together to give you full control over module lifecycle management.
Tracking Module Dependency
Kernel modules often depend on other modules. For example, a filesystem driver may rely on core block device modules.
This is where tracking module dependency becomes important.
How Dependencies Are Managed
- The kernel tracks symbol usage
- Dependencies are recorded during module build
depmodgenerates dependency maps
Viewing Dependencies
lsmod
The output shows:
- Module name
- Size
- Which modules depend on it
Why modprobe Matters
Unlike insmod, modprobe:
- Automatically loads dependent modules
- Prevents missing symbol errors
Understanding dependency tracking is essential in real driver development and a key part of modules programming basics.
Module Parameters Explained Simply
Module parameters allow you to pass values to a kernel module at load time. Think of them as command-line arguments for kernel code.
This feature alone makes modules extremely flexible.
Defining Module Parameters
static int debug = 0;
module_param(debug, int, 0644);
Passing Parameters
sudo insmod mymodule.ko debug=1
Why Module Parameters Matter
- Enable debugging without recompiling
- Configure behavior dynamically
- Used heavily in production drivers
Module parameters are widely used in real systems and understanding them is a core part of modules programming basics.
Understanding the Kernel Symbol Table
The kernel symbol table is one of those topics that sounds scary but is actually very logical.
The kernel symbol table:
- Contains exported symbols
- Allows modules to access kernel functions
- Enables communication between modules
Viewing Kernel Symbols
cat /proc/kallsyms
This file lists:
- Function names
- Variable names
- Memory addresses
When a module is loaded, the kernel checks this table to resolve symbols used by the module.
If a symbol is not found, the module fails to load.
Exporting Module Symbols
Sometimes, you want one module to use functions from another module. This is where exporting module symbols comes in.
Exporting a Symbol
void my_helper_function(void)
{
printk(KERN_INFO "Helper function called\n");
}
EXPORT_SYMBOL(my_helper_function);
Now other modules can use my_helper_function.
Why Export Symbols?
- Share common logic
- Split large drivers into smaller modules
- Build layered kernel designs
This concept is critical in real-world kernel development and often appears in interviews related to modules programming basics.
Kernel Module Licensing and Why It Matters
Every kernel module must declare its license.
MODULE_LICENSE("GPL");
Why is this important?
- Some kernel symbols are GPL-only
- Non-GPL modules cannot access them
- The kernel enforces this at load time
If you forget this, you may see warnings or missing symbol errors.
Debugging Kernel Modules Like a Pro
Debugging kernel code is different from user-space debugging.
Common Debugging Techniques
printkfor loggingdmesgfor viewing kernel logs- Dynamic debug
- Kernel crash dumps
Example:
printk(KERN_INFO "Module loaded successfully\n");
Kernel debugging is an art, and mastering it starts with solid module programming basics.
Common Mistakes Beginners Make
Let’s save you some pain.
Frequent Errors
- Forgetting to clean up resources
- Incorrect module parameters
- Missing symbol exports
- Using blocking calls in wrong context
Every kernel developer makes these mistakes. The key is understanding why they happen.
How Modules Programming Basics Helps Your Career
If you are targeting:
- Embedded Linux roles
- Kernel driver positions
- BSP development
- Automotive Linux jobs
Then mastering modules programming basics is not optional. Interviewers expect you to understand:
- Module lifecycle
- Dependency handling
- Symbol exporting
- Build systems
This knowledge separates real kernel developers from tutorial followers.
Practical Learning Path
Here is a simple roadmap:
- Write a hello world module
- Add module parameters
- Export symbols
- Create two dependent modules
- Debug load failures
- Explore real drivers in
/drivers
This hands-on path builds confidence fast.
Modules Programming Basics: Real Character Driver Walkthrough and lsmod, /proc Internals
If kernel modules are the entry gate to kernel development, then character device drivers are where theory finally meets reality.
Most beginners understand what a kernel module is, but they get stuck when asked a simple question in interviews:
“How does a character driver actually work end to end?”
In this guide, we will do two important things:
- Walk through a real character driver module, step by step
- Break down lsmod and /proc internals so you understand what the kernel is really tracking behind the scenes
This is a natural continuation of modules programming basics, and once this clicks, Linux kernel development stops feeling mysterious.
What Is a Character Driver in Simple Words?
A character driver is a kernel module that allows user-space programs to talk to hardware or kernel services using a stream of bytes.
Key traits of character drivers:
- Data is transferred byte by byte
- Accessed using file operations like
open,read,write,close - Appears as a device file in
/dev
Examples you already use:
/dev/tty/dev/console/dev/null
Character drivers are the best starting point because they teach:
- Kernel to user communication
- File operations inside the kernel
- Device registration and cleanup
High-Level Flow of a Character Driver
Before touching code, let’s understand the flow.
- Module loads into the kernel
- Driver registers a character device number
- Kernel creates a device entry
- User program opens
/dev/mydevice - Kernel routes calls to driver functions
- Module unloads and cleans everything
This flow is the backbone of character driver development.
Real Character Driver Module: Step-by-Step Walkthrough
Now let’s walk through a minimal but real character driver.
Step 1: Include Required Kernel Headers
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
These headers provide:
- Module macros
- Kernel logging
- File operation structures
- User-kernel memory copy helpers
Step 2: Define Device Information
#define DEVICE_NAME "mychardev"
static int major_number;
The major number is how the kernel knows which driver handles which device.
Step 3: Implement File Operations
These are the heart of a character driver.
static int my_open(struct inode *inode, struct file *file)
{
printk(KERN_INFO "Device opened\n");
return 0;
}
static int my_release(struct inode *inode, struct file *file)
{
printk(KERN_INFO "Device closed\n");
return 0;
}
static ssize_t my_read(struct file *file, char __user *buffer,
size_t len, loff_t *offset)
{
printk(KERN_INFO "Read requested\n");
return 0;
}
What is happening here?
openruns when user opens/dev/mychardevreadruns when user reads from itreleaseruns when file is closed
This mirrors user-space file behavior, which is why character drivers feel familiar.
Step 4: Map File Operations to the Driver
static struct file_operations fops = {
.owner = THIS_MODULE,
.open = my_open,
.read = my_read,
.release = my_release,
};
This structure tells the kernel:
“When someone accesses this device, call these functions.”
Step 5: Register the Character Device
static int __init my_init(void)
{
major_number = register_chrdev(0, DEVICE_NAME, &fops);
if (major_number < 0) {
printk(KERN_ALERT "Failed to register device\n");
return major_number;
}
printk(KERN_INFO "Registered with major number %d\n", major_number);
return 0;
}
Key points:
0means kernel assigns a major number dynamically- Registration connects your driver to the kernel VFS
- This is a core concept in modules programming basics
Step 6: Cleanup on Module Removal
static void __exit my_exit(void)
{
unregister_chrdev(major_number, DEVICE_NAME);
printk(KERN_INFO "Device unregistered\n");
}
Kernel code must always clean up.
If you forget this, you crash systems in real products.
Step 7: Module Metadata
module_init(my_init);
module_exit(my_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kernel Developer");
MODULE_DESCRIPTION("Simple Character Driver");
Without this, your module is incomplete.
Building and Testing the Character Driver
Build the Module
Use the same kernel module Makefile you already learned.
Load the Module
sudo insmod mychardev.ko
Check Kernel Log
dmesg
You will see the assigned major number.
Create Device Node
sudo mknod /dev/mychardev c <major> 0
Now your driver is accessible from user space.
Test from User Space
cat /dev/mychardev
You should see kernel logs confirming read access.
Congratulations.
You just walked through a real character driver module.
How lsmod Really Works Internally
Most people use lsmod without knowing what it does.
Let’s fix that.
What lsmod Shows
lsmod
Output columns:
- Module name
- Size
- Used by (dependency count)
This data does not come from nowhere.
lsmod Reads From /proc/modules
Internally, lsmod reads:
/proc/modules
This file is generated by the kernel dynamically.
It contains:
- Loaded module list
- Memory usage
- Reference counts
- Dependency information
So when you load your character driver, it instantly appears here.
Understanding /proc Internals Like a Kernel Developer
The /proc filesystem is a virtual filesystem.
Files here do not exist on disk.
They are views into kernel data structures.
Important /proc Files for Module Developers
/proc/modules
- Tracks loaded kernel modules
- Used by lsmod
/proc/kallsyms
- Kernel symbol table
- Lists exported functions and variables
/proc/devices
- Lists registered character and block devices
- Shows major numbers
Example:
cat /proc/devices
You will see your character driver listed under character devices.
How /proc Connects to Modules Programming Basics
When you:
- Register a device
- Export a symbol
- Load a module
The kernel updates internal structures that /proc exposes.
That means:
/procis not magic- It is a debug window into kernel state
Understanding this gives you confidence during debugging.
How Module Dependencies Appear in /proc
When a module depends on another:
- Kernel tracks symbol usage
- Reference counts increase
/proc/modulesreflects this relationship
This is how modprobe safely loads and unloads modules.
Why Interviewers Love These Topics
Interviewers ask about:
- Character driver flow
- lsmod output
- /proc internals
Not because they want commands, but because these topics prove:
- You understand kernel architecture
- You can debug real systems
- You know how kernel modules live and die
Mastering this puts you ahead of most candidates.
Common Beginner Confusions Cleared
/procfiles are not real files- lsmod is just a viewer, not a controller
- Character drivers are not optional in kernel learning
- Cleanup is as important as initialization
Final Thoughts
If modules programming basics is the foundation, then:
- Character drivers are the walls
- lsmod and /proc internals are the wiring behind them
Once you understand these:
- Writing drivers becomes logical
- Debugging becomes faster
- Kernel code stops feeling dangerous
You are no longer guessing.
You are observing the kernel from the inside.
FAQ : Modules Programming Basics
1. What is a Linux kernel module (LKM)?
A Linux kernel module is a piece of code that can be loaded into or removed from the Linux kernel at runtime. It extends the kernel functionality without the need to reboot the system.
2. Why should I learn Linux kernel modules?
Learning LKMs allows you to write device drivers, implement new system features, or optimize kernel behavior. It’s essential for embedded systems, OS development, and low-level programming.
3. How do I create a Linux kernel module?
You write a C file containing init and exit functions, compile it with the kernel build system, and use insmod to load it and rmmod to remove it.
4. What are the key functions in a kernel module?
Every kernel module has at least:
init_module()ormodule_init()– runs when the module is loadedcleanup_module()ormodule_exit()– runs when the module is removed
5. How do I check if a kernel module is loaded?
Use the command:
lsmod
It lists all currently loaded kernel modules.
6. What is modprobe and how is it different from insmod?
insmodloads a module manuallymodprobeautomatically handles module dependencies before loading
7. Can I pass parameters to a kernel module?
Yes, you can pass parameters using module_param() macros. For example, you can set buffer sizes, device IDs, or debugging flags at load time.
8. How do kernel modules help with device drivers?
Modules allow drivers to be loaded only when hardware is present, reducing memory usage and keeping the kernel modular and efficient.
9. What are kernel module dependencies?
Some modules require other modules to work. modprobe automatically loads dependencies, while insmod requires manual handling.
10. How do I debug Linux kernel modules?
You can use:
dmesgfor kernel messagesprintk()to print debug info from your module- Kernel debuggers like
kgdbfor advanced debugging
11. Can I update a module without rebooting Linux?
Yes, one of the main advantages of LKMs is hot-swapping – you can remove and reload updated modules without restarting the system.
12. What are the best practices for writing kernel modules?
- Keep modules small and focused
- Check return values and handle errors
- Avoid blocking operations in the kernel
- Use proper synchronization for shared resources
13. Which tools do I need to work with Linux kernel modules?
- GCC compiler for C
- Makefile for kernel build system
insmod,rmmod,modprobe,lsmod, anddmesgcommands
14. Are Linux kernel modules secure?
Modules run in kernel space, so a buggy or malicious module can crash or compromise the system. Always validate code and test in a safe environment.
Read More about Process : What is is Process
Read More about System Call in Linux : What is System call
Read More about IPC : What is IPC
Mr. Raj Kumar is a highly experienced Technical Content Engineer with 7 years of dedicated expertise in the intricate field of embedded systems. At Embedded Prep, Raj is at the forefront of creating and curating high-quality technical content designed to educate and empower aspiring and seasoned professionals in the embedded domain.
Throughout his career, Raj has honed a unique skill set that bridges the gap between deep technical understanding and effective communication. His work encompasses a wide range of educational materials, including in-depth tutorials, practical guides, course modules, and insightful articles focused on embedded hardware and software solutions. He possesses a strong grasp of embedded architectures, microcontrollers, real-time operating systems (RTOS), firmware development, and various communication protocols relevant to the embedded industry.
Raj is adept at collaborating closely with subject matter experts, engineers, and instructional designers to ensure the accuracy, completeness, and pedagogical effectiveness of the content. His meticulous attention to detail and commitment to clarity are instrumental in transforming complex embedded concepts into easily digestible and engaging learning experiences. At Embedded Prep, he plays a crucial role in building a robust knowledge base that helps learners master the complexities of embedded technologies.
