【问题标题】:Kernel module source file after preprocessing预处理后的内核模块源文件
【发布时间】:2014-01-17 04:29:26
【问题描述】:

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

#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) 是什么?它是如何工作的?

【问题讨论】:

  • 您在寻找gcc -E吗?
  • @Nemo 在我的情况下如何使用?当我们编写内核 Makefile 时,我们使用的是包含在 /lib/modules/$(shell uname -r)/build 的子 make。

标签: c linux macros linux-kernel


【解决方案1】:

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

制作模块路径/srcfile.i

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

制作驱动程序/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");
}

【讨论】:

  • 对于树外的情况,“make -C $kbuild M=/path/to/driver srcfile.i”也可以
【解决方案2】:

如果你只打算获取内核模块的预处理输出,不要使用 Makefile,因为 Makefiles (sub-make) 会尝试生成一个能够插入内核的目标文件。这与gcc -E 相矛盾,后者在预处理后停止。因此,只需使用gcc 执行以下操作:

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

-E 用于获取预处理输出,$TREE 是内核树的位置,如果您使用其他架构,则更改 x86。我们知道,gcc 将包含目录参数与-I 一起传递,因此将所有内核包含目录传递给-I。希望这会有所帮助!

【讨论】:

  • 致命错误:linux/init.h:没有这样的文件或目录编译终止。
  • 我已经测试了发布的解决方案。而且,linux/init.h应该在内核的include/目录下,介意再检查一遍吗?
【解决方案3】:

,查看中间文件。即编译器预处理后的.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}

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

【讨论】:

  • 对于拥有工作 makefile 的人来说更简洁明了!
【解决方案4】:

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

要获得完整的内核命令行,您必须将V=1 添加到make 命令行。为避免搜索冗长的日志,请先构建所有内容,然后删除有问题的.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.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

我从详细的编译器输出中剪切并粘贴了该行,添加了 -E 并更改了 -o 以将输出捕获到文件中。 (当然,您可以删除 -o &lt;arg&gt; 以使其在标准输出中使用)。

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

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

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

【讨论】:

  • 我收到以下警告:致命错误:生成/autoconf.h:没有此类文件或目录编译终止。
  • 您在此处使用的编译命令是基于 .config 文件生成的,尤其是那些 定义的宏 可能会更改包含路径左右,因为这些是配置驱动的,所以它是还有一个问题是你将如何对待他们。在此之后,我看不出你的回答有什么好处。
  • @rakib 我怀疑你在错误的目录中。你跑make -C &lt;dir&gt; ...了吗?如果是这样,编译器命令行是相对于&lt;dir&gt;
  • 我可以从那个目录编译模块并提取V=1 输出。根据您的回答 - 这应该足够了。
【解决方案5】:

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

【讨论】:

    【解决方案6】:

    一个快速但(非常)肮脏的方法,如果你不需要预处理以外的任何东西,就是将行 ccflags-y += -E 放在模块的 Makefile 中。生成的 .o 文件实际上是经过预处理的输出文件。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-06-28
      • 1970-01-01
      • 2021-07-16
      • 1970-01-01
      • 1970-01-01
      • 2019-02-17
      • 2018-12-27
      相关资源
      最近更新 更多