Search code examples
clinux-device-driverkbuild

ERROR: "func" [drivers/bluetooth/hci_uart.ko] undefined


I have a large repository that I want to modify. The part I'm working on is basically a linux kernel with some modifications. The simplified file structure looks like this:

├── asm
│   ├── mytee.h
├── kernel
│   ├── mytee.S
├── drivers
│   ├── bluetooth
|   |   ├── hci_uart.h
|   |   ├── hci_h4.c
│   ├── video
|   |   ├── fbmem.c

mytee.h declares some functions which are implemented in mytee.S in the following way:

ENTRY(func)
// assembly code
ENDPROC(func)

If I want to use them in hci_h4.c, I get the following error: ERROR: "func" [drivers/bluetooth/hci_uart.ko] undefined! hci_uart.ko is the header file to hci_h4.c.

These functions are however already successfully used in fbmem.c and without my changes the whole repository compiles. So my guess is, something goes wrong during the linking process. The Code is compiled using Kbuild Makefiles and since it is quite large, it uses multiple layers of them.

The relevant lines of both makefiles look like this:

obj-$(CONFIG_FB)                  += fb.o
fb-y                              := fbmem.o fbmon.o fbcmap.o fbsysfs.o \
                                     modedb.o fbcvt.o
fb-objs                           := $(fb-y)

What I have already tried:

  • func is defined
  • mytee.h is included in both hci_h4.c and fbmem.c
  • I don't see any relevant differences between the makefiles, Kbuild or Kconfig files of hci_h4.c and fbmem.c
  • There is no difference in the use of func
  • As far as I can tell fbmem.c and hci_h4.c are added to the makefile more or less at the same time (they are both added to drivers-y in the driver makefile), and more importantly after mytee.S
  • There are no files with the same name that could be confused with the relevant files

Additional questions which might be relevant:

  • How are c and assembly files linked? I don't see mytee.h and mytee.S referencing each other.
  • The functions take Hypercall arguments, how do they actually work?
  • mytee.h isn't listed in any makefile, does it even get compiled and if not why are the functions still declared?
  • hci_uart.ko appears in module.order but not in modules.builtin, fb.ko doesn't appear in module.order but in modules.builtin

Unfortunately I'm relatively new to c and makefiles, so there might be some mechanics which I don't understand. I can provide additional Information if needed.


Solution

  • Thanks to @0andriy who pointed me in the right direction.

    hci_uart.h gets compiled to a loadable module, you can see this in the .config file in the root directory. This means it can only call kernel functions if they are exported. You can see all of the exported functions in the file Module.symvers.

    I think the correct way to export them is using EXPORT_SYMBOL(func) from export.h in the file which implements func. But I couldn't get it to work in assembly, in c it worked fine for me.

    My solution was to rename mytee.S to myteeasm.S and add the file mytee.c with the following code:

    #include <linux/module.h>
    #include <asm/mytee.h>
    
    EXPORT_SYMBOL(func);
    

    and in the makefile change obj-$(CONFIG_MYTEE)+= mytee.o to obj-$(CONFIG_MYTEE)+= mytee.o myteeasm.o