[英]Kernel module source file after preprocessing
讓我們編寫以下最簡單的模塊源文件:
#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)
什么? 這個怎么運作?
如果您的驅動程序在內核中,您可以通過執行以下操作來獲取它:
制作模塊路徑/srcfile.i
例如,我在drivers/staging/下創建了一個test目錄,把你的文件放在那里,創建了一個簡單的Kconfig和Makefile,在staging中更新了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");
}
如果您只打算獲取內核模塊的預處理輸出,請不要使用 Makefile,因為 Makefile(子 make)會嘗試生成具有插入內核能力的目標文件。 這與gcc -E
相矛盾,后者在預處理后停止。 因此,只需使用gcc
執行以下操作:
gcc -E new.c -I$TREE/include -I$TREE/arch/x86/include -I$TREE/include/uapi
-E
是獲得預處理的輸出,$TREE 是你的內核樹的位置,如果你使用其他 arch 則更改 x86。 而我們知道, gcc
需要包括與DIR參數-I
,所以通過所有的內核包括通過DIR -I
希望這可以幫助!
,查看中間文件。 即編譯器預處理后的.i文件和.s文件,更改Makefile並添加EXTRA_CFLAGS='-save-temps'
生成文件:
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}
帶有預處理器更改的源代碼幾乎在文件末尾可用。
為內核源文件捕獲正確的預處理翻譯單元的方法是首先確定用於編譯.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
使用make -C <dir> ...
,然后make
修改目錄<dir>
做任何事情之前。 它從該目錄中讀取Makefile
,依此類推; 它幾乎與執行命令(cd <dir>; make ...)
。 在這種情況下,您從構建輸出中獲得的命令行將包含僅在<dir>
解析的相對路徑; 在嘗試運行命令之前更改為<dir>
,或者用(cd <dir>; <command>)
將其包裝起來。
在 Makefile 中只需添加以下標志,這將保存“.i”和“.s”文件- DEBUG_CFLAGS := -save-temps
一個快速但(非常)骯臟的方法,如果你不需要預處理以外的任何東西,就是將 ccflags-y += -E 行放在模塊的 Makefile 中。 生成的 .o 文件實際上是預處理的輸出文件。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.