How do I link a static library when building a kernel module? - linux

I want to build a Linux kernel module foo.ko from an existing file foo.c and a static library support.a. The library support.a is compiled from Rust so there is no support.c.
I've used the following Makefile
KERNEL_DIR := /lib/modules/$(shell uname -r)/build
obj-m += foo.o
foo-obs += support.a
all:
$(MAKE) -C $(KERNEL_DIR) SUBDIRS=$(PWD) modules V=1
It seems that support.a is not linked; there are warnings that the functions called from foo.c (and implemented in support.a) are undefined.
Update 0: the Makefile works on Ubuntu LTS (I've tested on 18.04 and 14.04) but not on Fedora (both 29/30). The output in case of Fedora is:
...
make -C /lib/modules/5.1.11-200.fc29.x86_64/build SUBDIRS=/public/Github/rustyvisor modules
make[1] : on entre dans le répertoire « /usr/src/kernels/5.1.11-200.fc29.x86_64 »
Makefile:205: ================= WARNING ================
Makefile:206: 'SUBDIRS' will be removed after Linux 5.3
Makefile:207: Please use 'M=' or 'KBUILD_EXTMOD' instead
Makefile:208: ==========================================
LD [M] /public/Github/rustyvisor/rustyvisor.o
Building modules, stage 2.
MODPOST 1 modules
WARNING: /public/Github/rustyvisor/rustyvisor.o(.init.text+0xbb): Section mismatch in reference from the function init_module() to the function .exit.text:rustyvisor_exit()
The function __init init_module() references
a function __exit rustyvisor_exit().
This is often seen when error handling in the init function
uses functionality in the exit path.
The fix is often to remove the __exit annotation of
rustyvisor_exit() so it may be used outside an exit section.
WARNING: "rustyvisor_core_unload" [/public/Github/rustyvisor/rustyvisor.ko] undefined!
WARNING: "rustyvisor_load" [/public/Github/rustyvisor/rustyvisor.ko] undefined!
WARNING: "rustyvisor_core_load" [/public/Github/rustyvisor/rustyvisor.ko] undefined!
WARNING: "rustyvisor_unload" [/public/Github/rustyvisor/rustyvisor.ko] undefined!
LD [M] /public/Github/rustyvisor/rustyvisor.ko
make[1] : on quitte le répertoire « /usr/src/kernels/5.1.11-200.fc29.x86_64 »
Update 1: There is very similar question but this question is to ask why the Makefile doesn't work on Fedora but I discovered that it works on Ubuntu.

Finally, I found a workaround for the problem (but I still don't understand why). On Fedora, the library name support.a should be changed to support.o, then the linker works!!!

Related

-Wimplicit-function-declaration while make module qmi_wwan

my Makefile:
obj-m += qmi_wwan.o
CFLAGS += -Werror -Wno-implicit-function-declaration
all:
make -C /lib/modules/5.10.103-v7l+/build M=$(PWD) modules
clean:
make -C /lib/modules/5.10.103-v7l+/build M=$(PWD) clean
Error i get while compiling:
warning: implicit declaration of function ‘dev_sw_netstats_tx_add’; did you mean ‘dev_sw_netstats_rx_add’? [-Wimplicit-function-declaration]
warning: implicit declaration of function ‘dev_addr_mod’; did you mean ‘dev_addr_add’? [-Wimplicit-function-declaration]
Additional informations:
I'm configuring qmi_wwan module to add Quectel RM520N as it was explained -> in this thread
Thanks in advance for any help.
Problem solved. I was compiling qmi_wwan from kernel 5.15.y on my current kernel 5.10.y, that's why I've got this error.
After compiling qmi_wwan driver from 5.10.y, the problem disappeared.

"Unknown symbol" from kernel module (dm9601 driver), does this require a rebuild of the kernel?

This is for a router running kernel version 2.6.21.5.
I am using the official (netgear) source tree and toolchain.
I have compiled the dm9601.c driver (from the source tree) using the toolchain, but after inserting the module dmesg prints:
dm9601: Unknown symbol mii_link_ok
dm9601: Unknown symbol bitrev32
dm9601: Unknown symbol mii_check_media
dm9601: Unknown symbol usbnet_get_settings
dm9601: Unknown symbol crc32_le
dm9601: Unknown symbol mii_nway_restart
dm9601: Unknown symbol usbnet_nway_reset
dm9601: Unknown symbol generic_mii_ioctl
dm9601: Unknown symbol usbnet_set_settings
dm9601: Unknown symbol mii_ethtool_gset
Referencing (it seems)
./lib/crc32.c
./lib/bitrev.c
./drivers/net/mii.c
./drivers/usb/net/usbnet.c
Is there some way to tell if these missing dependencies requires a rebuild of the kernel. Or can I load them with the driver?
Makefile:
obj-m += dm9601.o
all:
make -C /home/chris/DGND3300_V1.1.00.41_NA_src M=$(PWD) modules
clean:
make -C /home/chris/DGND3300_V1.1.00.41_NA_src M=$(PWD) clean
Make command:
make ARCH=mips CROSS_COMPILE="/home/chris/EVG2000_v2.2.0.12_with_toolchain_src/uclibc-crosstools-gcc-4.2.3-3/usr/bin/mips-linux-uclibc-"
Updated Makefile with missing modules:
obj-m += crc32.o
obj-m += bitrev.o
obj-m += mii.o
obj-m += usbnet.o
obj-m += dm9601.o
all:
make -C /home/chris/messabout3/DGND3300_V1.1.00.41_NA_src/kernel/linux M=$(PWD) modules
clean:
make -C /home/chris/messabout3/DGND3300_V1.1.00.41_NA_src/kernel/linux M=$(PWD) clean
First check, if the symbols are part of kernel symbols list,
for ex: cat /proc/kallsyms | grep mii_link_ok
If symbols are not present, then those symbols need to be exported using EXPORT_SYMBOL() or EXPORT_SYMBOL_GPL().
If symbols are present try one of the below,
Include **KBUILD_EXTRA_SYMBOLS=<"absolute path to the Module.symvers of the kernel module which is exporting function or variable"> in the Makefile of the kernel module which will use exported function or variable, in your case dm9601 Makefile.
for ex: KBUILD_EXTRA_SYMBOLS := absolute_path_to_Module.symvers_of_mii
EXPORT_SYMBOL in kernel module | undefined symbol during insmod
List item
Unknown symbol in while loading a kernel module
Hope this will solve the issue!.

Dynamic linking failing on linux/powerpc

I have a Xilinx FPGA running a soft processor (PowerPC). I recently cross compiled Boost libraries for PowerPC and wanted to test it. So I used one of the sample programs and tried to cross compile it for my target. Below is the code
#include <boost/thread/thread.hpp>
void helloworld()
{
printf( "Hello World!");
}
int main()
{
boost::thread thrd(&helloworld);
thrd.join();
}
Below is my make file
CPP=ppc_4xx-g++
CFLAGS=-c -g -Wall
LDFLAGS_PowerPC=-L/shared/deps/powerpc/lib -L/opt/ELDK/4.2/ppc_4xx/lib/
LIBS_PowerPC=-lboost_thread -lboost_system -lpthread -lrt
INCLUDES=-I. -I./4.2.2/ -I./include -I/opt/ELDK/4.2/ppc_4xx/usr/include/
CPPFLAGS_PowerPC=-I/shared/deps/common/include
CPPFLAGS_COMMON=-I/shared/deps/powerpc/include
CPPFLAGS=$(CPPFLAGS_COMMON) $(CPPFLAGS_PowerPC)
all: helloworld
helloworld: helloworld.o
$(CPP) $(LDFLAGS_PowerPC) $(LIBS_PowerPC) helloworld.o -o helloworld
helloworld.o: helloworld.cpp
$(CPP) $(CFLAGS) $(CPPFLAGS) $(INCLUDES) helloworld.cpp
clean:
rm -rf *.o helloWorld
I was able to generate the binaries but when I run the program on my target I get the below error
-/bin/sh: ./helloworld: not found
I checked online and found that the above problem comes when we have dynamic linking. My Boost libraries are present in the location /shared/deps/powerpc/lib and I have set the variable LD_LIBRARY_PATH accordingly using the below command.
export LD_LIBRARY_PATH=/shared/deps/powerpc/lib/:/opt/ELDK/4.2/ppc_4xx/lib/
But even then I get the same problem.
Below is the output of uname -ars
Linux (none) 3.0.0-14.1-build3+ #23 PREEMPT Thu Jan 3 18:44:27 CST 2013 ppc GNU/Linux
I don't have ldd installed on my target so I can't check the dynamic dependencies. But I am sure that, libraries are included. How can I proceed ?
Even though my embedded Linux system had a dynamic linker, it was not working. The problem was resolved when I used a dynamic linker provided with my tool chain and replaced it the correct directory. Now dynamic linking is fine.

cmake fortran undefined reference to MAIN__ on linux

I trying to get a cmake build system working on linux. The project contains a bunch of executables and two libraries. One of the executables is first built as a library, then that library is linked with the object file containing the man subroutine. This was done because the rest of the executables depend on that library. The tricky part is that the main subroutine is defined inside a module that the rest of sources depend on so this needs to be compiled before the rest of the sources. The effect is that the main subroutine gets added to the resulting library. This seems to work fine on Mac OS X but, the linking state fails on Linux.
The cmake file for the failing part looks like
cmake_minimum_required (VERSION 2.8)
# Create an empty variable to hold all the source files.
set (vmec_sources "")
# Add subdirectory for all the sources.
add_subdirectory (Sources)
add_library (vmec STATIC ${vmec_sources})
add_dependencies (vmec stell)
# Define an executable and link all libraries.
add_executable (xvmec ${CMAKE_CURRENT_SOURCE_DIR}/Sources/General/vmec_main.f)
add_dependencies (xvmec vmec)
target_link_libraries (xvmec vmec stell)
if ((NOT ${NETCDF_C} STREQUAL "") AND (NOT ${NETCDF_F} STREQUAL ""))
target_link_libraries (xvmec ${NETCDF_C} ${NETCDF_F})
endif ()
When running cmake, everything configures fine and generates a make file when I run make Mac OS X everything works fine. When I run make on Linux it fails.
The output from the make VERBOSE=1 On Linux produces
Linking Fortran executable ../build/bin/xvmec
cd /home/user/reconstruction/VMEC2000 && /usr/bin/cmake -E cmake_link_script CMakeFiles/xvmec.dir/link.txt --verbose=1
/usr/bin/gfortran -cpp -D NETCDF -I /usr/include CMakeFiles/xvmec.dir/Sources/General/vmec_main.f.o -o ../build/bin/xvmec -rdynamic ../build/lib/libvmec.a ../build/lib/libstell.a /usr/lib/libnetcdf.so /usr/lib/libnetcdff.so
/usr/lib/gcc/x86_64-linux-gnu/4.4.3/libgfortranbegin.a(fmain.o): In function `main':
(.text+0x26): undefined reference to `MAIN__'
collect2: ld returned 1 exit status
make[2]: *** [build/bin/xvmec] Error 1
make[2]: Leaving directory `/home/user/reconstruction'
make[1]: *** [VMEC2000/CMakeFiles/xvmec.dir/all] Error 2
make[1]: Leaving directory `/home/user/reconstruction'
make: *** [all] Error 2
On Mac OS X, I get
Linking Fortran executable ../build/bin/xvmec
cd /Users/user/repo/trunk/VMEC2000 && "/Applications/CMake 2.8-8.app/Contents/bin/cmake" -E cmake_link_script CMakeFiles/xvmec.dir/link.txt --verbose=1
/usr/local/bin/gfortran -framework Accelerate -cpp -D DARWIN -D NETCDF -I /Users/user/NetCDF/include -O3 -ftree-vectorize -m64 -march=native -fomit-frame-pointer -falign-functions -mfpmath=sse CMakeFiles/xvmec.dir/Sources/General/vmec_main.f.o -o ../build/bin/xvmec ../build/lib/libvmec.a ../build/lib/libstell.a /Users/user/NetCDF/lib/libnetcdf.dylib /Users/user/NetCDF/lib/libnetcdff.dylib
"/Applications/CMake 2.8-8.app/Contents/bin/cmake" -E cmake_progress_report /Users/user/repo/trunk/CMakeFiles 100
[100%] Built target xvmec
The link line looks like it is linking all the same stuff in the correct order so I don't understand why this is failing on Linux.
Turns out I had the wrong file listed as containing the main method. It seems that later versions of gfortran can link 'MAIN__' from a inside a library while gfortran-4.4 cannot.

building "out of the source tree" kernel module

I'm building a sample kernel module under linux . The module sources are "out of the kernel tree". I've got kernel source tree from git. But it takes time to configure the kernel. So at this moment i'm just trying to build the module against kernel headers provided by my Distribution.
My Makefile :
KVERSION=$(shell uname -r)
PWD := $(shell pwd)
all:
make -C /lib/modules/$(KVERSION)/build/ M=$(PWD) modules
clean:
make -C /lib/modules/$(KVERSION)/build M=$(PWD) clean
$(info Building with KERNELRELEASE = ${KERNELRELEASE})
obj-m := hello.o
But make stops with reporting that i could not find etc, that means it could not find the headers.
but the files are there :
$ls /lib/modules/$(uname -r)/build
$arch block crypto drivers firmware fs include init ipc kernel lib Makefile Makefile.common mm Module.symvers net samples scripts security sound System.map tools usr virt
I guess its a trivial problem. But still i could not find the solution.
Thanks in advance.
EDIT: Errors :
Building with KERNELRELEASE =
make -C /lib/modules/2.6.32-220.el6.x86_64/build/ M=/usr/local/src/kernel_mods
make[1]: Entering directory `/usr/src/kernels/2.6.32-220.el6.x86_64'
Building with KERNELRELEASE = 2.6.32-220.el6.x86_64
LD /usr/local/src/kernel_mods/built-in.o
CC [M] /usr/local/src/kernel_mods/hello.o
/usr/local/src/kernel_mods/hello.c:2:27: error: linux/modules.h: No such file or directory
/usr/local/src/kernel_mods/hello.c:21: error: expected declaration specifiers or â...â before string constant
/usr/local/src/kernel_mods/hello.c:21: warning: data definition has no type or storage class
/usr/local/src/kernel_mods/hello.c:21: warning: type defaults to âintâ in declaration of âMODULE_LICENSEâ
/usr/local/src/kernel_mods/hello.c:21: warning: function declaration isnât a prototype
/usr/local/src/kernel_mods/hello.c:22: error: expected declaration specifiers or â...â before string constant
/usr/local/src/kernel_mods/hello.c:22: warning: data definition has no type or storage class
/usr/local/src/kernel_mods/hello.c:22: warning: type defaults to âintâ in declaration of âMODULE_AUTHORâ
/usr/local/src/kernel_mods/hello.c:22: warning: function declaration isnât a prototype
/usr/local/src/kernel_mods/hello.c:23: error: expected declaration specifiers or â...â before string constant
/usr/local/src/kernel_mods/hello.c:23: warning: data definition has no type or storage class
/usr/local/src/kernel_mods/hello.c:23: warning: type defaults to âintâ in declaration of âMODULE_DESCRIPTIONâ
/usr/local/src/kernel_mods/hello.c:23: warning: function declaration isnât a prototype
make[2]: *** [/usr/local/src/kernel_mods/hello.o] Error 1
make[1]: *** [_module_/usr/local/src/kernel_mods] Error 2
make[1]: Leaving directory `/usr/src/kernels/2.6.32-220.el6.x86_64'
make: *** [all] Error 2
I think you meant to do
#include <linux/module.h>
rather than
#include <linux/modules.h>

Resources