【问题标题】:Undefined functions while compiling linux kernel module编译linux内核模块时未定义的函数
【发布时间】:2016-09-25 19:47:36
【问题描述】:

我正在尝试使用 linux softirq。 A 有一个简单的程序,它使用linux/interrupt.h 中定义的 linux 系统调用:

//
// Created by kivi on 24.09.16.
//

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

#define SHARED_IRQ 17

static int irq = SHARED_IRQ, my_dev_id, irq_counter = 0;
module_param( irq, int, S_IRUGO );

/* The interrupt handler */ 
static irqreturn_t xxx_interrupt( int irq, void *dev_id ) { 
    printk( KERN_INFO "In the top-half: counter = %d\n", irq_counter );
   raise_softirq( XXX_SOFT_IRQ ); 
   return IRQ_HANDLED; 
}

/* The bottom half */ 
void xxx_analyze(struct softirq_action *str) { 
    irq_counter++;
    printk( KERN_INFO "In the bottom-half: counter = %d\n", irq_counter );
}

static int __init my_init( void ) {
    request_irq( irq, xxx_interrupt, 0, "xxx", NULL );
    open_softirq( XXX_SOFT_IRQ, xxx_analyze); 
    printk( KERN_INFO "Successfully set softirq handler on IRQ %d\n", irq );
    return 0;
}

static void __exit my_exit( void ) {
    synchronize_irq( irq );
    free_irq( irq, &my_dev_id );
    printk( KERN_INFO "Successfully unloading, irq_counter = %d\n", irq_counter );
}

module_init( my_init );
module_exit( my_exit );
MODULE_LICENSE( "GPL v2" );

当我尝试编译这个模块时,我得到链接器错误,函数 open_softirq()raise_softirq() 没有定义:

kivi@kivi-pc:~/sp_labs/irq_exc/softirq$ make
make -C /lib/modules/4.7.5-custom/build M=/home/kivi/sp_labs/irq_exc/softirq modules
make[1]: Entering directory '/home/kivi/Downloads/linux-4.7.5'
  Building modules, stage 2.
  MODPOST 1 modules
WARNING: "open_softirq" [/home/kivi/sp_labs/irq_exc/softirq/softirq.ko] undefined!
WARNING: "raise_softirq" [/home/kivi/sp_labs/irq_exc/softirq/softirq.ko] undefined!
make[1]: Leaving directory '/home/kivi/Downloads/linux-4.7.5'

有趣的是函数request_irq() e.t.c.在interrupt.h文件中也有定义,但它们不会引起任何问题。

这是我的 Makefile:

obj-m += softirq.o

all:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

那么任何人都可以帮我解决我的问题。

附:我用谷歌搜索了我的问题并找到了一些建议,我应该在编译时添加KBUILD_EXTRA_SYMBOLS=*module path*/Module.symvers,但这没有帮助。

【问题讨论】:

  • 我不是 LKM 大师,但上次我写内核模块时遇到了类似的问题,我必须设置一些特殊的 #define 才能链接标有 EXPORT_SYMBOL_GPL() 的符号
  • 能否请您提供更详细的说明如何做到这一点

标签: c linux linux-kernel


【解决方案1】:

问题在于open_softirqraise_softirq 函数未导出,因此您无法链接到它们。导出的函数标有EXPORT_SYMBOLEXPORT_SYMBOL_GPL 宏。

另一方面,你会看到request_irq是如何导出的(实际上是inlinedrequest_threaded_irqis导出的)。

您可以找到有关EXPORT_SYMBOL 宏的大量信息。例如,here's Robert Love 的解释。

现在,您可能想知道为什么不导出这些函数。好吧,softirqs 是一种低级机制,旨在供其他更高级别的设施使用,因此目的是防止它在非核心内核代码中使用。

模块应该使用更高级别的工具(例如计时器)。

检查内核有多少个软中断用户很有趣。

$ git grep open_softirq
block/blk-softirq.c:    open_softirq(BLOCK_SOFTIRQ, blk_done_softirq);
include/linux/interrupt.h:extern void open_softirq(int nr, void (*action)(struct softirq_action *));
kernel/rcu/tiny.c:      open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);
kernel/rcu/tree.c:      open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);
kernel/sched/fair.c:    open_softirq(SCHED_SOFTIRQ, run_rebalance_domains);
kernel/softirq.c:void open_softirq(int nr, void (*action)(struct softirq_action *))
kernel/softirq.c:       open_softirq(TASKLET_SOFTIRQ, tasklet_action);
kernel/softirq.c:       open_softirq(HI_SOFTIRQ, tasklet_hi_action);
kernel/time/timer.c:    open_softirq(TIMER_SOFTIRQ, run_timer_softirq);
lib/irq_poll.c: open_softirq(IRQ_POLL_SOFTIRQ, irq_poll_softirq);
net/core/dev.c: open_softirq(NET_TX_SOFTIRQ, net_tx_action);
net/core/dev.c: open_softirq(NET_RX_SOFTIRQ, net_rx_action);

只有 12 岁!

这种模式在内核中重复出现:维护者认为低级的东西不会被导出,并且仅用于核心内核代码。

【讨论】:

  • 你能给我一些例子,如何将它用于 linux 内核函数。我用谷歌搜索了一些东西,我发现的只是从模块中导出您自己的符号的示例。我尝试为raise_softirqopen_softirq 添加EXPORT_SYMBOL,但现在出现编译错误。
  • 另外,谷歌说,如果符号已经用EXPORT_SYMBOL 导出到某个地方,那么它在所有内核模块中都可用。 open_softirqraise_softirq 已在 kernel/softirq.c 中导出。所以我真的不明白发生了什么。
  • 首先,no open/raise_sofirqnot 导出的。 open_softirq 出口早在 2006 年就被删除了,请参阅此处 lkml.org/lkml/2006/7/11/264
  • 第二,构建错误可能是XXX_SOFT_IRQ没有在任何地方定义?否则,请指出您的构建错误。但这与这个特定问题无关;)
  • 我手动将 XXX_SOFT_IRQ 添加到 interrupts.h 文件中并重建内核。编译我的模块时出现两个错误:include/linux/export.h:63:39: error: section attribute cannot be specified for local variables __visible const struct kernel_symbol __ksymtab_##sym \ ; include/linux/export.h:63:39: 错误:没有链接的“__ksymtab_raise_softirq”声明遵循 extern 声明 __visible const struct kernel_symbol __ksymtab_##sym \ 我不明白它们是什么意思
猜你喜欢
  • 2014-10-26
  • 2011-05-03
  • 2014-12-06
  • 2011-06-06
  • 1970-01-01
  • 2011-07-15
  • 2012-05-11
相关资源
最近更新 更多