7

我正在尝试编写 Linux 设备驱动程序。在我尝试使用“memcpy”之前,我已经让它工作得很好。我什至没有收到编译器错误,当我“制作”时它只是警告我:

WARNING: "memcpy" [/root/homedir/sv/main.ko] undefined!

好的,当我尝试通过 insmod 加载时,我进入控制台:

insmod: error inserting './main.ko': -1 Unknown symbol in module

在 dmesg 上:

main: Unknown symbol memcpy (err 0)

我包括以下内容:

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>

#include <linux/kernel.h> /* printk() */
#include <linux/slab.h>  /* kmalloc() */
#include <linux/fs.h>  /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/types.h> /* size_t */
#include <linux/fcntl.h> /* O_ACCMODE */
#include <linux/cdev.h>
#include <asm/system.h>  /* cli(), *_flags */
#include <asm/uaccess.h> /* copy_*_user */

使用 memcpy 的函数:

static int dc_copy_to_user(char __user *buf, size_t count, loff_t *f_pos, 
        struct sv_data_dev *dev)
{
    char data[MAX_KEYLEN];
    size_t i = 0;

    /* Copy the bulk as long as there are 10 more bytes to copy */
    while (i < (count + MAX_KEYLEN)) {
        memcpy(data, &dev->data[*f_pos + i], MAX_KEYLEN);
        ec_block(dev->key, data, MAX_KEYLEN);
        if (copy_to_user(&buf[i], data, MAX_KEYLEN)) {
            return -EFAULT;
        }
        i += MAX_KEYLEN;
     }

     return 0;
 }

有人可以帮助我吗?我以为事情在 linux/string.h 中,但我得到的错误是一样的。我正在使用内核 2.6.37-rc1(我在用户模式 ​​linux 中进行操作,它仅从 2.6.37-rc1 开始工作)。任何帮助是极大的赞赏。

# Context dependent makefile that can be called directly and will invoke itself
# through the kernel module building system.
KERNELDIR=/usr/src/linux

ifneq ($(KERNELRELEASE),)

EXTRA_CFLAGS+=-I $(PWD) -ARCH=um
obj-m := main.o

else

KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD = $(shell pwd)

all:
 $(MAKE) V=1 ARCH=um -C $(KERNELDIR) M=$(PWD) modules

clean:
 rm -rf Module.symvers .*.cmd *.ko .*.o *.o *.mod.c .tmp_versions *.order

endif
4

7 回答 7

2

我在用户模式Linux中做

您可以尝试不使用用户模式 ​​Linux 吗?

内核不与 libc 链接,但 UML 是一个例外。这可以解释您的链接错误。

于 2011-01-04T20:51:05.570 回答
1

memcpy在lib/string.c中被定义为特定于架构的 (if __HAVE_ARCH_MEMCPY) 或通用版本。无论哪种情况,它都应该可用。查看/proc/kallsyms ,使用objdump检查您的模块,并验证符号版本控制没有搞砸。

于 2010-12-31T15:29:39.160 回答
1

第一点是这是一个链接错误而不是编译错误。实际上这是一个动态链接问题。尽管带有警告,但您的模块编译得很好。只有当你加载它时才会失败。所以这与头文件无关。第二点是 memcpy 在内核中被定义和广泛使用,所以没有理由找不到 memcpy 符号。

原因可能只是 GCC 本身的问题。GCC 使用内置函数,其中一些可能引用内核中不存在的 libgcc。如果是这种情况,可以通过使用编译器选项来解决-fno-builtin

于 2010-12-31T15:52:13.530 回答
0

memcpy 在您错过的 string.h 中定义。

于 2010-12-31T14:44:35.640 回答
0

让我发表这条评论作为答案,因为还有更多的空间可以写。

首先,“err 0”听起来很可疑。(因为 0 表示成功。)然后,您的 Makefile 有两条 KERNELDIR 行,后者是 ?=d,因此它可能无法执行您想要的操作。还有 CFLAGS="-ARCH=um" 听起来非常错误。-I$PWD 是多余的。也不需要 KERNELRELASE 检查。总的来说,它看起来过于复杂。使用这个更简单的 MF:

obj-m := main.o

KERNELDIR = /lib/modules/$(shell uname -r)/build

全部:模块

模块 modules_install 清洁:
        ${MAKE} V=1 ARCH=um -C ${KERNELDIR} M=$$PWD $@;
于 2010-12-31T15:07:25.393 回答
0

包括正确的string.h标题;

#include <linux/string.h>

如果您对此有编译错误,请改为发布。

于 2010-12-31T15:41:05.010 回答
0

问题可能出在EXTRA_CFLAGS声明上。-尝试删除包含和架构的额外空间,

EXTRA_CFLAGS+=-I$(PWD) ARCH=um
于 2011-01-04T19:46:44.367 回答