Fundamentals 8 min read

How Linux Kernel Invokes Module Init Functions via fs_initcall

The article explains how the Linux kernel discovers and calls module initialization functions like inet_init by using the fs_initcall macro, which creates static initcall variables placed in specially‑named sections that the linker groups and the kernel iterates at boot time.

Liangxu Linux
Liangxu Linux
Liangxu Linux
How Linux Kernel Invokes Module Init Functions via fs_initcall

When studying Linux kernel source code, you may notice that module initialization functions such as static int __init inet_init(void) are never called directly. The call is hidden behind the macro fs_initcall(inet_init).

Macro Expansion

The fs_initcall macro is defined in include/linux/init.h as:

#define ___define_initcall(fn, id, __sec) \
        static initcall_t __initcall_##fn##id __used \
                __attribute__((__section__(#__sec ".init"))) = fn;
#define __define_initcall(fn, id) ___define_initcall(fn, id, .initcall##id)
#define fs_initcall(fn)                 __define_initcall(fn, 5)

After expansion, the line becomes roughly:

static initcall_t __initcall_inet_init5 __attribute__((__section__(".initcall5.init"))) = inet_init;

This defines a static variable of type initcall_t (a function‑pointer type typedef int (*initcall_t)(void);) whose value is the address of inet_init. The variable is placed in the custom ELF section .initcall5.init.

Linker Script and Sections

The kernel’s linker script (e.g., arch/x86/kernel/vmlinux.lds.S) uses macros like INIT_CALLS_LEVEL to collect all sections named .initcallN.init into contiguous memory regions:

#define INIT_CALLS_LEVEL(level)                 \
                __initcall##level##_start = .;  \
                KEEP(*(.initcall##level##.init))\
                KEEP(*(.initcall##level##s.init))

#define INIT_CALLS                              \
                __initcall_start = .;           \
                KEEP(*(.initcallearly.init))    \
                INIT_CALLS_LEVEL(0)              \
                INIT_CALLS_LEVEL(1)              \
                ...                              \
                INIT_CALLS_LEVEL(5)              \
                ...                              \
                __initcall_end = .;

All static variables placed in the same level (e.g., level 5) end up in a contiguous array whose start address is exported as __initcall5_start.

Runtime Invocation

During kernel boot, do_initcalls() walks through each initcall level:

extern initcall_entry_t __initcall0_start[];
extern initcall_entry_t __initcall1_start[];
/* … */
extern initcall_entry_t __initcall5_start[];
/* … */
static initcall_entry_t *initcall_levels[] __initdata = {
        __initcall0_start,
        __initcall1_start,
        /* … */
        __initcall5_start,
        /* … */
        __initcall_end,
};

static void __init do_initcall_level(int level)
{
        initcall_entry_t *fn;
        for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)
                do_one_initcall(initcall_from_entry(fn));
}

static void __init do_initcalls(void)
{
        int level;
        for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++)
                do_initcall_level(level);
}

The function do_initcalls() iterates over every level; for each level it walks the array of initcall_t pointers and invokes the pointed‑to initialization functions. The inet_init function resides in level 5, so it is called when the kernel processes that level.

Key Takeaways

Module init functions are registered with macros like fs_initcall, which create static variables placed in specially‑named ELF sections.

The linker script groups all variables of the same initcall level into a contiguous memory region.

At boot, the kernel walks these regions via do_initcalls(), calling each function pointer in order.

This mechanism allows the Linux kernel to discover and execute initialization code without explicit calls scattered throughout the source.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

KernelCLinuxLinkerInitcallfs_initcall
Liangxu Linux
Written by

Liangxu Linux

Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.