7

Let we've written the following simplest module source file:

#include <linux/init.h>
#include <linux/module.h>

static int __init md_init(void){
    printk("Hello kernel");
    return 0;
}

static void __exit md_exit(void){
    printk("Goodbye kernel");
}

module_init(md_init);
module_exit(md_exit);

How can I see this source after preprocessing? I want to know how are __init and __exit macros deployed and what's the module_init(md_init) and module_exit(md_exit)? How it works?

  • fyi: http://stackoverflow.com/questions/8832114/what-does-init-mean-in-the-linux-kernel-code – tristan Jan 17 '14 at 04:35
  • Are you looking for [`gcc -E`](http://gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/Overall-Options.html#index-E-81)? – Nemo Jan 17 '14 at 04:40
  • @Nemo How it to use in my case? When we're writting the kernel Makefile we're using a sub-make which conatains at `/lib/modules/$(shell uname -r)/build`. –  Jan 17 '14 at 04:44

6 Answers6

9

If you have your driver in the kernel, you can get it by doing:

make path-to-module/srcfile.i

As an example, I created a test directory under drivers/staging/, put your file in there, created a simple Kconfig and Makefile, updated the Kconfig and Makefile in staging, then ran

make drivers/staging/test/test.i

If you have the source outside the kernel tree, but have a Kconfig and Makefile set up, then:

make -C /path/to/kernel/src M=/path/to/driver srcfile.i

The result was of init and exit macros:

static int __attribute__ ((__section__(".init.text"))) __attribute__((__cold__)) __attribute__((no_instrument_function)) md_init(void)
{
 printk("Hello kernel");
 return 0;
}

static void __attribute__ ((__section__(".exit.text"))) __attribute__((__used__)) __attribute__((__cold__)) __attribute__((no_instrument_function)) md_exit(void)
{
 printk("Goodbye kernel");
}
  • 2
    For the out-of-tree case, "make -C $kbuild M=/path/to/driver srcfile.i" also works – fche Feb 22 '15 at 00:13
5

,To see the intermediate files. i.e the .i files and .s files after the compiler pre-processing, change the Makefile and add EXTRA_CFLAGS=’-save-temps’

Makefile:

make -C /usr/lib/modules/$(shell uname -r)/build M=$(shell pwd) modules EXTRA_CFLAGS=’-save-temps

after this, once you run 'make' you can see the your_module_filename.i in

ls /usr/lib/modules/$(uname -r)/build/{your_modulename.i}

and the source with pre-processor changes will be available almost at the end of the file.

Soorej P
  • 501
  • 5
  • 4
4

If you only plan to get the preprocessed output of kernel module, don't use Makefile, cause Makefiles (sub-make) will try to produce an object file with ability to insert into the kernel. Which contradicts with gcc -E, which just stops after preprocessing. So, just do the followings by using gcc:

  gcc -E new.c -I$TREE/include -I$TREE/arch/x86/include -I$TREE/include/uapi

-E is to get the preprocessed output, $TREE is the location of your kernel tree and if you use other arch then change x86. And we know that, gcc takes include dir parameter with -I, so pass all the kernel include dir through -I. Hope this helps!

rakib_
  • 136,911
  • 4
  • 20
  • 26
  • fatal error: linux/init.h: No such file or directory compilation terminated. –  Jan 18 '14 at 03:22
  • I've tested the posted solution. And, linux/init.h should be under kernel include/ directory, mind checking it again? – rakib_ Jan 18 '14 at 14:36
2

The way to capture the correct preprocessed translation unit for a kernel source file is to first determine the exact command line that is being used to compile the .o. Then run the same command line, but add -E. Also, change the -o option.

To obtain the full kernel command line you have to add V=1 to the make command line. To avoid searching through a long, verbose log, build everything first, then just remove the .o in question, and rebuild with V=1.

For instance, I'm compiling for arm using a gcc called arm-linux-gnueabi-gcc. To get the preprocessed version of kernel/spinlock.c, this works in my case:

arm-linux-gnueabi-gcc-E-B arm-linux-gnueabi- -Wp,-MD,kernel/.spinlock.o.d -nostdinc -isystem /usr/lib/gcc/arm-linux-gnueabi/4.6/include -I/personal/localhome/kaz/git/kernel/arch/arm/include -Iarch/arm/include/generated -Iinclude -include include/generated/autoconf.h -D__KERNEL__ -mlittle-endian -Iarch/arm/mach-capri/include -Iarch/arm/plat-kona/include -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -Werror-implicit-function-declaration -Wno-format-security -fno-delete-null-pointer-checks -O2 -marm -fno-dwarf2-cfi-asm -mabi=aapcs-linux -mno-thumb-interwork -funwind-tables -D__LINUX_ARM_ARCH__=7 -march=armv7-a -Uarm -mfpu=vfp3 -mfloat-abi=softfp -Wframe-larger-than=1024 -fno-stack-protector -Wno-unused-but-set-variable -fomit-frame-pointer -Wdeclaration-after-statement -Wno-pointer-sign -fno-strict-overflow -fconserve-stack -DCC_HAVE_ASM_GOTO -D"KBUILD_STR(s)=#s" -D"KBUILD_BASENAME=KBUILD_STR(spinlock)" -D"KBUILD_MODNAME=KBUILD_STR(spinlock)" -c-o kernel/spinlock.prepro.ckernel/spinlock.c

I cut and pasted the line from the verbose compiler output, added -E and changed -o to capture the output in a file. (You can remove the -o <arg> to get it on standard output, of course).

Of course, many of the options in that command line do not affect preprocessing, but some do, such as anything that defines a macro, alters the include paths.

You don't want to be guessing at these things manually.

Note that if you invoke make using make -C <dir> ..., then make changes directory to <dir> before doing anything. It reads the Makefile from that directory, and so forth; it is almost the same as executing the command (cd <dir>; make ...). In this case, the command line that you get out of the build output will contain relative paths that only resolve in <dir>; change to <dir> before trying to run the command, or wrap it with (cd <dir>; <command>).

Kaz
  • 55,781
  • 9
  • 100
  • 149
  • I get the following warning: fatal error: generated/autoconf.h: No such file or directory compilation terminated. – rakib_ Apr 18 '14 at 06:51
  • What compilation command you are using here was generated was based on .config file particularly those *defined macros* which might change the include paths or so, since those are config driven so it's also a question of how you'll treat them. After this I don't see any good points for your answer. – rakib_ Apr 18 '14 at 07:08
  • @rakib I suspect you are in the wrong directory. Did you run `make -C ...`? If so, the compiler command lines are relative to ``. – Kaz Apr 18 '14 at 14:37
  • I can compile the module from that directory and can extract the `V=1` output. As per your answer - that should be enough. – rakib_ Apr 18 '14 at 16:36
0

In Makefile just add below flags, this will save ".i" and ".s" files- DEBUG_CFLAGS := -save-temps

0

A quick but (very) dirty method, if you do not need anything else than preprocessing, is to put the line ccflags-y += -E in the Makefile of the module. The generated .o files are then actually the preprocessed output files.

oscar1919
  • 129
  • 3