让我们写下如下最简单的模块源文件:
#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
macros,以及module_init(md_init)
和module_exit(md_exit)
什么? 怎么运行的?
如果只打算获得内核模块的预处理输出,不要使用Makefile,因为Makefiles(sub-make)会尝试生成一个能够插入内核的对象文件。 这与gcc -E
相矛盾, gcc -E
在预处理之后就停止了。 所以,用gcc
做下面的事情:
gcc -E new.c -I$TREE/include -I$TREE/arch/x86/include -I$TREE/include/uapi
-E
是得到预处理输出,$ TREE是内核树的位置,如果你使用其他的arch,那么更改x86。 而且我们知道, gcc
需要带-I
参数包括dir参数,所以通过-I
所有的内核包括dir。 希望这可以帮助!
如果你在内核里有你的驱动程序,你可以通过下面的方法得到它:
使路径到模块/ srcfile.i
作为一个例子,我在drivers / staging /下创建了一个测试目录,把你的文件放在那里,创建一个简单的Kconfig和Makefile,在升级Kconfig和Makefile的时候更新,然后运行
使司机/分期/测试/ 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"); }
为内核源文件捕获正确的预处理翻译单元的方法是首先确定用于编译.o
的确切命令行。 然后运行相同的命令行,但添加-E
。 另外,更改-o
选项。
要获得完整的内核命令行,您必须在make
命令行中添加V=1
。 为了避免通过冗长的日志查找,首先创建所有内容,然后删除问题中的.o
,然后重新生成V=1
。
例如,我正在使用名为arm-linux-gnueabi-gcc
的gcc编译arm
。 要获得kernel/spinlock.c
的预处理版本,这在我的情况下工作:
arm-linux-gnueabi-gcc
-E
-B arm-linux-gnueabi- -Wp,-MD,kernel/.spinlock.od -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
-o kernel/spinlock.prepro.c
kernel/spinlock.c
我从详细的编译器输出中剪切并粘贴了行,添加了-E
并且改变了-o
以捕获文件中的输出。 (当然,您可以删除-o <arg>
以在标准输出上获取它)。
当然,该命令行中的许多选项不会影响预处理,但是其中一些选项(如定义宏的任何选项)会更改包含路径。
你不想手动猜测这些事情。
请注意,如果您使用make -C <dir> ...
调用make
,则在执行任何操作之前,请将make -C <dir> ...
更改为<dir>
。 它从该目录读取Makefile
,等等。 它与执行命令(cd <dir>; make ...)
几乎相同。 在这种情况下,您从构建输出中获得的命令行将包含仅在<dir>
解析的相对路径。 尝试运行该命令之前更改为<dir>
,或者用(cd <dir>; <command>)
包装它。
,查看中间文件。 即编译器预处理后的.i文件和.s文件,更改Makefile并添加EXTRA_CFLAGS =' – save-temps'
Makefile文件:
make -C / usr / lib / modules / $(shell uname -r)/ build M = $(shell pwd)modules EXTRA_CFLAGS ='- save-temps '
在此之后,一旦运行“make”,您可以看到your_module_filename.i
ls / usr / lib / modules / $(uname -r)/ build / {your_modulename.i}
并且具有预处理器更改的源将在文件的结尾几乎可用。