预处理后的内核模块源文件

时间:2014-01-17 04:29:27

标签: c linux macros linux-kernel

让我们编写以下最简单的模块源文件:

#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);

如何在预处理后看到此来源?我想知道如何部署__init__exit宏以及module_init(md_init)module_exit(md_exit)是什么?它是如何工作的?

5 个答案:

答案 0 :(得分:5)

如果你的驱动程序在内核中,你可以通过以下方式获得它:

make path-to-module / srcfile.i

作为一个例子,我在drivers / staging /下创建了一个测试目录,将你的文件放在那里,创建了一个简单的Kconfig和Makefile,在staging中更新了Kconfig和Makefile,然后运行了

make drivers / staging / test / test.i

如果你的源代码在内核树之外,但是设置了Kconfig和Makefile,那么:

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

结果是init和exit宏:

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");
}

答案 1 :(得分:2)

,查看中间文件。即编译器预处理后的.i文件和.s文件,更改Makefile并添加 EXTRA_CFLAGS =' - save-temps'

<强>生成文件:

  

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

在此之后,运行'make'后,您可以在

中看到your_module_filename.i
  

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

并且具有预处理器更改的源几乎在文件末尾可用。

答案 2 :(得分:1)

如果您只计划获取内核模块的预处理输出,请不要使用Makefile,因为Makefile(sub-make)会尝试生成一个能够插入内核的目标文件。这与gcc -E相矛盾,gcc在预处理后停止。因此,只需使用 gcc -E new.c -I$TREE/include -I$TREE/arch/x86/include -I$TREE/include/uapi

执行以下操作
-E

gcc是获取预处理的输出,$ TREE是内核树的位置,如果使用其他arch,则更改x86。我们知道,-I包含带-I的dir参数,因此通过{{1}}传递所有内核包括dir。希望这有帮助!

答案 3 :(得分:1)

为内核源文件捕获正确的预处理转换单元的方法是首先确定用于编译.o的确切命令行。然后运行相同的命令行,但添加-E。另外,请更改-o选项。

要获取完整的内核命令行,您必须将V=1添加到make命令行。要避免搜索冗长详细的日志,请先构建所有内容,然后只需删除相关的.o,然后使用V=1进行重建。

例如,我正在使用名为arm的gcc为arm-linux-gnueabi-gcc进行编译。要获得kernel/spinlock.c的预处理版本,这适用于我的情况:

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.c kernel/spinlock.c

我剪切并粘贴了详细编译器输出中的行,添加了-E并更改了-o以捕获文件中的输出。 (当然,您可以删除-o <arg>以获得标准输出。)

当然,该命令行中的许多选项不会影响预处理,但有些选项(如定义宏的任何内容)会改变包含路径。

你不想手动猜测这些事情。

请注意,如果您使用make调用make -C <dir> ...,则make会在执行任何操作之前将目录更改为<dir>。它从该目录中读取Makefile,依此类推;它与执行命令(cd <dir>; make ...)几乎相同。在这种情况下,从构建输出中获取的命令行将包含仅在<dir>中解析的相对路径;在尝试运行命令之前更改为<dir>,或使用(cd <dir>; <command>)包装它。

答案 4 :(得分:0)

在 Makefile 中只需添加以下标志,这将保存“.i”和“.s”文件- DEBUG_CFLAGS := -save-temps