Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Linux Kernel Programming

You're reading from   Linux Kernel Programming A comprehensive and practical guide to kernel internals, writing modules, and kernel synchronization

Arrow left icon
Product type Paperback
Published in Feb 2024
Publisher Packt
ISBN-13 9781803232225
Length 826 pages
Edition 2nd Edition
Languages
Tools
Arrow right icon
Author (1):
Arrow left icon
Kaiwan N. Billimoria Kaiwan N. Billimoria
Author Profile Icon Kaiwan N. Billimoria
Kaiwan N. Billimoria
Arrow right icon
View More author details
Toc

Table of Contents (16) Chapters Close

Preface 1. Linux Kernel Programming – A Quick Introduction 2. Building the 6.x Linux Kernel from Source – Part 1 FREE CHAPTER 3. Building the 6.x Linux Kernel from Source – Part 2 4. Writing Your First Kernel Module – Part 1 5. Writing Your First Kernel Module – Part 2 6. Kernel Internals Essentials – Processes and Threads 7. Memory Management Internals – Essentials 8. Kernel Memory Allocation for Module Authors – Part 1 9. Kernel Memory Allocation for Module Authors – Part 2 10. The CPU Scheduler – Part 1 11. The CPU Scheduler – Part 2 12. Kernel Synchronization – Part 1 13. Kernel Synchronization – Part 2 14. Other Books You May Enjoy
15. Index

Understanding the basics of a kernel module Makefile

You may have noticed by now that we tend to follow a one-kernel-module-per-directory rule of sorts. Yes, that definitely helps keep things organized. So, let’s take our second kernel module, the ch4/printk_loglvl one. To build it, we just cd to its folder, type make, and (fingers crossed!) voilà, it’s done. We have the printk_loglevel.ko kernel module object freshly generated (which we can then apply insmod/rmmod to). But how exactly did it get built when we typed make? Explaining this is the purpose of this section.

First off, we do expect you to understand the basics regarding make and the Makefile. If not, don’t fret, we’ve provided links to check this out, within the Further reading section (in the paragraph labeled Makefiles: introductory stuff) of this chapter. . Check it out! (Link: https://github.com/PacktPublishing/Linux-Kernel-Programming_2E/blob/main/Further_Reading.md#chapter-4-writing-your-first-kernel-module-lkms-part-1---further-reading).

Next, as this is our very first chapter that deals with the LKM framework and its corresponding Makefile, we will keep things nice and simple, especially regarding the Makefile. However, early on in Chapter 5, Writing Your First Kernel Module – Part 2, in the A better Makefile template for your kernel modules section, we shall introduce a more sophisticated, and (what we hope is) a better Makefile, that is still quite simple to understand. We shall then use this better Makefile in all subsequent code (but not right now); do look out for it and use it!

As you will know, the make command will by default look for a file named Makefile in the current directory; if it exists, it will parse it and execute command sequences as specified within it. Here’s our simple Makefile for the printk_loglevel kernel module project (I use the nl – “number lines” – utility to show it with line numbers prefixed):

$ nl Makefile 
     1    # ch4/printk_loglvl/Makefile
     2    PWD          := $(shell pwd)
     3    KDIR          := /lib/modules/$(shell uname -r)/build/
     4    obj-m       += printk_loglvl.o
       
     5    # Enable the pr_debug() and pr_devel() as well by removing the comment from
     6    # one of the lines below
     7    # (Note: EXTRA_CFLAGS deprecated; use ccflags-y)
     8    #ccflags-y += -DDEBUG
     9    #CFLAGS_printk_loglvl.o := -DDEBUG
       
    10    all:
    11        make -C $(KDIR) M=$(PWD) modules
    12    install:
    13        make -C $(KDIR) M=$(PWD) modules_install
    14    clean:
    15        make -C $(KDIR) M=$(PWD) clean

It should go without saying that the Unix Makefile syntax demands this basic format:

target: [dependent-source-file(s)]
     rule(s)

The rule(s) instances are always prefixed with a [Tab] character, not white space.

Let’s gather the basics regarding how this (module) Makefile works. First off, a key point is this: the kernel’s Kbuild system (which we’ve been mentioning and using since Chapter 2, Building the 6.x Linux Kernel from Source – Part 1), primarily uses two variable strings of software to build, chained up within the two variables obj-y and obj-m.

The obj-y string has the concatenated list of all objects to build and merge into the final kernel image files – the uncompressed vmlinux and the compressed (boot-able) [b][z]Image images. Think about it – it makes sense: the y in obj-y stands for Yes. All kernel built-in and Kconfig options that were set to Y during the kernel configuration process (or are Y by default) are chained together via this item, built, and ultimately woven into the final kernel image files by the Kbuild build system.

On the other hand, it’s now easy to see that the obj-m string is a concatenated list of all kernel objects to build separately, as kernel modules! This is precisely why our Makefile has this all-important line (line 4):

obj-m += printk_loglvl.o

In effect, it tells the Kbuild system to include our code; more correctly, it tells it to implicitly compile the printk_loglvl.c source code into the printk_loglvl.o binary object, and then add this object to the obj-m list. Next, with the default rule for make being the all rule (lines 10 and 11), it is processed:

all:
    make -C $(KDIR) M=$(PWD) modules

The processing of this single statement (line 11) is quite involved; here’s what transpires:

  1. The -C option switch to make has the make process change directory (via the chdir() system call) to the directory name that follows -C. Thus, it changes the directory to the $(KDIR) directory, which is set (in line 3) to the kernel build symbolic link under /lib/modules/$(uname -r) (which, as we covered earlier, points to the location of the limited kernel source tree that got installed via the kernel-headers package). To remind you, here it is (on my Ubuntu guest):
    $ ls -l /lib/modules/$(uname -r)/build
    lrwxrwxrwx 1 root root    31 May  5 10:51 build -> /home/c2kp/kernels/linux-6.1.25/
    
  2. So, clearly, the make process changes directory to the folder ~/kernels/linux-6.1.25/, which, in this case, points back to our original 6.1.25 kernel source tree (as we’re running off the custom kernel that we built earlier). Once there, it automatically parses in the content of the kernel’s top-level Makefile – that is, the Makefile that resides there, in the root of this kernel source tree. This is a key point. The kernel top-level Makefile is a rather large and sophisticated one (on 6.1.25, it’s well over 2,000 lines) and contains key build details and variables. This way, being parsed in every time even an out-of-tree module is being built, it’s guaranteed that all kernel modules are tightly coupled to the kernel that they are being built against (more on this a bit later). This also guarantees that kernel modules are built with the exact same set of rules – that is, the compiler/linker configurations (the *CFLAGS* options, the compiler option switches, and so on) – as the kernel image itself is. This is required for binary compatibility.
  3. Next, in the Makefile, still on line 11, you can see the initialization of the variable named M (to the present working directory), and that the target specified is modules; hence, the make process now changes the directory to that specified by the M variable, to $(PWD) – the very folder we started from (line 2: PWD := $(shell pwd) in the Makefile initializes it to the correct value)!

So, interestingly, it’s a recursive build: the build process, having – very importantly – parsed the kernel top-level Makefile, now switches back to the kernel module’s directory and builds the module(s) therein.

Lines 12 and 13 make up the install target (which we cover in the next chapter), and lines 14 and 15 make up the clean target.

Did you notice that when a kernel module is built, a fair number of intermediate working files are generated as well? Among them are modules.order, <file>.mod.c, <file>.o, Module.symvers, <file>.mod.o, .<file>.o.cmd, .<file>.ko.cmd, a folder called .tmp_versions/, and, of course, the kernel module binary object itself, <file>.ko – the whole point of the build exercise. Further, there are several hidden files generated as well. Getting rid of all these temporary build artifacts, including the target (the kernel module object itself) is easy: just perform make clean. The clean rule cleans it all up. We shall delve into the install target in the following chapter.

A screenshot helps convey the output seen on building and then cleaning up:

Figure 4.13: Screenshot showing the build (make) and “make clean” of our printk_loglvl kernel module (on our x86_64 Ubuntu 22.04 guest running our custom-built 6.1.25 LTS kernel)

You can look up what the modules.order and modules.builtin files (and other files) are meant for within the kernel documentation here: https://elixir.bootlin.com/linux/v6.1.25/source/Documentation/kbuild/kbuild.rst. Also, as mentioned previously, we shall, in the following chapter, introduce and use a more sophisticated Makefile variant – a “better” Makefile. It is designed to help you, the kernel module/driver developer, improve code quality by running targets related to kernel coding style checks, static analysis, simple packaging, and (a dummy target) for dynamic analysis.

With that, we conclude this chapter. Well done – you are now well on your way to learning Linux kernel development!

lock icon The rest of the chapter is locked
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime
Banner background image