This is probably a stupid question, but I looked for hours online and couldn't find an answer...
I'm writing a kernel module that also creates a character device. It compiles with no errors and warnings but when I try sudo insmod my_mod.ko I get:
insmod: error inserting 'my_mod.ko': -1 Unknown symbol in module
and when I try to look at dmesg I see:
my_mod: Unknown symbol __class_create (err 0)
my_mod: Unknown symbol device_create_file (err 0)
my_mod: Unknown symbol device_create (err 0)
I'm guessing that I missed an include but I can't find which...
What are the includes needed?
My includes are currently:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/ip.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/cdev.h>
#include <linux/fs.h>
The function __class_create is exported only for GPL modules (exported with EXPORT_SYMBOL_GPL). So, you need to use a GPL license with MODULE_LICENSE macro to make use of that function. Same goes for other functions as well.
This should do the trick:
MODULE_LICENSE("GPL");
To learn about what exporting is, take a look at here. Basically, dynamic modules do not have access to variables and functions in kernel, and kernel needs to specify what to export, to enable access. That's the purpose of EXPORT_SYMBOL and EXPORT_SYMBOL_GPL macros, which are used everywhere.
And the difference between EXPORT_SYMBOL and EXPORT_SYMBOL_GPL is that the latter only reveals the function or the variable if the module is GPL licensed.
Related
I keep getting a group of errors when I run my code as follows:
LNK 2001 unresolved external symbol IID_IMediaEvent
LNK 2001 unresolved external symbol IID_IMediaControl
LNK 2001 unresolved external symbol IID_IGraphBuilder
LNK 2001 unresolved external symbol CLSID_FilterGraph
My code is here:
#include <dshow.h>
#include <stdio.h>
#include <Windows.h>
void main(void)
{
HRESULT hr = CoInitialize(NULL);
if (FAILED(hr))
{
printf("FAIL");
}
else
{
printf("PASS");
}
IGraphBuilder *pGraph=NULL;
hr=CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,&IID_IGraphBuilder, (void **)&pGraph);
if (FAILED(hr))
{
printf("ERROR - Could not create the Filter Graph Manager.");
return;
}
IMediaControl *pControl=NULL;
IMediaEvent *pEvent=NULL;
hr = pGraph->lpVtbl->QueryInterface(pGraph,&IID_IMediaControl, (void**)&pControl);
hr = pGraph->lpVtbl->QueryInterface(pGraph,&IID_IMediaEvent, (void**)&pEvent);
hr = pGraph->lpVtbl->RenderFile(pGraph,L"C:/Users/User/Desktop/AudioPlayer/trn.wav", NULL);
hr = pControl->lpVtbl->Run(pControl);
long evCode = 0;
pEvent->lpVtbl->WaitForCompletion(pEvent,INFINITE, &evCode);
pControl->lpVtbl->Release(pControl);
pEvent->lpVtbl->Release(pEvent);
pGraph->lpVtbl->Release(pGraph);
CoUninitialize();
}
I have been searching for around two weeks trying to find an answer, but to no help. I think its something to do with linkers, but I have no idea on what I'm doing wrong because I'm fairly new to C and Visual Studio.
The core issue here is that the interface (IID) and class (CLSID) IDs are declared, but not defined. The compiler happily proceeds, delegating the ID lookup to the linker. Since the IDs aren't defined nor exported by any of the supplied import libraries, the linker gives up with an LNK2001 error.
To resolve the issue there are two options: Either have the header files also define the IDs, or pass the import library (strmiids.lib) that exports them to the linker.
The first option has the advantage of working with any compiler. It requires an #include <initguid.h> directive ahead of including any header file that would otherwise merely declare the IDs. <initguid.h> does two things: It defines the INITGUID preprocessor symbol, and subsequently includes <guiddef.h>. It is the latter that changes the preprocessor symbols to define the respective IDs, properly marked as __declspec(selectany) to prevent multiply-defined symbol linker errors.
#include <initguid.h>
#include <dshow.h>
#include <stdio.h>
#include <Windows.h>
...
This should resolve all linker errors.
The other option is to pass the import library strmiids.lib to the linker. This can be done in source code using a #pragma comment(lib, "strmiids") directive, or by passing the import library on the linker command line.
The downside of this is that it needs to be toolchain-specific: Only MSVC and Clang support #pragma comment(lib, ...), and Clang and GCC use different naming for import libraries (libfoo vs. foo.lib). Unless you have a specific reason to use the import library you should go with the first option.
Aside: Since #include <initguid.h> works for any scenario, why do we have options? And why do we need the <initguid.h> toggle at all?
This is probably down to historic events, from a time before the __declspec(selectany) modifier was introduced (Visual Studio 2012). Prior to that, every symbol could be defined at most once. If more than one compilation unit defined the same symbol, the linker would generate a LNK2005, and ultimately fail to produce an artifact.
In those times, client code would generally have a single (usually otherwise empty) compilation unit that had an #include <initguid.h> directive, followed by other headers that declared (and defined) the IDs. The remaining compilation units merely included the header files to declare the IDs, without the <initguid.h> toggle.
After the __declspec(selectany) modifier was introduced, symbols (such as the IDs) could be defined any number of times, so long as the definitions are identical (which the SDK ensures). So today, you can simply #include <initguid.h> in every compilation unit, and things work just fine.
At least that's my interpretation of history derived from a look into the <guiddef.h> file of the Windows SDK.
I tried to redo the code of the kernel module found in this topic How can I obtain battery level inside a Linux kernel module?. But when I try to use the functions contained in the power_supply.h header file, the loading of the module fails because it does not recognize the power_supply_get_by_name function.
Here is the code that I am using on Ubuntu 18.04 with kernel version 4.15.0-101-generic:
#include <linux/module.h>
#include <linux/power_supply.h>
static int __init test_init (void)
{
struct power_supply *psy;
char name[] = "BAT1";
psy = power_supply_get_by_name(name);
printk(KERN_DEBUG "Test module inserted");
return 0;
}
static void __exit test_exit (void)
{
printk(KERN_DEBUG "Test module removed");
}
module_init (test_init);
module_exit (test_exit);
I get no error at compiling except a warning concerning the module license which is I think not related to my problem but I get the following errors:
when running insmod in the terminal: "insmod: ERROR: could not insert module test.ko: Unknown symbol in module"
in the /var/log/kern.log file: "test: Unknown symbol power_supply_get_by_name (err 0)"
I checked the kallsyms proc file and the function is indicated as usable in other kernel modules if I understood well this topic What is the difference between T and t in /proc/kallsyms. Here is the output from reading the kallsyms file:
ffffffff8e9bd270 T power_supply_get_by_name
Does anyone knows why this is not working while I can use other linux headers functions without any problem and, if so, how I can fix my problem?
Thanks in advance
This may actually be related to the module license! If you look at the kernel source code, the function power_supply_get_by_name is exported here. You can see it's using EXPORT_SYMBOL_GPL. As this answer explains:
EXPORT_SYMBOL_GPL will show the symbol only in GPL-licensed modules
The use of this macro is controversial, but that's the way the project operates... To gain access to the symbols you need, you'll need to license your module as GPL:
MODULE_LICENSE("GPL");
I am currently writing a Linux Kernel Module (for the first time).
I am trying to use the stat function. I understand that regular imports are not going to work in Kernel code, so I imported their equivalent (that is what I thought...):
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/unistd.h>
I don't get any error about the imports directly, but I get the following messages:
error: implicit declaration of function ‘stat’ [-Werror=implicit-function-declaration]
error: ‘errno’ undeclared (first use in this function)
For the two lines respectively:
int ret = stat(pathname, statbuf);
and
errno = ENOENT;
Any help woule be welcome.
Thank you.
PS: I am working on Kali 4.9.0-kali4-amd64 but I am trying to write something generic, that could work on multiple versions of Linux.
I am programming in CCS (based on Eclipse) to learn to use microcontrollers.
I'm having some problems with includes.
I have 4 files:
GPIO.h - macros and prototypes of GPIO functions
GPIO.c - implementation of GPIO functions declared in GPIO.h
main.c - main program
util.h - macros and typedefs essential to all other files
In each of the programs put the includes, I ctrl + c / ctrl + v of my code:
I really try with " ", I would like to make my code run, it would be rewarding.
GPIO.h - #include "util.h"
GPIO.c - #include "GPIO.h"
main.c - #include "GPIO.c"
util.h - (no includes)
As in eclipse all files are placed in the project folder. Already checked manually by accessing the folder, and they are there.
When I compile and run, there are 2 errors referring to include:
"../GPIO.c", Line 9: fatal error # 1965: Can not open source file "GPIO.h"
"../main.c", Line 1: fatal error # 1965: Can not open source file "GPIO.c"
I do not understand what's wrong!
I made the edit so that people understand that even with "" the error continues (# mame98). I made it clear that I am using the CCS IDE based on Eclipse and now my suspicion is with the operating system. I will have the opportunity to test on Windows only now.
You should only include H files as Eugene Sh. Points out... Also, use #include "util.h" and #include "gpio.h" as they are local files and they are not in the default search path of your compiler. If you want to include 'global' headers (which are in the search path) you have to use #include <file.h>.
Maybe also note, that it is possible to add your local folder to the search path with using the -I. option for GCC (should work with other compilers too).
For more infos about the search path, see here.
<> is for libraries like #include <stdio.h>
"" is used for your own files #include "GPIO.h"
Be careful including .c! If GPIO.h is included in GPIO.c, too, you could get errors..(multiple inclusion protection is useful here!)
I'm writing an API as a kernel module that provides device drivers with various functions. I wrote three functions in mycode.c. I then built and loaded the module, then copied mycode.h into < kernel >/include/linux. In a device driver, I have a #include < linux/mycode.h > and call those three functions. But when I build the driver module, I get three linker warnings saying that those functions are undefined.
Notes:
The functions are declared extern in mycode.h
The functions are exported using EXPORT_SYMBOL(func_name) in mycode.c
Running the command nm mycode.ko shows all three functions as being available in the symbol table (capital T next to them, meaning the symbols are found in the text (code) section)
After loading the module, the command grep func_name /proc/kallsyms shows all three functions as being loaded
So clearly the functions are being exported correctly and the kernel knows what and where they are. So why can't the driver see their definitions? Any idea what am I missing?
EDIT: I found some information about this here: http://www.kernel.org/doc/Documentation/kbuild/modules.txt
Sometimes, an external module uses exported symbols from another
external module. kbuild needs to have full knowledge of all symbols
to avoid spitting out warnings about undefined symbols. Three
solutions exist for this situation.
NOTE: The method with a top-level kbuild file is recommended but may
be impractical in certain situations.
Use a top-level kbuild file If you have two modules, foo.ko and
bar.ko, where foo.ko needs symbols from bar.ko, you can use a
common top-level kbuild file so both modules are compiled in the
same build. Consider the following directory layout:
./foo/ <= contains foo.ko
./bar/ <= contains bar.ko
The top-level kbuild file would then look like:
#./Kbuild (or ./Makefile):
obj-y := foo/ bar/
And executing
$ make -C $KDIR M=$PWD
will then do the expected and compile both modules with full
knowledge of symbols from either module.
Use an extra Module.symvers file When an external module is built,
a Module.symvers file is generated containing all exported symbols
which are not defined in the kernel. To get access to symbols from
bar.ko, copy the Module.symvers file from the compilation of bar.ko
to the directory where foo.ko is built. During the module build,
kbuild will read the Module.symvers file in the directory of the
external module, and when the build is finished, a new
Module.symvers file is created containing the sum of all symbols
defined and not part of the kernel.
Use "make" variable KBUILD_EXTRA_SYMBOLS If it is impractical to
copy Module.symvers from another module, you can assign a space
separated list of files to KBUILD_EXTRA_SYMBOLS in your build file.
These files will be loaded by modpost during the initialization of
its symbol tables.
But with all three of these solutions, in order for any driver to use my API, it would have to either create a new Makefile or have direct access to my Module.symvers file? That seems a bit inconvenient. I was hoping they'd just be able to #include my header file and be good to go. Do no other alternatives exist?
From my research, it seems that those are the only three ways to handle this situation, and I've gotten each of them to work, so I think I'll just pick my favorite out of those.
Minimal QEMU + Buildroot example
I have tested the following in a fully reproducible QEMU + Buildroot environment, so maybe having this working version version will help you find out what is wong with your code.
GitHub upstream is centered on the files:
dep.c
dep2.c
Makefile
dep.c
#include <linux/delay.h> /* usleep_range */
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/module.h>
MODULE_LICENSE("GPL");
int lkmc_dep = 0;
EXPORT_SYMBOL(lkmc_dep);
static struct task_struct *kthread;
static int work_func(void *data)
{
while (!kthread_should_stop()) {
printk(KERN_INFO "%d\n", lkmc_dep);
usleep_range(1000000, 1000001);
}
return 0;
}
static int myinit(void)
{
kthread = kthread_create(work_func, NULL, "mykthread");
wake_up_process(kthread);
return 0;
}
static void myexit(void)
{
kthread_stop(kthread);
}
module_init(myinit)
module_exit(myexit)
dep2.c
#include <linux/delay.h> /* usleep_range */
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/module.h>
MODULE_LICENSE("GPL");
extern int lkmc_dep;
static struct task_struct *kthread;
static int work_func(void *data)
{
while (!kthread_should_stop()) {
usleep_range(1000000, 1000001);
lkmc_dep++;
}
return 0;
}
static int myinit(void)
{
kthread = kthread_create(work_func, NULL, "mykthread");
wake_up_process(kthread);
return 0;
}
static void myexit(void)
{
kthread_stop(kthread);
}
module_init(myinit)
module_exit(myexit)
And now you can do:
insmod dep.ko
insmod dep2.ko
With that Buildroot setup, things are already configuring depmod /lib/module/*/depmod with the dependency, so just this is enough to load both:
modprobe dep
Also, if you built your kernel with CONFIG_KALLSYMS_ALL=y, then the exported symbol can be seen with:
grep lkmc_dep /proc/kallsyms
see also: Does kallsyms have all the symbol of kernel functions?
OK: You have one module where the function is and one place what wants to import it right?
You must use "EXPORT_SYMBOL("name of the function") such as foo in the place where the function is. So in the "c" file have the function "foo" defined and put in:
EXPORT_SYMBOL(foo)
Make sure you have the prototype for "foo" in a common header file (you can have it in separate places for each module and it will work but you are asking for trouble if the signatures change). So say: void foo(void *arg);
Then the other module that wants it just invoke "foo" and you are good.
Also: Make sure that you load the module with foo first. If you have cross dependencies like module2 needs foo from module1 and module1 needs bar from module2 you need to have one register functions with another. If you want to know please ask a separate Q.