我正在开发一个Linux内核模块,我想调用函数get_futex_key.我怎么能这样做呢?最终目标是使用内核函数返回包含给定Futex的线程列表.

我按照这个tutorial创建了一个"Hello World"模块.它使用printk函数.我理解使用printk是可能的,因为它是内核可见的符号之一.

# cat /proc/kallsyms | grep printk
...
ffffffff9ebb9c32 T printk
...

功能get_futex_key/proc/kallsyms中也可见.它是在futex.c,而不是futex.h中定义的.例如,请看这个source.

# cat /proc/kallsyms | grep "get_futex_key"
ffffffff9e3223c0 t get_futex_key_refs.isra.11
ffffffff9e322a30 t get_futex_key

假设0x20566a0是用strace得到的uaddr.

# strace -p  117589
strace: Process 117589 attached
futex(0x20566a0, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, 0, NULL, 0xffffffff^Cstrace: Process 117589 detached

我以fut.c的身份try 了以下代码.

#include <linux/module.h>    // included for all kernel modules
#include <linux/kernel.h>    // included for KERN_INFO
#include <linux/init.h>      // included for __init and __exit macros
#include <linux/futex.h>
#include <kernel/futex.c>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("FutexTestAuthor");
MODULE_DESCRIPTION("Futex Examiner");

static int __init hello_init(void)
{
    union futex_key key1 = FUTEX_KEY_INIT;
    printk(KERN_INFO "Get futex key\n");
    //futex_key key1 = FUTEX_KEY_INIT;
    get_futex_key(0x20566a0, 0, &key1, VERIFY_READ);
    printk(KERN_INFO "key1 = %p\n", &key1);
    return 0;    // Non-zero return means that the module couldn't be loaded.
}

static void __exit hello_cleanup(void)
{
    printk(KERN_INFO "Cleaning up futex module.\n");
}

module_init(hello_init);
module_exit(hello_cleanup);

The 100

obj-m += fut.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

Output of 100

# make
make -C /lib/modules/4.15.0-204-generic/build M=/home/myusername/git/LinuxExamples/kernel/fut modules
make[1]: Entering directory '/usr/src/linux-headers-4.15.0-204-generic'
  CC [M]  /home/myusername/git/LinuxExamples/kernel/fut/fut.o
/home/myusername/git/LinuxExamples/kernel/fut/fut.c:5:10: fatal error: kernel/futex.c: No such file or directory
 #include <kernel/futex.c>
          ^~~~~~~~~~~~~~~~
compilation terminated.
scripts/Makefile.build:340: recipe for target '/home/myusername/git/LinuxExamples/kernel/fut/fut.o' failed
make[2]: *** [/home/myusername/git/LinuxExamples/kernel/fut/fut.o] Error 1
Makefile:1596: recipe for target '_module_/home/myusername/git/LinuxExamples/kernel/fut' failed
make[1]: *** [_module_/home/myusername/git/LinuxExamples/kernel/fut] Error 2
make[1]: Leaving directory '/usr/src/linux-headers-4.15.0-204-generic'
Makefile:4: recipe for target 'all' failed
make: *** [all] Error 2

推荐答案

内核不会导出get_futex_key()函数.您可以通过两种方式注意到这一点:

  1. 查看内核源代码,导出的函数在其定义后通常有一个EXPORT_SYMBOL(name).但这一次不是.
  2. /proc/kallsyms的输出中,导出的函数具有大写T符号,而其他输出函数具有小写t符号.这个就是后者.

您不能创建直接使用get_futex_key()的模块,因为它将无法链接,因为内核不会导出它.您也不能也永远不应该在模块中包含.c个文件,只能包含.h个(头)文件.事实上,在大多数情况下,.c个文件一开始就不能供您使用,但只有.h个文件可供您使用.

有了上面所说的,你可以look at the source code of get_futex_key()了解它是如何工作的,并在你的模块中重新实现它的部分功能,或者看看这个另一个问题,看看这个问题,它将允许你从模块中获得未导出的符号:Proper way of getting the address of non-exported kernel symbols in a Linux kernel module

C++相关问答推荐

va_arg -Linux和Windows上的不同行为

需要大整数和浮点数.使用long long int和long double

手动矢量化性能差异较大

__VA_OPT__(,)是否可以检测后面没有任何内容的尾随逗号?

如何在C中从函数返回指向数组的指针?

C:fopen是如何实现二进制模式和文本模式的?

C是否用0填充多维数组的其余部分?

是否可以使用指针算法在不对齐的情况下在 struct 中相同类型的字段的连续序列之间移动?

在为hashmap创建加载器时,我的存储桶指向它自己

C-使用指针返回修改后的整数数组

对于C中给定数组中的每个查询,如何正确编码以输出给定索引范围(1到N)中所有数字的总和?

有什么方法可以将字符串与我们 Select 的子字符串分开吗?喜欢:SIN(LOG(10))

初始成员、公共初始序列、匿名联合和严格别名如何在C中交互?

我正在try 将QSORT算法实现为C++中的泛型函数

如何读取程序中嵌入的数据S自己的ELF?

为什么GCC不能在 struct 初始值设定项中以sizeof作为条件的三进制中处理复合文字的编译时求值?

DennisM.Ritchie的C编程语言一书中关于二进制搜索的代码出现错误?

关于不同C编译器中的__attribute__支持

保存有符号整数结果的变量是否会溢出(后增量的副作用),并且此后从未在任何表达式中使用过它,是否会导致 UB?

为什么需要struct in_addr