7

I'm trying to write a Linux device driver. I've got it to work really well, until I tried to use "memcpy". I don't even get a compiler error, when I "make" it just warns me:

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

OK and when I try to load via insmod, I get on the console:

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

and on dmesg:

main: Unknown symbol memcpy (err 0)

I include the following:

#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 */

The function using 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;
 }

Could someone help me? I thought the thing was in linux/string.h, but I get the error just the same. I'm using kernel 2.6.37-rc1 (I'm doing in in user-mode-linux, which works only since 2.6.37-rc1). Any help is greatly appreciated.

# 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
Fred Foo
  • 355,277
  • 75
  • 744
  • 836
Hinton
  • 2,320
  • 4
  • 26
  • 32
  • 1
    I think you are missing `#include `... obviously unless one of the linux headers already includes it :p – Machinarius Dec 31 '10 at 14:38
  • 4
    @Drknezz it doesn't and that's because you can't use it. The kernel isn't a hosted environment and there is no stdio. And the code doesn't include stdio so there's also no *reason* to include it. – hobbs Dec 31 '10 at 14:50
  • @Hinton that's a linking error, not a compilation error. How are you building your module? – hobbs Dec 31 '10 at 14:53
  • @hobbs Oh sorry then. I know nothing about linux kernel driver development, just thought of a generic solution ;) – Machinarius Dec 31 '10 at 14:53
  • @hobbs I've edited my question to include the makefile; does that help? oddly enough, I've built the module about 300 times before this memcpy stuff and it worked – Hinton Dec 31 '10 at 14:58
  • on the `EXTRA_CFLAGS` line, should `-ARCH=um` be `-DARCH=um` ? – hobbs Dec 31 '10 at 15:06
  • 2
    Why is this question tagged c++? – Fred Foo Dec 31 '10 at 15:14
  • @larsman: I didn't do it – Hinton Dec 31 '10 at 15:20
  • @Hinton, changed it to `c`. I was afraid for a moment you were writing a Linux kernel module in C++ (which might have explained the linker errors, though). – Fred Foo Dec 31 '10 at 15:22

7 Answers7

2

I'm doing it in user-mode-linux

Could you try without User-mode Linux?

The kernel does not link with the libc but UML is an exception. That could explain your linking error.

Christophe Vu-Brugier
  • 2,645
  • 26
  • 21
  • Yes, you were definitely right about the UML, but: The problem solved itself today (without my help). Memcpy just seems to work... The only reason I see for this is that: This is a college project, and Lead compiles the UML for us. I'm quite sure they messed something up some days ago and fixed it now; thanks for the answer. The only thing I can recommend now is compiling the UML for yourself and doing it properly. – Hinton Jan 05 '11 at 08:01
1

memcpy is either defined as arch specific (if __HAVE_ARCH_MEMCPY) or as a generic version in lib/string.c. In either case, it should be available. Look in /proc/kallsyms, check your module with objdump and also verify symbol versioning isn't messing things up.

Jester
  • 56,577
  • 4
  • 81
  • 125
1

The first point is that this is a linking error and not a compile error. In fact it is a dynamic link problem. You module compiles fine albeit with a warning. It is only when you load it that this fails. So this has nothing to do with header files. The second point is that memcpy is defined and used extensively in the kernel so the so there is no reason why the memcpy symbol is not being found.

The reason could simply be a problem with GCC itself. GCC uses builtin functions of which some may refer to libgcc which is not present in the kernel. If this is the case, this can be solved by using the compiler option -fno-builtin

doron
  • 27,972
  • 12
  • 65
  • 103
  • If any options were needed, they would have already been added in the kernel makefiles. Speaking of which, some arch makefiles already add `-fno-builtin-memcpy` sometimes. – user502515 Dec 31 '10 at 19:14
0

memcpy is defined in string.h which you missed to include.

Emil Vikström
  • 90,431
  • 16
  • 141
  • 175
  • 1
    In the kernel, I cannot just include string.h; I tried it with linux/string.h which may be used in the kernel, but that didn't work... I should have got a compiler error/warning anyway instead of this build system error if something was wrong with the includes – Hinton Dec 31 '10 at 14:55
0

Let me post this comment as an answer, because there's more room to write.

First, "err 0" sound suspicious. (Because 0 is success.) Then, your Makefile has two KERNELDIR lines, the latter of which is ?=d, so it might not do what you want. There is also CFLAGS="-ARCH=um" which sounds so terribly wrong. -I$PWD is redundant. The KERNELRELASE check is not needed either. In total, it looks overly convoluted. Use this much simpler MF:

obj-m := main.o

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

all: modules

modules modules_install clean:
        ${MAKE} V=1 ARCH=um -C ${KERNELDIR} M=$$PWD $@;
user502515
  • 4,346
  • 24
  • 20
0

Include the right string.hheader;

#include <linux/string.h>

If you have a compile error with this, post that instead.

ismail
  • 46,010
  • 9
  • 86
  • 95
  • Yes because its not including the right header, Hinton claims `linux/string.h` gives a compile error and I am asking for that. – ismail Dec 31 '10 at 16:03
0

The issue might be with the EXTRA_CFLAGS declaration. Try removing the extra space for the include and the - for the architecture, i.e. :

EXTRA_CFLAGS+=-I$(PWD) ARCH=um
ctuffli
  • 3,559
  • 4
  • 31
  • 43